blob: 4fef0f2d3f568e9bb99f84dee9bfecf526fbdcbe [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 */
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000045#define DEBUG 0
Eric Andersen2870d962001-07-02 17:27:21 +000046
Eric Andersen2870d962001-07-02 17:27:21 +000047
Eric Andersen5bb16772001-09-06 18:00:41 +000048#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000049
Eric Andersenc470f442003-07-28 09:56:35 +000050#define PROFILE 0
51
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000052#include "busybox.h"
53
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000054#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +000055#define _GNU_SOURCE
56#endif
57
58#include <sys/types.h>
Eric Andersenc470f442003-07-28 09:56:35 +000059#include <sys/ioctl.h>
60#include <sys/param.h>
61#include <sys/resource.h>
62#include <sys/stat.h>
Eric Andersenc470f442003-07-28 09:56:35 +000063#include <sys/wait.h>
64
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <unistd.h>
69
70#include <stdarg.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000071#include <stddef.h>
Eric Andersenc470f442003-07-28 09:56:35 +000072#include <assert.h>
Eric Andersencb57d552001-06-28 07:25:16 +000073#include <ctype.h>
74#include <dirent.h>
75#include <errno.h>
76#include <fcntl.h>
77#include <limits.h>
78#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000079#include <setjmp.h>
80#include <signal.h>
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000081/*#include <stdint.h>*/
Eric Andersenef02f822004-03-11 13:34:24 +000082#include <time.h>
Eric Andersenc470f442003-07-28 09:56:35 +000083#include <fnmatch.h>
Eric Andersenc470f442003-07-28 09:56:35 +000084
Eric Andersend35c5df2002-01-09 15:37:36 +000085#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000086#define JOBS 1
87#else
Eric Andersenca162042003-07-29 07:15:17 +000088#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +000089#endif
90
Paul Fox02eb9342005-09-07 16:56:02 +000091#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
Eric Andersencb57d552001-06-28 07:25:16 +000092#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +000093#endif
94
Eric Andersen2870d962001-07-02 17:27:21 +000095#include "cmdedit.h"
96
Eric Andersenc470f442003-07-28 09:56:35 +000097#ifdef __GLIBC__
98/* glibc sucks */
99static int *dash_errno;
100#undef errno
101#define errno (*dash_errno)
102#endif
103
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000104#if defined(__uClinux__)
105#error "Do not even bother, ash will not run on uClinux"
106#endif
107
Denis Vlasenkoa7189f02006-11-17 20:29:00 +0000108#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +0000109#define _DIAGASSERT(assert_expr) assert(assert_expr)
110#else
111#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000112#endif
113
Eric Andersen2870d962001-07-02 17:27:21 +0000114
Eric Andersenc470f442003-07-28 09:56:35 +0000115#ifdef CONFIG_ASH_ALIAS
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000116/* alias.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000117
118#define ALIASINUSE 1
119#define ALIASDEAD 2
120
121struct alias {
122 struct alias *next;
123 char *name;
124 char *val;
125 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000126};
127
Eric Andersenc470f442003-07-28 09:56:35 +0000128static struct alias *lookupalias(const char *, int);
129static int aliascmd(int, char **);
130static int unaliascmd(int, char **);
131static void rmaliases(void);
132static int unalias(const char *);
133static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000134#endif
135
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000136/* cd.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000137
138
139static void setpwd(const char *, int);
140
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000141/* error.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000142
143
144/*
145 * Types of operations (passed to the errmsg routine).
146 */
147
148
149static const char not_found_msg[] = "%s: not found";
150
151
152#define E_OPEN "No such file" /* opening a file */
153#define E_CREAT "Directory nonexistent" /* creating a file */
154#define E_EXEC not_found_msg+4 /* executing a program */
155
156/*
157 * We enclose jmp_buf in a structure so that we can declare pointers to
158 * jump locations. The global variable handler contains the location to
159 * jump to when an exception occurs, and the global variable exception
Eric Andersenaff114c2004-04-14 17:51:38 +0000160 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000161 * exception handlers, the user should save the value of handler on entry
162 * to an inner scope, set handler to point to a jmploc structure for the
163 * inner scope, and restore handler on exit from the scope.
164 */
165
166struct jmploc {
167 jmp_buf loc;
168};
169
170static struct jmploc *handler;
171static int exception;
172static volatile int suppressint;
173static volatile sig_atomic_t intpending;
174
Eric Andersenc470f442003-07-28 09:56:35 +0000175/* exceptions */
176#define EXINT 0 /* SIGINT received */
177#define EXERROR 1 /* a generic error */
178#define EXSHELLPROC 2 /* execute a shell procedure */
179#define EXEXEC 3 /* command execution failed */
180#define EXEXIT 4 /* exit the shell */
181#define EXSIG 5 /* trapped signal in wait(1) */
182
183
184/* do we generate EXSIG events */
185static int exsig;
186/* last pending signal */
187static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000188
189/*
190 * These macros allow the user to suspend the handling of interrupt signals
191 * over a period of time. This is similar to SIGHOLD to or sigblock, but
192 * much more efficient and portable. (But hacking the kernel is so much
193 * more fun than worrying about efficiency and portability. :-))
194 */
195
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000196#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
Eric Andersenc470f442003-07-28 09:56:35 +0000197#define INTOFF \
198 ({ \
199 suppressint++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000200 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000201 0; \
202 })
203#define SAVEINT(v) ((v) = suppressint)
204#define RESTOREINT(v) \
205 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000206 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000207 if ((suppressint = (v)) == 0 && intpending) onint(); \
208 0; \
209 })
210#define EXSIGON() \
211 ({ \
212 exsig++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000213 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000214 if (pendingsigs) \
215 exraise(EXSIG); \
216 0; \
217 })
218/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000219
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000220
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000221static void exraise(int) ATTRIBUTE_NORETURN;
222static void onint(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000223
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000224static void sh_error(const char *, ...) ATTRIBUTE_NORETURN;
225static void exerror(int, const char *, ...) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000226
227static void sh_warnx(const char *, ...);
228
229#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
230static void
231inton(void) {
232 if (--suppressint == 0 && intpending) {
233 onint();
234 }
235}
236#define INTON inton()
237static void forceinton(void)
238{
239 suppressint = 0;
240 if (intpending)
241 onint();
242}
Eric Andersen3102ac42001-07-06 04:26:23 +0000243#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000244#else
Eric Andersenc470f442003-07-28 09:56:35 +0000245#define INTON \
246 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000247 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000248 if (--suppressint == 0 && intpending) onint(); \
249 0; \
250 })
251#define FORCEINTON \
252 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000253 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000254 suppressint = 0; \
255 if (intpending) onint(); \
256 0; \
257 })
258#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000259
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000260/* expand.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000261
262struct strlist {
263 struct strlist *next;
264 char *text;
265};
266
267
268struct arglist {
269 struct strlist *list;
270 struct strlist **lastp;
271};
272
Eric Andersenc470f442003-07-28 09:56:35 +0000273/*
274 * expandarg() flags
275 */
276#define EXP_FULL 0x1 /* perform word splitting & file globbing */
277#define EXP_TILDE 0x2 /* do normal tilde expansion */
278#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
279#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
280#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
281#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
282#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
283#define EXP_WORD 0x80 /* expand word in parameter expansion */
284#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
285
286
287union node;
288static void expandarg(union node *, struct arglist *, int);
289#define rmescapes(p) _rmescapes((p), 0)
290static char *_rmescapes(char *, int);
291static int casematch(union node *, char *);
292
293#ifdef CONFIG_ASH_MATH_SUPPORT
294static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000295#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000296
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000297/* eval.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000298
Eric Andersenc470f442003-07-28 09:56:35 +0000299static char *commandname; /* currently executing command */
300static struct strlist *cmdenviron; /* environment for builtin command */
301static int exitstatus; /* exit status of last command */
302static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000303
Eric Andersenc470f442003-07-28 09:56:35 +0000304
305struct backcmd { /* result of evalbackcmd */
306 int fd; /* file descriptor to read from */
307 char *buf; /* buffer */
308 int nleft; /* number of chars in buffer */
309 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000310};
311
Eric Andersen62483552001-07-10 06:09:16 +0000312/*
Eric Andersenc470f442003-07-28 09:56:35 +0000313 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000314 */
Eric Andersenc470f442003-07-28 09:56:35 +0000315
316#define NCMD 0
317#define NPIPE 1
318#define NREDIR 2
319#define NBACKGND 3
320#define NSUBSHELL 4
321#define NAND 5
322#define NOR 6
323#define NSEMI 7
324#define NIF 8
325#define NWHILE 9
326#define NUNTIL 10
327#define NFOR 11
328#define NCASE 12
329#define NCLIST 13
330#define NDEFUN 14
331#define NARG 15
332#define NTO 16
333#define NCLOBBER 17
334#define NFROM 18
335#define NFROMTO 19
336#define NAPPEND 20
337#define NTOFD 21
338#define NFROMFD 22
339#define NHERE 23
340#define NXHERE 24
341#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000342
343
344
Eric Andersenc470f442003-07-28 09:56:35 +0000345struct ncmd {
346 int type;
347 union node *assign;
348 union node *args;
349 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000350};
351
352
Eric Andersenc470f442003-07-28 09:56:35 +0000353struct npipe {
354 int type;
355 int backgnd;
356 struct nodelist *cmdlist;
357};
Eric Andersen62483552001-07-10 06:09:16 +0000358
359
Eric Andersenc470f442003-07-28 09:56:35 +0000360struct nredir {
361 int type;
362 union node *n;
363 union node *redirect;
364};
Eric Andersen62483552001-07-10 06:09:16 +0000365
366
Eric Andersenc470f442003-07-28 09:56:35 +0000367struct nbinary {
368 int type;
369 union node *ch1;
370 union node *ch2;
371};
Eric Andersen2870d962001-07-02 17:27:21 +0000372
Eric Andersen2870d962001-07-02 17:27:21 +0000373
Eric Andersenc470f442003-07-28 09:56:35 +0000374struct nif {
375 int type;
376 union node *test;
377 union node *ifpart;
378 union node *elsepart;
379};
380
381
382struct nfor {
383 int type;
384 union node *args;
385 union node *body;
386 char *var;
387};
388
389
390struct ncase {
391 int type;
392 union node *expr;
393 union node *cases;
394};
395
396
397struct nclist {
398 int type;
399 union node *next;
400 union node *pattern;
401 union node *body;
402};
403
404
405struct narg {
406 int type;
407 union node *next;
408 char *text;
409 struct nodelist *backquote;
410};
411
412
413struct nfile {
414 int type;
415 union node *next;
416 int fd;
417 union node *fname;
418 char *expfname;
419};
420
421
422struct ndup {
423 int type;
424 union node *next;
425 int fd;
426 int dupfd;
427 union node *vname;
428};
429
430
431struct nhere {
432 int type;
433 union node *next;
434 int fd;
435 union node *doc;
436};
437
438
439struct nnot {
440 int type;
441 union node *com;
442};
443
444
445union node {
446 int type;
447 struct ncmd ncmd;
448 struct npipe npipe;
449 struct nredir nredir;
450 struct nbinary nbinary;
451 struct nif nif;
452 struct nfor nfor;
453 struct ncase ncase;
454 struct nclist nclist;
455 struct narg narg;
456 struct nfile nfile;
457 struct ndup ndup;
458 struct nhere nhere;
459 struct nnot nnot;
460};
461
462
463struct nodelist {
464 struct nodelist *next;
465 union node *n;
466};
467
468
469struct funcnode {
470 int count;
471 union node n;
472};
473
474
475static void freefunc(struct funcnode *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000476/* parser.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000477
478/* control characters in argument strings */
479#define CTL_FIRST '\201' /* first 'special' character */
480#define CTLESC '\201' /* escape next character */
481#define CTLVAR '\202' /* variable defn */
482#define CTLENDVAR '\203'
483#define CTLBACKQ '\204'
484#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
485/* CTLBACKQ | CTLQUOTE == '\205' */
486#define CTLARI '\206' /* arithmetic expression */
487#define CTLENDARI '\207'
488#define CTLQUOTEMARK '\210'
489#define CTL_LAST '\210' /* last 'special' character */
490
491/* variable substitution byte (follows CTLVAR) */
492#define VSTYPE 0x0f /* type of variable substitution */
493#define VSNUL 0x10 /* colon--treat the empty string as unset */
494#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
495
496/* values of VSTYPE field */
497#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
498#define VSMINUS 0x2 /* ${var-text} */
499#define VSPLUS 0x3 /* ${var+text} */
500#define VSQUESTION 0x4 /* ${var?message} */
501#define VSASSIGN 0x5 /* ${var=text} */
502#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
503#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
504#define VSTRIMLEFT 0x8 /* ${var#pattern} */
505#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
506#define VSLENGTH 0xa /* ${#var} */
507
508/* values of checkkwd variable */
509#define CHKALIAS 0x1
510#define CHKKWD 0x2
511#define CHKNL 0x4
512
513#define IBUFSIZ (BUFSIZ + 1)
514
515/*
516 * NEOF is returned by parsecmd when it encounters an end of file. It
517 * must be distinct from NULL, so we use the address of a variable that
518 * happens to be handy.
519 */
520static int plinno = 1; /* input line number */
521
522/* number of characters left in input buffer */
523static int parsenleft; /* copy of parsefile->nleft */
524static int parselleft; /* copy of parsefile->lleft */
525
526/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000527static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000528
529struct strpush {
530 struct strpush *prev; /* preceding string on stack */
531 char *prevstring;
532 int prevnleft;
533#ifdef CONFIG_ASH_ALIAS
534 struct alias *ap; /* if push was associated with an alias */
535#endif
536 char *string; /* remember the string since it may change */
537};
538
539struct parsefile {
540 struct parsefile *prev; /* preceding file on stack */
541 int linno; /* current line */
542 int fd; /* file descriptor (or -1 if string) */
543 int nleft; /* number of chars left in this line */
544 int lleft; /* number of chars left in this buffer */
545 char *nextc; /* next char in buffer */
546 char *buf; /* input buffer */
547 struct strpush *strpush; /* for pushing strings at this level */
548 struct strpush basestrpush; /* so pushing one is fast */
549};
550
Eric Andersenc470f442003-07-28 09:56:35 +0000551static struct parsefile basepf; /* top level input file */
"Vladimir N. Oleynik"6f347ef2005-10-15 10:23:55 +0000552#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
Eric Andersenc470f442003-07-28 09:56:35 +0000553static struct parsefile *parsefile = &basepf; /* current input file */
554
555
556static int tokpushback; /* last token pushed back */
557#define NEOF ((union node *)&tokpushback)
558static int parsebackquote; /* nonzero if we are inside backquotes */
559static int doprompt; /* if set, prompt the user */
560static int needprompt; /* true if interactive and at start of line */
561static int lasttoken; /* last token read */
562static char *wordtext; /* text of last word returned by readtoken */
563static int checkkwd;
564static struct nodelist *backquotelist;
565static union node *redirnode;
566static struct heredoc *heredoc;
567static int quoteflag; /* set if (part of) last token was quoted */
568static int startlinno; /* line # where last token started */
569
570static union node *parsecmd(int);
571static void fixredir(union node *, const char *, int);
572static const char *const *findkwd(const char *);
573static char *endofname(const char *);
574
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000575/* shell.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000576
577typedef void *pointer;
578
579static char nullstr[1]; /* zero length string */
580static const char spcstr[] = " ";
581static const char snlfmt[] = "%s\n";
582static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
583static const char illnum[] = "Illegal number: %s";
584static const char homestr[] = "HOME";
585
Denis Vlasenkoa7189f02006-11-17 20:29:00 +0000586#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +0000587#define TRACE(param) trace param
588#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000589#else
Eric Andersenc470f442003-07-28 09:56:35 +0000590#define TRACE(param)
591#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000592#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000593
Eric Andersenc470f442003-07-28 09:56:35 +0000594#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
595#define __builtin_expect(x, expected_value) (x)
596#endif
597
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000598#define xlikely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000599
Eric Andersenc470f442003-07-28 09:56:35 +0000600
601#define TEOF 0
602#define TNL 1
603#define TREDIR 2
604#define TWORD 3
605#define TSEMI 4
606#define TBACKGND 5
607#define TAND 6
608#define TOR 7
609#define TPIPE 8
610#define TLP 9
611#define TRP 10
612#define TENDCASE 11
613#define TENDBQUOTE 12
614#define TNOT 13
615#define TCASE 14
616#define TDO 15
617#define TDONE 16
618#define TELIF 17
619#define TELSE 18
620#define TESAC 19
621#define TFI 20
622#define TFOR 21
623#define TIF 22
624#define TIN 23
625#define TTHEN 24
626#define TUNTIL 25
627#define TWHILE 26
628#define TBEGIN 27
629#define TEND 28
630
631/* first char is indicating which tokens mark the end of a list */
632static const char *const tokname_array[] = {
633 "\1end of file",
634 "\0newline",
635 "\0redirection",
636 "\0word",
637 "\0;",
638 "\0&",
639 "\0&&",
640 "\0||",
641 "\0|",
642 "\0(",
643 "\1)",
644 "\1;;",
645 "\1`",
646#define KWDOFFSET 13
647 /* the following are keywords */
648 "\0!",
649 "\0case",
650 "\1do",
651 "\1done",
652 "\1elif",
653 "\1else",
654 "\1esac",
655 "\1fi",
656 "\0for",
657 "\0if",
658 "\0in",
659 "\1then",
660 "\0until",
661 "\0while",
662 "\0{",
663 "\1}",
664};
665
666static const char *tokname(int tok)
667{
668 static char buf[16];
669
670 if (tok >= TSEMI)
671 buf[0] = '"';
672 sprintf(buf + (tok >= TSEMI), "%s%c",
673 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
674 return buf;
675}
676
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000677/* machdep.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000678
679/*
680 * Most machines require the value returned from malloc to be aligned
681 * in some way. The following macro will get this right on many machines.
682 */
683
684#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
685/*
686 * It appears that grabstackstr() will barf with such alignments
687 * because stalloc() will return a string allocated in a new stackblock.
688 */
689#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
690
691/*
692 * This file was generated by the mksyntax program.
693 */
694
695
696/* Syntax classes */
697#define CWORD 0 /* character is nothing special */
698#define CNL 1 /* newline character */
699#define CBACK 2 /* a backslash character */
700#define CSQUOTE 3 /* single quote */
701#define CDQUOTE 4 /* double quote */
702#define CENDQUOTE 5 /* a terminating quote */
703#define CBQUOTE 6 /* backwards single quote */
704#define CVAR 7 /* a dollar sign */
705#define CENDVAR 8 /* a '}' character */
706#define CLP 9 /* a left paren in arithmetic */
707#define CRP 10 /* a right paren in arithmetic */
708#define CENDFILE 11 /* end of file */
709#define CCTL 12 /* like CWORD, except it must be escaped */
710#define CSPCL 13 /* these terminate a word */
711#define CIGN 14 /* character should be ignored */
712
713#ifdef CONFIG_ASH_ALIAS
714#define SYNBASE 130
715#define PEOF -130
716#define PEOA -129
717#define PEOA_OR_PEOF PEOA
718#else
719#define SYNBASE 129
720#define PEOF -129
721#define PEOA_OR_PEOF PEOF
722#endif
723
724#define is_digit(c) ((unsigned)((c) - '0') <= 9)
725#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
726#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
727
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000728/* C99 say: "char" declaration may be signed or unsigned default */
729#define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int)
730
Eric Andersenc470f442003-07-28 09:56:35 +0000731/*
732 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
733 * (assuming ascii char codes, as the original implementation did)
734 */
735#define is_special(c) \
736 ( (((unsigned int)c) - 33 < 32) \
737 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
738
739#define digit_val(c) ((c) - '0')
740
741/*
742 * This file was generated by the mksyntax program.
743 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000744
Eric Andersend35c5df2002-01-09 15:37:36 +0000745#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000746#define USE_SIT_FUNCTION
747#endif
748
749/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000750#define BASESYNTAX 0 /* not in quotes */
751#define DQSYNTAX 1 /* in double quotes */
752#define SQSYNTAX 2 /* in single quotes */
753#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000754
Eric Andersenc470f442003-07-28 09:56:35 +0000755#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000756static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000757#ifdef CONFIG_ASH_ALIAS
758 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
759#endif
760 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
761 {CNL, CNL, CNL, CNL}, /* 2, \n */
762 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
763 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
764 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
765 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
766 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
767 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
768 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
769 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
770 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000771#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000772 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
773 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
774 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000775#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000776};
Eric Andersenc470f442003-07-28 09:56:35 +0000777#else
778static const char S_I_T[][3] = {
779#ifdef CONFIG_ASH_ALIAS
780 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
781#endif
782 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
783 {CNL, CNL, CNL}, /* 2, \n */
784 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
785 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
786 {CVAR, CVAR, CWORD}, /* 5, $ */
787 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
788 {CSPCL, CWORD, CWORD}, /* 7, ( */
789 {CSPCL, CWORD, CWORD}, /* 8, ) */
790 {CBACK, CBACK, CCTL}, /* 9, \ */
791 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
792 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
793#ifndef USE_SIT_FUNCTION
794 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
795 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
796 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
797#endif
798};
799#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000800
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000801#ifdef USE_SIT_FUNCTION
802
803#define U_C(c) ((unsigned char)(c))
804
805static int SIT(int c, int syntax)
806{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000807 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000808#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000809 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000810 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
811 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
812 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
813 11, 3 /* "}~" */
814 };
815#else
816 static const char syntax_index_table[] = {
817 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
818 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
819 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
820 10, 2 /* "}~" */
821 };
822#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000823 const char *s;
824 int indx;
825
Eric Andersenc470f442003-07-28 09:56:35 +0000826 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000827 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000828#ifdef CONFIG_ASH_ALIAS
829 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000830 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000831 else
832#endif
833 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
834 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000835 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000836 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000837 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000838 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000839 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000840 }
841 return S_I_T[indx][syntax];
842}
843
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000844#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000845
846#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
847
Eric Andersenc470f442003-07-28 09:56:35 +0000848#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000849#define CSPCL_CIGN_CIGN_CIGN 0
850#define CSPCL_CWORD_CWORD_CWORD 1
851#define CNL_CNL_CNL_CNL 2
852#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000853#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000854#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000855#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000856#define CSPCL_CWORD_CWORD_CLP 7
857#define CSPCL_CWORD_CWORD_CRP 8
858#define CBACK_CBACK_CCTL_CBACK 9
859#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
860#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
861#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
862#define CWORD_CWORD_CWORD_CWORD 13
863#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000864#else
865#define CSPCL_CWORD_CWORD_CWORD 0
866#define CNL_CNL_CNL_CNL 1
867#define CWORD_CCTL_CCTL_CWORD 2
868#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
869#define CVAR_CVAR_CWORD_CVAR 4
870#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
871#define CSPCL_CWORD_CWORD_CLP 6
872#define CSPCL_CWORD_CWORD_CRP 7
873#define CBACK_CBACK_CCTL_CBACK 8
874#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
875#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
876#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
877#define CWORD_CWORD_CWORD_CWORD 12
878#define CCTL_CCTL_CCTL_CCTL 13
879#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000880
881static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000882 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000883 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
884#ifdef CONFIG_ASH_ALIAS
885 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
886#endif
887 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
888 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
889 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
890 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
891 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
892 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
893 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
894 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
895 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000896 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
897 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
898 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
899 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
900 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
901 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
902 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
903 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
904 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
905 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
906 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
907 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
908 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
909 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
910 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
911 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
912 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
913 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
914 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
915 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
916 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
917 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
918 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
919 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
920 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
921 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
922 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
923 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
924 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
925 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
926 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
927 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
928 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
929 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
930 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
931 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
932 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
933 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
934 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
935 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
936 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
937 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
938 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
939 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
940 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
941 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
942 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
943 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
944 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
945 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
946 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
947 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
948 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
949 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
950 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
951 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
952 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
953 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
954 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
955 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
956 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
957 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
958 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
959 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
960 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
961 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
962 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
963 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
964 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
965 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
966 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
967 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
968 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
969 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
970 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
971 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
972 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
973 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
974 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
975 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
976 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
977 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
978 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
979 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
980 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
981 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
982 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
983 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
984 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
985 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
986 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
987 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
988 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
989 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
990 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
991 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
992 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
993 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
994 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
995 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
996 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
997 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
998 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
999 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1025 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1026 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1048 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001049 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001050 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1051 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1052 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1053 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001054 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001055 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1056 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1057 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1058 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1059 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1060 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1061 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1062 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1063 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1064 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1072 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1073 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1074 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1075 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1076 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1077 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1078 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1079 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1107 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1108 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1109 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1112 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1140 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1141 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1142 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001143};
1144
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001145#endif /* USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00001146
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001147/* alias.c */
Eric Andersen2870d962001-07-02 17:27:21 +00001148
Eric Andersen2870d962001-07-02 17:27:21 +00001149
Eric Andersenc470f442003-07-28 09:56:35 +00001150#define ATABSIZE 39
1151
1152static int funcblocksize; /* size of structures in function */
1153static int funcstringsize; /* size of strings in node */
1154static pointer funcblock; /* block to allocate function from */
1155static char *funcstring; /* block to allocate strings from */
1156
1157static const short nodesize[26] = {
1158 SHELL_ALIGN(sizeof (struct ncmd)),
1159 SHELL_ALIGN(sizeof (struct npipe)),
1160 SHELL_ALIGN(sizeof (struct nredir)),
1161 SHELL_ALIGN(sizeof (struct nredir)),
1162 SHELL_ALIGN(sizeof (struct nredir)),
1163 SHELL_ALIGN(sizeof (struct nbinary)),
1164 SHELL_ALIGN(sizeof (struct nbinary)),
1165 SHELL_ALIGN(sizeof (struct nbinary)),
1166 SHELL_ALIGN(sizeof (struct nif)),
1167 SHELL_ALIGN(sizeof (struct nbinary)),
1168 SHELL_ALIGN(sizeof (struct nbinary)),
1169 SHELL_ALIGN(sizeof (struct nfor)),
1170 SHELL_ALIGN(sizeof (struct ncase)),
1171 SHELL_ALIGN(sizeof (struct nclist)),
1172 SHELL_ALIGN(sizeof (struct narg)),
1173 SHELL_ALIGN(sizeof (struct narg)),
1174 SHELL_ALIGN(sizeof (struct nfile)),
1175 SHELL_ALIGN(sizeof (struct nfile)),
1176 SHELL_ALIGN(sizeof (struct nfile)),
1177 SHELL_ALIGN(sizeof (struct nfile)),
1178 SHELL_ALIGN(sizeof (struct nfile)),
1179 SHELL_ALIGN(sizeof (struct ndup)),
1180 SHELL_ALIGN(sizeof (struct ndup)),
1181 SHELL_ALIGN(sizeof (struct nhere)),
1182 SHELL_ALIGN(sizeof (struct nhere)),
1183 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001184};
1185
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001186
Eric Andersenc470f442003-07-28 09:56:35 +00001187static void calcsize(union node *);
1188static void sizenodelist(struct nodelist *);
1189static union node *copynode(union node *);
1190static struct nodelist *copynodelist(struct nodelist *);
1191static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001192
1193
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001194static int evalstring(char *, int mask);
Eric Andersenc470f442003-07-28 09:56:35 +00001195union node; /* BLETCH for ansi C */
1196static void evaltree(union node *, int);
1197static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001198
Eric Andersenc470f442003-07-28 09:56:35 +00001199static int evalskip; /* set if we are skipping commands */
1200static int skipcount; /* number of levels to skip */
1201static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001202
1203/* reasons for skipping commands (see comment on breakcmd routine) */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001204#define SKIPBREAK (1 << 0)
1205#define SKIPCONT (1 << 1)
1206#define SKIPFUNC (1 << 2)
1207#define SKIPFILE (1 << 3)
1208#define SKIPEVAL (1 << 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001209
Eric Andersenc470f442003-07-28 09:56:35 +00001210/*
1211 * This file was generated by the mkbuiltins program.
1212 */
Eric Andersen2870d962001-07-02 17:27:21 +00001213
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001214#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001215static int bgcmd(int, char **);
1216#endif
1217static int breakcmd(int, char **);
1218static int cdcmd(int, char **);
1219#ifdef CONFIG_ASH_CMDCMD
1220static int commandcmd(int, char **);
1221#endif
1222static int dotcmd(int, char **);
1223static int evalcmd(int, char **);
Paul Fox0b621582005-08-09 19:38:05 +00001224#ifdef CONFIG_ASH_BUILTIN_ECHO
1225static int echocmd(int, char **);
1226#endif
Paul Fox6ab03782006-06-08 21:37:26 +00001227#ifdef CONFIG_ASH_BUILTIN_TEST
1228static int testcmd(int, char **);
1229#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001230static int execcmd(int, char **);
1231static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001232static int exportcmd(int, char **);
1233static int falsecmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001234#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001235static int fgcmd(int, char **);
1236#endif
1237#ifdef CONFIG_ASH_GETOPTS
1238static int getoptscmd(int, char **);
1239#endif
1240static int hashcmd(int, char **);
1241#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1242static int helpcmd(int argc, char **argv);
1243#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001244#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001245static int jobscmd(int, char **);
1246#endif
Eric Andersen90898442003-08-06 11:20:52 +00001247#ifdef CONFIG_ASH_MATH_SUPPORT
1248static int letcmd(int, char **);
1249#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001250static int localcmd(int, char **);
1251static int pwdcmd(int, char **);
1252static int readcmd(int, char **);
1253static int returncmd(int, char **);
1254static int setcmd(int, char **);
1255static int shiftcmd(int, char **);
1256static int timescmd(int, char **);
1257static int trapcmd(int, char **);
1258static int truecmd(int, char **);
1259static int typecmd(int, char **);
1260static int umaskcmd(int, char **);
1261static int unsetcmd(int, char **);
1262static int waitcmd(int, char **);
1263static int ulimitcmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001264#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001265static int killcmd(int, char **);
1266#endif
1267
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001268/* mail.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001269
1270#ifdef CONFIG_ASH_MAIL
1271static void chkmail(void);
1272static void changemail(const char *);
1273#endif
1274
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001275/* exec.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001276
1277/* values of cmdtype */
1278#define CMDUNKNOWN -1 /* no entry in table for command */
1279#define CMDNORMAL 0 /* command is an executable program */
1280#define CMDFUNCTION 1 /* command is a shell function */
1281#define CMDBUILTIN 2 /* command is a shell builtin */
1282
1283struct builtincmd {
1284 const char *name;
1285 int (*builtin)(int, char **);
1286 /* unsigned flags; */
1287};
1288
Paul Fox0b621582005-08-09 19:38:05 +00001289
1290#define COMMANDCMD (builtincmd + 5 + \
Paul Fox6ab03782006-06-08 21:37:26 +00001291 2 * ENABLE_ASH_BUILTIN_TEST + \
1292 ENABLE_ASH_ALIAS + \
1293 ENABLE_ASH_JOB_CONTROL)
Paul Fox0b621582005-08-09 19:38:05 +00001294#define EXECCMD (builtincmd + 7 + \
Paul Fox6ab03782006-06-08 21:37:26 +00001295 2 * ENABLE_ASH_BUILTIN_TEST + \
1296 ENABLE_ASH_ALIAS + \
1297 ENABLE_ASH_JOB_CONTROL + \
1298 ENABLE_ASH_CMDCMD + \
1299 ENABLE_ASH_BUILTIN_ECHO)
Eric Andersenc470f442003-07-28 09:56:35 +00001300
1301#define BUILTIN_NOSPEC "0"
1302#define BUILTIN_SPECIAL "1"
1303#define BUILTIN_REGULAR "2"
1304#define BUILTIN_SPEC_REG "3"
1305#define BUILTIN_ASSIGN "4"
1306#define BUILTIN_SPEC_ASSG "5"
1307#define BUILTIN_REG_ASSG "6"
1308#define BUILTIN_SPEC_REG_ASSG "7"
1309
1310#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1311#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
Paul Foxc3850c82005-07-20 18:23:39 +00001312#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001313
Bernhard Reutner-Fischer35492132006-06-21 18:19:53 +00001314/* make sure to keep these in proper order since it is searched via bsearch() */
Eric Andersenc470f442003-07-28 09:56:35 +00001315static const struct builtincmd builtincmd[] = {
1316 { BUILTIN_SPEC_REG ".", dotcmd },
1317 { BUILTIN_SPEC_REG ":", truecmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001318#ifdef CONFIG_ASH_BUILTIN_TEST
1319 { BUILTIN_REGULAR "[", testcmd },
1320 { BUILTIN_REGULAR "[[", testcmd },
1321#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001322#ifdef CONFIG_ASH_ALIAS
1323 { BUILTIN_REG_ASSG "alias", aliascmd },
1324#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001325#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001326 { BUILTIN_REGULAR "bg", bgcmd },
1327#endif
1328 { BUILTIN_SPEC_REG "break", breakcmd },
1329 { BUILTIN_REGULAR "cd", cdcmd },
1330 { BUILTIN_NOSPEC "chdir", cdcmd },
1331#ifdef CONFIG_ASH_CMDCMD
1332 { BUILTIN_REGULAR "command", commandcmd },
1333#endif
1334 { BUILTIN_SPEC_REG "continue", breakcmd },
Paul Fox0b621582005-08-09 19:38:05 +00001335#ifdef CONFIG_ASH_BUILTIN_ECHO
1336 { BUILTIN_REGULAR "echo", echocmd },
1337#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001338 { BUILTIN_SPEC_REG "eval", evalcmd },
1339 { BUILTIN_SPEC_REG "exec", execcmd },
1340 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001341 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1342 { BUILTIN_REGULAR "false", falsecmd },
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001343#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001344 { BUILTIN_REGULAR "fg", fgcmd },
1345#endif
1346#ifdef CONFIG_ASH_GETOPTS
1347 { BUILTIN_REGULAR "getopts", getoptscmd },
1348#endif
1349 { BUILTIN_NOSPEC "hash", hashcmd },
1350#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1351 { BUILTIN_NOSPEC "help", helpcmd },
1352#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001353#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001354 { BUILTIN_REGULAR "jobs", jobscmd },
1355 { BUILTIN_REGULAR "kill", killcmd },
1356#endif
1357#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001358 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001359#endif
1360 { BUILTIN_ASSIGN "local", localcmd },
1361 { BUILTIN_NOSPEC "pwd", pwdcmd },
1362 { BUILTIN_REGULAR "read", readcmd },
1363 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1364 { BUILTIN_SPEC_REG "return", returncmd },
1365 { BUILTIN_SPEC_REG "set", setcmd },
1366 { BUILTIN_SPEC_REG "shift", shiftcmd },
Mike Frysingerc2ad4f52006-06-21 18:04:49 +00001367 { BUILTIN_SPEC_REG "source", dotcmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001368#ifdef CONFIG_ASH_BUILTIN_TEST
1369 { BUILTIN_REGULAR "test", testcmd },
1370#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001371 { BUILTIN_SPEC_REG "times", timescmd },
1372 { BUILTIN_SPEC_REG "trap", trapcmd },
1373 { BUILTIN_REGULAR "true", truecmd },
1374 { BUILTIN_NOSPEC "type", typecmd },
1375 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1376 { BUILTIN_REGULAR "umask", umaskcmd },
1377#ifdef CONFIG_ASH_ALIAS
1378 { BUILTIN_REGULAR "unalias", unaliascmd },
1379#endif
1380 { BUILTIN_SPEC_REG "unset", unsetcmd },
1381 { BUILTIN_REGULAR "wait", waitcmd },
1382};
1383
1384#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1385
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00001386static const char *safe_applets[] = {
1387 "[", "test", "echo", "cat",
1388 "ln", "cp", "touch", "mkdir", "rm",
1389 "cut", "hexdump", "awk", "sort",
1390 "find", "xargs", "ls", "dd",
1391 "chown", "chmod"
1392};
Eric Andersenc470f442003-07-28 09:56:35 +00001393
1394
1395struct cmdentry {
1396 int cmdtype;
1397 union param {
1398 int index;
1399 const struct builtincmd *cmd;
1400 struct funcnode *func;
1401 } u;
1402};
1403
1404
1405/* action to find_command() */
1406#define DO_ERR 0x01 /* prints errors */
1407#define DO_ABS 0x02 /* checks absolute paths */
1408#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1409#define DO_ALTPATH 0x08 /* using alternate path */
1410#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1411
1412static const char *pathopt; /* set by padvance */
1413
1414static void shellexec(char **, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001415 ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00001416static char *padvance(const char **, const char *);
1417static void find_command(char *, struct cmdentry *, int, const char *);
1418static struct builtincmd *find_builtin(const char *);
1419static void hashcd(void);
1420static void changepath(const char *);
1421static void defun(char *, union node *);
1422static void unsetfunc(const char *);
1423
Eric Andersened9ecf72004-06-22 08:29:45 +00001424#ifdef CONFIG_ASH_MATH_SUPPORT_64
1425typedef int64_t arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001426#define arith_t_type (long long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001427#else
1428typedef long arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001429#define arith_t_type (long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001430#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001431
1432#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001433static arith_t dash_arith(const char *);
1434static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001435#endif
1436
Eric Andersen16767e22004-03-16 05:14:10 +00001437#ifdef CONFIG_ASH_RANDOM_SUPPORT
1438static unsigned long rseed;
1439static void change_random(const char *);
1440# ifndef DYNAMIC_VAR
1441# define DYNAMIC_VAR
1442# endif
1443#endif
1444
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001445/* init.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001446
1447static void reset(void);
1448
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001449/* var.h */
Eric Andersen2870d962001-07-02 17:27:21 +00001450
1451/*
1452 * Shell variables.
1453 */
1454
1455/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001456#define VEXPORT 0x01 /* variable is exported */
1457#define VREADONLY 0x02 /* variable cannot be modified */
1458#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1459#define VTEXTFIXED 0x08 /* text is statically allocated */
1460#define VSTACK 0x10 /* text is allocated on the stack */
1461#define VUNSET 0x20 /* the variable is not set */
1462#define VNOFUNC 0x40 /* don't call the callback function */
1463#define VNOSET 0x80 /* do not set variable - just readonly test */
1464#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001465#ifdef DYNAMIC_VAR
1466# define VDYNAMIC 0x200 /* dynamic variable */
1467# else
1468# define VDYNAMIC 0
1469#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001470
1471struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001472 struct var *next; /* next entry in hash list */
1473 int flags; /* flags are defined above */
1474 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001475 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001476 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001477};
1478
1479struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001480 struct localvar *next; /* next local variable in list */
1481 struct var *vp; /* the variable that was made local */
1482 int flags; /* saved flags */
1483 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001484};
1485
1486
Eric Andersen2870d962001-07-02 17:27:21 +00001487static struct localvar *localvars;
1488
Eric Andersenc470f442003-07-28 09:56:35 +00001489/*
1490 * Shell variables.
1491 */
1492
1493#ifdef CONFIG_ASH_GETOPTS
1494static void getoptsreset(const char *);
1495#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001496
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001497#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001498static void change_lc_all(const char *value);
1499static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001500#endif
1501
Eric Andersenef02f822004-03-11 13:34:24 +00001502
Eric Andersen2870d962001-07-02 17:27:21 +00001503#define VTABSIZE 39
1504
Eric Andersen90898442003-08-06 11:20:52 +00001505static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001506#ifdef IFS_BROKEN
1507static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001508#define defifs (defifsvar + 4)
1509#else
Eric Andersenc470f442003-07-28 09:56:35 +00001510static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001511#endif
1512
Eric Andersenc470f442003-07-28 09:56:35 +00001513
1514static struct var varinit[] = {
1515#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001516 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001517#else
Eric Andersen16767e22004-03-16 05:14:10 +00001518 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001519#endif
1520
1521#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001522 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1523 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001524#endif
1525
Eric Andersen16767e22004-03-16 05:14:10 +00001526 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1527 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1528 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1529 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001530#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001531 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1532#endif
1533#ifdef CONFIG_ASH_RANDOM_SUPPORT
1534 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001535#endif
1536#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001537 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1538 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001539#endif
1540#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001541 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001542#endif
1543};
1544
1545#define vifs varinit[0]
1546#ifdef CONFIG_ASH_MAIL
1547#define vmail (&vifs)[1]
1548#define vmpath (&vmail)[1]
1549#else
1550#define vmpath vifs
1551#endif
1552#define vpath (&vmpath)[1]
1553#define vps1 (&vpath)[1]
1554#define vps2 (&vps1)[1]
1555#define vps4 (&vps2)[1]
1556#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001557#ifdef CONFIG_ASH_GETOPTS
1558#define vrandom (&voptind)[1]
1559#else
1560#define vrandom (&vps4)[1]
1561#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001562#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001563
1564/*
1565 * The following macros access the values of the above variables.
1566 * They have to skip over the name. They return the null string
1567 * for unset variables.
1568 */
1569
1570#define ifsval() (vifs.text + 4)
1571#define ifsset() ((vifs.flags & VUNSET) == 0)
1572#define mailval() (vmail.text + 5)
1573#define mpathval() (vmpath.text + 9)
1574#define pathval() (vpath.text + 5)
1575#define ps1val() (vps1.text + 4)
1576#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001577#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001578#define optindval() (voptind.text + 7)
1579
1580#define mpathset() ((vmpath.flags & VUNSET) == 0)
1581
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001582static void setvar(const char *, const char *, int);
1583static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001584static void listsetvar(struct strlist *, int);
1585static char *lookupvar(const char *);
1586static char *bltinlookup(const char *);
1587static char **listvars(int, int, char ***);
1588#define environment() listvars(VEXPORT, VUNSET, 0)
1589static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001590static void poplocalvars(void);
1591static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001592#ifdef CONFIG_ASH_GETOPTS
1593static int setvarsafe(const char *, const char *, int);
1594#endif
1595static int varcmp(const char *, const char *);
1596static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001597
1598
Rob Landley88621d72006-08-29 19:41:06 +00001599static int varequal(const char *a, const char *b) {
Eric Andersenc470f442003-07-28 09:56:35 +00001600 return !varcmp(a, b);
1601}
Eric Andersen2870d962001-07-02 17:27:21 +00001602
1603
Eric Andersenc470f442003-07-28 09:56:35 +00001604static int loopnest; /* current loop nesting level */
1605
Eric Andersenc470f442003-07-28 09:56:35 +00001606/*
1607 * The parsefile structure pointed to by the global variable parsefile
1608 * contains information about the current file being read.
1609 */
1610
1611
1612struct redirtab {
1613 struct redirtab *next;
1614 int renamed[10];
1615 int nullredirs;
1616};
1617
1618static struct redirtab *redirlist;
1619static int nullredirs;
1620
1621extern char **environ;
1622
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001623/* output.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001624
1625
1626static void outstr(const char *, FILE *);
1627static void outcslow(int, FILE *);
1628static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001629static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001630static int out1fmt(const char *, ...)
1631 __attribute__((__format__(__printf__,1,2)));
1632static int fmtstr(char *, size_t, const char *, ...)
1633 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001634
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001635static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001636
Eric Andersenc470f442003-07-28 09:56:35 +00001637
1638static void out1str(const char *p)
1639{
1640 outstr(p, stdout);
1641}
1642
1643static void out2str(const char *p)
1644{
1645 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001646 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001647}
1648
1649/*
1650 * Initialization code.
1651 */
1652
1653/*
1654 * This routine initializes the builtin variables.
1655 */
1656
Rob Landley88621d72006-08-29 19:41:06 +00001657static void initvar(void)
Eric Andersenc470f442003-07-28 09:56:35 +00001658{
1659 struct var *vp;
1660 struct var *end;
1661 struct var **vpp;
1662
1663 /*
1664 * PS1 depends on uid
1665 */
1666#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1667 vps1.text = "PS1=\\w \\$ ";
1668#else
1669 if (!geteuid())
1670 vps1.text = "PS1=# ";
1671#endif
1672 vp = varinit;
1673 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1674 do {
1675 vpp = hashvar(vp->text);
1676 vp->next = *vpp;
1677 *vpp = vp;
1678 } while (++vp < end);
1679}
1680
Rob Landley88621d72006-08-29 19:41:06 +00001681static void init(void)
Eric Andersenc470f442003-07-28 09:56:35 +00001682{
1683
1684 /* from input.c: */
1685 {
1686 basepf.nextc = basepf.buf = basebuf;
1687 }
1688
1689 /* from trap.c: */
1690 {
1691 signal(SIGCHLD, SIG_DFL);
1692 }
1693
1694 /* from var.c: */
1695 {
1696 char **envp;
1697 char ppid[32];
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001698 const char *p;
1699 struct stat st1, st2;
Eric Andersenc470f442003-07-28 09:56:35 +00001700
1701 initvar();
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001702 for (envp = environ ; envp && *envp ; envp++) {
Eric Andersenc470f442003-07-28 09:56:35 +00001703 if (strchr(*envp, '=')) {
1704 setvareq(*envp, VEXPORT|VTEXTFIXED);
1705 }
1706 }
1707
1708 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1709 setvar("PPID", ppid, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001710
1711 p = lookupvar("PWD");
1712 if (p)
1713 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1714 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1715 p = 0;
1716 setpwd(p, 0);
Eric Andersenc470f442003-07-28 09:56:35 +00001717 }
1718}
1719
1720/* PEOF (the end of file marker) */
1721
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001722enum {
1723 INPUT_PUSH_FILE = 1,
1724 INPUT_NOFILE_OK = 2,
1725};
1726
Eric Andersenc470f442003-07-28 09:56:35 +00001727/*
1728 * The input line number. Input.c just defines this variable, and saves
1729 * and restores it when files are pushed and popped. The user of this
1730 * package must set its value.
1731 */
1732
1733static int pgetc(void);
1734static int pgetc2(void);
1735static int preadbuffer(void);
1736static void pungetc(void);
1737static void pushstring(char *, void *);
1738static void popstring(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001739static void setinputfd(int, int);
1740static void setinputstring(char *);
1741static void popfile(void);
1742static void popallfiles(void);
1743static void closescript(void);
1744
1745
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001746/* jobs.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001747
1748
1749/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1750#define FORK_FG 0
1751#define FORK_BG 1
1752#define FORK_NOJOB 2
1753
1754/* mode flags for showjob(s) */
1755#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1756#define SHOW_PID 0x04 /* include process pid */
1757#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1758
1759
1760/*
1761 * A job structure contains information about a job. A job is either a
1762 * single process or a set of processes contained in a pipeline. In the
1763 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1764 * array of pids.
1765 */
1766
1767struct procstat {
1768 pid_t pid; /* process id */
1769 int status; /* last process status from wait() */
1770 char *cmd; /* text of command being run */
1771};
1772
1773struct job {
1774 struct procstat ps0; /* status of process */
1775 struct procstat *ps; /* status or processes when more than one */
1776#if JOBS
1777 int stopstatus; /* status of a stopped job */
1778#endif
1779 uint32_t
1780 nprocs: 16, /* number of processes */
1781 state: 8,
1782#define JOBRUNNING 0 /* at least one proc running */
1783#define JOBSTOPPED 1 /* all procs are stopped */
1784#define JOBDONE 2 /* all procs are completed */
1785#if JOBS
1786 sigint: 1, /* job was killed by SIGINT */
1787 jobctl: 1, /* job running under job control */
1788#endif
1789 waited: 1, /* true if this entry has been waited for */
1790 used: 1, /* true if this entry is in used */
1791 changed: 1; /* true if status has changed */
1792 struct job *prev_job; /* previous job */
1793};
1794
1795static pid_t backgndpid; /* pid of last background process */
1796static int job_warning; /* user was warned about stopped jobs */
1797#if JOBS
1798static int jobctl; /* true if doing job control */
1799#endif
1800
1801static struct job *makejob(union node *, int);
1802static int forkshell(struct job *, union node *, int);
1803static int waitforjob(struct job *);
1804static int stoppedjobs(void);
1805
1806#if ! JOBS
1807#define setjobctl(on) /* do nothing */
1808#else
1809static void setjobctl(int);
1810static void showjobs(FILE *, int);
1811#endif
1812
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001813/* main.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001814
1815
1816/* pid of main shell */
1817static int rootpid;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001818/* shell level: 0 for the main shell, 1 for its children, and so on */
1819static int shlvl;
1820#define rootshell (!shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00001821
1822static void readcmdfile(char *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001823static int cmdloop(int);
Eric Andersenc470f442003-07-28 09:56:35 +00001824
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001825/* memalloc.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001826
1827
1828struct stackmark {
1829 struct stack_block *stackp;
1830 char *stacknxt;
1831 size_t stacknleft;
1832 struct stackmark *marknext;
1833};
1834
1835/* minimum size of a block */
1836#define MINSIZE SHELL_ALIGN(504)
1837
1838struct stack_block {
1839 struct stack_block *prev;
1840 char space[MINSIZE];
1841};
1842
1843static struct stack_block stackbase;
1844static struct stack_block *stackp = &stackbase;
1845static struct stackmark *markp;
1846static char *stacknxt = stackbase.space;
1847static size_t stacknleft = MINSIZE;
1848static char *sstrend = stackbase.space + MINSIZE;
1849static int herefd = -1;
1850
1851
1852static pointer ckmalloc(size_t);
1853static pointer ckrealloc(pointer, size_t);
1854static char *savestr(const char *);
1855static pointer stalloc(size_t);
1856static void stunalloc(pointer);
1857static void setstackmark(struct stackmark *);
1858static void popstackmark(struct stackmark *);
1859static void growstackblock(void);
1860static void *growstackstr(void);
1861static char *makestrspace(size_t, char *);
1862static char *stnputs(const char *, size_t, char *);
1863static char *stputs(const char *, char *);
1864
1865
Rob Landley88621d72006-08-29 19:41:06 +00001866static char *_STPUTC(int c, char *p) {
Eric Andersenc470f442003-07-28 09:56:35 +00001867 if (p == sstrend)
1868 p = growstackstr();
1869 *p++ = c;
1870 return p;
1871}
1872
1873#define stackblock() ((void *)stacknxt)
1874#define stackblocksize() stacknleft
1875#define STARTSTACKSTR(p) ((p) = stackblock())
1876#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1877#define CHECKSTRSPACE(n, p) \
1878 ({ \
1879 char *q = (p); \
1880 size_t l = (n); \
1881 size_t m = sstrend - q; \
1882 if (l > m) \
1883 (p) = makestrspace(l, q); \
1884 0; \
1885 })
1886#define USTPUTC(c, p) (*p++ = (c))
1887#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1888#define STUNPUTC(p) (--p)
1889#define STTOPC(p) p[-1]
1890#define STADJUST(amount, p) (p += (amount))
1891
1892#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1893#define ungrabstackstr(s, p) stunalloc((s))
1894#define stackstrend() ((void *)sstrend)
1895
1896#define ckfree(p) free((pointer)(p))
1897
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001898/* mystring.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001899
1900
1901#define DOLATSTRLEN 4
1902
1903static char *prefix(const char *, const char *);
1904static int number(const char *);
1905static int is_number(const char *);
1906static char *single_quote(const char *);
1907static char *sstrdup(const char *);
1908
1909#define equal(s1, s2) (strcmp(s1, s2) == 0)
1910#define scopy(s1, s2) ((void)strcpy(s2, s1))
1911
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001912/* options.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001913
1914struct shparam {
1915 int nparam; /* # of positional parameters (without $0) */
1916 unsigned char malloc; /* if parameter list dynamically allocated */
1917 char **p; /* parameter list */
1918#ifdef CONFIG_ASH_GETOPTS
1919 int optind; /* next parameter to be processed by getopts */
1920 int optoff; /* used by getopts */
1921#endif
1922};
1923
1924
1925#define eflag optlist[0]
1926#define fflag optlist[1]
1927#define Iflag optlist[2]
1928#define iflag optlist[3]
1929#define mflag optlist[4]
1930#define nflag optlist[5]
1931#define sflag optlist[6]
1932#define xflag optlist[7]
1933#define vflag optlist[8]
1934#define Cflag optlist[9]
1935#define aflag optlist[10]
1936#define bflag optlist[11]
1937#define uflag optlist[12]
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001938#define viflag optlist[13]
Eric Andersenc470f442003-07-28 09:56:35 +00001939
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00001940#if DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001941#define nolog optlist[14]
1942#define debug optlist[15]
Paul Fox3f11b1b2005-08-04 19:04:46 +00001943#endif
1944
1945#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1946#define setvimode(on) viflag = 0 /* forcibly keep the option off */
Eric Andersenc470f442003-07-28 09:56:35 +00001947#endif
1948
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001949/* options.c */
Eric Andersenc470f442003-07-28 09:56:35 +00001950
1951
Paul Fox3f11b1b2005-08-04 19:04:46 +00001952static const char *const optletters_optnames[] = {
Eric Andersenc470f442003-07-28 09:56:35 +00001953 "e" "errexit",
1954 "f" "noglob",
1955 "I" "ignoreeof",
1956 "i" "interactive",
1957 "m" "monitor",
1958 "n" "noexec",
1959 "s" "stdin",
1960 "x" "xtrace",
1961 "v" "verbose",
1962 "C" "noclobber",
1963 "a" "allexport",
1964 "b" "notify",
1965 "u" "nounset",
Paul Fox3f11b1b2005-08-04 19:04:46 +00001966 "\0" "vi",
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00001967#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00001968 "\0" "nolog",
1969 "\0" "debug",
1970#endif
1971};
1972
1973#define optletters(n) optletters_optnames[(n)][0]
1974#define optnames(n) (&optletters_optnames[(n)][1])
1975
Paul Fox3f11b1b2005-08-04 19:04:46 +00001976#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001977
1978static char optlist[NOPTS];
1979
1980
1981static char *arg0; /* value of $0 */
1982static struct shparam shellparam; /* $@ current positional parameters */
1983static char **argptr; /* argument list for builtin commands */
1984static char *optionarg; /* set by nextopt (like getopt) */
1985static char *optptr; /* used by nextopt */
1986
1987static char *minusc; /* argument to -c option */
1988
1989
1990static void procargs(int, char **);
1991static void optschanged(void);
1992static void setparam(char **);
1993static void freeparam(volatile struct shparam *);
1994static int shiftcmd(int, char **);
1995static int setcmd(int, char **);
1996static int nextopt(const char *);
1997
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001998/* redir.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001999
2000/* flags passed to redirect */
2001#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002002#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00002003
2004union node;
2005static void redirect(union node *, int);
2006static void popredir(int);
2007static void clearredir(int);
2008static int copyfd(int, int);
2009static int redirectsafe(union node *, int);
2010
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002011/* show.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002012
2013
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00002014#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00002015static void showtree(union node *);
2016static void trace(const char *, ...);
2017static void tracev(const char *, va_list);
2018static void trargs(char **);
2019static void trputc(int);
2020static void trputs(const char *);
2021static void opentrace(void);
2022#endif
2023
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002024/* trap.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002025
2026
2027/* trap handler commands */
2028static char *trap[NSIG];
2029/* current value of signal */
2030static char sigmode[NSIG - 1];
2031/* indicates specified signal received */
2032static char gotsig[NSIG - 1];
2033
2034static void clear_traps(void);
2035static void setsignal(int);
2036static void ignoresig(int);
2037static void onsig(int);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002038static int dotrap(void);
Eric Andersenc470f442003-07-28 09:56:35 +00002039static void setinteractive(int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002040static void exitshell(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00002041
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002042
2043static int is_safe_applet(char *name)
2044{
2045 int n = sizeof(safe_applets) / sizeof(char *);
2046 int i;
2047 for (i = 0; i < n; i++)
2048 if (strcmp(safe_applets[i], name) == 0)
2049 return 1;
2050
2051 return 0;
2052}
2053
2054
Eric Andersenc470f442003-07-28 09:56:35 +00002055/*
2056 * This routine is called when an error or an interrupt occurs in an
2057 * interactive shell and control is returned to the main command loop.
2058 */
2059
2060static void
2061reset(void)
2062{
2063 /* from eval.c: */
2064 {
2065 evalskip = 0;
2066 loopnest = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002067 }
2068
2069 /* from input.c: */
2070 {
2071 parselleft = parsenleft = 0; /* clear input buffer */
2072 popallfiles();
2073 }
2074
2075 /* from parser.c: */
2076 {
2077 tokpushback = 0;
2078 checkkwd = 0;
2079 }
2080
2081 /* from redir.c: */
2082 {
2083 clearredir(0);
2084 }
2085
2086}
2087
2088#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002089static struct alias *atab[ATABSIZE];
2090
Eric Andersenc470f442003-07-28 09:56:35 +00002091static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002092static struct alias *freealias(struct alias *);
2093static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002094
Eric Andersenc470f442003-07-28 09:56:35 +00002095static void
2096setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002097{
2098 struct alias *ap, **app;
2099
2100 app = __lookupalias(name);
2101 ap = *app;
2102 INTOFF;
2103 if (ap) {
2104 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002105 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002106 }
Eric Andersenc470f442003-07-28 09:56:35 +00002107 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002108 ap->flag &= ~ALIASDEAD;
2109 } else {
2110 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002111 ap = ckmalloc(sizeof (struct alias));
2112 ap->name = savestr(name);
2113 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002114 ap->flag = 0;
2115 ap->next = 0;
2116 *app = ap;
2117 }
2118 INTON;
2119}
2120
Eric Andersenc470f442003-07-28 09:56:35 +00002121static int
2122unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002123{
Eric Andersencb57d552001-06-28 07:25:16 +00002124 struct alias **app;
2125
2126 app = __lookupalias(name);
2127
2128 if (*app) {
2129 INTOFF;
2130 *app = freealias(*app);
2131 INTON;
2132 return (0);
2133 }
2134
2135 return (1);
2136}
2137
Eric Andersenc470f442003-07-28 09:56:35 +00002138static void
2139rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002140{
Eric Andersencb57d552001-06-28 07:25:16 +00002141 struct alias *ap, **app;
2142 int i;
2143
2144 INTOFF;
2145 for (i = 0; i < ATABSIZE; i++) {
2146 app = &atab[i];
2147 for (ap = *app; ap; ap = *app) {
2148 *app = freealias(*app);
2149 if (ap == *app) {
2150 app = &ap->next;
2151 }
2152 }
2153 }
2154 INTON;
2155}
2156
Eric Andersenc470f442003-07-28 09:56:35 +00002157static struct alias *
2158lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002159{
Eric Andersenc470f442003-07-28 09:56:35 +00002160 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002161
Eric Andersenc470f442003-07-28 09:56:35 +00002162 if (check && ap && (ap->flag & ALIASINUSE))
2163 return (NULL);
2164 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002165}
2166
Eric Andersencb57d552001-06-28 07:25:16 +00002167/*
2168 * TODO - sort output
2169 */
Eric Andersenc470f442003-07-28 09:56:35 +00002170static int
2171aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002172{
2173 char *n, *v;
2174 int ret = 0;
2175 struct alias *ap;
2176
2177 if (argc == 1) {
2178 int i;
2179
2180 for (i = 0; i < ATABSIZE; i++)
2181 for (ap = atab[i]; ap; ap = ap->next) {
2182 printalias(ap);
2183 }
2184 return (0);
2185 }
2186 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002187 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002188 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002189 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002190 ret = 1;
2191 } else
2192 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002193 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002194 *v++ = '\0';
2195 setalias(n, v);
2196 }
2197 }
2198
2199 return (ret);
2200}
2201
Eric Andersenc470f442003-07-28 09:56:35 +00002202static int
2203unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002204{
2205 int i;
2206
2207 while ((i = nextopt("a")) != '\0') {
2208 if (i == 'a') {
2209 rmaliases();
2210 return (0);
2211 }
2212 }
2213 for (i = 0; *argptr; argptr++) {
2214 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002215 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002216 i = 1;
2217 }
2218 }
2219
2220 return (i);
2221}
2222
Eric Andersenc470f442003-07-28 09:56:35 +00002223static struct alias *
2224freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002225 struct alias *next;
2226
2227 if (ap->flag & ALIASINUSE) {
2228 ap->flag |= ALIASDEAD;
2229 return ap;
2230 }
2231
2232 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002233 ckfree(ap->name);
2234 ckfree(ap->val);
2235 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002236 return next;
2237}
2238
Eric Andersenc470f442003-07-28 09:56:35 +00002239static void
2240printalias(const struct alias *ap) {
2241 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2242}
Eric Andersencb57d552001-06-28 07:25:16 +00002243
Eric Andersenc470f442003-07-28 09:56:35 +00002244static struct alias **
2245__lookupalias(const char *name) {
2246 unsigned int hashval;
2247 struct alias **app;
2248 const char *p;
2249 unsigned int ch;
2250
2251 p = name;
2252
2253 ch = (unsigned char)*p;
2254 hashval = ch << 4;
2255 while (ch) {
2256 hashval += ch;
2257 ch = (unsigned char)*++p;
2258 }
2259 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002260
2261 for (; *app; app = &(*app)->next) {
2262 if (equal(name, (*app)->name)) {
2263 break;
2264 }
2265 }
2266
2267 return app;
2268}
Eric Andersenc470f442003-07-28 09:56:35 +00002269#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002270
Eric Andersencb57d552001-06-28 07:25:16 +00002271
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002272/* cd.c */
Eric Andersen2870d962001-07-02 17:27:21 +00002273
Eric Andersencb57d552001-06-28 07:25:16 +00002274/*
Eric Andersenc470f442003-07-28 09:56:35 +00002275 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002276 */
2277
Eric Andersenc470f442003-07-28 09:56:35 +00002278#define CD_PHYSICAL 1
2279#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002280
Eric Andersenc470f442003-07-28 09:56:35 +00002281static int docd(const char *, int);
2282static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002283
Eric Andersenc470f442003-07-28 09:56:35 +00002284static char *curdir = nullstr; /* current working directory */
2285static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002286
Eric Andersenc470f442003-07-28 09:56:35 +00002287static int
2288cdopt(void)
2289{
2290 int flags = 0;
2291 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002292
Eric Andersenc470f442003-07-28 09:56:35 +00002293 j = 'L';
2294 while ((i = nextopt("LP"))) {
2295 if (i != j) {
2296 flags ^= CD_PHYSICAL;
2297 j = i;
2298 }
2299 }
Eric Andersencb57d552001-06-28 07:25:16 +00002300
Eric Andersenc470f442003-07-28 09:56:35 +00002301 return flags;
2302}
Eric Andersen2870d962001-07-02 17:27:21 +00002303
Eric Andersenc470f442003-07-28 09:56:35 +00002304static int
2305cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002306{
2307 const char *dest;
2308 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002309 const char *p;
2310 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002311 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002312 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002313
Eric Andersenc470f442003-07-28 09:56:35 +00002314 flags = cdopt();
2315 dest = *argptr;
2316 if (!dest)
2317 dest = bltinlookup(homestr);
2318 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002319 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002320 flags |= CD_PRINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002321 }
Eric Andersenc470f442003-07-28 09:56:35 +00002322 if (!dest)
2323 dest = nullstr;
2324 if (*dest == '/')
2325 goto step7;
2326 if (*dest == '.') {
2327 c = dest[1];
2328dotdot:
2329 switch (c) {
2330 case '\0':
2331 case '/':
2332 goto step6;
2333 case '.':
2334 c = dest[2];
2335 if (c != '.')
2336 goto dotdot;
2337 }
2338 }
2339 if (!*dest)
2340 dest = ".";
2341 if (!(path = bltinlookup("CDPATH"))) {
2342step6:
2343step7:
2344 p = dest;
2345 goto docd;
2346 }
2347 do {
2348 c = *path;
2349 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002350 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002351 if (c && c != ':')
2352 flags |= CD_PRINT;
2353docd:
2354 if (!docd(p, flags))
2355 goto out;
2356 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002357 }
Eric Andersenc470f442003-07-28 09:56:35 +00002358 } while (path);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002359 sh_error("can't cd to %s", dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002360 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002361out:
2362 if (flags & CD_PRINT)
2363 out1fmt(snlfmt, curdir);
2364 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002365}
2366
2367
2368/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002369 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002370 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002371 */
2372
Rob Landley88621d72006-08-29 19:41:06 +00002373static const char * updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002374{
Eric Andersenc470f442003-07-28 09:56:35 +00002375 char *new;
2376 char *p;
2377 char *cdcomppath;
2378 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002379
Eric Andersenc470f442003-07-28 09:56:35 +00002380 cdcomppath = sstrdup(dir);
2381 STARTSTACKSTR(new);
2382 if (*dir != '/') {
2383 if (curdir == nullstr)
2384 return 0;
2385 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002386 }
Eric Andersenc470f442003-07-28 09:56:35 +00002387 new = makestrspace(strlen(dir) + 2, new);
2388 lim = stackblock() + 1;
2389 if (*dir != '/') {
2390 if (new[-1] != '/')
2391 USTPUTC('/', new);
2392 if (new > lim && *lim == '/')
2393 lim++;
2394 } else {
2395 USTPUTC('/', new);
2396 cdcomppath++;
2397 if (dir[1] == '/' && dir[2] != '/') {
2398 USTPUTC('/', new);
2399 cdcomppath++;
2400 lim++;
2401 }
2402 }
2403 p = strtok(cdcomppath, "/");
2404 while (p) {
2405 switch(*p) {
2406 case '.':
2407 if (p[1] == '.' && p[2] == '\0') {
2408 while (new > lim) {
2409 STUNPUTC(new);
2410 if (new[-1] == '/')
2411 break;
2412 }
2413 break;
2414 } else if (p[1] == '\0')
2415 break;
2416 /* fall through */
2417 default:
2418 new = stputs(p, new);
2419 USTPUTC('/', new);
2420 }
2421 p = strtok(0, "/");
2422 }
2423 if (new > lim)
2424 STUNPUTC(new);
2425 *new = 0;
2426 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002427}
2428
2429/*
Eric Andersenc470f442003-07-28 09:56:35 +00002430 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2431 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002432 */
2433
Eric Andersenc470f442003-07-28 09:56:35 +00002434static int
2435docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002436{
Eric Andersenc470f442003-07-28 09:56:35 +00002437 const char *dir = 0;
2438 int err;
2439
2440 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2441
Eric Andersencb57d552001-06-28 07:25:16 +00002442 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002443 if (!(flags & CD_PHYSICAL)) {
2444 dir = updatepwd(dest);
2445 if (dir)
2446 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002447 }
Eric Andersenc470f442003-07-28 09:56:35 +00002448 err = chdir(dest);
2449 if (err)
2450 goto out;
2451 setpwd(dir, 1);
2452 hashcd();
2453out:
Eric Andersencb57d552001-06-28 07:25:16 +00002454 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002455 return err;
2456}
2457
2458/*
2459 * Find out what the current directory is. If we already know the current
2460 * directory, this routine returns immediately.
2461 */
Rob Landley88621d72006-08-29 19:41:06 +00002462static char * getpwd(void)
Eric Andersenc470f442003-07-28 09:56:35 +00002463{
2464 char *dir = getcwd(0, 0);
2465 return dir ? dir : nullstr;
2466}
2467
2468static int
2469pwdcmd(int argc, char **argv)
2470{
2471 int flags;
2472 const char *dir = curdir;
2473
2474 flags = cdopt();
2475 if (flags) {
2476 if (physdir == nullstr)
2477 setpwd(dir, 0);
2478 dir = physdir;
2479 }
2480 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002481 return 0;
2482}
2483
Eric Andersenc470f442003-07-28 09:56:35 +00002484static void
2485setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002486{
Eric Andersenc470f442003-07-28 09:56:35 +00002487 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002488
Eric Andersenc470f442003-07-28 09:56:35 +00002489 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002490
Eric Andersencb57d552001-06-28 07:25:16 +00002491 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002492 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002493 }
2494 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002495 if (physdir != nullstr) {
2496 if (physdir != oldcur)
2497 free(physdir);
2498 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002499 }
Eric Andersenc470f442003-07-28 09:56:35 +00002500 if (oldcur == val || !val) {
2501 char *s = getpwd();
2502 physdir = s;
2503 if (!val)
2504 dir = s;
2505 } else
2506 dir = savestr(val);
2507 if (oldcur != dir && oldcur != nullstr) {
2508 free(oldcur);
2509 }
2510 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002511 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002512 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002513}
2514
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002515/* error.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002516
Eric Andersencb57d552001-06-28 07:25:16 +00002517/*
2518 * Errors and exceptions.
2519 */
2520
2521/*
2522 * Code to handle exceptions in C.
2523 */
2524
Eric Andersen2870d962001-07-02 17:27:21 +00002525
Eric Andersencb57d552001-06-28 07:25:16 +00002526
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002527static void exverror(int, const char *, va_list)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002528 ATTRIBUTE_NORETURN;
Eric Andersencb57d552001-06-28 07:25:16 +00002529
2530/*
2531 * Called to raise an exception. Since C doesn't include exceptions, we
2532 * just do a longjmp to the exception handler. The type of exception is
2533 * stored in the global variable "exception".
2534 */
2535
Eric Andersenc470f442003-07-28 09:56:35 +00002536static void
2537exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002538{
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00002539#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002540 if (handler == NULL)
2541 abort();
2542#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002543 INTOFF;
2544
Eric Andersencb57d552001-06-28 07:25:16 +00002545 exception = e;
2546 longjmp(handler->loc, 1);
2547}
2548
2549
2550/*
2551 * Called from trap.c when a SIGINT is received. (If the user specifies
2552 * that SIGINT is to be trapped or ignored using the trap builtin, then
2553 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002554 * are held using the INTOFF macro. (The test for iflag is just
2555 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002556 */
2557
Eric Andersenc470f442003-07-28 09:56:35 +00002558static void
2559onint(void) {
2560 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002561
Eric Andersencb57d552001-06-28 07:25:16 +00002562 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002563 i = EXSIG;
2564 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2565 if (!(rootshell && iflag)) {
2566 signal(SIGINT, SIG_DFL);
2567 raise(SIGINT);
2568 }
2569 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002570 }
Eric Andersenc470f442003-07-28 09:56:35 +00002571 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002572 /* NOTREACHED */
2573}
2574
Eric Andersenc470f442003-07-28 09:56:35 +00002575static void
2576exvwarning(const char *msg, va_list ap)
2577{
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002578 FILE *errs;
Eric Andersencb57d552001-06-28 07:25:16 +00002579
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002580 errs = stderr;
2581 fprintf(errs, "%s: ", arg0);
2582 if (commandname) {
2583 const char *fmt = (!iflag || parsefile->fd) ?
2584 "%s: %d: " : "%s: ";
2585 fprintf(errs, fmt, commandname, startlinno);
2586 }
2587 vfprintf(errs, msg, ap);
2588 outcslow('\n', errs);
Eric Andersenc470f442003-07-28 09:56:35 +00002589}
Eric Andersen2870d962001-07-02 17:27:21 +00002590
Eric Andersencb57d552001-06-28 07:25:16 +00002591/*
Eric Andersenc470f442003-07-28 09:56:35 +00002592 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002593 * is not NULL then error prints an error message using printf style
2594 * formatting. It then raises the error exception.
2595 */
Eric Andersenc470f442003-07-28 09:56:35 +00002596static void
2597exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002598{
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00002599#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002600 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002601 TRACE(("exverror(%d, \"", cond));
2602 TRACEV((msg, ap));
2603 TRACE(("\") pid=%d\n", getpid()));
2604 } else
2605 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2606 if (msg)
2607#endif
2608 exvwarning(msg, ap);
2609
2610 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002611 exraise(cond);
2612 /* NOTREACHED */
2613}
2614
2615
Eric Andersenc470f442003-07-28 09:56:35 +00002616static void
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002617sh_error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002618{
Eric Andersencb57d552001-06-28 07:25:16 +00002619 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002620
Eric Andersencb57d552001-06-28 07:25:16 +00002621 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002622 exverror(EXERROR, msg, ap);
2623 /* NOTREACHED */
2624 va_end(ap);
2625}
2626
2627
Eric Andersenc470f442003-07-28 09:56:35 +00002628static void
2629exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002630{
Eric Andersencb57d552001-06-28 07:25:16 +00002631 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002632
Eric Andersencb57d552001-06-28 07:25:16 +00002633 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002634 exverror(cond, msg, ap);
2635 /* NOTREACHED */
2636 va_end(ap);
2637}
2638
Eric Andersencb57d552001-06-28 07:25:16 +00002639/*
Eric Andersenc470f442003-07-28 09:56:35 +00002640 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002641 */
2642
Eric Andersenc470f442003-07-28 09:56:35 +00002643static void
2644sh_warnx(const char *fmt, ...)
2645{
2646 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002647
Eric Andersenc470f442003-07-28 09:56:35 +00002648 va_start(ap, fmt);
2649 exvwarning(fmt, ap);
2650 va_end(ap);
2651}
Eric Andersen2870d962001-07-02 17:27:21 +00002652
Eric Andersencb57d552001-06-28 07:25:16 +00002653
2654/*
2655 * Return a string describing an error. The returned string may be a
2656 * pointer to a static buffer that will be overwritten on the next call.
2657 * Action describes the operation that got the error.
2658 */
2659
Eric Andersenc470f442003-07-28 09:56:35 +00002660static const char *
2661errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002662{
Eric Andersenc470f442003-07-28 09:56:35 +00002663 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002664
Eric Andersenc470f442003-07-28 09:56:35 +00002665 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002666 }
Eric Andersenc470f442003-07-28 09:56:35 +00002667 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002668}
2669
2670
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002671/* eval.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002672
2673/*
2674 * Evaluate a command.
2675 */
Eric Andersencb57d552001-06-28 07:25:16 +00002676
2677/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002678#define EV_EXIT 01 /* exit after evaluating tree */
2679#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2680#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002681
2682
Eric Andersenc470f442003-07-28 09:56:35 +00002683static void evalloop(union node *, int);
2684static void evalfor(union node *, int);
2685static void evalcase(union node *, int);
2686static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002687static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002688static void evalpipe(union node *, int);
2689static void evalcommand(union node *, int);
2690static int evalbltin(const struct builtincmd *, int, char **);
2691static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002692static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002693static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002694
Eric Andersenc470f442003-07-28 09:56:35 +00002695
2696static const struct builtincmd bltin = {
2697 "\0\0", bltincmd
2698};
2699
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002700
Eric Andersencb57d552001-06-28 07:25:16 +00002701/*
2702 * Called to reset things after an exception.
2703 */
2704
Eric Andersencb57d552001-06-28 07:25:16 +00002705/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002706 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002707 */
2708
Eric Andersenc470f442003-07-28 09:56:35 +00002709static int
2710evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002711{
Eric Andersen2870d962001-07-02 17:27:21 +00002712 char *p;
2713 char *concat;
2714 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002715
Eric Andersen2870d962001-07-02 17:27:21 +00002716 if (argc > 1) {
2717 p = argv[1];
2718 if (argc > 2) {
2719 STARTSTACKSTR(concat);
2720 ap = argv + 2;
2721 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002722 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002723 if ((p = *ap++) == NULL)
2724 break;
2725 STPUTC(' ', concat);
2726 }
2727 STPUTC('\0', concat);
2728 p = grabstackstr(concat);
2729 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002730 evalstring(p, ~SKIPEVAL);
2731
Eric Andersen2870d962001-07-02 17:27:21 +00002732 }
2733 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002734}
2735
Eric Andersenc470f442003-07-28 09:56:35 +00002736
Eric Andersencb57d552001-06-28 07:25:16 +00002737/*
2738 * Execute a command or commands contained in a string.
2739 */
2740
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002741static int
2742evalstring(char *s, int mask)
Eric Andersen2870d962001-07-02 17:27:21 +00002743{
Eric Andersencb57d552001-06-28 07:25:16 +00002744 union node *n;
2745 struct stackmark smark;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002746 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002747
Eric Andersencb57d552001-06-28 07:25:16 +00002748 setinputstring(s);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002749 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002750
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002751 skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002752 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002753 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002754 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002755 skip = evalskip;
2756 if (skip)
Eric Andersenc470f442003-07-28 09:56:35 +00002757 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002758 }
2759 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002760
2761 skip &= mask;
2762 evalskip = skip;
2763 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002764}
2765
Eric Andersenc470f442003-07-28 09:56:35 +00002766
Eric Andersen62483552001-07-10 06:09:16 +00002767
2768/*
Eric Andersenc470f442003-07-28 09:56:35 +00002769 * Evaluate a parse tree. The value is left in the global variable
2770 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002771 */
2772
Eric Andersenc470f442003-07-28 09:56:35 +00002773static void
2774evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002775{
Eric Andersenc470f442003-07-28 09:56:35 +00002776 int checkexit = 0;
2777 void (*evalfn)(union node *, int);
2778 unsigned isor;
2779 int status;
2780 if (n == NULL) {
2781 TRACE(("evaltree(NULL) called\n"));
2782 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002783 }
Eric Andersenc470f442003-07-28 09:56:35 +00002784 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2785 getpid(), n, n->type, flags));
2786 switch (n->type) {
2787 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00002788#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00002789 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002790 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002791 break;
2792#endif
2793 case NNOT:
2794 evaltree(n->nnot.com, EV_TESTED);
2795 status = !exitstatus;
2796 goto setstatus;
2797 case NREDIR:
2798 expredir(n->nredir.redirect);
2799 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2800 if (!status) {
2801 evaltree(n->nredir.n, flags & EV_TESTED);
2802 status = exitstatus;
2803 }
2804 popredir(0);
2805 goto setstatus;
2806 case NCMD:
2807 evalfn = evalcommand;
2808checkexit:
2809 if (eflag && !(flags & EV_TESTED))
2810 checkexit = ~0;
2811 goto calleval;
2812 case NFOR:
2813 evalfn = evalfor;
2814 goto calleval;
2815 case NWHILE:
2816 case NUNTIL:
2817 evalfn = evalloop;
2818 goto calleval;
2819 case NSUBSHELL:
2820 case NBACKGND:
2821 evalfn = evalsubshell;
2822 goto calleval;
2823 case NPIPE:
2824 evalfn = evalpipe;
2825 goto checkexit;
2826 case NCASE:
2827 evalfn = evalcase;
2828 goto calleval;
2829 case NAND:
2830 case NOR:
2831 case NSEMI:
2832#if NAND + 1 != NOR
2833#error NAND + 1 != NOR
2834#endif
2835#if NOR + 1 != NSEMI
2836#error NOR + 1 != NSEMI
2837#endif
2838 isor = n->type - NAND;
2839 evaltree(
2840 n->nbinary.ch1,
2841 (flags | ((isor >> 1) - 1)) & EV_TESTED
2842 );
2843 if (!exitstatus == isor)
2844 break;
2845 if (!evalskip) {
2846 n = n->nbinary.ch2;
2847evaln:
2848 evalfn = evaltree;
2849calleval:
2850 evalfn(n, flags);
2851 break;
2852 }
2853 break;
2854 case NIF:
2855 evaltree(n->nif.test, EV_TESTED);
2856 if (evalskip)
2857 break;
2858 if (exitstatus == 0) {
2859 n = n->nif.ifpart;
2860 goto evaln;
2861 } else if (n->nif.elsepart) {
2862 n = n->nif.elsepart;
2863 goto evaln;
2864 }
2865 goto success;
2866 case NDEFUN:
2867 defun(n->narg.text, n->narg.next);
2868success:
2869 status = 0;
2870setstatus:
2871 exitstatus = status;
2872 break;
2873 }
2874out:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002875 if ((checkexit & exitstatus))
2876 evalskip |= SKIPEVAL;
2877 else if (pendingsigs && dotrap())
2878 goto exexit;
2879
2880 if (flags & EV_EXIT) {
2881exexit:
Eric Andersenc470f442003-07-28 09:56:35 +00002882 exraise(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002883 }
Eric Andersen62483552001-07-10 06:09:16 +00002884}
2885
Eric Andersenc470f442003-07-28 09:56:35 +00002886
2887#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2888static
2889#endif
2890void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2891
2892
2893static void
2894evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002895{
2896 int status;
2897
2898 loopnest++;
2899 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002900 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002901 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002902 int i;
2903
Eric Andersencb57d552001-06-28 07:25:16 +00002904 evaltree(n->nbinary.ch1, EV_TESTED);
2905 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002906skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002907 evalskip = 0;
2908 continue;
2909 }
2910 if (evalskip == SKIPBREAK && --skipcount <= 0)
2911 evalskip = 0;
2912 break;
2913 }
Eric Andersenc470f442003-07-28 09:56:35 +00002914 i = exitstatus;
2915 if (n->type != NWHILE)
2916 i = !i;
2917 if (i != 0)
2918 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002919 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002920 status = exitstatus;
2921 if (evalskip)
2922 goto skipping;
2923 }
2924 loopnest--;
2925 exitstatus = status;
2926}
2927
Eric Andersenc470f442003-07-28 09:56:35 +00002928
2929
2930static void
2931evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002932{
2933 struct arglist arglist;
2934 union node *argp;
2935 struct strlist *sp;
2936 struct stackmark smark;
2937
2938 setstackmark(&smark);
2939 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002940 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002941 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002942 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002943 if (evalskip)
2944 goto out;
2945 }
2946 *arglist.lastp = NULL;
2947
2948 exitstatus = 0;
2949 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002950 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002951 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002952 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002953 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002954 if (evalskip) {
2955 if (evalskip == SKIPCONT && --skipcount <= 0) {
2956 evalskip = 0;
2957 continue;
2958 }
2959 if (evalskip == SKIPBREAK && --skipcount <= 0)
2960 evalskip = 0;
2961 break;
2962 }
2963 }
2964 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002965out:
Eric Andersencb57d552001-06-28 07:25:16 +00002966 popstackmark(&smark);
2967}
2968
Eric Andersenc470f442003-07-28 09:56:35 +00002969
2970
2971static void
2972evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002973{
2974 union node *cp;
2975 union node *patp;
2976 struct arglist arglist;
2977 struct stackmark smark;
2978
2979 setstackmark(&smark);
2980 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002981 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002982 exitstatus = 0;
2983 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2984 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002985 if (casematch(patp, arglist.list->text)) {
2986 if (evalskip == 0) {
2987 evaltree(cp->nclist.body, flags);
2988 }
2989 goto out;
2990 }
2991 }
2992 }
Eric Andersenc470f442003-07-28 09:56:35 +00002993out:
Eric Andersencb57d552001-06-28 07:25:16 +00002994 popstackmark(&smark);
2995}
2996
Eric Andersenc470f442003-07-28 09:56:35 +00002997
2998
2999/*
3000 * Kick off a subshell to evaluate a tree.
3001 */
3002
3003static void
3004evalsubshell(union node *n, int flags)
3005{
3006 struct job *jp;
3007 int backgnd = (n->type == NBACKGND);
3008 int status;
3009
3010 expredir(n->nredir.redirect);
3011 if (!backgnd && flags & EV_EXIT && !trap[0])
3012 goto nofork;
3013 INTOFF;
3014 jp = makejob(n, 1);
3015 if (forkshell(jp, n, backgnd) == 0) {
3016 INTON;
3017 flags |= EV_EXIT;
3018 if (backgnd)
3019 flags &=~ EV_TESTED;
3020nofork:
3021 redirect(n->nredir.redirect, 0);
3022 evaltreenr(n->nredir.n, flags);
3023 /* never returns */
3024 }
3025 status = 0;
3026 if (! backgnd)
3027 status = waitforjob(jp);
3028 exitstatus = status;
3029 INTON;
3030}
3031
3032
3033
3034/*
3035 * Compute the names of the files in a redirection list.
3036 */
3037
3038static void
3039expredir(union node *n)
3040{
3041 union node *redir;
3042
3043 for (redir = n ; redir ; redir = redir->nfile.next) {
3044 struct arglist fn;
Denis Vlasenko5f031582006-10-16 01:33:16 +00003045 memset(&fn, 0, sizeof(struct arglist));
Eric Andersenc470f442003-07-28 09:56:35 +00003046 fn.lastp = &fn.list;
3047 switch (redir->type) {
3048 case NFROMTO:
3049 case NFROM:
3050 case NTO:
3051 case NCLOBBER:
3052 case NAPPEND:
3053 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3054 redir->nfile.expfname = fn.list->text;
3055 break;
3056 case NFROMFD:
3057 case NTOFD:
3058 if (redir->ndup.vname) {
3059 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko5f031582006-10-16 01:33:16 +00003060 if (fn.list != NULL)
3061 fixredir(redir, fn.list->text, 1);
3062 else
3063 sh_error("redir error");
Eric Andersenc470f442003-07-28 09:56:35 +00003064 }
3065 break;
3066 }
3067 }
3068}
3069
3070
3071
Eric Andersencb57d552001-06-28 07:25:16 +00003072/*
Eric Andersencb57d552001-06-28 07:25:16 +00003073 * Evaluate a pipeline. All the processes in the pipeline are children
3074 * of the process creating the pipeline. (This differs from some versions
3075 * of the shell, which make the last process in a pipeline the parent
3076 * of all the rest.)
3077 */
3078
Eric Andersenc470f442003-07-28 09:56:35 +00003079static void
3080evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003081{
3082 struct job *jp;
3083 struct nodelist *lp;
3084 int pipelen;
3085 int prevfd;
3086 int pip[2];
3087
Eric Andersenc470f442003-07-28 09:56:35 +00003088 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003089 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003090 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003091 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003092 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003093 INTOFF;
3094 jp = makejob(n, pipelen);
3095 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003096 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003097 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003098 pip[1] = -1;
3099 if (lp->next) {
3100 if (pipe(pip) < 0) {
3101 close(prevfd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003102 sh_error("Pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00003103 }
3104 }
3105 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3106 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003107 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003108 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003109 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003110 if (prevfd > 0) {
3111 dup2(prevfd, 0);
3112 close(prevfd);
3113 }
3114 if (pip[1] > 1) {
3115 dup2(pip[1], 1);
3116 close(pip[1]);
3117 }
Eric Andersenc470f442003-07-28 09:56:35 +00003118 evaltreenr(lp->n, flags);
3119 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003120 }
3121 if (prevfd >= 0)
3122 close(prevfd);
3123 prevfd = pip[0];
3124 close(pip[1]);
3125 }
Eric Andersencb57d552001-06-28 07:25:16 +00003126 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003127 exitstatus = waitforjob(jp);
3128 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003129 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003130 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003131}
3132
Eric Andersen62483552001-07-10 06:09:16 +00003133
3134
3135/*
3136 * Execute a command inside back quotes. If it's a builtin command, we
3137 * want to save its output in a block obtained from malloc. Otherwise
3138 * we fork off a subprocess and get the output of the command via a pipe.
3139 * Should be called with interrupts off.
3140 */
3141
Eric Andersenc470f442003-07-28 09:56:35 +00003142static void
3143evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003144{
Eric Andersenc470f442003-07-28 09:56:35 +00003145 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003146
Eric Andersen62483552001-07-10 06:09:16 +00003147 result->fd = -1;
3148 result->buf = NULL;
3149 result->nleft = 0;
3150 result->jp = NULL;
3151 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003152 goto out;
3153 }
Eric Andersenc470f442003-07-28 09:56:35 +00003154
3155 saveherefd = herefd;
3156 herefd = -1;
3157
3158 {
3159 int pip[2];
3160 struct job *jp;
3161
3162 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003163 sh_error("Pipe call failed");
Eric Andersenc470f442003-07-28 09:56:35 +00003164 jp = makejob(n, 1);
3165 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3166 FORCEINTON;
3167 close(pip[0]);
3168 if (pip[1] != 1) {
3169 close(1);
3170 copyfd(pip[1], 1);
3171 close(pip[1]);
3172 }
3173 eflag = 0;
3174 evaltreenr(n, EV_EXIT);
3175 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003176 }
Eric Andersenc470f442003-07-28 09:56:35 +00003177 close(pip[1]);
3178 result->fd = pip[0];
3179 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003180 }
Eric Andersenc470f442003-07-28 09:56:35 +00003181 herefd = saveherefd;
3182out:
Eric Andersen62483552001-07-10 06:09:16 +00003183 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003184 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003185}
3186
Eric Andersenc470f442003-07-28 09:56:35 +00003187#ifdef CONFIG_ASH_CMDCMD
Rob Landley88621d72006-08-29 19:41:06 +00003188static char ** parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00003189{
3190 char *cp, c;
3191
3192 for (;;) {
3193 cp = *++argv;
3194 if (!cp)
3195 return 0;
3196 if (*cp++ != '-')
3197 break;
3198 if (!(c = *cp++))
3199 break;
3200 if (c == '-' && !*cp) {
3201 argv++;
3202 break;
3203 }
3204 do {
3205 switch (c) {
3206 case 'p':
3207 *path = defpath;
3208 break;
3209 default:
3210 /* run 'typecmd' for other options */
3211 return 0;
3212 }
3213 } while ((c = *cp++));
3214 }
3215 return argv;
3216}
3217#endif
3218
Rob Landley88621d72006-08-29 19:41:06 +00003219static int isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00003220{
3221 const char *q = endofname(p);
3222 if (p == q)
3223 return 0;
3224 return *q == '=';
3225}
Eric Andersen62483552001-07-10 06:09:16 +00003226
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003227#ifdef CONFIG_ASH_EXPAND_PRMT
3228static const char *expandstr(const char *ps);
3229#else
3230#define expandstr(s) s
3231#endif
3232
Eric Andersen62483552001-07-10 06:09:16 +00003233/*
3234 * Execute a simple command.
3235 */
Eric Andersencb57d552001-06-28 07:25:16 +00003236
Eric Andersenc470f442003-07-28 09:56:35 +00003237static void
3238evalcommand(union node *cmd, int flags)
3239{
3240 struct stackmark smark;
3241 union node *argp;
3242 struct arglist arglist;
3243 struct arglist varlist;
3244 char **argv;
3245 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003246 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003247 struct cmdentry cmdentry;
3248 struct job *jp;
3249 char *lastarg;
3250 const char *path;
3251 int spclbltin;
3252 int cmd_is_exec;
3253 int status;
3254 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003255 struct builtincmd *bcmd;
3256 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003257
3258 /* First expand the arguments. */
3259 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3260 setstackmark(&smark);
3261 back_exitstatus = 0;
3262
3263 cmdentry.cmdtype = CMDBUILTIN;
3264 cmdentry.u.cmd = &bltin;
3265 varlist.lastp = &varlist.list;
3266 *varlist.lastp = NULL;
3267 arglist.lastp = &arglist.list;
3268 *arglist.lastp = NULL;
3269
3270 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003271 if (cmd->ncmd.args)
3272 {
3273 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3274 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3275 }
3276
Eric Andersenc470f442003-07-28 09:56:35 +00003277 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3278 struct strlist **spp;
3279
3280 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003281 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00003282 expandarg(argp, &arglist, EXP_VARTILDE);
3283 else
3284 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3285
Eric Andersenc470f442003-07-28 09:56:35 +00003286 for (sp = *spp; sp; sp = sp->next)
3287 argc++;
3288 }
3289
3290 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3291 for (sp = arglist.list ; sp ; sp = sp->next) {
3292 TRACE(("evalcommand arg: %s\n", sp->text));
3293 *nargv++ = sp->text;
3294 }
3295 *nargv = NULL;
3296
3297 lastarg = NULL;
3298 if (iflag && funcnest == 0 && argc > 0)
3299 lastarg = nargv[-1];
3300
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003301 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003302 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003303 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003304
3305 path = vpath.text;
3306 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3307 struct strlist **spp;
3308 char *p;
3309
3310 spp = varlist.lastp;
3311 expandarg(argp, &varlist, EXP_VARTILDE);
3312
3313 /*
3314 * Modify the command lookup path, if a PATH= assignment
3315 * is present
3316 */
3317 p = (*spp)->text;
3318 if (varequal(p, path))
3319 path = p;
3320 }
3321
3322 /* Print the command if xflag is set. */
3323 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003324 int n;
3325 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003326
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003327 p++;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003328 dprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003329
3330 sp = varlist.list;
3331 for(n = 0; n < 2; n++) {
3332 while (sp) {
3333 dprintf(preverrout_fd, p, sp->text);
3334 sp = sp->next;
3335 if(*p == '%') {
3336 p--;
3337 }
3338 }
3339 sp = arglist.list;
3340 }
Rob Landley53437472006-07-16 08:14:35 +00003341 full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003342 }
3343
3344 cmd_is_exec = 0;
3345 spclbltin = -1;
3346
3347 /* Now locate the command. */
3348 if (argc) {
3349 const char *oldpath;
3350 int cmd_flag = DO_ERR;
3351
3352 path += 5;
3353 oldpath = path;
3354 for (;;) {
3355 find_command(argv[0], &cmdentry, cmd_flag, path);
3356 if (cmdentry.cmdtype == CMDUNKNOWN) {
3357 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003358 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003359 goto bail;
3360 }
3361
3362 /* implement bltin and command here */
3363 if (cmdentry.cmdtype != CMDBUILTIN)
3364 break;
3365 if (spclbltin < 0)
3366 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3367 if (cmdentry.u.cmd == EXECCMD)
3368 cmd_is_exec++;
3369#ifdef CONFIG_ASH_CMDCMD
3370 if (cmdentry.u.cmd == COMMANDCMD) {
3371
3372 path = oldpath;
3373 nargv = parse_command_args(argv, &path);
3374 if (!nargv)
3375 break;
3376 argc -= nargv - argv;
3377 argv = nargv;
3378 cmd_flag |= DO_NOFUNC;
3379 } else
3380#endif
3381 break;
3382 }
3383 }
3384
3385 if (status) {
3386 /* We have a redirection error. */
3387 if (spclbltin > 0)
3388 exraise(EXERROR);
3389bail:
3390 exitstatus = status;
3391 goto out;
3392 }
3393
3394 /* Execute the command. */
3395 switch (cmdentry.cmdtype) {
3396 default:
3397 /* Fork off a child process if necessary. */
3398 if (!(flags & EV_EXIT) || trap[0]) {
3399 INTOFF;
3400 jp = makejob(cmd, 1);
3401 if (forkshell(jp, cmd, FORK_FG) != 0) {
3402 exitstatus = waitforjob(jp);
3403 INTON;
3404 break;
3405 }
3406 FORCEINTON;
3407 }
3408 listsetvar(varlist.list, VEXPORT|VSTACK);
3409 shellexec(argv, path, cmdentry.u.index);
3410 /* NOTREACHED */
3411
3412 case CMDBUILTIN:
3413 cmdenviron = varlist.list;
3414 if (cmdenviron) {
3415 struct strlist *list = cmdenviron;
3416 int i = VNOSET;
3417 if (spclbltin > 0 || argc == 0) {
3418 i = 0;
3419 if (cmd_is_exec && argc > 1)
3420 i = VEXPORT;
3421 }
3422 listsetvar(list, i);
3423 }
3424 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3425 int exit_status;
3426 int i, j;
3427
3428 i = exception;
3429 if (i == EXEXIT)
3430 goto raise;
3431
3432 exit_status = 2;
3433 j = 0;
3434 if (i == EXINT)
3435 j = SIGINT;
3436 if (i == EXSIG)
3437 j = pendingsigs;
3438 if (j)
3439 exit_status = j + 128;
3440 exitstatus = exit_status;
3441
3442 if (i == EXINT || spclbltin > 0) {
3443raise:
3444 longjmp(handler->loc, 1);
3445 }
3446 FORCEINTON;
3447 }
3448 break;
3449
3450 case CMDFUNCTION:
3451 listsetvar(varlist.list, 0);
3452 if (evalfun(cmdentry.u.func, argc, argv, flags))
3453 goto raise;
3454 break;
3455 }
3456
3457out:
3458 popredir(cmd_is_exec);
3459 if (lastarg)
3460 /* dsl: I think this is intended to be used to support
3461 * '_' in 'vi' command mode during line editing...
3462 * However I implemented that within libedit itself.
3463 */
3464 setvar("_", lastarg, 0);
3465 popstackmark(&smark);
3466}
3467
3468static int
3469evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3470 char *volatile savecmdname;
3471 struct jmploc *volatile savehandler;
3472 struct jmploc jmploc;
3473 int i;
3474
3475 savecmdname = commandname;
3476 if ((i = setjmp(jmploc.loc)))
3477 goto cmddone;
3478 savehandler = handler;
3479 handler = &jmploc;
3480 commandname = argv[0];
3481 argptr = argv + 1;
3482 optptr = NULL; /* initialize nextopt */
3483 exitstatus = (*cmd->builtin)(argc, argv);
3484 flushall();
3485cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003486 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00003487 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003488 commandname = savecmdname;
3489 exsig = 0;
3490 handler = savehandler;
3491
3492 return i;
3493}
3494
3495static int
3496evalfun(struct funcnode *func, int argc, char **argv, int flags)
3497{
3498 volatile struct shparam saveparam;
3499 struct localvar *volatile savelocalvars;
3500 struct jmploc *volatile savehandler;
3501 struct jmploc jmploc;
3502 int e;
3503
3504 saveparam = shellparam;
3505 savelocalvars = localvars;
3506 if ((e = setjmp(jmploc.loc))) {
3507 goto funcdone;
3508 }
3509 INTOFF;
3510 savehandler = handler;
3511 handler = &jmploc;
3512 localvars = NULL;
3513 shellparam.malloc = 0;
3514 func->count++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003515 funcnest++;
Eric Andersenc470f442003-07-28 09:56:35 +00003516 INTON;
3517 shellparam.nparam = argc - 1;
3518 shellparam.p = argv + 1;
3519#ifdef CONFIG_ASH_GETOPTS
3520 shellparam.optind = 1;
3521 shellparam.optoff = -1;
3522#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003523 evaltree(&func->n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00003524funcdone:
3525 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003526 funcnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00003527 freefunc(func);
3528 poplocalvars();
3529 localvars = savelocalvars;
3530 freeparam(&shellparam);
3531 shellparam = saveparam;
3532 handler = savehandler;
3533 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003534 evalskip &= ~SKIPFUNC;
Eric Andersenc470f442003-07-28 09:56:35 +00003535 return e;
3536}
3537
3538
Rob Landley88621d72006-08-29 19:41:06 +00003539static int goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003540{
3541 return !*endofname(p);
3542}
3543
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003544/*
3545 * Search for a command. This is called before we fork so that the
3546 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003547 * the child. The check for "goodname" is an overly conservative
3548 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003549 */
3550
Eric Andersenc470f442003-07-28 09:56:35 +00003551static void
3552prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003553{
3554 struct cmdentry entry;
3555
3556 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003557 if (goodname(n->ncmd.args->narg.text))
3558 find_command(n->ncmd.args->narg.text, &entry, 0,
3559 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003560}
3561
Eric Andersencb57d552001-06-28 07:25:16 +00003562
Eric Andersenc470f442003-07-28 09:56:35 +00003563
Eric Andersencb57d552001-06-28 07:25:16 +00003564/*
3565 * Builtin commands. Builtin commands whose functions are closely
3566 * tied to evaluation are implemented here.
3567 */
3568
3569/*
Eric Andersenc470f442003-07-28 09:56:35 +00003570 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003571 */
3572
Eric Andersenc470f442003-07-28 09:56:35 +00003573static int
3574bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003575{
3576 /*
3577 * Preserve exitstatus of a previous possible redirection
3578 * as POSIX mandates
3579 */
Eric Andersenc470f442003-07-28 09:56:35 +00003580 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003581}
3582
3583
3584/*
3585 * Handle break and continue commands. Break, continue, and return are
3586 * all handled by setting the evalskip flag. The evaluation routines
3587 * above all check this flag, and if it is set they start skipping
3588 * commands rather than executing them. The variable skipcount is
3589 * the number of loops to break/continue, or the number of function
3590 * levels to return. (The latter is always 1.) It should probably
3591 * be an error to break out of more loops than exist, but it isn't
3592 * in the standard shell so we don't make it one here.
3593 */
3594
Eric Andersenc470f442003-07-28 09:56:35 +00003595static int
3596breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003597{
3598 int n = argc > 1 ? number(argv[1]) : 1;
3599
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003600 if (n <= 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003601 sh_error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003602 if (n > loopnest)
3603 n = loopnest;
3604 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003605 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003606 skipcount = n;
3607 }
3608 return 0;
3609}
3610
3611
3612/*
3613 * The return command.
3614 */
3615
Eric Andersenc470f442003-07-28 09:56:35 +00003616static int
3617returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003618{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003619 /*
3620 * If called outside a function, do what ksh does;
3621 * skip the rest of the file.
3622 */
3623 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
3624 return argv[1] ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003625}
3626
3627
Eric Andersenc470f442003-07-28 09:56:35 +00003628static int
3629falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003630{
3631 return 1;
3632}
3633
Eric Andersenc470f442003-07-28 09:56:35 +00003634
3635static int
3636truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003637{
3638 return 0;
3639}
Eric Andersen2870d962001-07-02 17:27:21 +00003640
Eric Andersencb57d552001-06-28 07:25:16 +00003641
Eric Andersenc470f442003-07-28 09:56:35 +00003642static int
3643execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003644{
3645 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003646 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003647 mflag = 0;
3648 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003649 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003650 }
3651 return 0;
3652}
3653
Eric Andersenc470f442003-07-28 09:56:35 +00003654
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003655/* exec.c */
Eric Andersenc470f442003-07-28 09:56:35 +00003656
3657/*
3658 * When commands are first encountered, they are entered in a hash table.
3659 * This ensures that a full path search will not have to be done for them
3660 * on each invocation.
3661 *
3662 * We should investigate converting to a linear search, even though that
3663 * would make the command name "hash" a misnomer.
3664 */
3665
3666#define CMDTABLESIZE 31 /* should be prime */
3667#define ARB 1 /* actual size determined at run time */
3668
3669
3670
3671struct tblentry {
3672 struct tblentry *next; /* next entry in hash chain */
3673 union param param; /* definition of builtin function */
3674 short cmdtype; /* index identifying command */
3675 char rehash; /* if set, cd done since entry created */
3676 char cmdname[ARB]; /* name of command */
3677};
3678
3679
3680static struct tblentry *cmdtable[CMDTABLESIZE];
3681static int builtinloc = -1; /* index in path of %builtin, or -1 */
3682
3683
3684static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003685static void clearcmdentry(int);
3686static struct tblentry *cmdlookup(const char *, int);
3687static void delete_cmd_entry(void);
3688
Eric Andersencb57d552001-06-28 07:25:16 +00003689
3690/*
3691 * Exec a program. Never returns. If you change this routine, you may
3692 * have to change the find_command routine as well.
3693 */
3694
Eric Andersenc470f442003-07-28 09:56:35 +00003695static void
3696shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003697{
3698 char *cmdname;
3699 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003700 char **envp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003701 int exerrno;
Eric Andersencb57d552001-06-28 07:25:16 +00003702
Eric Andersenc470f442003-07-28 09:56:35 +00003703 clearredir(1);
3704 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003705 if (strchr(argv[0], '/') != NULL
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00003706 || is_safe_applet(argv[0])
Eric Andersenbf8bf102002-09-17 08:41:08 +00003707#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3708 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003709#endif
3710 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003711 tryexec(argv[0], argv, envp);
3712 e = errno;
3713 } else {
3714 e = ENOENT;
3715 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3716 if (--idx < 0 && pathopt == NULL) {
3717 tryexec(cmdname, argv, envp);
3718 if (errno != ENOENT && errno != ENOTDIR)
3719 e = errno;
3720 }
3721 stunalloc(cmdname);
3722 }
3723 }
3724
3725 /* Map to POSIX errors */
3726 switch (e) {
3727 case EACCES:
3728 exerrno = 126;
3729 break;
3730 case ENOENT:
3731 exerrno = 127;
3732 break;
3733 default:
3734 exerrno = 2;
3735 break;
3736 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003737 exitstatus = exerrno;
Eric Andersenc470f442003-07-28 09:56:35 +00003738 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3739 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003740 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3741 /* NOTREACHED */
3742}
3743
Eric Andersen2870d962001-07-02 17:27:21 +00003744
Eric Andersenc470f442003-07-28 09:56:35 +00003745static void
3746tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003747{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003748 int repeated = 0;
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00003749 struct BB_applet *a;
3750 int argc = 0;
3751 char **c;
3752
3753 if(strchr(cmd, '/') == NULL && is_safe_applet(cmd) && (a = find_applet_by_name(cmd)) != NULL) {
3754 c = argv;
3755 while (*c != NULL) {
3756 c++; argc++;
3757 }
Denis Vlasenko8f8f2682006-10-03 21:00:43 +00003758 applet_name = cmd;
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00003759 exit(a->main(argc, argv));
3760 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003761#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003762 if(find_applet_by_name(cmd) != NULL) {
3763 /* re-exec ourselves with the new arguments */
Rob Landleya34b48a2006-06-14 01:27:01 +00003764 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp);
Rob Landley0fcd9432005-05-07 08:27:34 +00003765 /* If they called chroot or otherwise made the binary no longer
3766 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003767 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003768#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003769
3770repeat:
3771#ifdef SYSV
3772 do {
3773 execve(cmd, argv, envp);
3774 } while (errno == EINTR);
3775#else
Eric Andersencb57d552001-06-28 07:25:16 +00003776 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003777#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003778 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003779 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003780 } else if (errno == ENOEXEC) {
3781 char **ap;
3782 char **new;
3783
Eric Andersenc470f442003-07-28 09:56:35 +00003784 for (ap = argv; *ap; ap++)
3785 ;
3786 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003787 ap[1] = cmd;
3788 *ap = cmd = (char *)DEFAULT_SHELL;
3789 ap += 2;
3790 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003791 while ((*ap++ = *argv++))
3792 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003793 argv = new;
3794 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003795 }
Eric Andersencb57d552001-06-28 07:25:16 +00003796}
3797
Eric Andersenc470f442003-07-28 09:56:35 +00003798
Eric Andersencb57d552001-06-28 07:25:16 +00003799
3800/*
3801 * Do a path search. The variable path (passed by reference) should be
3802 * set to the start of the path before the first call; padvance will update
3803 * this value as it proceeds. Successive calls to padvance will return
3804 * the possible path expansions in sequence. If an option (indicated by
3805 * a percent sign) appears in the path entry then the global variable
3806 * pathopt will be set to point to it; otherwise pathopt will be set to
3807 * NULL.
3808 */
3809
Eric Andersenc470f442003-07-28 09:56:35 +00003810static char *
3811padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003812{
Eric Andersencb57d552001-06-28 07:25:16 +00003813 const char *p;
3814 char *q;
3815 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003816 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003817
3818 if (*path == NULL)
3819 return NULL;
3820 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003821 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3822 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003823 while (stackblocksize() < len)
3824 growstackblock();
3825 q = stackblock();
3826 if (p != start) {
3827 memcpy(q, start, p - start);
3828 q += p - start;
3829 *q++ = '/';
3830 }
3831 strcpy(q, name);
3832 pathopt = NULL;
3833 if (*p == '%') {
3834 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003835 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003836 }
3837 if (*p == ':')
3838 *path = p + 1;
3839 else
3840 *path = NULL;
3841 return stalloc(len);
3842}
3843
3844
Eric Andersencb57d552001-06-28 07:25:16 +00003845/*** Command hashing code ***/
3846
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003847static void
3848printentry(struct tblentry *cmdp)
3849{
3850 int idx;
3851 const char *path;
3852 char *name;
3853
3854 idx = cmdp->param.index;
3855 path = pathval();
3856 do {
3857 name = padvance(&path, cmdp->cmdname);
3858 stunalloc(name);
3859 } while (--idx >= 0);
3860 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3861}
3862
Eric Andersenc470f442003-07-28 09:56:35 +00003863
3864static int
3865hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003866{
3867 struct tblentry **pp;
3868 struct tblentry *cmdp;
3869 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003870 struct cmdentry entry;
3871 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003872
Eric Andersenc470f442003-07-28 09:56:35 +00003873 while ((c = nextopt("r")) != '\0') {
3874 clearcmdentry(0);
3875 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003876 }
3877 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003878 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3879 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3880 if (cmdp->cmdtype == CMDNORMAL)
3881 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003882 }
3883 }
3884 return 0;
3885 }
3886 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003887 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003888 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003889 && (cmdp->cmdtype == CMDNORMAL
3890 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003891 delete_cmd_entry();
3892 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003893 if (entry.cmdtype == CMDUNKNOWN)
3894 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003895 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003896 }
3897 return c;
3898}
3899
Eric Andersenc470f442003-07-28 09:56:35 +00003900
Eric Andersencb57d552001-06-28 07:25:16 +00003901/*
3902 * Resolve a command name. If you change this routine, you may have to
3903 * change the shellexec routine as well.
3904 */
3905
3906static void
Eric Andersenc470f442003-07-28 09:56:35 +00003907find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003908{
3909 struct tblentry *cmdp;
3910 int idx;
3911 int prev;
3912 char *fullname;
3913 struct stat statb;
3914 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003915 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003916 struct builtincmd *bcmd;
3917
Eric Andersenc470f442003-07-28 09:56:35 +00003918 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003919 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003920 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003921 if (act & DO_ABS) {
3922 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003923#ifdef SYSV
3924 if (errno == EINTR)
3925 continue;
3926#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003927 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003928 return;
3929 }
Eric Andersencb57d552001-06-28 07:25:16 +00003930 }
3931 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003932 return;
3933 }
3934
Eric Andersenbf8bf102002-09-17 08:41:08 +00003935#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3936 if (find_applet_by_name(name)) {
3937 entry->cmdtype = CMDNORMAL;
3938 entry->u.index = -1;
3939 return;
3940 }
3941#endif
3942
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00003943 if (is_safe_applet(name)) {
3944 entry->cmdtype = CMDNORMAL;
3945 entry->u.index = -1;
3946 return;
3947 }
3948
Eric Andersenc470f442003-07-28 09:56:35 +00003949 updatetbl = (path == pathval());
3950 if (!updatetbl) {
3951 act |= DO_ALTPATH;
3952 if (strstr(path, "%builtin") != NULL)
3953 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003954 }
3955
Eric Andersenc470f442003-07-28 09:56:35 +00003956 /* If name is in the table, check answer will be ok */
3957 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3958 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003959
Eric Andersenc470f442003-07-28 09:56:35 +00003960 switch (cmdp->cmdtype) {
3961 default:
3962#if DEBUG
3963 abort();
3964#endif
3965 case CMDNORMAL:
3966 bit = DO_ALTPATH;
3967 break;
3968 case CMDFUNCTION:
3969 bit = DO_NOFUNC;
3970 break;
3971 case CMDBUILTIN:
3972 bit = DO_ALTBLTIN;
3973 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003974 }
Eric Andersenc470f442003-07-28 09:56:35 +00003975 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003976 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003977 cmdp = NULL;
3978 } else if (cmdp->rehash == 0)
3979 /* if not invalidated by cd, we're done */
3980 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003981 }
3982
3983 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003984 bcmd = find_builtin(name);
3985 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3986 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3987 )))
3988 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003989
3990 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003991 prev = -1; /* where to start */
3992 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003993 if (cmdp->cmdtype == CMDBUILTIN)
3994 prev = builtinloc;
3995 else
3996 prev = cmdp->param.index;
3997 }
3998
3999 e = ENOENT;
4000 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00004001loop:
Eric Andersencb57d552001-06-28 07:25:16 +00004002 while ((fullname = padvance(&path, name)) != NULL) {
4003 stunalloc(fullname);
4004 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00004005 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00004006 if (prefix(pathopt, "builtin")) {
4007 if (bcmd)
4008 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00004009 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004010 } else if (!(act & DO_NOFUNC) &&
4011 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00004012 /* handled below */
4013 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004014 /* ignore unimplemented options */
4015 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00004016 }
4017 }
4018 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00004019 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00004020 if (idx < prev)
4021 continue;
4022 TRACE(("searchexec \"%s\": no change\n", name));
4023 goto success;
4024 }
4025 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00004026#ifdef SYSV
4027 if (errno == EINTR)
4028 continue;
4029#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004030 if (errno != ENOENT && errno != ENOTDIR)
4031 e = errno;
4032 goto loop;
4033 }
Eric Andersenc470f442003-07-28 09:56:35 +00004034 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004035 if (!S_ISREG(statb.st_mode))
4036 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004037 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004038 stalloc(strlen(fullname) + 1);
4039 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004040 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4041 cmdp->cmdtype != CMDFUNCTION)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004042 sh_error("%s not defined in %s", name, fullname);
Eric Andersencb57d552001-06-28 07:25:16 +00004043 stunalloc(fullname);
4044 goto success;
4045 }
Eric Andersencb57d552001-06-28 07:25:16 +00004046 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004047 if (!updatetbl) {
4048 entry->cmdtype = CMDNORMAL;
4049 entry->u.index = idx;
4050 return;
4051 }
4052 INTOFF;
4053 cmdp = cmdlookup(name, 1);
4054 cmdp->cmdtype = CMDNORMAL;
4055 cmdp->param.index = idx;
4056 INTON;
4057 goto success;
4058 }
4059
4060 /* We failed. If there was an entry for this command, delete it */
4061 if (cmdp && updatetbl)
4062 delete_cmd_entry();
4063 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004064 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004065 entry->cmdtype = CMDUNKNOWN;
4066 return;
4067
Eric Andersenc470f442003-07-28 09:56:35 +00004068builtin_success:
4069 if (!updatetbl) {
4070 entry->cmdtype = CMDBUILTIN;
4071 entry->u.cmd = bcmd;
4072 return;
4073 }
4074 INTOFF;
4075 cmdp = cmdlookup(name, 1);
4076 cmdp->cmdtype = CMDBUILTIN;
4077 cmdp->param.cmd = bcmd;
4078 INTON;
4079success:
Eric Andersencb57d552001-06-28 07:25:16 +00004080 cmdp->rehash = 0;
4081 entry->cmdtype = cmdp->cmdtype;
4082 entry->u = cmdp->param;
4083}
4084
4085
Eric Andersenc470f442003-07-28 09:56:35 +00004086/*
4087 * Wrapper around strcmp for qsort/bsearch/...
4088 */
4089static int pstrcmp(const void *a, const void *b)
4090{
4091 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4092}
Eric Andersencb57d552001-06-28 07:25:16 +00004093
4094/*
4095 * Search the table of builtin commands.
4096 */
4097
Eric Andersenc470f442003-07-28 09:56:35 +00004098static struct builtincmd *
4099find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004100{
4101 struct builtincmd *bp;
4102
Eric Andersenc470f442003-07-28 09:56:35 +00004103 bp = bsearch(
4104 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4105 pstrcmp
4106 );
Eric Andersencb57d552001-06-28 07:25:16 +00004107 return bp;
4108}
4109
4110
Eric Andersenc470f442003-07-28 09:56:35 +00004111
Eric Andersencb57d552001-06-28 07:25:16 +00004112/*
4113 * Called when a cd is done. Marks all commands so the next time they
4114 * are executed they will be rehashed.
4115 */
4116
Eric Andersenc470f442003-07-28 09:56:35 +00004117static void
4118hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004119{
Eric Andersencb57d552001-06-28 07:25:16 +00004120 struct tblentry **pp;
4121 struct tblentry *cmdp;
4122
Eric Andersenc470f442003-07-28 09:56:35 +00004123 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4124 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4125 if (cmdp->cmdtype == CMDNORMAL || (
4126 cmdp->cmdtype == CMDBUILTIN &&
4127 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4128 builtinloc > 0
4129 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004130 cmdp->rehash = 1;
4131 }
4132 }
4133}
4134
4135
4136
4137/*
Eric Andersenc470f442003-07-28 09:56:35 +00004138 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004139 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004140 * pathval() still returns the old value at this point.
4141 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004142 */
4143
Eric Andersenc470f442003-07-28 09:56:35 +00004144static void
4145changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004146{
Eric Andersenc470f442003-07-28 09:56:35 +00004147 const char *old, *new;
4148 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004149 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004150 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004151
Eric Andersenc470f442003-07-28 09:56:35 +00004152 old = pathval();
4153 new = newval;
4154 firstchange = 9999; /* assume no change */
4155 idx = 0;
4156 idx_bltin = -1;
4157 for (;;) {
4158 if (*old != *new) {
4159 firstchange = idx;
4160 if ((*old == '\0' && *new == ':')
4161 || (*old == ':' && *new == '\0'))
4162 firstchange++;
4163 old = new; /* ignore subsequent differences */
4164 }
4165 if (*new == '\0')
4166 break;
4167 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4168 idx_bltin = idx;
4169 if (*new == ':') {
4170 idx++;
4171 }
4172 new++, old++;
4173 }
4174 if (builtinloc < 0 && idx_bltin >= 0)
4175 builtinloc = idx_bltin; /* zap builtins */
4176 if (builtinloc >= 0 && idx_bltin < 0)
4177 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004178 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004179 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004180}
4181
4182
4183/*
4184 * Clear out command entries. The argument specifies the first entry in
4185 * PATH which has changed.
4186 */
4187
Eric Andersenc470f442003-07-28 09:56:35 +00004188static void
4189clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004190{
4191 struct tblentry **tblp;
4192 struct tblentry **pp;
4193 struct tblentry *cmdp;
4194
4195 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004196 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004197 pp = tblp;
4198 while ((cmdp = *pp) != NULL) {
4199 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004200 cmdp->param.index >= firstchange)
4201 || (cmdp->cmdtype == CMDBUILTIN &&
4202 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004203 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004204 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004205 } else {
4206 pp = &cmdp->next;
4207 }
4208 }
4209 }
4210 INTON;
4211}
4212
4213
Eric Andersenc470f442003-07-28 09:56:35 +00004214
Eric Andersencb57d552001-06-28 07:25:16 +00004215/*
Eric Andersencb57d552001-06-28 07:25:16 +00004216 * Locate a command in the command hash table. If "add" is nonzero,
4217 * add the command to the table if it is not already present. The
4218 * variable "lastcmdentry" is set to point to the address of the link
4219 * pointing to the entry, so that delete_cmd_entry can delete the
4220 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004221 *
4222 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004223 */
4224
Eric Andersen2870d962001-07-02 17:27:21 +00004225static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004226
Eric Andersenc470f442003-07-28 09:56:35 +00004227
4228static struct tblentry *
4229cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004230{
Eric Andersenc470f442003-07-28 09:56:35 +00004231 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004232 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004233 struct tblentry *cmdp;
4234 struct tblentry **pp;
4235
4236 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004237 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004238 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004239 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004240 hashval &= 0x7FFF;
4241 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004242 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004243 if (equal(cmdp->cmdname, name))
4244 break;
4245 pp = &cmdp->next;
4246 }
4247 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004248 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4249 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004250 cmdp->next = NULL;
4251 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004252 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004253 }
4254 lastcmdentry = pp;
4255 return cmdp;
4256}
4257
4258/*
4259 * Delete the command entry returned on the last lookup.
4260 */
4261
Eric Andersenc470f442003-07-28 09:56:35 +00004262static void
4263delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004264{
Eric Andersencb57d552001-06-28 07:25:16 +00004265 struct tblentry *cmdp;
4266
4267 INTOFF;
4268 cmdp = *lastcmdentry;
4269 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004270 if (cmdp->cmdtype == CMDFUNCTION)
4271 freefunc(cmdp->param.func);
4272 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004273 INTON;
4274}
4275
4276
Eric Andersenc470f442003-07-28 09:56:35 +00004277/*
4278 * Add a new command entry, replacing any existing command entry for
4279 * the same name - except special builtins.
4280 */
Eric Andersencb57d552001-06-28 07:25:16 +00004281
Rob Landley88621d72006-08-29 19:41:06 +00004282static void addcmdentry(char *name, struct cmdentry *entry)
Eric Andersenc470f442003-07-28 09:56:35 +00004283{
4284 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004285
Eric Andersenc470f442003-07-28 09:56:35 +00004286 cmdp = cmdlookup(name, 1);
4287 if (cmdp->cmdtype == CMDFUNCTION) {
4288 freefunc(cmdp->param.func);
4289 }
4290 cmdp->cmdtype = entry->cmdtype;
4291 cmdp->param = entry->u;
4292 cmdp->rehash = 0;
4293}
Eric Andersencb57d552001-06-28 07:25:16 +00004294
Eric Andersenc470f442003-07-28 09:56:35 +00004295/*
4296 * Make a copy of a parse tree.
4297 */
Eric Andersencb57d552001-06-28 07:25:16 +00004298
Rob Landley88621d72006-08-29 19:41:06 +00004299static struct funcnode * copyfunc(union node *n)
Eric Andersenc470f442003-07-28 09:56:35 +00004300{
4301 struct funcnode *f;
4302 size_t blocksize;
4303
4304 funcblocksize = offsetof(struct funcnode, n);
4305 funcstringsize = 0;
4306 calcsize(n);
4307 blocksize = funcblocksize;
4308 f = ckmalloc(blocksize + funcstringsize);
4309 funcblock = (char *) f + offsetof(struct funcnode, n);
4310 funcstring = (char *) f + blocksize;
4311 copynode(n);
4312 f->count = 0;
4313 return f;
4314}
4315
4316/*
4317 * Define a shell function.
4318 */
4319
4320static void
4321defun(char *name, union node *func)
4322{
4323 struct cmdentry entry;
4324
4325 INTOFF;
4326 entry.cmdtype = CMDFUNCTION;
4327 entry.u.func = copyfunc(func);
4328 addcmdentry(name, &entry);
4329 INTON;
4330}
Eric Andersencb57d552001-06-28 07:25:16 +00004331
4332
4333/*
4334 * Delete a function if it exists.
4335 */
4336
Eric Andersenc470f442003-07-28 09:56:35 +00004337static void
4338unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004339{
Eric Andersencb57d552001-06-28 07:25:16 +00004340 struct tblentry *cmdp;
4341
Eric Andersenc470f442003-07-28 09:56:35 +00004342 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4343 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004344 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004345}
4346
Eric Andersen2870d962001-07-02 17:27:21 +00004347/*
Eric Andersencb57d552001-06-28 07:25:16 +00004348 * Locate and print what a word is...
4349 */
4350
Eric Andersenc470f442003-07-28 09:56:35 +00004351
4352#ifdef CONFIG_ASH_CMDCMD
4353static int
4354describe_command(char *command, int describe_command_verbose)
4355#else
4356#define describe_command_verbose 1
4357static int
4358describe_command(char *command)
4359#endif
4360{
4361 struct cmdentry entry;
4362 struct tblentry *cmdp;
4363#ifdef CONFIG_ASH_ALIAS
4364 const struct alias *ap;
4365#endif
4366 const char *path = pathval();
4367
4368 if (describe_command_verbose) {
4369 out1str(command);
4370 }
4371
4372 /* First look at the keywords */
4373 if (findkwd(command)) {
4374 out1str(describe_command_verbose ? " is a shell keyword" : command);
4375 goto out;
4376 }
4377
4378#ifdef CONFIG_ASH_ALIAS
4379 /* Then look at the aliases */
4380 if ((ap = lookupalias(command, 0)) != NULL) {
4381 if (describe_command_verbose) {
4382 out1fmt(" is an alias for %s", ap->val);
4383 } else {
4384 out1str("alias ");
4385 printalias(ap);
4386 return 0;
4387 }
4388 goto out;
4389 }
4390#endif
4391 /* Then check if it is a tracked alias */
4392 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4393 entry.cmdtype = cmdp->cmdtype;
4394 entry.u = cmdp->param;
4395 } else {
4396 /* Finally use brute force */
4397 find_command(command, &entry, DO_ABS, path);
4398 }
4399
4400 switch (entry.cmdtype) {
4401 case CMDNORMAL: {
4402 int j = entry.u.index;
4403 char *p;
4404 if (j == -1) {
4405 p = command;
4406 } else {
4407 do {
4408 p = padvance(&path, command);
4409 stunalloc(p);
4410 } while (--j >= 0);
4411 }
4412 if (describe_command_verbose) {
4413 out1fmt(" is%s %s",
4414 (cmdp ? " a tracked alias for" : nullstr), p
4415 );
4416 } else {
4417 out1str(p);
4418 }
4419 break;
4420 }
4421
4422 case CMDFUNCTION:
4423 if (describe_command_verbose) {
4424 out1str(" is a shell function");
4425 } else {
4426 out1str(command);
4427 }
4428 break;
4429
4430 case CMDBUILTIN:
4431 if (describe_command_verbose) {
4432 out1fmt(" is a %sshell builtin",
4433 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4434 "special " : nullstr
4435 );
4436 } else {
4437 out1str(command);
4438 }
4439 break;
4440
4441 default:
4442 if (describe_command_verbose) {
4443 out1str(": not found\n");
4444 }
4445 return 127;
4446 }
4447
4448out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004449 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004450 return 0;
4451}
4452
4453static int
4454typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004455{
4456 int i;
4457 int err = 0;
4458
4459 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004460#ifdef CONFIG_ASH_CMDCMD
4461 err |= describe_command(argv[i], 1);
4462#else
4463 err |= describe_command(argv[i]);
4464#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004465 }
4466 return err;
4467}
4468
Eric Andersend35c5df2002-01-09 15:37:36 +00004469#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004470static int
4471commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004472{
4473 int c;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004474 enum {
4475 VERIFY_BRIEF = 1,
4476 VERIFY_VERBOSE = 2,
4477 } verify = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004478
4479 while ((c = nextopt("pvV")) != '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004480 if (c == 'V')
4481 verify |= VERIFY_VERBOSE;
4482 else if (c == 'v')
4483 verify |= VERIFY_BRIEF;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00004484#if DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004485 else if (c != 'p')
4486 abort();
Eric Andersenc470f442003-07-28 09:56:35 +00004487#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004488 if (verify)
4489 return describe_command(*argptr, verify - VERIFY_BRIEF);
Eric Andersencb57d552001-06-28 07:25:16 +00004490
4491 return 0;
4492}
Eric Andersen2870d962001-07-02 17:27:21 +00004493#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004494
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004495/* expand.c */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004496
Eric Andersencb57d552001-06-28 07:25:16 +00004497/*
4498 * Routines to expand arguments to commands. We have to deal with
4499 * backquotes, shell variables, and file metacharacters.
4500 */
Eric Andersenc470f442003-07-28 09:56:35 +00004501
Eric Andersencb57d552001-06-28 07:25:16 +00004502/*
4503 * _rmescape() flags
4504 */
Eric Andersenc470f442003-07-28 09:56:35 +00004505#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4506#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4507#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4508#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4509#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004510
4511/*
4512 * Structure specifying which parts of the string should be searched
4513 * for IFS characters.
4514 */
4515
4516struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004517 struct ifsregion *next; /* next region in list */
4518 int begoff; /* offset of start of region */
4519 int endoff; /* offset of end of region */
4520 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004521};
4522
Eric Andersenc470f442003-07-28 09:56:35 +00004523/* output of current string */
4524static char *expdest;
4525/* list of back quote expressions */
4526static struct nodelist *argbackq;
4527/* first struct in list of ifs regions */
4528static struct ifsregion ifsfirst;
4529/* last struct in list */
4530static struct ifsregion *ifslastp;
4531/* holds expanded arg list */
4532static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004533
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004534static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004535static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004536static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004537static const char *subevalvar(char *, char *, int, int, int, int, int);
4538static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004539static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004540static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004541static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004542static void recordregion(int, int, int);
4543static void removerecordregions(int);
4544static void ifsbreakup(char *, struct arglist *);
4545static void ifsfree(void);
4546static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004547static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004548
Eric Andersened9ecf72004-06-22 08:29:45 +00004549static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004550static size_t esclen(const char *, const char *);
4551static char *scanleft(char *, char *, char *, char *, int, int);
4552static char *scanright(char *, char *, char *, char *, int, int);
4553static void varunset(const char *, const char *, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00004554 ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004555
Eric Andersenc470f442003-07-28 09:56:35 +00004556
4557#define pmatch(a, b) !fnmatch((a), (b), 0)
4558/*
Eric Andersen90898442003-08-06 11:20:52 +00004559 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004560 *
4561 * Returns an stalloced string.
4562 */
4563
Rob Landley88621d72006-08-29 19:41:06 +00004564static char * preglob(const char *pattern, int quoted, int flag) {
Eric Andersenc470f442003-07-28 09:56:35 +00004565 flag |= RMESCAPE_GLOB;
4566 if (quoted) {
4567 flag |= RMESCAPE_QUOTED;
4568 }
4569 return _rmescapes((char *)pattern, flag);
4570}
4571
4572
4573static size_t
4574esclen(const char *start, const char *p) {
4575 size_t esc = 0;
4576
4577 while (p > start && *--p == CTLESC) {
4578 esc++;
4579 }
4580 return esc;
4581}
4582
Eric Andersencb57d552001-06-28 07:25:16 +00004583
4584/*
4585 * Expand shell variables and backquotes inside a here document.
4586 */
4587
Rob Landley88621d72006-08-29 19:41:06 +00004588static void expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004589{
Eric Andersencb57d552001-06-28 07:25:16 +00004590 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004591 expandarg(arg, (struct arglist *)NULL, 0);
Rob Landley53437472006-07-16 08:14:35 +00004592 full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004593}
4594
4595
4596/*
4597 * Perform variable substitution and command substitution on an argument,
4598 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4599 * perform splitting and file name expansion. When arglist is NULL, perform
4600 * here document expansion.
4601 */
4602
Eric Andersenc470f442003-07-28 09:56:35 +00004603void
4604expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004605{
4606 struct strlist *sp;
4607 char *p;
4608
4609 argbackq = arg->narg.backquote;
4610 STARTSTACKSTR(expdest);
4611 ifsfirst.next = NULL;
4612 ifslastp = NULL;
4613 argstr(arg->narg.text, flag);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004614 p = _STPUTC('\0', expdest);
4615 expdest = p - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004616 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004617 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004618 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004619 p = grabstackstr(p);
Eric Andersencb57d552001-06-28 07:25:16 +00004620 exparg.lastp = &exparg.list;
4621 /*
4622 * TODO - EXP_REDIR
4623 */
4624 if (flag & EXP_FULL) {
4625 ifsbreakup(p, &exparg);
4626 *exparg.lastp = NULL;
4627 exparg.lastp = &exparg.list;
4628 expandmeta(exparg.list, flag);
4629 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004630 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004631 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004632 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004633 sp->text = p;
4634 *exparg.lastp = sp;
4635 exparg.lastp = &sp->next;
4636 }
Eric Andersenc470f442003-07-28 09:56:35 +00004637 if (ifsfirst.next)
4638 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004639 *exparg.lastp = NULL;
4640 if (exparg.list) {
4641 *arglist->lastp = exparg.list;
4642 arglist->lastp = exparg.lastp;
4643 }
4644}
4645
4646
Eric Andersenc470f442003-07-28 09:56:35 +00004647/*
4648 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4649 * characters to allow for further processing. Otherwise treat
4650 * $@ like $* since no splitting will be performed.
4651 */
4652
4653static void
4654argstr(char *p, int flag)
4655{
4656 static const char spclchars[] = {
4657 '=',
4658 ':',
4659 CTLQUOTEMARK,
4660 CTLENDVAR,
4661 CTLESC,
4662 CTLVAR,
4663 CTLBACKQ,
4664 CTLBACKQ | CTLQUOTE,
4665#ifdef CONFIG_ASH_MATH_SUPPORT
4666 CTLENDARI,
4667#endif
4668 0
4669 };
4670 const char *reject = spclchars;
4671 int c;
4672 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4673 int breakall = flag & EXP_WORD;
4674 int inquotes;
4675 size_t length;
4676 int startloc;
4677
4678 if (!(flag & EXP_VARTILDE)) {
4679 reject += 2;
4680 } else if (flag & EXP_VARTILDE2) {
4681 reject++;
4682 }
4683 inquotes = 0;
4684 length = 0;
4685 if (flag & EXP_TILDE) {
4686 char *q;
4687
4688 flag &= ~EXP_TILDE;
4689tilde:
4690 q = p;
4691 if (*q == CTLESC && (flag & EXP_QWORD))
4692 q++;
4693 if (*q == '~')
4694 p = exptilde(p, q, flag);
4695 }
4696start:
4697 startloc = expdest - (char *)stackblock();
4698 for (;;) {
4699 length += strcspn(p + length, reject);
4700 c = p[length];
4701 if (c && (!(c & 0x80)
4702#ifdef CONFIG_ASH_MATH_SUPPORT
4703 || c == CTLENDARI
4704#endif
4705 )) {
4706 /* c == '=' || c == ':' || c == CTLENDARI */
4707 length++;
4708 }
4709 if (length > 0) {
4710 int newloc;
4711 expdest = stnputs(p, length, expdest);
4712 newloc = expdest - (char *)stackblock();
4713 if (breakall && !inquotes && newloc > startloc) {
4714 recordregion(startloc, newloc, 0);
4715 }
4716 startloc = newloc;
4717 }
4718 p += length + 1;
4719 length = 0;
4720
4721 switch (c) {
4722 case '\0':
4723 goto breakloop;
4724 case '=':
4725 if (flag & EXP_VARTILDE2) {
4726 p--;
4727 continue;
4728 }
4729 flag |= EXP_VARTILDE2;
4730 reject++;
4731 /* fall through */
4732 case ':':
4733 /*
4734 * sort of a hack - expand tildes in variable
4735 * assignments (after the first '=' and after ':'s).
4736 */
4737 if (*--p == '~') {
4738 goto tilde;
4739 }
4740 continue;
4741 }
4742
4743 switch (c) {
4744 case CTLENDVAR: /* ??? */
4745 goto breakloop;
4746 case CTLQUOTEMARK:
4747 /* "$@" syntax adherence hack */
4748 if (
4749 !inquotes &&
4750 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4751 (p[4] == CTLQUOTEMARK || (
4752 p[4] == CTLENDVAR &&
4753 p[5] == CTLQUOTEMARK
4754 ))
4755 ) {
4756 p = evalvar(p + 1, flag) + 1;
4757 goto start;
4758 }
4759 inquotes = !inquotes;
4760addquote:
4761 if (quotes) {
4762 p--;
4763 length++;
4764 startloc++;
4765 }
4766 break;
4767 case CTLESC:
4768 startloc++;
4769 length++;
4770 goto addquote;
4771 case CTLVAR:
4772 p = evalvar(p, flag);
4773 goto start;
4774 case CTLBACKQ:
4775 c = 0;
4776 case CTLBACKQ|CTLQUOTE:
4777 expbackq(argbackq->n, c, quotes);
4778 argbackq = argbackq->next;
4779 goto start;
4780#ifdef CONFIG_ASH_MATH_SUPPORT
4781 case CTLENDARI:
4782 p--;
4783 expari(quotes);
4784 goto start;
4785#endif
4786 }
4787 }
4788breakloop:
4789 ;
4790}
4791
4792static char *
4793exptilde(char *startp, char *p, int flag)
4794{
4795 char c;
4796 char *name;
4797 struct passwd *pw;
4798 const char *home;
4799 int quotes = flag & (EXP_FULL | EXP_CASE);
4800 int startloc;
4801
4802 name = p + 1;
4803
4804 while ((c = *++p) != '\0') {
4805 switch(c) {
4806 case CTLESC:
4807 return (startp);
4808 case CTLQUOTEMARK:
4809 return (startp);
4810 case ':':
4811 if (flag & EXP_VARTILDE)
4812 goto done;
4813 break;
4814 case '/':
4815 case CTLENDVAR:
4816 goto done;
4817 }
4818 }
4819done:
4820 *p = '\0';
4821 if (*name == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004822 home = lookupvar(homestr);
Eric Andersenc470f442003-07-28 09:56:35 +00004823 } else {
4824 if ((pw = getpwnam(name)) == NULL)
4825 goto lose;
4826 home = pw->pw_dir;
4827 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004828 if (!home || !*home)
Eric Andersenc470f442003-07-28 09:56:35 +00004829 goto lose;
4830 *p = c;
4831 startloc = expdest - (char *)stackblock();
4832 strtodest(home, SQSYNTAX, quotes);
4833 recordregion(startloc, expdest - (char *)stackblock(), 0);
4834 return (p);
4835lose:
4836 *p = c;
4837 return (startp);
4838}
4839
4840
4841static void
4842removerecordregions(int endoff)
4843{
4844 if (ifslastp == NULL)
4845 return;
4846
4847 if (ifsfirst.endoff > endoff) {
4848 while (ifsfirst.next != NULL) {
4849 struct ifsregion *ifsp;
4850 INTOFF;
4851 ifsp = ifsfirst.next->next;
4852 ckfree(ifsfirst.next);
4853 ifsfirst.next = ifsp;
4854 INTON;
4855 }
4856 if (ifsfirst.begoff > endoff)
4857 ifslastp = NULL;
4858 else {
4859 ifslastp = &ifsfirst;
4860 ifsfirst.endoff = endoff;
4861 }
4862 return;
4863 }
4864
4865 ifslastp = &ifsfirst;
4866 while (ifslastp->next && ifslastp->next->begoff < endoff)
4867 ifslastp=ifslastp->next;
4868 while (ifslastp->next != NULL) {
4869 struct ifsregion *ifsp;
4870 INTOFF;
4871 ifsp = ifslastp->next->next;
4872 ckfree(ifslastp->next);
4873 ifslastp->next = ifsp;
4874 INTON;
4875 }
4876 if (ifslastp->endoff > endoff)
4877 ifslastp->endoff = endoff;
4878}
4879
4880
4881#ifdef CONFIG_ASH_MATH_SUPPORT
4882/*
4883 * Expand arithmetic expression. Backup to start of expression,
4884 * evaluate, place result in (backed up) result, adjust string position.
4885 */
4886void
4887expari(int quotes)
4888{
4889 char *p, *start;
4890 int begoff;
4891 int flag;
4892 int len;
4893
4894 /* ifsfree(); */
4895
4896 /*
4897 * This routine is slightly over-complicated for
4898 * efficiency. Next we scan backwards looking for the
4899 * start of arithmetic.
4900 */
4901 start = stackblock();
4902 p = expdest - 1;
4903 *p = '\0';
4904 p--;
4905 do {
4906 int esc;
4907
4908 while (*p != CTLARI) {
4909 p--;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00004910#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00004911 if (p < start) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004912 sh_error("missing CTLARI (shouldn't happen)");
Eric Andersenc470f442003-07-28 09:56:35 +00004913 }
4914#endif
4915 }
4916
4917 esc = esclen(start, p);
4918 if (!(esc % 2)) {
4919 break;
4920 }
4921
4922 p -= esc + 1;
4923 } while (1);
4924
4925 begoff = p - start;
4926
4927 removerecordregions(begoff);
4928
4929 flag = p[1];
4930
4931 expdest = p;
4932
4933 if (quotes)
4934 rmescapes(p + 2);
4935
4936 len = cvtnum(dash_arith(p + 2));
4937
4938 if (flag != '"')
4939 recordregion(begoff, begoff + len, 0);
4940}
4941#endif
4942
4943/*
4944 * Expand stuff in backwards quotes.
4945 */
4946
4947static void
4948expbackq(union node *cmd, int quoted, int quotes)
4949{
4950 struct backcmd in;
4951 int i;
4952 char buf[128];
4953 char *p;
4954 char *dest;
4955 int startloc;
4956 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4957 struct stackmark smark;
4958
4959 INTOFF;
4960 setstackmark(&smark);
4961 dest = expdest;
4962 startloc = dest - (char *)stackblock();
4963 grabstackstr(dest);
4964 evalbackcmd(cmd, (struct backcmd *) &in);
4965 popstackmark(&smark);
4966
4967 p = in.buf;
4968 i = in.nleft;
4969 if (i == 0)
4970 goto read;
4971 for (;;) {
4972 memtodest(p, i, syntax, quotes);
4973read:
4974 if (in.fd < 0)
4975 break;
4976 i = safe_read(in.fd, buf, sizeof buf);
4977 TRACE(("expbackq: read returns %d\n", i));
4978 if (i <= 0)
4979 break;
4980 p = buf;
4981 }
4982
4983 if (in.buf)
4984 ckfree(in.buf);
4985 if (in.fd >= 0) {
4986 close(in.fd);
4987 back_exitstatus = waitforjob(in.jp);
4988 }
4989 INTON;
4990
4991 /* Eat all trailing newlines */
4992 dest = expdest;
4993 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4994 STUNPUTC(dest);
4995 expdest = dest;
4996
4997 if (quoted == 0)
4998 recordregion(startloc, dest - (char *)stackblock(), 0);
4999 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5000 (dest - (char *)stackblock()) - startloc,
5001 (dest - (char *)stackblock()) - startloc,
5002 stackblock() + startloc));
5003}
5004
5005
5006static char *
Eric Andersen90898442003-08-06 11:20:52 +00005007scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5008 int zero)
5009{
Eric Andersenc470f442003-07-28 09:56:35 +00005010 char *loc;
5011 char *loc2;
5012 char c;
5013
5014 loc = startp;
5015 loc2 = rmesc;
5016 do {
5017 int match;
5018 const char *s = loc2;
5019 c = *loc2;
5020 if (zero) {
5021 *loc2 = '\0';
5022 s = rmesc;
5023 }
5024 match = pmatch(str, s);
5025 *loc2 = c;
5026 if (match)
5027 return loc;
5028 if (quotes && *loc == CTLESC)
5029 loc++;
5030 loc++;
5031 loc2++;
5032 } while (c);
5033 return 0;
5034}
5035
5036
5037static char *
Eric Andersen90898442003-08-06 11:20:52 +00005038scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5039 int zero)
5040{
Eric Andersenc470f442003-07-28 09:56:35 +00005041 int esc = 0;
5042 char *loc;
5043 char *loc2;
5044
5045 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5046 int match;
5047 char c = *loc2;
5048 const char *s = loc2;
5049 if (zero) {
5050 *loc2 = '\0';
5051 s = rmesc;
5052 }
5053 match = pmatch(str, s);
5054 *loc2 = c;
5055 if (match)
5056 return loc;
5057 loc--;
5058 if (quotes) {
5059 if (--esc < 0) {
5060 esc = esclen(startp, loc);
5061 }
5062 if (esc % 2) {
5063 esc--;
5064 loc--;
5065 }
5066 }
5067 }
5068 return 0;
5069}
5070
5071static const char *
5072subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5073{
5074 char *startp;
5075 char *loc;
5076 int saveherefd = herefd;
5077 struct nodelist *saveargbackq = argbackq;
5078 int amount;
5079 char *rmesc, *rmescend;
5080 int zero;
5081 char *(*scan)(char *, char *, char *, char *, int , int);
5082
5083 herefd = -1;
5084 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5085 STPUTC('\0', expdest);
5086 herefd = saveherefd;
5087 argbackq = saveargbackq;
5088 startp = stackblock() + startloc;
5089
5090 switch (subtype) {
5091 case VSASSIGN:
5092 setvar(str, startp, 0);
5093 amount = startp - expdest;
5094 STADJUST(amount, expdest);
5095 return startp;
5096
5097 case VSQUESTION:
5098 varunset(p, str, startp, varflags);
5099 /* NOTREACHED */
5100 }
5101
5102 subtype -= VSTRIMRIGHT;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00005103#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00005104 if (subtype < 0 || subtype > 3)
5105 abort();
5106#endif
5107
5108 rmesc = startp;
5109 rmescend = stackblock() + strloc;
5110 if (quotes) {
5111 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5112 if (rmesc != startp) {
5113 rmescend = expdest;
5114 startp = stackblock() + startloc;
5115 }
5116 }
5117 rmescend--;
5118 str = stackblock() + strloc;
5119 preglob(str, varflags & VSQUOTE, 0);
5120
5121 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5122 zero = subtype >> 1;
5123 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5124 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5125
5126 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5127 if (loc) {
5128 if (zero) {
5129 memmove(startp, loc, str - loc);
5130 loc = startp + (str - loc) - 1;
5131 }
5132 *loc = '\0';
5133 amount = loc - expdest;
5134 STADJUST(amount, expdest);
5135 }
5136 return loc;
5137}
5138
5139
Eric Andersen62483552001-07-10 06:09:16 +00005140/*
5141 * Expand a variable, and return a pointer to the next character in the
5142 * input string.
5143 */
Eric Andersenc470f442003-07-28 09:56:35 +00005144static char *
5145evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005146{
5147 int subtype;
5148 int varflags;
5149 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005150 int patloc;
5151 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005152 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005153 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005154 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005155 int quotes;
5156 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005157
Eric Andersenc470f442003-07-28 09:56:35 +00005158 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005159 varflags = *p++;
5160 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005161 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005162 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005163 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005164 startloc = expdest - (char *)stackblock();
5165 p = strchr(p, '=') + 1;
5166
Eric Andersenc470f442003-07-28 09:56:35 +00005167again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005168 varlen = varvalue(var, varflags, flag);
5169 if (varflags & VSNUL)
5170 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005171
Glenn L McGrath76620622004-01-13 10:19:37 +00005172 if (subtype == VSPLUS) {
5173 varlen = -1 - varlen;
5174 goto vsplus;
5175 }
Eric Andersen62483552001-07-10 06:09:16 +00005176
Eric Andersenc470f442003-07-28 09:56:35 +00005177 if (subtype == VSMINUS) {
5178vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005179 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005180 argstr(
5181 p, flag | EXP_TILDE |
5182 (quoted ? EXP_QWORD : EXP_WORD)
5183 );
5184 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005185 }
5186 if (easy)
5187 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005188 goto end;
5189 }
Eric Andersen62483552001-07-10 06:09:16 +00005190
Eric Andersenc470f442003-07-28 09:56:35 +00005191 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005192 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005193 if (subevalvar(p, var, 0, subtype, startloc,
5194 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005195 varflags &= ~VSNUL;
5196 /*
5197 * Remove any recorded regions beyond
5198 * start of variable
5199 */
5200 removerecordregions(startloc);
5201 goto again;
5202 }
Eric Andersenc470f442003-07-28 09:56:35 +00005203 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005204 }
5205 if (easy)
5206 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005207 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005208 }
5209
Glenn L McGrath76620622004-01-13 10:19:37 +00005210 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005211 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005212
Eric Andersenc470f442003-07-28 09:56:35 +00005213 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005214 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005215 goto record;
5216 }
5217
5218 if (subtype == VSNORMAL) {
5219 if (!easy)
5220 goto end;
5221record:
5222 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5223 goto end;
5224 }
5225
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00005226#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00005227 switch (subtype) {
5228 case VSTRIMLEFT:
5229 case VSTRIMLEFTMAX:
5230 case VSTRIMRIGHT:
5231 case VSTRIMRIGHTMAX:
5232 break;
5233 default:
5234 abort();
5235 }
5236#endif
5237
Glenn L McGrath76620622004-01-13 10:19:37 +00005238 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005239 /*
5240 * Terminate the string and start recording the pattern
5241 * right after it
5242 */
5243 STPUTC('\0', expdest);
5244 patloc = expdest - (char *)stackblock();
5245 if (subevalvar(p, NULL, patloc, subtype,
5246 startloc, varflags, quotes) == 0) {
5247 int amount = expdest - (
5248 (char *)stackblock() + patloc - 1
5249 );
5250 STADJUST(-amount, expdest);
5251 }
5252 /* Remove any recorded regions beyond start of variable */
5253 removerecordregions(startloc);
5254 goto record;
5255 }
5256
5257end:
5258 if (subtype != VSNORMAL) { /* skip to end of alternative */
5259 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005260 for (;;) {
5261 if ((c = *p++) == CTLESC)
5262 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005263 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005264 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005265 argbackq = argbackq->next;
5266 } else if (c == CTLVAR) {
5267 if ((*p++ & VSTYPE) != VSNORMAL)
5268 nesting++;
5269 } else if (c == CTLENDVAR) {
5270 if (--nesting == 0)
5271 break;
5272 }
5273 }
5274 }
5275 return p;
5276}
5277
Eric Andersencb57d552001-06-28 07:25:16 +00005278
Eric Andersencb57d552001-06-28 07:25:16 +00005279/*
5280 * Put a string on the stack.
5281 */
5282
Eric Andersenc470f442003-07-28 09:56:35 +00005283static void
5284memtodest(const char *p, size_t len, int syntax, int quotes) {
5285 char *q = expdest;
5286
5287 q = makestrspace(len * 2, q);
5288
5289 while (len--) {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005290 int c = SC2INT(*p++);
Eric Andersenc470f442003-07-28 09:56:35 +00005291 if (!c)
5292 continue;
5293 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5294 USTPUTC(CTLESC, q);
5295 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005296 }
Eric Andersenc470f442003-07-28 09:56:35 +00005297
5298 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005299}
5300
Eric Andersenc470f442003-07-28 09:56:35 +00005301
5302static void
5303strtodest(const char *p, int syntax, int quotes)
5304{
5305 memtodest(p, strlen(p), syntax, quotes);
5306}
5307
5308
Eric Andersencb57d552001-06-28 07:25:16 +00005309/*
5310 * Add the value of a specialized variable to the stack string.
5311 */
5312
Glenn L McGrath76620622004-01-13 10:19:37 +00005313static ssize_t
5314varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005315{
5316 int num;
5317 char *p;
5318 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005319 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005320 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005321 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005322 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005323 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005324 int quoted = varflags & VSQUOTE;
5325 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005326 int quotes = flags & (EXP_FULL | EXP_CASE);
5327
Glenn L McGrath76620622004-01-13 10:19:37 +00005328 if (quoted && (flags & EXP_FULL))
5329 sep = 1 << CHAR_BIT;
5330
Eric Andersencb57d552001-06-28 07:25:16 +00005331 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5332 switch (*name) {
5333 case '$':
5334 num = rootpid;
5335 goto numvar;
5336 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005337 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005338 goto numvar;
5339 case '#':
5340 num = shellparam.nparam;
5341 goto numvar;
5342 case '!':
5343 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005344 if (num == 0)
5345 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005346numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005347 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005348 break;
5349 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005350 p = makestrspace(NOPTS, expdest);
5351 for (i = NOPTS - 1; i >= 0; i--) {
5352 if (optlist[i]) {
5353 USTPUTC(optletters(i), p);
5354 len++;
5355 }
Eric Andersencb57d552001-06-28 07:25:16 +00005356 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005357 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005358 break;
5359 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005360 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005361 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005362 /* fall through */
5363 case '*':
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005364 sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005365 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5366 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005367param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005368 if (!(ap = shellparam.p))
5369 return -1;
5370 while ((p = *ap++)) {
5371 size_t partlen;
5372
5373 partlen = strlen(p);
Glenn L McGrath76620622004-01-13 10:19:37 +00005374 len += partlen;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00005375
5376 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5377 memtodest(p, partlen, syntax, quotes);
5378
5379 if (*ap && sep) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005380 char *q;
5381
5382 len++;
5383 if (subtype == VSPLUS || subtype == VSLENGTH) {
5384 continue;
5385 }
5386 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005387 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005388 STPUTC(CTLESC, q);
5389 STPUTC(sep, q);
5390 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005391 }
5392 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005393 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005394 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005395 case '1':
5396 case '2':
5397 case '3':
5398 case '4':
5399 case '5':
5400 case '6':
5401 case '7':
5402 case '8':
5403 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005404 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005405 if (num < 0 || num > shellparam.nparam)
5406 return -1;
5407 p = num ? shellparam.p[num - 1] : arg0;
5408 goto value;
5409 default:
5410 p = lookupvar(name);
5411value:
5412 if (!p)
5413 return -1;
5414
5415 len = strlen(p);
5416 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5417 memtodest(p, len, syntax, quotes);
5418 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005419 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005420
5421 if (subtype == VSPLUS || subtype == VSLENGTH)
5422 STADJUST(-len, expdest);
5423 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005424}
5425
5426
Eric Andersencb57d552001-06-28 07:25:16 +00005427/*
5428 * Record the fact that we have to scan this region of the
5429 * string for IFS characters.
5430 */
5431
Eric Andersenc470f442003-07-28 09:56:35 +00005432static void
5433recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005434{
5435 struct ifsregion *ifsp;
5436
5437 if (ifslastp == NULL) {
5438 ifsp = &ifsfirst;
5439 } else {
5440 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005441 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005442 ifsp->next = NULL;
5443 ifslastp->next = ifsp;
5444 INTON;
5445 }
5446 ifslastp = ifsp;
5447 ifslastp->begoff = start;
5448 ifslastp->endoff = end;
5449 ifslastp->nulonly = nulonly;
5450}
5451
5452
Eric Andersencb57d552001-06-28 07:25:16 +00005453/*
5454 * Break the argument string into pieces based upon IFS and add the
5455 * strings to the argument list. The regions of the string to be
5456 * searched for IFS characters have been stored by recordregion.
5457 */
Eric Andersenc470f442003-07-28 09:56:35 +00005458static void
5459ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005460{
Eric Andersencb57d552001-06-28 07:25:16 +00005461 struct ifsregion *ifsp;
5462 struct strlist *sp;
5463 char *start;
5464 char *p;
5465 char *q;
5466 const char *ifs, *realifs;
5467 int ifsspc;
5468 int nulonly;
5469
5470
5471 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005472 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005473 ifsspc = 0;
5474 nulonly = 0;
5475 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005476 ifsp = &ifsfirst;
5477 do {
5478 p = string + ifsp->begoff;
5479 nulonly = ifsp->nulonly;
5480 ifs = nulonly ? nullstr : realifs;
5481 ifsspc = 0;
5482 while (p < string + ifsp->endoff) {
5483 q = p;
5484 if (*p == CTLESC)
5485 p++;
5486 if (strchr(ifs, *p)) {
5487 if (!nulonly)
5488 ifsspc = (strchr(defifs, *p) != NULL);
5489 /* Ignore IFS whitespace at start */
5490 if (q == start && ifsspc) {
5491 p++;
5492 start = p;
5493 continue;
5494 }
5495 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005496 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 p++;
5501 if (!nulonly) {
5502 for (;;) {
5503 if (p >= string + ifsp->endoff) {
5504 break;
5505 }
5506 q = p;
5507 if (*p == CTLESC)
5508 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005509 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005510 p = q;
5511 break;
5512 } else if (strchr(defifs, *p) == NULL) {
5513 if (ifsspc) {
5514 p++;
5515 ifsspc = 0;
5516 } else {
5517 p = q;
5518 break;
5519 }
5520 } else
5521 p++;
5522 }
5523 }
5524 start = p;
5525 } else
5526 p++;
5527 }
5528 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005529 if (nulonly)
5530 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005531 }
5532
Eric Andersenc470f442003-07-28 09:56:35 +00005533 if (!*start)
5534 return;
5535
5536add:
5537 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005538 sp->text = start;
5539 *arglist->lastp = sp;
5540 arglist->lastp = &sp->next;
5541}
5542
Eric Andersenc470f442003-07-28 09:56:35 +00005543static void
5544ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005545{
Eric Andersenc470f442003-07-28 09:56:35 +00005546 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005547
Eric Andersenc470f442003-07-28 09:56:35 +00005548 INTOFF;
5549 p = ifsfirst.next;
5550 do {
5551 struct ifsregion *ifsp;
5552 ifsp = p->next;
5553 ckfree(p);
5554 p = ifsp;
5555 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005556 ifslastp = NULL;
5557 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005558 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005559}
5560
Eric Andersen90898442003-08-06 11:20:52 +00005561static void expmeta(char *, char *);
5562static struct strlist *expsort(struct strlist *);
5563static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005564
Eric Andersen90898442003-08-06 11:20:52 +00005565static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005566
Eric Andersencb57d552001-06-28 07:25:16 +00005567
Eric Andersenc470f442003-07-28 09:56:35 +00005568static void
Eric Andersen90898442003-08-06 11:20:52 +00005569expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005570{
Eric Andersen90898442003-08-06 11:20:52 +00005571 static const char metachars[] = {
5572 '*', '?', '[', 0
5573 };
Eric Andersencb57d552001-06-28 07:25:16 +00005574 /* TODO - EXP_REDIR */
5575
5576 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005577 struct strlist **savelastp;
5578 struct strlist *sp;
5579 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005580
Eric Andersencb57d552001-06-28 07:25:16 +00005581 if (fflag)
5582 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005583 if (!strpbrk(str->text, metachars))
5584 goto nometa;
5585 savelastp = exparg.lastp;
5586
Eric Andersencb57d552001-06-28 07:25:16 +00005587 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005588 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005589 {
5590 int i = strlen(str->text);
5591 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5592 }
5593
5594 expmeta(expdir, p);
5595 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005596 if (p != str->text)
5597 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005598 INTON;
5599 if (exparg.lastp == savelastp) {
5600 /*
5601 * no matches
5602 */
Eric Andersenc470f442003-07-28 09:56:35 +00005603nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005604 *exparg.lastp = str;
5605 rmescapes(str->text);
5606 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005607 } else {
5608 *exparg.lastp = NULL;
5609 *savelastp = sp = expsort(*savelastp);
5610 while (sp->next != NULL)
5611 sp = sp->next;
5612 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005613 }
5614 str = str->next;
5615 }
5616}
5617
Eric Andersencb57d552001-06-28 07:25:16 +00005618/*
Eric Andersenc470f442003-07-28 09:56:35 +00005619 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005620 */
5621
Eric Andersenc470f442003-07-28 09:56:35 +00005622static void
Eric Andersen90898442003-08-06 11:20:52 +00005623addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005624{
Eric Andersencb57d552001-06-28 07:25:16 +00005625 struct strlist *sp;
5626
Eric Andersenc470f442003-07-28 09:56:35 +00005627 sp = (struct strlist *)stalloc(sizeof *sp);
5628 sp->text = sstrdup(name);
5629 *exparg.lastp = sp;
5630 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005631}
5632
5633
Eric Andersencb57d552001-06-28 07:25:16 +00005634/*
Eric Andersen90898442003-08-06 11:20:52 +00005635 * Do metacharacter (i.e. *, ?, [...]) expansion.
5636 */
5637
5638static void
5639expmeta(char *enddir, char *name)
5640{
5641 char *p;
5642 const char *cp;
5643 char *start;
5644 char *endname;
5645 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005646 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005647 DIR *dirp;
5648 struct dirent *dp;
5649 int atend;
5650 int matchdot;
5651
5652 metaflag = 0;
5653 start = name;
5654 for (p = name; *p; p++) {
5655 if (*p == '*' || *p == '?')
5656 metaflag = 1;
5657 else if (*p == '[') {
5658 char *q = p + 1;
5659 if (*q == '!')
5660 q++;
5661 for (;;) {
5662 if (*q == '\\')
5663 q++;
5664 if (*q == '/' || *q == '\0')
5665 break;
5666 if (*++q == ']') {
5667 metaflag = 1;
5668 break;
5669 }
5670 }
5671 } else if (*p == '\\')
5672 p++;
5673 else if (*p == '/') {
5674 if (metaflag)
5675 goto out;
5676 start = p + 1;
5677 }
5678 }
5679out:
5680 if (metaflag == 0) { /* we've reached the end of the file name */
5681 if (enddir != expdir)
5682 metaflag++;
5683 p = name;
5684 do {
5685 if (*p == '\\')
5686 p++;
5687 *enddir++ = *p;
5688 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005689 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005690 addfname(expdir);
5691 return;
5692 }
5693 endname = p;
5694 if (name < start) {
5695 p = name;
5696 do {
5697 if (*p == '\\')
5698 p++;
5699 *enddir++ = *p++;
5700 } while (p < start);
5701 }
5702 if (enddir == expdir) {
5703 cp = ".";
5704 } else if (enddir == expdir + 1 && *expdir == '/') {
5705 cp = "/";
5706 } else {
5707 cp = expdir;
5708 enddir[-1] = '\0';
5709 }
5710 if ((dirp = opendir(cp)) == NULL)
5711 return;
5712 if (enddir != expdir)
5713 enddir[-1] = '/';
5714 if (*endname == 0) {
5715 atend = 1;
5716 } else {
5717 atend = 0;
5718 *endname++ = '\0';
5719 }
5720 matchdot = 0;
5721 p = start;
5722 if (*p == '\\')
5723 p++;
5724 if (*p == '.')
5725 matchdot++;
5726 while (! intpending && (dp = readdir(dirp)) != NULL) {
5727 if (dp->d_name[0] == '.' && ! matchdot)
5728 continue;
5729 if (pmatch(start, dp->d_name)) {
5730 if (atend) {
5731 scopy(dp->d_name, enddir);
5732 addfname(expdir);
5733 } else {
5734 for (p = enddir, cp = dp->d_name;
5735 (*p++ = *cp++) != '\0';)
5736 continue;
5737 p[-1] = '/';
5738 expmeta(p, endname);
5739 }
5740 }
5741 }
5742 closedir(dirp);
5743 if (! atend)
5744 endname[-1] = '/';
5745}
5746
5747/*
5748 * Sort the results of file name expansion. It calculates the number of
5749 * strings to sort and then calls msort (short for merge sort) to do the
5750 * work.
5751 */
5752
5753static struct strlist *
5754expsort(struct strlist *str)
5755{
5756 int len;
5757 struct strlist *sp;
5758
5759 len = 0;
5760 for (sp = str ; sp ; sp = sp->next)
5761 len++;
5762 return msort(str, len);
5763}
5764
5765
5766static struct strlist *
5767msort(struct strlist *list, int len)
5768{
5769 struct strlist *p, *q = NULL;
5770 struct strlist **lpp;
5771 int half;
5772 int n;
5773
5774 if (len <= 1)
5775 return list;
5776 half = len >> 1;
5777 p = list;
5778 for (n = half ; --n >= 0 ; ) {
5779 q = p;
5780 p = p->next;
5781 }
5782 q->next = NULL; /* terminate first half of list */
5783 q = msort(list, half); /* sort first half of list */
5784 p = msort(p, len - half); /* sort second half */
5785 lpp = &list;
5786 for (;;) {
5787#ifdef CONFIG_LOCALE_SUPPORT
5788 if (strcoll(p->text, q->text) < 0)
5789#else
5790 if (strcmp(p->text, q->text) < 0)
5791#endif
5792 {
5793 *lpp = p;
5794 lpp = &p->next;
5795 if ((p = *lpp) == NULL) {
5796 *lpp = q;
5797 break;
5798 }
5799 } else {
5800 *lpp = q;
5801 lpp = &q->next;
5802 if ((q = *lpp) == NULL) {
5803 *lpp = p;
5804 break;
5805 }
5806 }
5807 }
5808 return list;
5809}
5810
5811
5812/*
Eric Andersencb57d552001-06-28 07:25:16 +00005813 * Returns true if the pattern matches the string.
5814 */
5815
Rob Landley88621d72006-08-29 19:41:06 +00005816static int patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005817{
Eric Andersenc470f442003-07-28 09:56:35 +00005818 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005819}
5820
5821
Eric Andersencb57d552001-06-28 07:25:16 +00005822/*
5823 * Remove any CTLESC characters from a string.
5824 */
5825
Eric Andersenc470f442003-07-28 09:56:35 +00005826static char *
5827_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005828{
5829 char *p, *q, *r;
5830 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005831 unsigned inquotes;
5832 int notescaped;
5833 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005834
5835 p = strpbrk(str, qchars);
5836 if (!p) {
5837 return str;
5838 }
5839 q = p;
5840 r = str;
5841 if (flag & RMESCAPE_ALLOC) {
5842 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005843 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005844
Eric Andersenc470f442003-07-28 09:56:35 +00005845 if (flag & RMESCAPE_GROW) {
5846 r = makestrspace(fulllen, expdest);
5847 } else if (flag & RMESCAPE_HEAP) {
5848 r = ckmalloc(fulllen);
5849 } else {
5850 r = stalloc(fulllen);
5851 }
5852 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005853 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005854 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005855 }
5856 }
Eric Andersenc470f442003-07-28 09:56:35 +00005857 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5858 globbing = flag & RMESCAPE_GLOB;
5859 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005860 while (*p) {
5861 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005862 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005863 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005864 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005865 continue;
5866 }
Eric Andersenc470f442003-07-28 09:56:35 +00005867 if (*p == '\\') {
5868 /* naked back slash */
5869 notescaped = 0;
5870 goto copy;
5871 }
Eric Andersencb57d552001-06-28 07:25:16 +00005872 if (*p == CTLESC) {
5873 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005874 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005875 *q++ = '\\';
5876 }
5877 }
Eric Andersenc470f442003-07-28 09:56:35 +00005878 notescaped = globbing;
5879copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005880 *q++ = *p++;
5881 }
5882 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005883 if (flag & RMESCAPE_GROW) {
5884 expdest = r;
5885 STADJUST(q - r + 1, expdest);
5886 }
Eric Andersencb57d552001-06-28 07:25:16 +00005887 return r;
5888}
Eric Andersencb57d552001-06-28 07:25:16 +00005889
5890
Eric Andersencb57d552001-06-28 07:25:16 +00005891/*
5892 * See if a pattern matches in a case statement.
5893 */
5894
Eric Andersenc470f442003-07-28 09:56:35 +00005895int
5896casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005897{
Eric Andersencb57d552001-06-28 07:25:16 +00005898 struct stackmark smark;
5899 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005900
5901 setstackmark(&smark);
5902 argbackq = pattern->narg.backquote;
5903 STARTSTACKSTR(expdest);
5904 ifslastp = NULL;
5905 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005906 STACKSTRNUL(expdest);
5907 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005908 popstackmark(&smark);
5909 return result;
5910}
5911
5912/*
5913 * Our own itoa().
5914 */
5915
Eric Andersenc470f442003-07-28 09:56:35 +00005916static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005917cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005918{
Eric Andersencb57d552001-06-28 07:25:16 +00005919 int len;
5920
Eric Andersenc470f442003-07-28 09:56:35 +00005921 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005922#ifdef CONFIG_ASH_MATH_SUPPORT_64
5923 len = fmtstr(expdest, 32, "%lld", (long long) num);
5924#else
Eric Andersenc470f442003-07-28 09:56:35 +00005925 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005926#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005927 STADJUST(len, expdest);
5928 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005929}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005930
Eric Andersenc470f442003-07-28 09:56:35 +00005931static void
5932varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005933{
Eric Andersenc470f442003-07-28 09:56:35 +00005934 const char *msg;
5935 const char *tail;
5936
5937 tail = nullstr;
5938 msg = "parameter not set";
5939 if (umsg) {
5940 if (*end == CTLENDVAR) {
5941 if (varflags & VSNUL)
5942 tail = " or null";
5943 } else
5944 msg = umsg;
5945 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005946 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005947}
Eric Andersen90898442003-08-06 11:20:52 +00005948
5949
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005950/* input.c */
Eric Andersencb57d552001-06-28 07:25:16 +00005951
Eric Andersencb57d552001-06-28 07:25:16 +00005952/*
Eric Andersen90898442003-08-06 11:20:52 +00005953 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005954 */
5955
Eric Andersenc470f442003-07-28 09:56:35 +00005956#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005957
Eric Andersenc470f442003-07-28 09:56:35 +00005958static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005959
Eric Andersencb57d552001-06-28 07:25:16 +00005960/*
Eric Andersenc470f442003-07-28 09:56:35 +00005961 * Read a character from the script, returning PEOF on end of file.
5962 * Nul characters in the input are silently discarded.
5963 */
5964
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005965
5966#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
Eric Andersenc470f442003-07-28 09:56:35 +00005967
5968#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5969#define pgetc_macro() pgetc()
5970static int
5971pgetc(void)
5972{
5973 return pgetc_as_macro();
5974}
5975#else
5976#define pgetc_macro() pgetc_as_macro()
5977static int
5978pgetc(void)
5979{
5980 return pgetc_macro();
5981}
5982#endif
5983
5984
5985/*
5986 * Same as pgetc(), but ignores PEOA.
5987 */
5988#ifdef CONFIG_ASH_ALIAS
5989static int pgetc2(void)
5990{
5991 int c;
5992
5993 do {
5994 c = pgetc_macro();
5995 } while (c == PEOA);
5996 return c;
5997}
5998#else
Rob Landley88621d72006-08-29 19:41:06 +00005999static int pgetc2(void)
Eric Andersenc470f442003-07-28 09:56:35 +00006000{
6001 return pgetc_macro();
6002}
6003#endif
6004
Glenn L McGrath28939ad2004-07-21 10:20:19 +00006005/*
6006 * Read a line from the script.
6007 */
6008
Rob Landley88621d72006-08-29 19:41:06 +00006009static char * pfgets(char *line, int len)
Glenn L McGrath28939ad2004-07-21 10:20:19 +00006010{
6011 char *p = line;
6012 int nleft = len;
6013 int c;
6014
6015 while (--nleft > 0) {
6016 c = pgetc2();
6017 if (c == PEOF) {
6018 if (p == line)
6019 return NULL;
6020 break;
6021 }
6022 *p++ = c;
6023 if (c == '\n')
6024 break;
6025 }
6026 *p = '\0';
6027 return line;
6028}
6029
6030
Eric Andersenc470f442003-07-28 09:56:35 +00006031
6032#ifdef CONFIG_FEATURE_COMMAND_EDITING
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006033#ifdef CONFIG_ASH_EXPAND_PRMT
6034static char *cmdedit_prompt;
6035#else
Eric Andersenc470f442003-07-28 09:56:35 +00006036static const char *cmdedit_prompt;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006037#endif
Rob Landley88621d72006-08-29 19:41:06 +00006038static void putprompt(const char *s)
Eric Andersenc470f442003-07-28 09:56:35 +00006039{
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006040#ifdef CONFIG_ASH_EXPAND_PRMT
6041 free(cmdedit_prompt);
Rob Landleyd921b2e2006-08-03 15:41:12 +00006042 cmdedit_prompt = xstrdup(s);
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006043#else
Eric Andersenc470f442003-07-28 09:56:35 +00006044 cmdedit_prompt = s;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006045#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006046}
6047#else
Rob Landley88621d72006-08-29 19:41:06 +00006048static void putprompt(const char *s)
Eric Andersenc470f442003-07-28 09:56:35 +00006049{
6050 out2str(s);
6051}
6052#endif
6053
Rob Landley88621d72006-08-29 19:41:06 +00006054static int preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006055{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006056 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006057 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006058 parsenextc = buf;
6059
Eric Andersenc470f442003-07-28 09:56:35 +00006060retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006061#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006062 if (!iflag || parsefile->fd)
6063 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6064 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006065#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006066 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006067#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006068 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6069 if(nr == 0) {
6070 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006071 if(trap[SIGINT]) {
6072 buf[0] = '\n';
6073 buf[1] = 0;
6074 raise(SIGINT);
6075 return 1;
6076 }
Eric Andersenc470f442003-07-28 09:56:35 +00006077 goto retry;
6078 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006079 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006080 /* Ctrl+D presend */
6081 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006082 }
Eric Andersencb57d552001-06-28 07:25:16 +00006083 }
6084#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006085 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006086#endif
6087
6088 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006089 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6090 int flags = fcntl(0, F_GETFL, 0);
6091 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006092 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006093 if (fcntl(0, F_SETFL, flags) >= 0) {
6094 out2str("sh: turning off NDELAY mode\n");
6095 goto retry;
6096 }
6097 }
6098 }
6099 }
6100 return nr;
6101}
6102
6103/*
6104 * Refill the input buffer and return the next input character:
6105 *
6106 * 1) If a string was pushed back on the input, pop it;
6107 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6108 * from a string so we can't refill the buffer, return EOF.
6109 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6110 * 4) Process input up to the next newline, deleting nul characters.
6111 */
6112
Eric Andersenc470f442003-07-28 09:56:35 +00006113int
6114preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006115{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006116 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00006117 int more;
6118 char savec;
6119
6120 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006121#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006122 if (parsenleft == -1 && parsefile->strpush->ap &&
6123 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006124 return PEOA;
6125 }
Eric Andersen2870d962001-07-02 17:27:21 +00006126#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006127 popstring();
6128 if (--parsenleft >= 0)
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006129 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006130 }
6131 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6132 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006133 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006134
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006135 more = parselleft;
6136 if (more <= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006137again:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006138 if ((more = preadfd()) <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006139 parselleft = parsenleft = EOF_NLEFT;
6140 return PEOF;
6141 }
6142 }
6143
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006144 q = parsenextc;
Eric Andersencb57d552001-06-28 07:25:16 +00006145
6146 /* delete nul characters */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006147 for (;;) {
6148 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00006149
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006150 more--;
6151 c = *q;
Eric Andersenc470f442003-07-28 09:56:35 +00006152
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006153 if (!c)
6154 memmove(q, q + 1, more);
6155 else {
6156 q++;
6157 if (c == '\n') {
6158 parsenleft = q - parsenextc - 1;
6159 break;
6160 }
Eric Andersencb57d552001-06-28 07:25:16 +00006161 }
6162
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006163 if (more <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006164 parsenleft = q - parsenextc - 1;
6165 if (parsenleft < 0)
6166 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006167 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006168 }
6169 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006170 parselleft = more;
Eric Andersencb57d552001-06-28 07:25:16 +00006171
6172 savec = *q;
6173 *q = '\0';
6174
6175 if (vflag) {
6176 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006177 }
6178
6179 *q = savec;
6180
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006181 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006182}
6183
Eric Andersenc470f442003-07-28 09:56:35 +00006184/*
6185 * Undo the last call to pgetc. Only one character may be pushed back.
6186 * PEOF may be pushed back.
6187 */
6188
6189void
6190pungetc(void)
6191{
6192 parsenleft++;
6193 parsenextc--;
6194}
Eric Andersencb57d552001-06-28 07:25:16 +00006195
6196/*
6197 * Push a string back onto the input at this current parsefile level.
6198 * We handle aliases this way.
6199 */
Eric Andersenc470f442003-07-28 09:56:35 +00006200void
6201pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006202{
Eric Andersencb57d552001-06-28 07:25:16 +00006203 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006204 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006205
Eric Andersenc470f442003-07-28 09:56:35 +00006206 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006207 INTOFF;
6208/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6209 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006210 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006211 sp->prev = parsefile->strpush;
6212 parsefile->strpush = sp;
6213 } else
6214 sp = parsefile->strpush = &(parsefile->basestrpush);
6215 sp->prevstring = parsenextc;
6216 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006217#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006218 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006219 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006220 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006221 sp->string = s;
6222 }
Eric Andersen2870d962001-07-02 17:27:21 +00006223#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006224 parsenextc = s;
6225 parsenleft = len;
6226 INTON;
6227}
6228
Eric Andersenc470f442003-07-28 09:56:35 +00006229void
6230popstring(void)
6231{
6232 struct strpush *sp = parsefile->strpush;
6233
6234 INTOFF;
6235#ifdef CONFIG_ASH_ALIAS
6236 if (sp->ap) {
6237 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6238 checkkwd |= CHKALIAS;
6239 }
6240 if (sp->string != sp->ap->val) {
6241 ckfree(sp->string);
6242 }
6243 sp->ap->flag &= ~ALIASINUSE;
6244 if (sp->ap->flag & ALIASDEAD) {
6245 unalias(sp->ap->name);
6246 }
6247 }
6248#endif
6249 parsenextc = sp->prevstring;
6250 parsenleft = sp->prevnleft;
6251/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6252 parsefile->strpush = sp->prev;
6253 if (sp != &(parsefile->basestrpush))
6254 ckfree(sp);
6255 INTON;
6256}
6257
6258/*
6259 * Set the input to take input from a file. If push is set, push the
6260 * old input onto the stack first.
6261 */
6262
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006263static int
6264setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00006265{
6266 int fd;
6267 int fd2;
6268
6269 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006270 if ((fd = open(fname, O_RDONLY)) < 0) {
6271 if (flags & INPUT_NOFILE_OK)
6272 goto out;
6273 sh_error("Can't open %s", fname);
6274 }
Eric Andersenc470f442003-07-28 09:56:35 +00006275 if (fd < 10) {
6276 fd2 = copyfd(fd, 10);
6277 close(fd);
6278 if (fd2 < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006279 sh_error("Out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +00006280 fd = fd2;
6281 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006282 setinputfd(fd, flags & INPUT_PUSH_FILE);
6283out:
Eric Andersenc470f442003-07-28 09:56:35 +00006284 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006285 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +00006286}
6287
6288
6289/*
6290 * Like setinputfile, but takes an open file descriptor. Call this with
6291 * interrupts off.
6292 */
6293
6294static void
6295setinputfd(int fd, int push)
6296{
6297 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6298 if (push) {
6299 pushfile();
6300 parsefile->buf = 0;
6301 }
6302 parsefile->fd = fd;
6303 if (parsefile->buf == NULL)
6304 parsefile->buf = ckmalloc(IBUFSIZ);
6305 parselleft = parsenleft = 0;
6306 plinno = 1;
6307}
6308
Eric Andersencb57d552001-06-28 07:25:16 +00006309
Eric Andersencb57d552001-06-28 07:25:16 +00006310/*
6311 * Like setinputfile, but takes input from a string.
6312 */
6313
Eric Andersenc470f442003-07-28 09:56:35 +00006314static void
6315setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006316{
Eric Andersencb57d552001-06-28 07:25:16 +00006317 INTOFF;
6318 pushfile();
6319 parsenextc = string;
6320 parsenleft = strlen(string);
6321 parsefile->buf = NULL;
6322 plinno = 1;
6323 INTON;
6324}
6325
6326
Eric Andersencb57d552001-06-28 07:25:16 +00006327/*
6328 * To handle the "." command, a stack of input files is used. Pushfile
6329 * adds a new entry to the stack and popfile restores the previous level.
6330 */
6331
Eric Andersenc470f442003-07-28 09:56:35 +00006332static void
6333pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006334{
Eric Andersencb57d552001-06-28 07:25:16 +00006335 struct parsefile *pf;
6336
6337 parsefile->nleft = parsenleft;
6338 parsefile->lleft = parselleft;
6339 parsefile->nextc = parsenextc;
6340 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006341 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006342 pf->prev = parsefile;
6343 pf->fd = -1;
6344 pf->strpush = NULL;
6345 pf->basestrpush.prev = NULL;
6346 parsefile = pf;
6347}
6348
Eric Andersenc470f442003-07-28 09:56:35 +00006349
6350static void
6351popfile(void)
6352{
6353 struct parsefile *pf = parsefile;
6354
6355 INTOFF;
6356 if (pf->fd >= 0)
6357 close(pf->fd);
6358 if (pf->buf)
6359 ckfree(pf->buf);
6360 while (pf->strpush)
6361 popstring();
6362 parsefile = pf->prev;
6363 ckfree(pf);
6364 parsenleft = parsefile->nleft;
6365 parselleft = parsefile->lleft;
6366 parsenextc = parsefile->nextc;
6367 plinno = parsefile->linno;
6368 INTON;
6369}
Eric Andersencb57d552001-06-28 07:25:16 +00006370
6371
Eric Andersen2870d962001-07-02 17:27:21 +00006372/*
Eric Andersenc470f442003-07-28 09:56:35 +00006373 * Return to top level.
6374 */
Eric Andersen2870d962001-07-02 17:27:21 +00006375
Eric Andersenc470f442003-07-28 09:56:35 +00006376static void
6377popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006378{
Eric Andersenc470f442003-07-28 09:56:35 +00006379 while (parsefile != &basepf)
6380 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006381}
6382
Eric Andersen2870d962001-07-02 17:27:21 +00006383
Eric Andersenc470f442003-07-28 09:56:35 +00006384/*
6385 * Close the file(s) that the shell is reading commands from. Called
6386 * after a fork is done.
6387 */
6388
6389static void
6390closescript(void)
6391{
6392 popallfiles();
6393 if (parsefile->fd > 0) {
6394 close(parsefile->fd);
6395 parsefile->fd = 0;
6396 }
6397}
Eric Andersenc470f442003-07-28 09:56:35 +00006398
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006399/* jobs.c */
Eric Andersenc470f442003-07-28 09:56:35 +00006400
6401/* mode flags for set_curjob */
6402#define CUR_DELETE 2
6403#define CUR_RUNNING 1
6404#define CUR_STOPPED 0
6405
6406/* mode flags for dowait */
6407#define DOWAIT_NORMAL 0
6408#define DOWAIT_BLOCK 1
6409
6410/* array of jobs */
6411static struct job *jobtab;
6412/* size of array */
6413static unsigned njobs;
6414#if JOBS
6415/* pgrp of shell on invocation */
6416static int initialpgrp;
6417static int ttyfd = -1;
6418#endif
6419/* current job */
6420static struct job *curjob;
6421/* number of presumed living untracked jobs */
6422static int jobless;
6423
6424static void set_curjob(struct job *, unsigned);
6425#if JOBS
6426static int restartjob(struct job *, int);
6427static void xtcsetpgrp(int, pid_t);
6428static char *commandtext(union node *);
6429static void cmdlist(union node *, int);
6430static void cmdtxt(union node *);
6431static void cmdputs(const char *);
6432static void showpipe(struct job *, FILE *);
6433#endif
6434static int sprint_status(char *, int, int);
6435static void freejob(struct job *);
6436static struct job *getjob(const char *, int);
6437static struct job *growjobtab(void);
6438static void forkchild(struct job *, union node *, int);
6439static void forkparent(struct job *, union node *, int, pid_t);
6440static int dowait(int, struct job *);
6441static int getstatus(struct job *);
6442
6443static void
6444set_curjob(struct job *jp, unsigned mode)
6445{
6446 struct job *jp1;
6447 struct job **jpp, **curp;
6448
6449 /* first remove from list */
6450 jpp = curp = &curjob;
6451 do {
6452 jp1 = *jpp;
6453 if (jp1 == jp)
6454 break;
6455 jpp = &jp1->prev_job;
6456 } while (1);
6457 *jpp = jp1->prev_job;
6458
6459 /* Then re-insert in correct position */
6460 jpp = curp;
6461 switch (mode) {
6462 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00006463#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00006464 abort();
6465#endif
6466 case CUR_DELETE:
6467 /* job being deleted */
6468 break;
6469 case CUR_RUNNING:
6470 /* newly created job or backgrounded job,
6471 put after all stopped jobs. */
6472 do {
6473 jp1 = *jpp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006474#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006475 if (!jp1 || jp1->state != JOBSTOPPED)
6476#endif
6477 break;
6478 jpp = &jp1->prev_job;
6479 } while (1);
6480 /* FALLTHROUGH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006481#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006482 case CUR_STOPPED:
6483#endif
6484 /* newly stopped job - becomes curjob */
6485 jp->prev_job = *jpp;
6486 *jpp = jp;
6487 break;
6488 }
6489}
6490
6491#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006492/*
6493 * Turn job control on and off.
6494 *
6495 * Note: This code assumes that the third arg to ioctl is a character
6496 * pointer, which is true on Berkeley systems but not System V. Since
6497 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006498 *
6499 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006500 */
6501
Eric Andersenc470f442003-07-28 09:56:35 +00006502void
6503setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006504{
Eric Andersenc470f442003-07-28 09:56:35 +00006505 int fd;
6506 int pgrp;
6507
6508 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006509 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006510 if (on) {
6511 int ofd;
6512 ofd = fd = open(_PATH_TTY, O_RDWR);
6513 if (fd < 0) {
6514 fd += 3;
6515 while (!isatty(fd) && --fd >= 0)
6516 ;
6517 }
6518 fd = fcntl(fd, F_DUPFD, 10);
6519 close(ofd);
6520 if (fd < 0)
6521 goto out;
6522 fcntl(fd, F_SETFD, FD_CLOEXEC);
6523 do { /* while we are in the background */
6524 if ((pgrp = tcgetpgrp(fd)) < 0) {
6525out:
6526 sh_warnx("can't access tty; job control turned off");
6527 mflag = on = 0;
6528 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006529 }
Eric Andersenc470f442003-07-28 09:56:35 +00006530 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006531 break;
6532 killpg(0, SIGTTIN);
6533 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006534 initialpgrp = pgrp;
6535
Eric Andersencb57d552001-06-28 07:25:16 +00006536 setsignal(SIGTSTP);
6537 setsignal(SIGTTOU);
6538 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006539 pgrp = rootpid;
6540 setpgid(0, pgrp);
6541 xtcsetpgrp(fd, pgrp);
6542 } else {
6543 /* turning job control off */
6544 fd = ttyfd;
6545 pgrp = initialpgrp;
6546 xtcsetpgrp(fd, pgrp);
6547 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006548 setsignal(SIGTSTP);
6549 setsignal(SIGTTOU);
6550 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006551close:
6552 close(fd);
6553 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006554 }
Eric Andersenc470f442003-07-28 09:56:35 +00006555 ttyfd = fd;
6556 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006557}
Eric Andersencb57d552001-06-28 07:25:16 +00006558
Eric Andersenc470f442003-07-28 09:56:35 +00006559static int
Eric Andersen90898442003-08-06 11:20:52 +00006560killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006561{
6562 int signo = -1;
6563 int list = 0;
6564 int i;
6565 pid_t pid;
6566 struct job *jp;
6567
6568 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006569usage:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006570 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006571"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6572"kill -l [exitstatus]"
6573 );
Eric Andersencb57d552001-06-28 07:25:16 +00006574 }
6575
Eric Andersenc470f442003-07-28 09:56:35 +00006576 if (**++argv == '-') {
Rob Landleyc9c1a412006-07-12 19:17:55 +00006577 signo = get_signum(*argv + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006578 if (signo < 0) {
6579 int c;
6580
6581 while ((c = nextopt("ls:")) != '\0')
6582 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006583 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00006584#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00006585 abort();
6586#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006587 case 'l':
6588 list = 1;
6589 break;
6590 case 's':
Rob Landleyc9c1a412006-07-12 19:17:55 +00006591 signo = get_signum(optionarg);
Eric Andersencb57d552001-06-28 07:25:16 +00006592 if (signo < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006593 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006594 "invalid signal number or name: %s",
6595 optionarg
6596 );
Eric Andersencb57d552001-06-28 07:25:16 +00006597 }
Eric Andersen2870d962001-07-02 17:27:21 +00006598 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006599 }
Eric Andersenc470f442003-07-28 09:56:35 +00006600 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006601 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006602 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006603 }
6604
6605 if (!list && signo < 0)
6606 signo = SIGTERM;
6607
Eric Andersenc470f442003-07-28 09:56:35 +00006608 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006609 goto usage;
6610 }
6611
6612 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006613 const char *name;
6614
Eric Andersenc470f442003-07-28 09:56:35 +00006615 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006616 for (i = 1; i < NSIG; i++) {
Rob Landleyc9c1a412006-07-12 19:17:55 +00006617 name = get_signame(i);
6618 if (isdigit(*name))
Eric Andersenc470f442003-07-28 09:56:35 +00006619 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006620 }
6621 return 0;
6622 }
Rob Landleyc9c1a412006-07-12 19:17:55 +00006623 name = get_signame(signo);
6624 if (isdigit(*name))
Eric Andersenc470f442003-07-28 09:56:35 +00006625 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006626 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006627 sh_error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006628 return 0;
6629 }
6630
Eric Andersenc470f442003-07-28 09:56:35 +00006631 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006632 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006633 if (**argv == '%') {
6634 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006635 pid = -jp->ps[0].pid;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006636 } else {
6637 pid = **argv == '-' ?
6638 -number(*argv + 1) : number(*argv);
6639 }
Eric Andersenc470f442003-07-28 09:56:35 +00006640 if (kill(pid, signo) != 0) {
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006641 sh_warnx("(%d) - %m", pid);
Eric Andersenc470f442003-07-28 09:56:35 +00006642 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006643 }
Eric Andersenc470f442003-07-28 09:56:35 +00006644 } while (*++argv);
6645
6646 return i;
6647}
6648#endif /* JOBS */
6649
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00006650#if defined(JOBS) || DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00006651static int
6652jobno(const struct job *jp)
6653{
6654 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006655}
6656#endif
6657
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006658#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006659static int
6660fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006661{
Eric Andersenc470f442003-07-28 09:56:35 +00006662 struct job *jp;
6663 FILE *out;
6664 int mode;
6665 int retval;
6666
6667 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6668 nextopt(nullstr);
6669 argv = argptr;
6670 out = stdout;
6671 do {
6672 jp = getjob(*argv, 1);
6673 if (mode == FORK_BG) {
6674 set_curjob(jp, CUR_RUNNING);
6675 fprintf(out, "[%d] ", jobno(jp));
6676 }
6677 outstr(jp->ps->cmd, out);
6678 showpipe(jp, out);
6679 retval = restartjob(jp, mode);
6680 } while (*argv && *++argv);
6681 return retval;
6682}
6683
6684static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6685
6686
6687static int
6688restartjob(struct job *jp, int mode)
6689{
6690 struct procstat *ps;
6691 int i;
6692 int status;
6693 pid_t pgid;
6694
6695 INTOFF;
6696 if (jp->state == JOBDONE)
6697 goto out;
6698 jp->state = JOBRUNNING;
6699 pgid = jp->ps->pid;
6700 if (mode == FORK_FG)
6701 xtcsetpgrp(ttyfd, pgid);
6702 killpg(pgid, SIGCONT);
6703 ps = jp->ps;
6704 i = jp->nprocs;
6705 do {
6706 if (WIFSTOPPED(ps->status)) {
6707 ps->status = -1;
6708 }
6709 } while (ps++, --i);
6710out:
6711 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6712 INTON;
6713 return status;
6714}
6715#endif
6716
6717static int
6718sprint_status(char *s, int status, int sigonly)
6719{
6720 int col;
6721 int st;
6722
6723 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006724 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006725#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006726 if (WIFSTOPPED(status))
6727 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006728 else
Eric Andersenc470f442003-07-28 09:56:35 +00006729#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006730 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006731 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006732 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006733 goto out;
6734#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006735 if (WIFSTOPPED(status))
6736 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006737#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006738 }
6739 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006740 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006741 if (WCOREDUMP(status)) {
6742 col += fmtstr(s + col, 16, " (core dumped)");
6743 }
6744 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006745 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006746 if (st)
6747 col = fmtstr(s, 16, "Done(%d)", st);
6748 else
6749 col = fmtstr(s, 16, "Done");
6750 }
6751
6752out:
6753 return col;
6754}
6755
6756#if JOBS
6757static void
6758showjob(FILE *out, struct job *jp, int mode)
6759{
6760 struct procstat *ps;
6761 struct procstat *psend;
6762 int col;
6763 int indent;
6764 char s[80];
6765
6766 ps = jp->ps;
6767
6768 if (mode & SHOW_PGID) {
6769 /* just output process (group) id of pipeline */
6770 fprintf(out, "%d\n", ps->pid);
6771 return;
6772 }
6773
6774 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6775 indent = col;
6776
6777 if (jp == curjob)
6778 s[col - 2] = '+';
6779 else if (curjob && jp == curjob->prev_job)
6780 s[col - 2] = '-';
6781
6782 if (mode & SHOW_PID)
6783 col += fmtstr(s + col, 16, "%d ", ps->pid);
6784
6785 psend = ps + jp->nprocs;
6786
6787 if (jp->state == JOBRUNNING) {
6788 scopy("Running", s + col);
6789 col += strlen("Running");
6790 } else {
6791 int status = psend[-1].status;
6792#if JOBS
6793 if (jp->state == JOBSTOPPED)
6794 status = jp->stopstatus;
6795#endif
6796 col += sprint_status(s + col, status, 0);
6797 }
6798
6799 goto start;
6800
6801 do {
6802 /* for each process */
6803 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6804
6805start:
Eric Andersen90898442003-08-06 11:20:52 +00006806 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006807 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6808 );
6809 if (!(mode & SHOW_PID)) {
6810 showpipe(jp, out);
6811 break;
6812 }
6813 if (++ps == psend) {
6814 outcslow('\n', out);
6815 break;
6816 }
6817 } while (1);
6818
6819 jp->changed = 0;
6820
6821 if (jp->state == JOBDONE) {
6822 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6823 freejob(jp);
6824 }
6825}
6826
6827
6828static int
6829jobscmd(int argc, char **argv)
6830{
6831 int mode, m;
6832 FILE *out;
6833
6834 mode = 0;
6835 while ((m = nextopt("lp")))
6836 if (m == 'l')
6837 mode = SHOW_PID;
6838 else
6839 mode = SHOW_PGID;
6840
6841 out = stdout;
6842 argv = argptr;
6843 if (*argv)
6844 do
6845 showjob(out, getjob(*argv,0), mode);
6846 while (*++argv);
6847 else
6848 showjobs(out, mode);
6849
Eric Andersencb57d552001-06-28 07:25:16 +00006850 return 0;
6851}
6852
6853
6854/*
6855 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6856 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006857 */
6858
Eric Andersenc470f442003-07-28 09:56:35 +00006859static void
6860showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006861{
Eric Andersencb57d552001-06-28 07:25:16 +00006862 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006863
Eric Andersenc470f442003-07-28 09:56:35 +00006864 TRACE(("showjobs(%x) called\n", mode));
6865
6866 /* If not even one one job changed, there is nothing to do */
6867 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6868 continue;
6869
6870 for (jp = curjob; jp; jp = jp->prev_job) {
6871 if (!(mode & SHOW_CHANGED) || jp->changed)
6872 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006873 }
6874}
Eric Andersenc470f442003-07-28 09:56:35 +00006875#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006876
6877/*
6878 * Mark a job structure as unused.
6879 */
6880
Eric Andersenc470f442003-07-28 09:56:35 +00006881static void
6882freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006883{
Eric Andersenc470f442003-07-28 09:56:35 +00006884 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006885 int i;
6886
6887 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006888 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006889 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006890 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006891 }
6892 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006893 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006894 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006895 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006896 INTON;
6897}
6898
6899
Eric Andersenc470f442003-07-28 09:56:35 +00006900static int
6901waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006902{
6903 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006904 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006905 struct job *jp;
6906
Eric Andersenc470f442003-07-28 09:56:35 +00006907 EXSIGON();
6908
6909 nextopt(nullstr);
6910 retval = 0;
6911
6912 argv = argptr;
6913 if (!*argv) {
6914 /* wait for all jobs */
6915 for (;;) {
6916 jp = curjob;
6917 while (1) {
6918 if (!jp) {
6919 /* no running procs */
6920 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006921 }
Eric Andersenc470f442003-07-28 09:56:35 +00006922 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006923 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006924 jp->waited = 1;
6925 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006926 }
Eric Andersenc470f442003-07-28 09:56:35 +00006927 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006928 }
6929 }
Eric Andersenc470f442003-07-28 09:56:35 +00006930
6931 retval = 127;
6932 do {
6933 if (**argv != '%') {
6934 pid_t pid = number(*argv);
6935 job = curjob;
6936 goto start;
6937 do {
6938 if (job->ps[job->nprocs - 1].pid == pid)
6939 break;
6940 job = job->prev_job;
6941start:
6942 if (!job)
6943 goto repeat;
6944 } while (1);
6945 } else
6946 job = getjob(*argv, 0);
6947 /* loop until process terminated or stopped */
6948 while (job->state == JOBRUNNING)
6949 dowait(DOWAIT_BLOCK, 0);
6950 job->waited = 1;
6951 retval = getstatus(job);
6952repeat:
6953 ;
6954 } while (*++argv);
6955
6956out:
6957 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006958}
6959
6960
Eric Andersencb57d552001-06-28 07:25:16 +00006961/*
6962 * Convert a job name to a job structure.
6963 */
6964
Eric Andersenc470f442003-07-28 09:56:35 +00006965static struct job *
6966getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006967{
Eric Andersencb57d552001-06-28 07:25:16 +00006968 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006969 struct job *found;
6970 const char *err_msg = "No such job: %s";
6971 unsigned num;
6972 int c;
6973 const char *p;
6974 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006975
Eric Andersenc470f442003-07-28 09:56:35 +00006976 jp = curjob;
6977 p = name;
6978 if (!p)
6979 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006980
Eric Andersenc470f442003-07-28 09:56:35 +00006981 if (*p != '%')
6982 goto err;
6983
6984 c = *++p;
6985 if (!c)
6986 goto currentjob;
6987
6988 if (!p[1]) {
6989 if (c == '+' || c == '%') {
6990currentjob:
6991 err_msg = "No current job";
6992 goto check;
6993 } else if (c == '-') {
6994 if (jp)
6995 jp = jp->prev_job;
6996 err_msg = "No previous job";
6997check:
6998 if (!jp)
6999 goto err;
7000 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00007001 }
7002 }
Eric Andersenc470f442003-07-28 09:56:35 +00007003
7004 if (is_number(p)) {
7005 num = atoi(p);
7006 if (num < njobs) {
7007 jp = jobtab + num - 1;
7008 if (jp->used)
7009 goto gotit;
7010 goto err;
7011 }
7012 }
7013
7014 match = prefix;
7015 if (*p == '?') {
7016 match = strstr;
7017 p++;
7018 }
7019
7020 found = 0;
7021 while (1) {
7022 if (!jp)
7023 goto err;
7024 if (match(jp->ps[0].cmd, p)) {
7025 if (found)
7026 goto err;
7027 found = jp;
7028 err_msg = "%s: ambiguous";
7029 }
7030 jp = jp->prev_job;
7031 }
7032
7033gotit:
7034#if JOBS
7035 err_msg = "job %s not created under job control";
7036 if (getctl && jp->jobctl == 0)
7037 goto err;
7038#endif
7039 return jp;
7040err:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007041 sh_error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007042}
7043
7044
Eric Andersencb57d552001-06-28 07:25:16 +00007045/*
Eric Andersenc470f442003-07-28 09:56:35 +00007046 * Return a new job structure.
7047 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007048 */
7049
Eric Andersenc470f442003-07-28 09:56:35 +00007050static struct job *
7051makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007052{
7053 int i;
7054 struct job *jp;
7055
Eric Andersenc470f442003-07-28 09:56:35 +00007056 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007057 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007058 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007059 break;
7060 }
7061 if (jp->used == 0)
7062 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007063 if (jp->state != JOBDONE || !jp->waited)
7064 continue;
7065#if JOBS
7066 if (jobctl)
7067 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007068#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007069 freejob(jp);
7070 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007071 }
Eric Andersenc470f442003-07-28 09:56:35 +00007072 memset(jp, 0, sizeof(*jp));
7073#if JOBS
7074 if (jobctl)
7075 jp->jobctl = 1;
7076#endif
7077 jp->prev_job = curjob;
7078 curjob = jp;
7079 jp->used = 1;
7080 jp->ps = &jp->ps0;
7081 if (nprocs > 1) {
7082 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7083 }
7084 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7085 jobno(jp)));
7086 return jp;
7087}
7088
7089static struct job *
7090growjobtab(void)
7091{
7092 size_t len;
7093 ptrdiff_t offset;
7094 struct job *jp, *jq;
7095
7096 len = njobs * sizeof(*jp);
7097 jq = jobtab;
7098 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7099
7100 offset = (char *)jp - (char *)jq;
7101 if (offset) {
7102 /* Relocate pointers */
7103 size_t l = len;
7104
7105 jq = (struct job *)((char *)jq + l);
7106 while (l) {
7107 l -= sizeof(*jp);
7108 jq--;
7109#define joff(p) ((struct job *)((char *)(p) + l))
7110#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007111 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007112 jmove(joff(jp)->ps);
7113 if (joff(jp)->prev_job)
7114 jmove(joff(jp)->prev_job);
7115 }
7116 if (curjob)
7117 jmove(curjob);
7118#undef joff
7119#undef jmove
7120 }
7121
7122 njobs += 4;
7123 jobtab = jp;
7124 jp = (struct job *)((char *)jp + len);
7125 jq = jp + 3;
7126 do {
7127 jq->used = 0;
7128 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007129 return jp;
7130}
7131
7132
7133/*
Eric Andersenc470f442003-07-28 09:56:35 +00007134 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007135 * own process group. Jp is a job structure that the job is to be added to.
7136 * N is the command that will be evaluated by the child. Both jp and n may
7137 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007138 * FORK_FG - Fork off a foreground process.
7139 * FORK_BG - Fork off a background process.
7140 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7141 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007142 *
7143 * When job control is turned off, background processes have their standard
7144 * input redirected to /dev/null (except for the second and later processes
7145 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007146 *
7147 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007148 */
7149
Rob Landley88621d72006-08-29 19:41:06 +00007150static void forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007151{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007152 int oldlvl;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007153
Eric Andersenc470f442003-07-28 09:56:35 +00007154 TRACE(("Child shell %d\n", getpid()));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007155 oldlvl = shlvl;
7156 shlvl++;
Eric Andersenc470f442003-07-28 09:56:35 +00007157
7158 closescript();
7159 clear_traps();
7160#if JOBS
7161 /* do job control only in root shell */
7162 jobctl = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007163 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007164 pid_t pgrp;
7165
7166 if (jp->nprocs == 0)
7167 pgrp = getpid();
7168 else
7169 pgrp = jp->ps[0].pid;
7170 /* This can fail because we are doing it in the parent also */
7171 (void)setpgid(0, pgrp);
7172 if (mode == FORK_FG)
7173 xtcsetpgrp(ttyfd, pgrp);
7174 setsignal(SIGTSTP);
7175 setsignal(SIGTTOU);
7176 } else
Eric Andersen62483552001-07-10 06:09:16 +00007177#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007178 if (mode == FORK_BG) {
7179 ignoresig(SIGINT);
7180 ignoresig(SIGQUIT);
7181 if (jp->nprocs == 0) {
7182 close(0);
Bernhard Reutner-Fischer0a8812b2006-05-19 13:12:21 +00007183 if (open(bb_dev_null, O_RDONLY) != 0)
7184 sh_error("Can't open %s", bb_dev_null);
Eric Andersencb57d552001-06-28 07:25:16 +00007185 }
Eric Andersencb57d552001-06-28 07:25:16 +00007186 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007187 if (!oldlvl && iflag) {
Eric Andersenc470f442003-07-28 09:56:35 +00007188 setsignal(SIGINT);
7189 setsignal(SIGQUIT);
7190 setsignal(SIGTERM);
7191 }
7192 for (jp = curjob; jp; jp = jp->prev_job)
7193 freejob(jp);
7194 jobless = 0;
7195}
7196
Rob Landley88621d72006-08-29 19:41:06 +00007197static void forkparent(struct job *jp, union node *n, int mode, pid_t pid)
Eric Andersenc470f442003-07-28 09:56:35 +00007198{
7199 TRACE(("In parent shell: child = %d\n", pid));
7200 if (!jp) {
7201 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7202 jobless++;
7203 return;
7204 }
7205#if JOBS
7206 if (mode != FORK_NOJOB && jp->jobctl) {
7207 int pgrp;
7208
7209 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007210 pgrp = pid;
7211 else
7212 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007213 /* This can fail because we are doing it in the child also */
7214 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007215 }
Eric Andersen62483552001-07-10 06:09:16 +00007216#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007217 if (mode == FORK_BG) {
7218 backgndpid = pid; /* set $! */
7219 set_curjob(jp, CUR_RUNNING);
7220 }
Eric Andersencb57d552001-06-28 07:25:16 +00007221 if (jp) {
7222 struct procstat *ps = &jp->ps[jp->nprocs++];
7223 ps->pid = pid;
7224 ps->status = -1;
7225 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007226#if JOBS
7227 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007228 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007229#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007230 }
Eric Andersencb57d552001-06-28 07:25:16 +00007231}
7232
Eric Andersenc470f442003-07-28 09:56:35 +00007233static int
7234forkshell(struct job *jp, union node *n, int mode)
7235{
7236 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007237
Eric Andersenc470f442003-07-28 09:56:35 +00007238 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7239 pid = fork();
7240 if (pid < 0) {
7241 TRACE(("Fork failed, errno=%d", errno));
7242 if (jp)
7243 freejob(jp);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007244 sh_error("Cannot fork");
Eric Andersenc470f442003-07-28 09:56:35 +00007245 }
7246 if (pid == 0)
7247 forkchild(jp, n, mode);
7248 else
7249 forkparent(jp, n, mode, pid);
7250 return pid;
7251}
Eric Andersencb57d552001-06-28 07:25:16 +00007252
7253/*
7254 * Wait for job to finish.
7255 *
7256 * Under job control we have the problem that while a child process is
7257 * running interrupts generated by the user are sent to the child but not
7258 * to the shell. This means that an infinite loop started by an inter-
7259 * active user may be hard to kill. With job control turned off, an
7260 * interactive user may place an interactive program inside a loop. If
7261 * the interactive program catches interrupts, the user doesn't want
7262 * these interrupts to also abort the loop. The approach we take here
7263 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007264 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007265 * signal if the child process was terminated by an interrupt signal.
7266 * Unfortunately, some programs want to do a bit of cleanup and then
7267 * exit on interrupt; unless these processes terminate themselves by
7268 * sending a signal to themselves (instead of calling exit) they will
7269 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007270 *
7271 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007272 */
7273
Eric Andersenc470f442003-07-28 09:56:35 +00007274int
7275waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007276{
Eric Andersencb57d552001-06-28 07:25:16 +00007277 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007278
Eric Andersenc470f442003-07-28 09:56:35 +00007279 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7280 while (jp->state == JOBRUNNING) {
7281 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007282 }
Eric Andersenc470f442003-07-28 09:56:35 +00007283 st = getstatus(jp);
7284#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007285 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007286 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007287 /*
7288 * This is truly gross.
7289 * If we're doing job control, then we did a TIOCSPGRP which
7290 * caused us (the shell) to no longer be in the controlling
7291 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7292 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007293 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007294 */
Eric Andersenc470f442003-07-28 09:56:35 +00007295 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007296 raise(SIGINT);
7297 }
Eric Andersen2870d962001-07-02 17:27:21 +00007298 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007299#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007300 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007301 return st;
7302}
7303
7304
Eric Andersen62483552001-07-10 06:09:16 +00007305/*
7306 * Do a wait system call. If job control is compiled in, we accept
7307 * stopped processes. If block is zero, we return a value of zero
7308 * rather than blocking.
7309 *
7310 * System V doesn't have a non-blocking wait system call. It does
7311 * have a SIGCLD signal that is sent to a process when one of it's
7312 * children dies. The obvious way to use SIGCLD would be to install
7313 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7314 * was received, and have waitproc bump another counter when it got
7315 * the status of a process. Waitproc would then know that a wait
7316 * system call would not block if the two counters were different.
7317 * This approach doesn't work because if a process has children that
7318 * have not been waited for, System V will send it a SIGCLD when it
7319 * installs a signal handler for SIGCLD. What this means is that when
7320 * a child exits, the shell will be sent SIGCLD signals continuously
7321 * until is runs out of stack space, unless it does a wait call before
7322 * restoring the signal handler. The code below takes advantage of
7323 * this (mis)feature by installing a signal handler for SIGCLD and
7324 * then checking to see whether it was called. If there are any
7325 * children to be waited for, it will be.
7326 *
Eric Andersenc470f442003-07-28 09:56:35 +00007327 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7328 * waits at all. In this case, the user will not be informed when
7329 * a background process until the next time she runs a real program
7330 * (as opposed to running a builtin command or just typing return),
7331 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007332 */
7333
Rob Landley88621d72006-08-29 19:41:06 +00007334static int waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007335{
Eric Andersenc470f442003-07-28 09:56:35 +00007336 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007337
Eric Andersenc470f442003-07-28 09:56:35 +00007338#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007339 if (jobctl)
7340 flags |= WUNTRACED;
7341#endif
7342 if (block == 0)
7343 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007344 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007345}
7346
Eric Andersenc470f442003-07-28 09:56:35 +00007347/*
7348 * Wait for a process to terminate.
7349 */
7350
7351static int
7352dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007353{
7354 int pid;
7355 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007356 struct job *jp;
7357 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007358 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007359
7360 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007361 pid = waitproc(block, &status);
7362 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007363 if (pid <= 0)
7364 return pid;
7365 INTOFF;
7366 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007367 for (jp = curjob; jp; jp = jp->prev_job) {
7368 struct procstat *sp;
7369 struct procstat *spend;
7370 if (jp->state == JOBDONE)
7371 continue;
7372 state = JOBDONE;
7373 spend = jp->ps + jp->nprocs;
7374 sp = jp->ps;
7375 do {
7376 if (sp->pid == pid) {
7377 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7378 sp->status = status;
7379 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007380 }
Eric Andersenc470f442003-07-28 09:56:35 +00007381 if (sp->status == -1)
7382 state = JOBRUNNING;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007383#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007384 if (state == JOBRUNNING)
7385 continue;
7386 if (WIFSTOPPED(sp->status)) {
7387 jp->stopstatus = sp->status;
7388 state = JOBSTOPPED;
7389 }
Eric Andersencb57d552001-06-28 07:25:16 +00007390#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007391 } while (++sp < spend);
7392 if (thisjob)
7393 goto gotjob;
7394 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007395#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007396 if (!WIFSTOPPED(status))
7397#endif
7398
7399 jobless--;
7400 goto out;
7401
7402gotjob:
7403 if (state != JOBRUNNING) {
7404 thisjob->changed = 1;
7405
7406 if (thisjob->state != state) {
7407 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7408 thisjob->state = state;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007409#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007410 if (state == JOBSTOPPED) {
7411 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007412 }
Eric Andersenc470f442003-07-28 09:56:35 +00007413#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007414 }
7415 }
Eric Andersencb57d552001-06-28 07:25:16 +00007416
Eric Andersenc470f442003-07-28 09:56:35 +00007417out:
7418 INTON;
7419
7420 if (thisjob && thisjob == job) {
7421 char s[48 + 1];
7422 int len;
7423
7424 len = sprint_status(s, status, 1);
7425 if (len) {
7426 s[len] = '\n';
7427 s[len + 1] = 0;
7428 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007429 }
Eric Andersencb57d552001-06-28 07:25:16 +00007430 }
7431 return pid;
7432}
7433
7434
Eric Andersencb57d552001-06-28 07:25:16 +00007435/*
7436 * return 1 if there are stopped jobs, otherwise 0
7437 */
Eric Andersen90898442003-08-06 11:20:52 +00007438
Eric Andersenc470f442003-07-28 09:56:35 +00007439int
7440stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007441{
Eric Andersencb57d552001-06-28 07:25:16 +00007442 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007443 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007444
Eric Andersenc470f442003-07-28 09:56:35 +00007445 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007446 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007447 goto out;
7448 jp = curjob;
7449 if (jp && jp->state == JOBSTOPPED) {
7450 out2str("You have stopped jobs.\n");
7451 job_warning = 2;
7452 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007453 }
7454
Eric Andersenc470f442003-07-28 09:56:35 +00007455out:
7456 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007457}
7458
7459/*
7460 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007461 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007462 */
7463
Eric Andersenc470f442003-07-28 09:56:35 +00007464#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007465static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007466
Eric Andersenc470f442003-07-28 09:56:35 +00007467static char *
7468commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007469{
Eric Andersenc470f442003-07-28 09:56:35 +00007470 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007471
Eric Andersenc470f442003-07-28 09:56:35 +00007472 STARTSTACKSTR(cmdnextc);
7473 cmdtxt(n);
7474 name = stackblock();
7475 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7476 name, cmdnextc, cmdnextc));
7477 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007478}
7479
Eric Andersenc470f442003-07-28 09:56:35 +00007480static void
7481cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007482{
Eric Andersencb57d552001-06-28 07:25:16 +00007483 union node *np;
7484 struct nodelist *lp;
7485 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007486 char s[2];
7487
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007488 if (!n)
7489 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007490 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007491 default:
7492#if DEBUG
7493 abort();
7494#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007495 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007496 lp = n->npipe.cmdlist;
7497 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007498 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007499 lp = lp->next;
7500 if (!lp)
7501 break;
7502 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007503 }
7504 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007505 case NSEMI:
7506 p = "; ";
7507 goto binop;
7508 case NAND:
7509 p = " && ";
7510 goto binop;
7511 case NOR:
7512 p = " || ";
7513binop:
7514 cmdtxt(n->nbinary.ch1);
7515 cmdputs(p);
7516 n = n->nbinary.ch2;
7517 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007518 case NREDIR:
7519 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007520 n = n->nredir.n;
7521 goto donode;
7522 case NNOT:
7523 cmdputs("!");
7524 n = n->nnot.com;
7525donode:
7526 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007527 break;
7528 case NIF:
7529 cmdputs("if ");
7530 cmdtxt(n->nif.test);
7531 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007532 n = n->nif.ifpart;
7533 if (n->nif.elsepart) {
7534 cmdtxt(n);
7535 cmdputs("; else ");
7536 n = n->nif.elsepart;
7537 }
7538 p = "; fi";
7539 goto dotail;
7540 case NSUBSHELL:
7541 cmdputs("(");
7542 n = n->nredir.n;
7543 p = ")";
7544 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007545 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007546 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007547 goto until;
7548 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007549 p = "until ";
7550until:
7551 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007552 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007553 n = n->nbinary.ch2;
7554 p = "; done";
7555dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007556 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007557dotail:
7558 cmdtxt(n);
7559 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007560 case NFOR:
7561 cmdputs("for ");
7562 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007563 cmdputs(" in ");
7564 cmdlist(n->nfor.args, 1);
7565 n = n->nfor.body;
7566 p = "; done";
7567 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007568 case NDEFUN:
7569 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007570 p = "() { ... }";
7571 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007572 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007573 cmdlist(n->ncmd.args, 1);
7574 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007575 break;
7576 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007577 p = n->narg.text;
7578dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007579 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007580 break;
7581 case NHERE:
7582 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007583 p = "<<...";
7584 goto dotail2;
7585 case NCASE:
7586 cmdputs("case ");
7587 cmdputs(n->ncase.expr->narg.text);
7588 cmdputs(" in ");
7589 for (np = n->ncase.cases; np; np = np->nclist.next) {
7590 cmdtxt(np->nclist.pattern);
7591 cmdputs(") ");
7592 cmdtxt(np->nclist.body);
7593 cmdputs(";; ");
7594 }
7595 p = "esac";
7596 goto dotail2;
7597 case NTO:
7598 p = ">";
7599 goto redir;
7600 case NCLOBBER:
7601 p = ">|";
7602 goto redir;
7603 case NAPPEND:
7604 p = ">>";
7605 goto redir;
7606 case NTOFD:
7607 p = ">&";
7608 goto redir;
7609 case NFROM:
7610 p = "<";
7611 goto redir;
7612 case NFROMFD:
7613 p = "<&";
7614 goto redir;
7615 case NFROMTO:
7616 p = "<>";
7617redir:
7618 s[0] = n->nfile.fd + '0';
7619 s[1] = '\0';
7620 cmdputs(s);
7621 cmdputs(p);
7622 if (n->type == NTOFD || n->type == NFROMFD) {
7623 s[0] = n->ndup.dupfd + '0';
7624 p = s;
7625 goto dotail2;
7626 } else {
7627 n = n->nfile.fname;
7628 goto donode;
7629 }
Eric Andersencb57d552001-06-28 07:25:16 +00007630 }
7631}
Eric Andersencb57d552001-06-28 07:25:16 +00007632
Eric Andersenc470f442003-07-28 09:56:35 +00007633static void
7634cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007635{
Eric Andersenc470f442003-07-28 09:56:35 +00007636 for (; np; np = np->narg.next) {
7637 if (!sep)
7638 cmdputs(spcstr);
7639 cmdtxt(np);
7640 if (sep && np->narg.next)
7641 cmdputs(spcstr);
7642 }
Eric Andersencb57d552001-06-28 07:25:16 +00007643}
7644
Eric Andersenc470f442003-07-28 09:56:35 +00007645static void
7646cmdputs(const char *s)
7647{
7648 const char *p, *str;
7649 char c, cc[2] = " ";
7650 char *nextc;
7651 int subtype = 0;
7652 int quoted = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007653 static const char vstype[VSTYPE + 1][4] = {
7654 "", "}", "-", "+", "?", "=",
7655 "%", "%%", "#", "##"
Eric Andersenc470f442003-07-28 09:56:35 +00007656 };
Eric Andersenc470f442003-07-28 09:56:35 +00007657 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7658 p = s;
7659 while ((c = *p++) != 0) {
7660 str = 0;
7661 switch (c) {
7662 case CTLESC:
7663 c = *p++;
7664 break;
7665 case CTLVAR:
7666 subtype = *p++;
7667 if ((subtype & VSTYPE) == VSLENGTH)
7668 str = "${#";
7669 else
7670 str = "${";
7671 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7672 quoted ^= 1;
7673 c = '"';
7674 } else
7675 goto dostr;
7676 break;
7677 case CTLENDVAR:
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007678 str = "\"}" + !(quoted & 1);
Eric Andersenc470f442003-07-28 09:56:35 +00007679 quoted >>= 1;
7680 subtype = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007681 goto dostr;
Eric Andersenc470f442003-07-28 09:56:35 +00007682 case CTLBACKQ:
7683 str = "$(...)";
7684 goto dostr;
7685 case CTLBACKQ+CTLQUOTE:
7686 str = "\"$(...)\"";
7687 goto dostr;
7688#ifdef CONFIG_ASH_MATH_SUPPORT
7689 case CTLARI:
7690 str = "$((";
7691 goto dostr;
7692 case CTLENDARI:
7693 str = "))";
7694 goto dostr;
7695#endif
7696 case CTLQUOTEMARK:
7697 quoted ^= 1;
7698 c = '"';
7699 break;
7700 case '=':
7701 if (subtype == 0)
7702 break;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007703 if ((subtype & VSTYPE) != VSNORMAL)
7704 quoted <<= 1;
Eric Andersenc470f442003-07-28 09:56:35 +00007705 str = vstype[subtype & VSTYPE];
7706 if (subtype & VSNUL)
7707 c = ':';
7708 else
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007709 goto checkstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007710 break;
7711 case '\'':
7712 case '\\':
7713 case '"':
7714 case '$':
7715 /* These can only happen inside quotes */
7716 cc[0] = c;
7717 str = cc;
7718 c = '\\';
7719 break;
7720 default:
7721 break;
7722 }
7723 USTPUTC(c, nextc);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007724checkstr:
Eric Andersenc470f442003-07-28 09:56:35 +00007725 if (!str)
7726 continue;
7727dostr:
7728 while ((c = *str++)) {
7729 USTPUTC(c, nextc);
7730 }
7731 }
7732 if (quoted & 1) {
7733 USTPUTC('"', nextc);
7734 }
7735 *nextc = 0;
7736 cmdnextc = nextc;
7737}
7738
7739
7740static void
7741showpipe(struct job *jp, FILE *out)
7742{
7743 struct procstat *sp;
7744 struct procstat *spend;
7745
7746 spend = jp->ps + jp->nprocs;
7747 for (sp = jp->ps + 1; sp < spend; sp++)
7748 fprintf(out, " | %s", sp->cmd);
7749 outcslow('\n', out);
7750 flushall();
7751}
7752
7753static void
7754xtcsetpgrp(int fd, pid_t pgrp)
7755{
7756 if (tcsetpgrp(fd, pgrp))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007757 sh_error("Cannot set tty process group (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +00007758}
7759#endif /* JOBS */
7760
7761static int
7762getstatus(struct job *job) {
7763 int status;
7764 int retval;
7765
7766 status = job->ps[job->nprocs - 1].status;
7767 retval = WEXITSTATUS(status);
7768 if (!WIFEXITED(status)) {
7769#if JOBS
7770 retval = WSTOPSIG(status);
7771 if (!WIFSTOPPED(status))
7772#endif
7773 {
7774 /* XXX: limits number of signals */
7775 retval = WTERMSIG(status);
7776#if JOBS
7777 if (retval == SIGINT)
7778 job->sigint = 1;
7779#endif
7780 }
7781 retval += 128;
7782 }
7783 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7784 jobno(job), job->nprocs, status, retval));
7785 return retval;
7786}
7787
Eric Andersend35c5df2002-01-09 15:37:36 +00007788#ifdef CONFIG_ASH_MAIL
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007789/* mail.c */
Eric Andersenec074692001-10-31 11:05:49 +00007790
Eric Andersencb57d552001-06-28 07:25:16 +00007791/*
Eric Andersenc470f442003-07-28 09:56:35 +00007792 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007793 */
7794
Eric Andersencb57d552001-06-28 07:25:16 +00007795#define MAXMBOXES 10
7796
Eric Andersenc470f442003-07-28 09:56:35 +00007797/* times of mailboxes */
7798static time_t mailtime[MAXMBOXES];
7799/* Set if MAIL or MAILPATH is changed. */
7800static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007801
7802
7803
7804/*
Eric Andersenc470f442003-07-28 09:56:35 +00007805 * Print appropriate message(s) if mail has arrived.
7806 * If mail_var_path_changed is set,
7807 * then the value of MAIL has mail_var_path_changed,
7808 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007809 */
7810
Eric Andersenc470f442003-07-28 09:56:35 +00007811static void
7812chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007813{
Eric Andersencb57d552001-06-28 07:25:16 +00007814 const char *mpath;
7815 char *p;
7816 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007817 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007818 struct stackmark smark;
7819 struct stat statb;
7820
Eric Andersencb57d552001-06-28 07:25:16 +00007821 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007822 mpath = mpathset() ? mpathval() : mailval();
7823 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007824 p = padvance(&mpath, nullstr);
7825 if (p == NULL)
7826 break;
7827 if (*p == '\0')
7828 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007829 for (q = p ; *q ; q++);
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00007830#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00007831 if (q[-1] != '/')
7832 abort();
7833#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007834 q[-1] = '\0'; /* delete trailing '/' */
7835 if (stat(p, &statb) < 0) {
7836 *mtp = 0;
7837 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007838 }
Eric Andersenc470f442003-07-28 09:56:35 +00007839 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7840 fprintf(
7841 stderr, snlfmt,
7842 pathopt ? pathopt : "you have mail"
7843 );
7844 }
7845 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007846 }
Eric Andersenc470f442003-07-28 09:56:35 +00007847 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007848 popstackmark(&smark);
7849}
Eric Andersencb57d552001-06-28 07:25:16 +00007850
Eric Andersenec074692001-10-31 11:05:49 +00007851
Eric Andersenc470f442003-07-28 09:56:35 +00007852static void
7853changemail(const char *val)
7854{
7855 mail_var_path_changed++;
7856}
7857
7858#endif /* CONFIG_ASH_MAIL */
7859
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007860/* main.c */
Eric Andersenc470f442003-07-28 09:56:35 +00007861
Eric Andersencb57d552001-06-28 07:25:16 +00007862
Eric Andersencb57d552001-06-28 07:25:16 +00007863#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007864static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007865extern int etext();
7866#endif
7867
Eric Andersenc470f442003-07-28 09:56:35 +00007868static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007869
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007870static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007871
Eric Andersencb57d552001-06-28 07:25:16 +00007872/*
7873 * Main routine. We initialize things, parse the arguments, execute
7874 * profiles if we're a login shell, and then call cmdloop to execute
7875 * commands. The setjmp call sets up the location to jump to when an
7876 * exception occurs. When an exception occurs the variable "state"
7877 * is used to figure out how far we had gotten.
7878 */
7879
Eric Andersenc470f442003-07-28 09:56:35 +00007880int
7881ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007882{
Eric Andersenc470f442003-07-28 09:56:35 +00007883 char *shinit;
7884 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007885 struct jmploc jmploc;
7886 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007887
Eric Andersenc470f442003-07-28 09:56:35 +00007888#ifdef __GLIBC__
7889 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007890#endif
7891
Eric Andersencb57d552001-06-28 07:25:16 +00007892#if PROFILE
7893 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7894#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007895 state = 0;
7896 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007897 int e;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007898 int s;
Eric Andersenc470f442003-07-28 09:56:35 +00007899
Eric Andersencb57d552001-06-28 07:25:16 +00007900 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007901
7902 e = exception;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007903 if (e == EXERROR)
7904 exitstatus = 2;
7905 s = state;
7906 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00007907 exitshell();
7908
Eric Andersen90898442003-08-06 11:20:52 +00007909 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007910 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007911 }
7912 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007913 FORCEINTON; /* enable interrupts */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007914 if (s == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00007915 goto state1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007916 else if (s == 2)
Eric Andersencb57d552001-06-28 07:25:16 +00007917 goto state2;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007918 else if (s == 3)
Eric Andersencb57d552001-06-28 07:25:16 +00007919 goto state3;
7920 else
7921 goto state4;
7922 }
7923 handler = &jmploc;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00007924#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00007925 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007926 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007927#endif
7928 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007929
7930#ifdef CONFIG_ASH_RANDOM_SUPPORT
7931 rseed = rootpid + ((time_t)time((time_t *)0));
7932#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007933 init();
7934 setstackmark(&smark);
7935 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007936#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7937 if ( iflag ) {
7938 const char *hp = lookupvar("HISTFILE");
7939
7940 if(hp == NULL ) {
7941 hp = lookupvar("HOME");
7942 if(hp != NULL) {
7943 char *defhp = concat_path_file(hp, ".ash_history");
7944 setvar("HISTFILE", defhp, 0);
7945 free(defhp);
7946 }
7947 }
7948 }
7949#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007950 if (argv[0] && argv[0][0] == '-')
7951 isloginsh = 1;
7952 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007953 state = 1;
7954 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007955state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007956 state = 2;
7957 read_profile(".profile");
7958 }
Eric Andersenc470f442003-07-28 09:56:35 +00007959state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007960 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007961 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007962#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007963 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007964#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007965 iflag
7966 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007967 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007968 read_profile(shinit);
7969 }
Eric Andersencb57d552001-06-28 07:25:16 +00007970 }
Eric Andersenc470f442003-07-28 09:56:35 +00007971state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007972 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007973 if (minusc)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007974 evalstring(minusc, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007975
7976 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007977#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007978 if ( iflag ) {
7979 const char *hp = lookupvar("HISTFILE");
7980
7981 if(hp != NULL )
7982 load_history ( hp );
7983 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007984#endif
Eric Andersen90898442003-08-06 11:20:52 +00007985state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007986 cmdloop(1);
7987 }
7988#if PROFILE
7989 monitor(0);
7990#endif
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00007991#ifdef GPROF
Eric Andersenc470f442003-07-28 09:56:35 +00007992 {
7993 extern void _mcleanup(void);
7994 _mcleanup();
7995 }
7996#endif
7997 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007998 /* NOTREACHED */
7999}
8000
8001
8002/*
8003 * Read and execute commands. "Top" is nonzero for the top level command
8004 * loop; it turns on prompting if the shell is interactive.
8005 */
8006
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008007static int
Eric Andersenc470f442003-07-28 09:56:35 +00008008cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008009{
8010 union node *n;
8011 struct stackmark smark;
8012 int inter;
8013 int numeof = 0;
8014
8015 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008016 for (;;) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008017 int skip;
8018
Glenn L McGrath76620622004-01-13 10:19:37 +00008019 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00008020#if JOBS
8021 if (jobctl)
8022 showjobs(stderr, SHOW_CHANGED);
8023#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008024 inter = 0;
8025 if (iflag && top) {
8026 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008027#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008028 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008029#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008030 }
8031 n = parsecmd(inter);
8032 /* showtree(n); DEBUG */
8033 if (n == NEOF) {
8034 if (!top || numeof >= 50)
8035 break;
8036 if (!stoppedjobs()) {
8037 if (!Iflag)
8038 break;
8039 out2str("\nUse \"exit\" to leave shell.\n");
8040 }
8041 numeof++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008042 } else if (nflag == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008043 job_warning = (job_warning == 2) ? 1 : 0;
8044 numeof = 0;
8045 evaltree(n, 0);
8046 }
8047 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008048 skip = evalskip;
8049
8050 if (skip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008051 evalskip = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008052 return skip & SKIPEVAL;
Eric Andersencb57d552001-06-28 07:25:16 +00008053 }
8054 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008055
8056 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008057}
8058
8059
Eric Andersencb57d552001-06-28 07:25:16 +00008060/*
8061 * Read /etc/profile or .profile. Return on error.
8062 */
8063
Eric Andersenc470f442003-07-28 09:56:35 +00008064static void
8065read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008066{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008067 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008068
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008069 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008070 return;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008071
8072 skip = cmdloop(0);
Eric Andersencb57d552001-06-28 07:25:16 +00008073 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008074
8075 if (skip)
8076 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00008077}
8078
8079
Eric Andersencb57d552001-06-28 07:25:16 +00008080/*
8081 * Read a file containing shell functions.
8082 */
8083
Eric Andersenc470f442003-07-28 09:56:35 +00008084static void
8085readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008086{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008087 setinputfile(name, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008088 cmdloop(0);
8089 popfile();
8090}
8091
8092
Eric Andersencb57d552001-06-28 07:25:16 +00008093/*
Eric Andersenc470f442003-07-28 09:56:35 +00008094 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008095 * search for the file, which is necessary to find sub-commands.
8096 */
8097
Rob Landley88621d72006-08-29 19:41:06 +00008098static char * find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008099{
8100 char *fullname;
8101 const char *path = pathval();
8102 struct stat statb;
8103
8104 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008105 if (strchr(name, '/'))
8106 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008107
Eric Andersenc470f442003-07-28 09:56:35 +00008108 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008109 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8110 /*
8111 * Don't bother freeing here, since it will
8112 * be freed by the caller.
8113 */
8114 return fullname;
8115 }
8116 stunalloc(fullname);
8117 }
8118
8119 /* not found in the PATH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008120 sh_error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008121 /* NOTREACHED */
8122}
8123
Eric Andersen1e6aba92004-04-12 19:12:13 +00008124static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008125{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008126 struct strlist *sp;
8127 volatile struct shparam saveparam;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008128 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008129
Eric Andersen1e6aba92004-04-12 19:12:13 +00008130 for (sp = cmdenviron; sp; sp = sp->next)
Rob Landleyd921b2e2006-08-03 15:41:12 +00008131 setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008132
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00008133 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008134 char *fullname;
Eric Andersencb57d552001-06-28 07:25:16 +00008135
Eric Andersencb57d552001-06-28 07:25:16 +00008136 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008137
8138 if (argc > 2) {
8139 saveparam = shellparam;
8140 shellparam.malloc = 0;
8141 shellparam.nparam = argc - 2;
8142 shellparam.p = argv + 2;
8143 };
8144
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008145 setinputfile(fullname, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008146 commandname = fullname;
8147 cmdloop(0);
8148 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008149
8150 if (argc > 2) {
8151 freeparam(&shellparam);
8152 shellparam = saveparam;
8153 };
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008154 status = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00008155 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008156 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008157}
8158
8159
Eric Andersenc470f442003-07-28 09:56:35 +00008160static int
8161exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008162{
8163 if (stoppedjobs())
8164 return 0;
8165 if (argc > 1)
8166 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008167 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008168 /* NOTREACHED */
8169}
Eric Andersen62483552001-07-10 06:09:16 +00008170
Paul Fox0b621582005-08-09 19:38:05 +00008171#ifdef CONFIG_ASH_BUILTIN_ECHO
8172static int
8173echocmd(int argc, char **argv)
8174{
8175 return bb_echo(argc, argv);
8176}
8177#endif
Paul Fox6ab03782006-06-08 21:37:26 +00008178
8179#ifdef CONFIG_ASH_BUILTIN_TEST
8180static int
8181testcmd(int argc, char **argv)
8182{
8183 return bb_test(argc, argv);
8184}
8185#endif
8186
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008187/* memalloc.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008188
8189/*
Eric Andersen90898442003-08-06 11:20:52 +00008190 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008191 */
8192
8193static pointer
8194ckrealloc(pointer p, size_t nbytes)
8195{
8196 p = realloc(p, nbytes);
8197 if (p == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008198 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008199 return p;
8200}
8201
Eric Andersen90898442003-08-06 11:20:52 +00008202static pointer
8203ckmalloc(size_t nbytes)
8204{
8205 return ckrealloc(NULL, nbytes);
8206}
Eric Andersenc470f442003-07-28 09:56:35 +00008207
8208/*
8209 * Make a copy of a string in safe storage.
8210 */
8211
8212static char *
8213savestr(const char *s)
8214{
8215 char *p = strdup(s);
8216 if (!p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008217 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008218 return p;
8219}
8220
8221
8222/*
8223 * Parse trees for commands are allocated in lifo order, so we use a stack
8224 * to make this more efficient, and also to avoid all sorts of exception
8225 * handling code to handle interrupts in the middle of a parse.
8226 *
8227 * The size 504 was chosen because the Ultrix malloc handles that size
8228 * well.
8229 */
8230
8231
8232static pointer
8233stalloc(size_t nbytes)
8234{
8235 char *p;
8236 size_t aligned;
8237
8238 aligned = SHELL_ALIGN(nbytes);
8239 if (aligned > stacknleft) {
8240 size_t len;
8241 size_t blocksize;
8242 struct stack_block *sp;
8243
8244 blocksize = aligned;
8245 if (blocksize < MINSIZE)
8246 blocksize = MINSIZE;
8247 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8248 if (len < blocksize)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008249 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008250 INTOFF;
8251 sp = ckmalloc(len);
8252 sp->prev = stackp;
8253 stacknxt = sp->space;
8254 stacknleft = blocksize;
8255 sstrend = stacknxt + blocksize;
8256 stackp = sp;
8257 INTON;
8258 }
8259 p = stacknxt;
8260 stacknxt += aligned;
8261 stacknleft -= aligned;
8262 return p;
8263}
8264
8265
8266void
8267stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008268{
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008269#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008270 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008271 write(2, "stunalloc\n", 10);
8272 abort();
8273 }
8274#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008275 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008276 stacknxt = p;
8277}
8278
8279
Eric Andersenc470f442003-07-28 09:56:35 +00008280void
8281setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008282{
Eric Andersencb57d552001-06-28 07:25:16 +00008283 mark->stackp = stackp;
8284 mark->stacknxt = stacknxt;
8285 mark->stacknleft = stacknleft;
8286 mark->marknext = markp;
8287 markp = mark;
8288}
8289
8290
Eric Andersenc470f442003-07-28 09:56:35 +00008291void
8292popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008293{
Eric Andersencb57d552001-06-28 07:25:16 +00008294 struct stack_block *sp;
8295
8296 INTOFF;
8297 markp = mark->marknext;
8298 while (stackp != mark->stackp) {
8299 sp = stackp;
8300 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008301 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008302 }
8303 stacknxt = mark->stacknxt;
8304 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008305 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008306 INTON;
8307}
8308
8309
8310/*
8311 * When the parser reads in a string, it wants to stick the string on the
8312 * stack and only adjust the stack pointer when it knows how big the
8313 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8314 * of space on top of the stack and stackblocklen returns the length of
8315 * this block. Growstackblock will grow this space by at least one byte,
8316 * possibly moving it (like realloc). Grabstackblock actually allocates the
8317 * part of the block that has been used.
8318 */
8319
Eric Andersenc470f442003-07-28 09:56:35 +00008320void
8321growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008322{
Eric Andersenc470f442003-07-28 09:56:35 +00008323 size_t newlen;
8324
8325 newlen = stacknleft * 2;
8326 if (newlen < stacknleft)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008327 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008328 if (newlen < 128)
8329 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008330
8331 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008332 struct stack_block *oldstackp;
8333 struct stackmark *xmark;
8334 struct stack_block *sp;
8335 struct stack_block *prevstackp;
8336 size_t grosslen;
8337
Eric Andersencb57d552001-06-28 07:25:16 +00008338 INTOFF;
8339 oldstackp = stackp;
8340 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008341 prevstackp = sp->prev;
8342 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8343 sp = ckrealloc((pointer)sp, grosslen);
8344 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008345 stackp = sp;
8346 stacknxt = sp->space;
8347 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008348 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008349
Eric Andersenc470f442003-07-28 09:56:35 +00008350 /*
8351 * Stack marks pointing to the start of the old block
8352 * must be relocated to point to the new block
8353 */
8354 xmark = markp;
8355 while (xmark != NULL && xmark->stackp == oldstackp) {
8356 xmark->stackp = stackp;
8357 xmark->stacknxt = stacknxt;
8358 xmark->stacknleft = stacknleft;
8359 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008360 }
8361 INTON;
8362 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008363 char *oldspace = stacknxt;
8364 int oldlen = stacknleft;
8365 char *p = stalloc(newlen);
8366
8367 /* free the space we just allocated */
8368 stacknxt = memcpy(p, oldspace, oldlen);
8369 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008370 }
8371}
8372
Rob Landley88621d72006-08-29 19:41:06 +00008373static void grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008374{
Eric Andersenc470f442003-07-28 09:56:35 +00008375 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008376 stacknxt += len;
8377 stacknleft -= len;
8378}
8379
Eric Andersencb57d552001-06-28 07:25:16 +00008380/*
Eric Andersenc470f442003-07-28 09:56:35 +00008381 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008382 * The user declares a variable of type STACKSTR, which may be declared
8383 * to be a register. The macro STARTSTACKSTR initializes things. Then
8384 * the user uses the macro STPUTC to add characters to the string. In
8385 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8386 * grown as necessary. When the user is done, she can just leave the
8387 * string there and refer to it using stackblock(). Or she can allocate
8388 * the space for it using grabstackstr(). If it is necessary to allow
8389 * someone else to use the stack temporarily and then continue to grow
8390 * the string, the user should use grabstack to allocate the space, and
8391 * then call ungrabstr(p) to return to the previous mode of operation.
8392 *
8393 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8394 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8395 * is space for at least one character.
8396 */
8397
Eric Andersenc470f442003-07-28 09:56:35 +00008398void *
8399growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008400{
Eric Andersenc470f442003-07-28 09:56:35 +00008401 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008402 if (herefd >= 0 && len >= 1024) {
Rob Landley53437472006-07-16 08:14:35 +00008403 full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008404 return stackblock();
8405 }
8406 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008407 return stackblock() + len;
8408}
8409
Eric Andersencb57d552001-06-28 07:25:16 +00008410/*
8411 * Called from CHECKSTRSPACE.
8412 */
8413
Eric Andersenc470f442003-07-28 09:56:35 +00008414char *
8415makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008416{
Eric Andersenc470f442003-07-28 09:56:35 +00008417 size_t len = p - stacknxt;
8418 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008419
Eric Andersenc470f442003-07-28 09:56:35 +00008420 for (;;) {
8421 size_t nleft;
8422
8423 size = stackblocksize();
8424 nleft = size - len;
8425 if (nleft >= newlen)
8426 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008427 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008428 }
Eric Andersencb57d552001-06-28 07:25:16 +00008429 return stackblock() + len;
8430}
8431
Eric Andersenc470f442003-07-28 09:56:35 +00008432char *
8433stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008434{
Eric Andersenc470f442003-07-28 09:56:35 +00008435 p = makestrspace(n, p);
8436 p = mempcpy(p, s, n);
8437 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008438}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008439
Eric Andersenc470f442003-07-28 09:56:35 +00008440char *
8441stputs(const char *s, char *p)
8442{
8443 return stnputs(s, strlen(s), p);
8444}
8445
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008446/* mystring.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008447
Eric Andersencb57d552001-06-28 07:25:16 +00008448/*
Eric Andersenc470f442003-07-28 09:56:35 +00008449 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008450 *
Eric Andersenc470f442003-07-28 09:56:35 +00008451 * number(s) Convert a string of digits to an integer.
8452 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008453 */
8454
Eric Andersencb57d552001-06-28 07:25:16 +00008455/*
8456 * prefix -- see if pfx is a prefix of string.
8457 */
8458
Eric Andersenc470f442003-07-28 09:56:35 +00008459char *
8460prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008461{
Eric Andersencb57d552001-06-28 07:25:16 +00008462 while (*pfx) {
8463 if (*pfx++ != *string++)
8464 return 0;
8465 }
Eric Andersenc470f442003-07-28 09:56:35 +00008466 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008467}
8468
8469
8470/*
8471 * Convert a string of digits to an integer, printing an error message on
8472 * failure.
8473 */
8474
Eric Andersenc470f442003-07-28 09:56:35 +00008475int
8476number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008477{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008478
Eric Andersenc470f442003-07-28 09:56:35 +00008479 if (! is_number(s))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008480 sh_error(illnum, s);
Eric Andersenc470f442003-07-28 09:56:35 +00008481 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008482}
8483
Eric Andersenc470f442003-07-28 09:56:35 +00008484
Eric Andersenc470f442003-07-28 09:56:35 +00008485/*
8486 * Check for a valid number. This should be elsewhere.
8487 */
8488
8489int
8490is_number(const char *p)
8491{
8492 do {
8493 if (! is_digit(*p))
8494 return 0;
8495 } while (*++p != '\0');
8496 return 1;
8497}
8498
8499
Eric Andersencb57d552001-06-28 07:25:16 +00008500/*
8501 * Produce a possibly single quoted string suitable as input to the shell.
8502 * The return string is allocated on the stack.
8503 */
8504
Eric Andersenc470f442003-07-28 09:56:35 +00008505char *
8506single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008507 char *p;
8508
8509 STARTSTACKSTR(p);
8510
8511 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008512 char *q;
8513 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008514
Eric Andersenc470f442003-07-28 09:56:35 +00008515 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008516
Eric Andersenc470f442003-07-28 09:56:35 +00008517 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008518
Eric Andersenc470f442003-07-28 09:56:35 +00008519 *q++ = '\'';
8520 q = mempcpy(q, s, len);
8521 *q++ = '\'';
8522 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008523
Eric Andersenc470f442003-07-28 09:56:35 +00008524 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008525
Eric Andersenc470f442003-07-28 09:56:35 +00008526 len = strspn(s, "'");
8527 if (!len)
8528 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008529
Eric Andersenc470f442003-07-28 09:56:35 +00008530 q = p = makestrspace(len + 3, p);
8531
8532 *q++ = '"';
8533 q = mempcpy(q, s, len);
8534 *q++ = '"';
8535 s += len;
8536
8537 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008538 } while (*s);
8539
8540 USTPUTC(0, p);
8541
Eric Andersenc470f442003-07-28 09:56:35 +00008542 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008543}
8544
8545/*
Eric Andersenc470f442003-07-28 09:56:35 +00008546 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008547 */
8548
Eric Andersenc470f442003-07-28 09:56:35 +00008549char *
8550sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008551{
Eric Andersenc470f442003-07-28 09:56:35 +00008552 size_t len = strlen(p) + 1;
8553 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008554}
Eric Andersenc470f442003-07-28 09:56:35 +00008555
8556
8557static void
8558calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008559{
Eric Andersenc470f442003-07-28 09:56:35 +00008560 if (n == NULL)
8561 return;
8562 funcblocksize += nodesize[n->type];
8563 switch (n->type) {
8564 case NCMD:
8565 calcsize(n->ncmd.redirect);
8566 calcsize(n->ncmd.args);
8567 calcsize(n->ncmd.assign);
8568 break;
8569 case NPIPE:
8570 sizenodelist(n->npipe.cmdlist);
8571 break;
8572 case NREDIR:
8573 case NBACKGND:
8574 case NSUBSHELL:
8575 calcsize(n->nredir.redirect);
8576 calcsize(n->nredir.n);
8577 break;
8578 case NAND:
8579 case NOR:
8580 case NSEMI:
8581 case NWHILE:
8582 case NUNTIL:
8583 calcsize(n->nbinary.ch2);
8584 calcsize(n->nbinary.ch1);
8585 break;
8586 case NIF:
8587 calcsize(n->nif.elsepart);
8588 calcsize(n->nif.ifpart);
8589 calcsize(n->nif.test);
8590 break;
8591 case NFOR:
8592 funcstringsize += strlen(n->nfor.var) + 1;
8593 calcsize(n->nfor.body);
8594 calcsize(n->nfor.args);
8595 break;
8596 case NCASE:
8597 calcsize(n->ncase.cases);
8598 calcsize(n->ncase.expr);
8599 break;
8600 case NCLIST:
8601 calcsize(n->nclist.body);
8602 calcsize(n->nclist.pattern);
8603 calcsize(n->nclist.next);
8604 break;
8605 case NDEFUN:
8606 case NARG:
8607 sizenodelist(n->narg.backquote);
8608 funcstringsize += strlen(n->narg.text) + 1;
8609 calcsize(n->narg.next);
8610 break;
8611 case NTO:
8612 case NCLOBBER:
8613 case NFROM:
8614 case NFROMTO:
8615 case NAPPEND:
8616 calcsize(n->nfile.fname);
8617 calcsize(n->nfile.next);
8618 break;
8619 case NTOFD:
8620 case NFROMFD:
8621 calcsize(n->ndup.vname);
8622 calcsize(n->ndup.next);
8623 break;
8624 case NHERE:
8625 case NXHERE:
8626 calcsize(n->nhere.doc);
8627 calcsize(n->nhere.next);
8628 break;
8629 case NNOT:
8630 calcsize(n->nnot.com);
8631 break;
8632 };
Eric Andersencb57d552001-06-28 07:25:16 +00008633}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008634
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008635
Eric Andersenc470f442003-07-28 09:56:35 +00008636static void
8637sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008638{
8639 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008640 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008641 calcsize(lp->n);
8642 lp = lp->next;
8643 }
8644}
Eric Andersencb57d552001-06-28 07:25:16 +00008645
8646
Eric Andersenc470f442003-07-28 09:56:35 +00008647static union node *
8648copynode(union node *n)
8649{
8650 union node *new;
8651
8652 if (n == NULL)
8653 return NULL;
8654 new = funcblock;
8655 funcblock = (char *) funcblock + nodesize[n->type];
8656 switch (n->type) {
8657 case NCMD:
8658 new->ncmd.redirect = copynode(n->ncmd.redirect);
8659 new->ncmd.args = copynode(n->ncmd.args);
8660 new->ncmd.assign = copynode(n->ncmd.assign);
8661 break;
8662 case NPIPE:
8663 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8664 new->npipe.backgnd = n->npipe.backgnd;
8665 break;
8666 case NREDIR:
8667 case NBACKGND:
8668 case NSUBSHELL:
8669 new->nredir.redirect = copynode(n->nredir.redirect);
8670 new->nredir.n = copynode(n->nredir.n);
8671 break;
8672 case NAND:
8673 case NOR:
8674 case NSEMI:
8675 case NWHILE:
8676 case NUNTIL:
8677 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8678 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8679 break;
8680 case NIF:
8681 new->nif.elsepart = copynode(n->nif.elsepart);
8682 new->nif.ifpart = copynode(n->nif.ifpart);
8683 new->nif.test = copynode(n->nif.test);
8684 break;
8685 case NFOR:
8686 new->nfor.var = nodesavestr(n->nfor.var);
8687 new->nfor.body = copynode(n->nfor.body);
8688 new->nfor.args = copynode(n->nfor.args);
8689 break;
8690 case NCASE:
8691 new->ncase.cases = copynode(n->ncase.cases);
8692 new->ncase.expr = copynode(n->ncase.expr);
8693 break;
8694 case NCLIST:
8695 new->nclist.body = copynode(n->nclist.body);
8696 new->nclist.pattern = copynode(n->nclist.pattern);
8697 new->nclist.next = copynode(n->nclist.next);
8698 break;
8699 case NDEFUN:
8700 case NARG:
8701 new->narg.backquote = copynodelist(n->narg.backquote);
8702 new->narg.text = nodesavestr(n->narg.text);
8703 new->narg.next = copynode(n->narg.next);
8704 break;
8705 case NTO:
8706 case NCLOBBER:
8707 case NFROM:
8708 case NFROMTO:
8709 case NAPPEND:
8710 new->nfile.fname = copynode(n->nfile.fname);
8711 new->nfile.fd = n->nfile.fd;
8712 new->nfile.next = copynode(n->nfile.next);
8713 break;
8714 case NTOFD:
8715 case NFROMFD:
8716 new->ndup.vname = copynode(n->ndup.vname);
8717 new->ndup.dupfd = n->ndup.dupfd;
8718 new->ndup.fd = n->ndup.fd;
8719 new->ndup.next = copynode(n->ndup.next);
8720 break;
8721 case NHERE:
8722 case NXHERE:
8723 new->nhere.doc = copynode(n->nhere.doc);
8724 new->nhere.fd = n->nhere.fd;
8725 new->nhere.next = copynode(n->nhere.next);
8726 break;
8727 case NNOT:
8728 new->nnot.com = copynode(n->nnot.com);
8729 break;
8730 };
8731 new->type = n->type;
8732 return new;
8733}
8734
8735
8736static struct nodelist *
8737copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008738{
8739 struct nodelist *start;
8740 struct nodelist **lpp;
8741
8742 lpp = &start;
8743 while (lp) {
8744 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008745 funcblock = (char *) funcblock +
8746 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008747 (*lpp)->n = copynode(lp->n);
8748 lp = lp->next;
8749 lpp = &(*lpp)->next;
8750 }
8751 *lpp = NULL;
8752 return start;
8753}
8754
8755
Eric Andersenc470f442003-07-28 09:56:35 +00008756static char *
8757nodesavestr(char *s)
8758{
8759 char *rtn = funcstring;
8760
8761 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008762 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008763}
8764
Eric Andersenc470f442003-07-28 09:56:35 +00008765
Eric Andersenc470f442003-07-28 09:56:35 +00008766/*
8767 * Free a parse tree.
8768 */
8769
8770static void
8771freefunc(struct funcnode *f)
8772{
8773 if (f && --f->count < 0)
8774 ckfree(f);
8775}
8776
8777
8778static void options(int);
8779static void setoption(int, int);
8780
Eric Andersencb57d552001-06-28 07:25:16 +00008781
Eric Andersencb57d552001-06-28 07:25:16 +00008782/*
8783 * Process the shell command line arguments.
8784 */
8785
Eric Andersenc470f442003-07-28 09:56:35 +00008786void
8787procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008788{
8789 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008790 const char *xminusc;
8791 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008792
Eric Andersenc470f442003-07-28 09:56:35 +00008793 xargv = argv;
8794 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008795 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008796 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008797 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008798 optlist[i] = 2;
8799 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008800 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008801 xargv = argptr;
8802 xminusc = minusc;
8803 if (*xargv == NULL) {
8804 if (xminusc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +00008805 sh_error(bb_msg_requires_arg, "-c");
Eric Andersencb57d552001-06-28 07:25:16 +00008806 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008807 }
Eric Andersencb57d552001-06-28 07:25:16 +00008808 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8809 iflag = 1;
8810 if (mflag == 2)
8811 mflag = iflag;
8812 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008813 if (optlist[i] == 2)
8814 optlist[i] = 0;
8815#if DEBUG == 2
8816 debug = 1;
8817#endif
8818 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8819 if (xminusc) {
8820 minusc = *xargv++;
8821 if (*xargv)
8822 goto setarg0;
8823 } else if (!sflag) {
8824 setinputfile(*xargv, 0);
8825setarg0:
8826 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008827 commandname = arg0;
8828 }
Eric Andersencb57d552001-06-28 07:25:16 +00008829
Eric Andersenc470f442003-07-28 09:56:35 +00008830 shellparam.p = xargv;
8831#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008832 shellparam.optind = 1;
8833 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008834#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008835 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008836 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008837 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008838 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008839 }
8840 optschanged();
8841}
8842
8843
Eric Andersenc470f442003-07-28 09:56:35 +00008844void
8845optschanged(void)
8846{
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008847#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008848 opentrace();
8849#endif
8850 setinteractive(iflag);
8851 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008852 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008853}
Eric Andersencb57d552001-06-28 07:25:16 +00008854
Rob Landley88621d72006-08-29 19:41:06 +00008855static void minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008856{
8857 int i;
8858
8859 if (name == NULL) {
8860 out1str("Current option settings\n");
8861 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008862 out1fmt("%-16s%s\n", optnames(i),
8863 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008864 } else {
8865 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008866 if (equal(name, optnames(i))) {
8867 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008868 return;
8869 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008870 sh_error("Illegal option -o %s", name);
Eric Andersen62483552001-07-10 06:09:16 +00008871 }
8872}
8873
Eric Andersenc470f442003-07-28 09:56:35 +00008874/*
8875 * Process shell options. The global variable argptr contains a pointer
8876 * to the argument list; we advance it past the options.
8877 */
Eric Andersen62483552001-07-10 06:09:16 +00008878
Eric Andersenc470f442003-07-28 09:56:35 +00008879static void
8880options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008881{
8882 char *p;
8883 int val;
8884 int c;
8885
8886 if (cmdline)
8887 minusc = NULL;
8888 while ((p = *argptr) != NULL) {
8889 argptr++;
8890 if ((c = *p++) == '-') {
8891 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008892 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8893 if (!cmdline) {
8894 /* "-" means turn off -x and -v */
8895 if (p[0] == '\0')
8896 xflag = vflag = 0;
8897 /* "--" means reset params */
8898 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008899 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008900 }
Eric Andersenc470f442003-07-28 09:56:35 +00008901 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008902 }
8903 } else if (c == '+') {
8904 val = 0;
8905 } else {
8906 argptr--;
8907 break;
8908 }
8909 while ((c = *p++) != '\0') {
8910 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008911 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008912 } else if (c == 'o') {
8913 minus_o(*argptr, val);
8914 if (*argptr)
8915 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008916 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008917 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008918 isloginsh = 1;
8919 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008920 } else {
8921 setoption(c, val);
8922 }
8923 }
8924 }
8925}
8926
Eric Andersencb57d552001-06-28 07:25:16 +00008927
Eric Andersenc470f442003-07-28 09:56:35 +00008928static void
8929setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008930{
Eric Andersencb57d552001-06-28 07:25:16 +00008931 int i;
8932
8933 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008934 if (optletters(i) == flag) {
8935 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008936 return;
8937 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008938 sh_error("Illegal option -%c", flag);
Eric Andersencb57d552001-06-28 07:25:16 +00008939 /* NOTREACHED */
8940}
8941
8942
8943
Eric Andersencb57d552001-06-28 07:25:16 +00008944/*
8945 * Set the shell parameters.
8946 */
8947
Eric Andersenc470f442003-07-28 09:56:35 +00008948void
8949setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008950{
Eric Andersencb57d552001-06-28 07:25:16 +00008951 char **newparam;
8952 char **ap;
8953 int nparam;
8954
Eric Andersenc470f442003-07-28 09:56:35 +00008955 for (nparam = 0 ; argv[nparam] ; nparam++);
8956 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008957 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008958 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008959 }
8960 *ap = NULL;
8961 freeparam(&shellparam);
8962 shellparam.malloc = 1;
8963 shellparam.nparam = nparam;
8964 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008965#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008966 shellparam.optind = 1;
8967 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008968#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008969}
8970
8971
8972/*
8973 * Free the list of positional parameters.
8974 */
8975
Eric Andersenc470f442003-07-28 09:56:35 +00008976void
8977freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008978{
Eric Andersencb57d552001-06-28 07:25:16 +00008979 char **ap;
8980
8981 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008982 for (ap = param->p ; *ap ; ap++)
8983 ckfree(*ap);
8984 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008985 }
8986}
8987
8988
8989
8990/*
8991 * The shift builtin command.
8992 */
8993
Eric Andersenc470f442003-07-28 09:56:35 +00008994int
8995shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008996{
8997 int n;
8998 char **ap1, **ap2;
8999
9000 n = 1;
9001 if (argc > 1)
9002 n = number(argv[1]);
9003 if (n > shellparam.nparam)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009004 sh_error("can't shift that many");
Eric Andersencb57d552001-06-28 07:25:16 +00009005 INTOFF;
9006 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009007 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009008 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009009 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009010 }
9011 ap2 = shellparam.p;
9012 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009013#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009014 shellparam.optind = 1;
9015 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009016#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009017 INTON;
9018 return 0;
9019}
9020
9021
9022
9023/*
9024 * The set command builtin.
9025 */
9026
Eric Andersenc470f442003-07-28 09:56:35 +00009027int
9028setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009029{
9030 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009031 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009032 INTOFF;
9033 options(0);
9034 optschanged();
9035 if (*argptr != NULL) {
9036 setparam(argptr);
9037 }
9038 INTON;
9039 return 0;
9040}
9041
9042
Eric Andersenc470f442003-07-28 09:56:35 +00009043#ifdef CONFIG_ASH_GETOPTS
9044static void
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00009045getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009046{
9047 shellparam.optind = number(value);
9048 shellparam.optoff = -1;
9049}
Eric Andersenc470f442003-07-28 09:56:35 +00009050#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009051
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009052#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009053static void change_lc_all(const char *value)
9054{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009055 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009056 setlocale(LC_ALL, value);
9057}
9058
9059static void change_lc_ctype(const char *value)
9060{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009061 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009062 setlocale(LC_CTYPE, value);
9063}
9064
9065#endif
9066
Eric Andersen16767e22004-03-16 05:14:10 +00009067#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009068/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009069static void change_random(const char *value)
9070{
Eric Andersen16767e22004-03-16 05:14:10 +00009071 if(value == NULL) {
9072 /* "get", generate */
9073 char buf[16];
9074
9075 rseed = rseed * 1103515245 + 12345;
9076 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9077 /* set without recursion */
9078 setvar(vrandom.text, buf, VNOFUNC);
9079 vrandom.flags &= ~VNOFUNC;
9080 } else {
9081 /* set/reset */
9082 rseed = strtoul(value, (char **)NULL, 10);
9083 }
Eric Andersenef02f822004-03-11 13:34:24 +00009084}
Eric Andersen16767e22004-03-16 05:14:10 +00009085#endif
9086
Eric Andersenef02f822004-03-11 13:34:24 +00009087
Eric Andersend35c5df2002-01-09 15:37:36 +00009088#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009089static int
Eric Andersenc470f442003-07-28 09:56:35 +00009090getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009091{
9092 char *p, *q;
9093 char c = '?';
9094 int done = 0;
9095 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009096 char s[12];
9097 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009098
Eric Andersena48b0a32003-10-22 10:56:47 +00009099 if(*param_optind < 1)
9100 return 1;
9101 optnext = optfirst + *param_optind - 1;
9102
9103 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009104 p = NULL;
9105 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009106 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009107 if (p == NULL || *p == '\0') {
9108 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009109 p = *optnext;
9110 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009111atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009112 p = NULL;
9113 done = 1;
9114 goto out;
9115 }
9116 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009117 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009118 goto atend;
9119 }
9120
9121 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009122 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009123 if (*q == '\0') {
9124 if (optstr[0] == ':') {
9125 s[0] = c;
9126 s[1] = '\0';
9127 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009128 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009129 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009130 (void) unsetvar("OPTARG");
9131 }
9132 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009133 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009134 }
9135 if (*++q == ':')
9136 q++;
9137 }
9138
9139 if (*++q == ':') {
9140 if (*p == '\0' && (p = *optnext) == NULL) {
9141 if (optstr[0] == ':') {
9142 s[0] = c;
9143 s[1] = '\0';
9144 err |= setvarsafe("OPTARG", s, 0);
9145 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009146 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009147 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009148 (void) unsetvar("OPTARG");
9149 c = '?';
9150 }
Eric Andersenc470f442003-07-28 09:56:35 +00009151 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009152 }
9153
9154 if (p == *optnext)
9155 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009156 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009157 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009158 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009159 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009160
Eric Andersenc470f442003-07-28 09:56:35 +00009161out:
Eric Andersencb57d552001-06-28 07:25:16 +00009162 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009163 *param_optind = optnext - optfirst + 1;
9164 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009165 err |= setvarsafe("OPTIND", s, VNOFUNC);
9166 s[0] = c;
9167 s[1] = '\0';
9168 err |= setvarsafe(optvar, s, 0);
9169 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009170 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009171 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009172 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009173 exraise(EXERROR);
9174 }
9175 return done;
9176}
Eric Andersenc470f442003-07-28 09:56:35 +00009177
9178/*
9179 * The getopts builtin. Shellparam.optnext points to the next argument
9180 * to be processed. Shellparam.optptr points to the next character to
9181 * be processed in the current argument. If shellparam.optnext is NULL,
9182 * then it's the first time getopts has been called.
9183 */
9184
9185int
9186getoptscmd(int argc, char **argv)
9187{
9188 char **optbase;
9189
9190 if (argc < 3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009191 sh_error("Usage: getopts optstring var [arg]");
Eric Andersenc470f442003-07-28 09:56:35 +00009192 else if (argc == 3) {
9193 optbase = shellparam.p;
9194 if (shellparam.optind > shellparam.nparam + 1) {
9195 shellparam.optind = 1;
9196 shellparam.optoff = -1;
9197 }
9198 }
9199 else {
9200 optbase = &argv[3];
9201 if (shellparam.optind > argc - 2) {
9202 shellparam.optind = 1;
9203 shellparam.optoff = -1;
9204 }
9205 }
9206
9207 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9208 &shellparam.optoff);
9209}
9210#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009211
9212/*
9213 * XXX - should get rid of. have all builtins use getopt(3). the
9214 * library getopt must have the BSD extension static variable "optreset"
9215 * otherwise it can't be used within the shell safely.
9216 *
9217 * Standard option processing (a la getopt) for builtin routines. The
9218 * only argument that is passed to nextopt is the option string; the
9219 * other arguments are unnecessary. It return the character, or '\0' on
9220 * end of input.
9221 */
9222
Eric Andersenc470f442003-07-28 09:56:35 +00009223static int
9224nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009225{
Eric Andersencb57d552001-06-28 07:25:16 +00009226 char *p;
9227 const char *q;
9228 char c;
9229
9230 if ((p = optptr) == NULL || *p == '\0') {
9231 p = *argptr;
9232 if (p == NULL || *p != '-' || *++p == '\0')
9233 return '\0';
9234 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009235 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009236 return '\0';
9237 }
9238 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009239 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009240 if (*q == '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009241 sh_error("Illegal option -%c", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009242 if (*++q == ':')
9243 q++;
9244 }
9245 if (*++q == ':') {
9246 if (*p == '\0' && (p = *argptr++) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009247 sh_error("No arg for -%c option", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009248 optionarg = p;
9249 p = NULL;
9250 }
9251 optptr = p;
9252 return c;
9253}
9254
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009255
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009256/* output.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009257
Eric Andersenc470f442003-07-28 09:56:35 +00009258void
9259outstr(const char *p, FILE *file)
9260{
9261 INTOFF;
9262 fputs(p, file);
9263 INTON;
9264}
9265
9266void
9267flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009268{
Eric Andersencb57d552001-06-28 07:25:16 +00009269 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009270 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009271 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009272 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009273}
9274
Eric Andersenc470f442003-07-28 09:56:35 +00009275void
Eric Andersen16767e22004-03-16 05:14:10 +00009276flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009277{
9278 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009279 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009280 INTON;
9281}
9282
9283static void
9284outcslow(int c, FILE *dest)
9285{
9286 INTOFF;
9287 putc(c, dest);
9288 fflush(dest);
9289 INTON;
9290}
9291
9292
9293static int
9294out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009295{
9296 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009297 int r;
9298
9299 INTOFF;
9300 va_start(ap, fmt);
9301 r = vprintf(fmt, ap);
9302 va_end(ap);
9303 INTON;
9304 return r;
9305}
9306
9307
9308int
9309fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9310{
9311 va_list ap;
9312 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009313
Eric Andersencb57d552001-06-28 07:25:16 +00009314 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009315 INTOFF;
9316 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009317 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009318 INTON;
9319 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009320}
9321
Eric Andersenc470f442003-07-28 09:56:35 +00009322
Eric Andersencb57d552001-06-28 07:25:16 +00009323
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009324/* parser.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009325
9326
Eric Andersencb57d552001-06-28 07:25:16 +00009327/*
9328 * Shell command parser.
9329 */
9330
9331#define EOFMARKLEN 79
9332
9333
Eric Andersencb57d552001-06-28 07:25:16 +00009334struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009335 struct heredoc *next; /* next here document in list */
9336 union node *here; /* redirection node */
9337 char *eofmark; /* string indicating end of input */
9338 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009339};
9340
9341
9342
Eric Andersenc470f442003-07-28 09:56:35 +00009343static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009344
9345
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009346static union node *list(int);
9347static union node *andor(void);
9348static union node *pipeline(void);
9349static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009350static union node *simplecmd(void);
9351static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009352static void parsefname(void);
9353static void parseheredoc(void);
9354static char peektoken(void);
9355static int readtoken(void);
9356static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009357static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009358static int noexpand(char *);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00009359static void synexpect(int) ATTRIBUTE_NORETURN;
9360static void synerror(const char *) ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009361static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009362
9363
Eric Andersenc470f442003-07-28 09:56:35 +00009364
Eric Andersenc470f442003-07-28 09:56:35 +00009365
Eric Andersencb57d552001-06-28 07:25:16 +00009366/*
9367 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9368 * valid parse tree indicating a blank line.)
9369 */
9370
Eric Andersenc470f442003-07-28 09:56:35 +00009371union node *
9372parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009373{
9374 int t;
9375
9376 tokpushback = 0;
9377 doprompt = interact;
9378 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009379 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009380 needprompt = 0;
9381 t = readtoken();
9382 if (t == TEOF)
9383 return NEOF;
9384 if (t == TNL)
9385 return NULL;
9386 tokpushback++;
9387 return list(1);
9388}
9389
9390
Eric Andersenc470f442003-07-28 09:56:35 +00009391static union node *
9392list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009393{
9394 union node *n1, *n2, *n3;
9395 int tok;
9396
Eric Andersenc470f442003-07-28 09:56:35 +00009397 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9398 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009399 return NULL;
9400 n1 = NULL;
9401 for (;;) {
9402 n2 = andor();
9403 tok = readtoken();
9404 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009405 if (n2->type == NPIPE) {
9406 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009407 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009408 if (n2->type != NREDIR) {
9409 n3 = stalloc(sizeof(struct nredir));
9410 n3->nredir.n = n2;
9411 n3->nredir.redirect = NULL;
9412 n2 = n3;
9413 }
9414 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009415 }
9416 }
9417 if (n1 == NULL) {
9418 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009419 }
9420 else {
9421 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009422 n3->type = NSEMI;
9423 n3->nbinary.ch1 = n1;
9424 n3->nbinary.ch2 = n2;
9425 n1 = n3;
9426 }
9427 switch (tok) {
9428 case TBACKGND:
9429 case TSEMI:
9430 tok = readtoken();
9431 /* fall through */
9432 case TNL:
9433 if (tok == TNL) {
9434 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009435 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009436 return n1;
9437 } else {
9438 tokpushback++;
9439 }
Eric Andersenc470f442003-07-28 09:56:35 +00009440 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009441 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009442 return n1;
9443 break;
9444 case TEOF:
9445 if (heredoclist)
9446 parseheredoc();
9447 else
Eric Andersenc470f442003-07-28 09:56:35 +00009448 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009449 return n1;
9450 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009451 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009452 synexpect(-1);
9453 tokpushback++;
9454 return n1;
9455 }
9456 }
9457}
9458
9459
9460
Eric Andersenc470f442003-07-28 09:56:35 +00009461static union node *
9462andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009463{
Eric Andersencb57d552001-06-28 07:25:16 +00009464 union node *n1, *n2, *n3;
9465 int t;
9466
Eric Andersencb57d552001-06-28 07:25:16 +00009467 n1 = pipeline();
9468 for (;;) {
9469 if ((t = readtoken()) == TAND) {
9470 t = NAND;
9471 } else if (t == TOR) {
9472 t = NOR;
9473 } else {
9474 tokpushback++;
9475 return n1;
9476 }
Eric Andersenc470f442003-07-28 09:56:35 +00009477 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009478 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009479 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009480 n3->type = t;
9481 n3->nbinary.ch1 = n1;
9482 n3->nbinary.ch2 = n2;
9483 n1 = n3;
9484 }
9485}
9486
9487
9488
Eric Andersenc470f442003-07-28 09:56:35 +00009489static union node *
9490pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009491{
Eric Andersencb57d552001-06-28 07:25:16 +00009492 union node *n1, *n2, *pipenode;
9493 struct nodelist *lp, *prev;
9494 int negate;
9495
9496 negate = 0;
9497 TRACE(("pipeline: entered\n"));
9498 if (readtoken() == TNOT) {
9499 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009500 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009501 } else
9502 tokpushback++;
9503 n1 = command();
9504 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009505 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009506 pipenode->type = NPIPE;
9507 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009508 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009509 pipenode->npipe.cmdlist = lp;
9510 lp->n = n1;
9511 do {
9512 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009513 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9514 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009515 lp->n = command();
9516 prev->next = lp;
9517 } while (readtoken() == TPIPE);
9518 lp->next = NULL;
9519 n1 = pipenode;
9520 }
9521 tokpushback++;
9522 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009523 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009524 n2->type = NNOT;
9525 n2->nnot.com = n1;
9526 return n2;
9527 } else
9528 return n1;
9529}
9530
9531
9532
Eric Andersenc470f442003-07-28 09:56:35 +00009533static union node *
9534command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009535{
Eric Andersencb57d552001-06-28 07:25:16 +00009536 union node *n1, *n2;
9537 union node *ap, **app;
9538 union node *cp, **cpp;
9539 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009540 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009541 int t;
9542
9543 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009544 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009545
Eric Andersencb57d552001-06-28 07:25:16 +00009546 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009547 default:
9548 synexpect(-1);
9549 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009550 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009551 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009552 n1->type = NIF;
9553 n1->nif.test = list(0);
9554 if (readtoken() != TTHEN)
9555 synexpect(TTHEN);
9556 n1->nif.ifpart = list(0);
9557 n2 = n1;
9558 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009559 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009560 n2 = n2->nif.elsepart;
9561 n2->type = NIF;
9562 n2->nif.test = list(0);
9563 if (readtoken() != TTHEN)
9564 synexpect(TTHEN);
9565 n2->nif.ifpart = list(0);
9566 }
9567 if (lasttoken == TELSE)
9568 n2->nif.elsepart = list(0);
9569 else {
9570 n2->nif.elsepart = NULL;
9571 tokpushback++;
9572 }
Eric Andersenc470f442003-07-28 09:56:35 +00009573 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009574 break;
9575 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009576 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009577 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009578 n1 = (union node *)stalloc(sizeof (struct nbinary));
9579 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009580 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009581 if ((got=readtoken()) != TDO) {
9582TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009583 synexpect(TDO);
9584 }
9585 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009586 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009587 break;
9588 }
9589 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009590 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009591 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009592 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009593 n1->type = NFOR;
9594 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009595 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009596 if (readtoken() == TIN) {
9597 app = &ap;
9598 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009599 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009600 n2->type = NARG;
9601 n2->narg.text = wordtext;
9602 n2->narg.backquote = backquotelist;
9603 *app = n2;
9604 app = &n2->narg.next;
9605 }
9606 *app = NULL;
9607 n1->nfor.args = ap;
9608 if (lasttoken != TNL && lasttoken != TSEMI)
9609 synexpect(-1);
9610 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009611 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009612 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009613 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009614 n2->narg.backquote = NULL;
9615 n2->narg.next = NULL;
9616 n1->nfor.args = n2;
9617 /*
9618 * Newline or semicolon here is optional (but note
9619 * that the original Bourne shell only allowed NL).
9620 */
9621 if (lasttoken != TNL && lasttoken != TSEMI)
9622 tokpushback++;
9623 }
Eric Andersenc470f442003-07-28 09:56:35 +00009624 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009625 if (readtoken() != TDO)
9626 synexpect(TDO);
9627 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009628 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009629 break;
9630 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009631 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009632 n1->type = NCASE;
9633 if (readtoken() != TWORD)
9634 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009635 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009636 n2->type = NARG;
9637 n2->narg.text = wordtext;
9638 n2->narg.backquote = backquotelist;
9639 n2->narg.next = NULL;
9640 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009641 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009642 } while (readtoken() == TNL);
9643 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009644 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009645 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009646next_case:
9647 checkkwd = CHKNL | CHKKWD;
9648 t = readtoken();
9649 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009650 if (lasttoken == TLP)
9651 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009652 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009653 cp->type = NCLIST;
9654 app = &cp->nclist.pattern;
9655 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009656 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009657 ap->type = NARG;
9658 ap->narg.text = wordtext;
9659 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009660 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009661 break;
9662 app = &ap->narg.next;
9663 readtoken();
9664 }
9665 ap->narg.next = NULL;
9666 if (lasttoken != TRP)
9667 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009668 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009669
Eric Andersenc470f442003-07-28 09:56:35 +00009670 cpp = &cp->nclist.next;
9671
9672 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009673 if ((t = readtoken()) != TESAC) {
9674 if (t != TENDCASE)
9675 synexpect(TENDCASE);
9676 else
Eric Andersenc470f442003-07-28 09:56:35 +00009677 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009678 }
Eric Andersenc470f442003-07-28 09:56:35 +00009679 }
Eric Andersencb57d552001-06-28 07:25:16 +00009680 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009681 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009682 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009683 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009684 n1->type = NSUBSHELL;
9685 n1->nredir.n = list(0);
9686 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009687 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009688 break;
9689 case TBEGIN:
9690 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009691 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009692 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009693 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009694 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009695 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009696 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009697 }
9698
Eric Andersenc470f442003-07-28 09:56:35 +00009699 if (readtoken() != t)
9700 synexpect(t);
9701
9702redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009703 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009704 checkkwd = CHKKWD | CHKALIAS;
9705 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009706 while (readtoken() == TREDIR) {
9707 *rpp = n2 = redirnode;
9708 rpp = &n2->nfile.next;
9709 parsefname();
9710 }
9711 tokpushback++;
9712 *rpp = NULL;
9713 if (redir) {
9714 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009715 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009716 n2->type = NREDIR;
9717 n2->nredir.n = n1;
9718 n1 = n2;
9719 }
9720 n1->nredir.redirect = redir;
9721 }
9722
9723 return n1;
9724}
9725
9726
Eric Andersenc470f442003-07-28 09:56:35 +00009727static union node *
9728simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009729 union node *args, **app;
9730 union node *n = NULL;
9731 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009732 union node **rpp, *redir;
9733 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009734
9735 args = NULL;
9736 app = &args;
9737 vars = NULL;
9738 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009739 redir = NULL;
9740 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009741
Eric Andersenc470f442003-07-28 09:56:35 +00009742 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009743 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009744 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009745 switch (readtoken()) {
9746 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009747 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009748 n->type = NARG;
9749 n->narg.text = wordtext;
9750 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009751 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009752 *vpp = n;
9753 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009754 } else {
9755 *app = n;
9756 app = &n->narg.next;
9757 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009758 }
9759 break;
9760 case TREDIR:
9761 *rpp = n = redirnode;
9762 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009763 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009764 break;
9765 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009766 if (
9767 args && app == &args->narg.next &&
9768 !vars && !redir
9769 ) {
9770 struct builtincmd *bcmd;
9771 const char *name;
9772
Eric Andersencb57d552001-06-28 07:25:16 +00009773 /* We have a function */
9774 if (readtoken() != TRP)
9775 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009776 name = n->narg.text;
9777 if (
9778 !goodname(name) || (
9779 (bcmd = find_builtin(name)) &&
9780 IS_BUILTIN_SPECIAL(bcmd)
9781 )
9782 )
9783 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009784 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009785 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009786 n->narg.next = command();
9787 return n;
9788 }
9789 /* fall through */
9790 default:
9791 tokpushback++;
9792 goto out;
9793 }
9794 }
Eric Andersenc470f442003-07-28 09:56:35 +00009795out:
Eric Andersencb57d552001-06-28 07:25:16 +00009796 *app = NULL;
9797 *vpp = NULL;
9798 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009799 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009800 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009801 n->ncmd.args = args;
9802 n->ncmd.assign = vars;
9803 n->ncmd.redirect = redir;
9804 return n;
9805}
9806
Eric Andersenc470f442003-07-28 09:56:35 +00009807static union node *
9808makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009809{
Eric Andersencb57d552001-06-28 07:25:16 +00009810 union node *n;
9811
Eric Andersenc470f442003-07-28 09:56:35 +00009812 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009813 n->type = NARG;
9814 n->narg.next = NULL;
9815 n->narg.text = wordtext;
9816 n->narg.backquote = backquotelist;
9817 return n;
9818}
9819
Eric Andersenc470f442003-07-28 09:56:35 +00009820void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009821{
Eric Andersencb57d552001-06-28 07:25:16 +00009822 TRACE(("Fix redir %s %d\n", text, err));
9823 if (!err)
9824 n->ndup.vname = NULL;
9825
9826 if (is_digit(text[0]) && text[1] == '\0')
9827 n->ndup.dupfd = digit_val(text[0]);
9828 else if (text[0] == '-' && text[1] == '\0')
9829 n->ndup.dupfd = -1;
9830 else {
9831
9832 if (err)
9833 synerror("Bad fd number");
9834 else
9835 n->ndup.vname = makename();
9836 }
9837}
9838
9839
Eric Andersenc470f442003-07-28 09:56:35 +00009840static void
9841parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009842{
Eric Andersencb57d552001-06-28 07:25:16 +00009843 union node *n = redirnode;
9844
9845 if (readtoken() != TWORD)
9846 synexpect(-1);
9847 if (n->type == NHERE) {
9848 struct heredoc *here = heredoc;
9849 struct heredoc *p;
9850 int i;
9851
9852 if (quoteflag == 0)
9853 n->type = NXHERE;
9854 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009855 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009856 synerror("Illegal eof marker for << redirection");
9857 rmescapes(wordtext);
9858 here->eofmark = wordtext;
9859 here->next = NULL;
9860 if (heredoclist == NULL)
9861 heredoclist = here;
9862 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009863 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009864 p->next = here;
9865 }
9866 } else if (n->type == NTOFD || n->type == NFROMFD) {
9867 fixredir(n, wordtext, 0);
9868 } else {
9869 n->nfile.fname = makename();
9870 }
9871}
9872
9873
9874/*
9875 * Input any here documents.
9876 */
9877
Eric Andersenc470f442003-07-28 09:56:35 +00009878static void
9879parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009880{
Eric Andersencb57d552001-06-28 07:25:16 +00009881 struct heredoc *here;
9882 union node *n;
9883
Eric Andersenc470f442003-07-28 09:56:35 +00009884 here = heredoclist;
9885 heredoclist = 0;
9886
9887 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009888 if (needprompt) {
9889 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009890 }
Eric Andersenc470f442003-07-28 09:56:35 +00009891 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9892 here->eofmark, here->striptabs);
9893 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009894 n->narg.type = NARG;
9895 n->narg.next = NULL;
9896 n->narg.text = wordtext;
9897 n->narg.backquote = backquotelist;
9898 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009899 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009900 }
9901}
9902
Eric Andersenc470f442003-07-28 09:56:35 +00009903static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009904{
Eric Andersencb57d552001-06-28 07:25:16 +00009905 int t;
9906
9907 t = readtoken();
9908 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009909 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009910}
9911
Eric Andersenc470f442003-07-28 09:56:35 +00009912static int
9913readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009914{
Eric Andersencb57d552001-06-28 07:25:16 +00009915 int t;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009916#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00009917 int alreadyseen = tokpushback;
9918#endif
9919
Eric Andersend35c5df2002-01-09 15:37:36 +00009920#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009921top:
Eric Andersen2870d962001-07-02 17:27:21 +00009922#endif
9923
Eric Andersencb57d552001-06-28 07:25:16 +00009924 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009925
Eric Andersenc470f442003-07-28 09:56:35 +00009926 /*
9927 * eat newlines
9928 */
9929 if (checkkwd & CHKNL) {
9930 while (t == TNL) {
9931 parseheredoc();
9932 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009933 }
9934 }
9935
Eric Andersenc470f442003-07-28 09:56:35 +00009936 if (t != TWORD || quoteflag) {
9937 goto out;
9938 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009939
Eric Andersenc470f442003-07-28 09:56:35 +00009940 /*
9941 * check for keywords
9942 */
9943 if (checkkwd & CHKKWD) {
9944 const char *const *pp;
9945
9946 if ((pp = findkwd(wordtext))) {
9947 lasttoken = t = pp - tokname_array;
9948 TRACE(("keyword %s recognized\n", tokname(t)));
9949 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009950 }
Eric Andersenc470f442003-07-28 09:56:35 +00009951 }
9952
9953 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009954#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009955 struct alias *ap;
9956 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009957 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009958 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009959 }
Eric Andersencb57d552001-06-28 07:25:16 +00009960 goto top;
9961 }
Eric Andersen2870d962001-07-02 17:27:21 +00009962#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009963 }
Eric Andersenc470f442003-07-28 09:56:35 +00009964out:
9965 checkkwd = 0;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009966#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00009967 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009968 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009969 else
Eric Andersenc470f442003-07-28 09:56:35 +00009970 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009971#endif
9972 return (t);
9973}
9974
9975
9976/*
9977 * Read the next input token.
9978 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009979 * backquotes. We set quoteflag to true if any part of the word was
9980 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009981 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009982 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009983 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009984 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009985 *
9986 * [Change comment: here documents and internal procedures]
9987 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9988 * word parsing code into a separate routine. In this case, readtoken
9989 * doesn't need to have any internal procedures, but parseword does.
9990 * We could also make parseoperator in essence the main routine, and
9991 * have parseword (readtoken1?) handle both words and redirection.]
9992 */
9993
Eric Andersen81fe1232003-07-29 06:38:40 +00009994#define NEW_xxreadtoken
9995#ifdef NEW_xxreadtoken
9996
9997/* singles must be first! */
9998static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9999
10000static const char xxreadtoken_tokens[] = {
10001 TNL, TLP, TRP, /* only single occurrence allowed */
10002 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10003 TEOF, /* corresponds to trailing nul */
10004 TAND, TOR, TENDCASE, /* if double occurrence */
10005};
10006
10007#define xxreadtoken_doubles \
10008 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10009#define xxreadtoken_singles \
10010 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10011
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +000010012static int xxreadtoken(void)
Eric Andersen81fe1232003-07-29 06:38:40 +000010013{
10014 int c;
10015
10016 if (tokpushback) {
10017 tokpushback = 0;
10018 return lasttoken;
10019 }
10020 if (needprompt) {
10021 setprompt(2);
Eric Andersen81fe1232003-07-29 06:38:40 +000010022 }
10023 startlinno = plinno;
10024 for (;;) { /* until token or start of word found */
10025 c = pgetc_macro();
10026
10027 if ((c != ' ') && (c != '\t')
10028#ifdef CONFIG_ASH_ALIAS
10029 && (c != PEOA)
10030#endif
10031 ) {
10032 if (c == '#') {
10033 while ((c = pgetc()) != '\n' && c != PEOF);
10034 pungetc();
10035 } else if (c == '\\') {
10036 if (pgetc() != '\n') {
10037 pungetc();
10038 goto READTOKEN1;
10039 }
10040 startlinno = ++plinno;
10041 if (doprompt)
10042 setprompt(2);
10043 } else {
10044 const char *p
10045 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10046
10047 if (c != PEOF) {
10048 if (c == '\n') {
10049 plinno++;
10050 needprompt = doprompt;
10051 }
10052
10053 p = strchr(xxreadtoken_chars, c);
10054 if (p == NULL) {
10055 READTOKEN1:
10056 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10057 }
10058
10059 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10060 if (pgetc() == *p) { /* double occurrence? */
10061 p += xxreadtoken_doubles + 1;
10062 } else {
10063 pungetc();
10064 }
10065 }
10066 }
10067
10068 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10069 }
10070 }
10071 }
10072}
10073
10074
10075#else
Eric Andersen2870d962001-07-02 17:27:21 +000010076#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010077
Eric Andersenc470f442003-07-28 09:56:35 +000010078static int
10079xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010080{
Eric Andersencb57d552001-06-28 07:25:16 +000010081 int c;
10082
10083 if (tokpushback) {
10084 tokpushback = 0;
10085 return lasttoken;
10086 }
10087 if (needprompt) {
10088 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010089 }
10090 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010091 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010092 c = pgetc_macro();
10093 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010094 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010095#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010096 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010097#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010098 continue;
10099 case '#':
10100 while ((c = pgetc()) != '\n' && c != PEOF);
10101 pungetc();
10102 continue;
10103 case '\\':
10104 if (pgetc() == '\n') {
10105 startlinno = ++plinno;
10106 if (doprompt)
10107 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010108 continue;
10109 }
10110 pungetc();
10111 goto breakloop;
10112 case '\n':
10113 plinno++;
10114 needprompt = doprompt;
10115 RETURN(TNL);
10116 case PEOF:
10117 RETURN(TEOF);
10118 case '&':
10119 if (pgetc() == '&')
10120 RETURN(TAND);
10121 pungetc();
10122 RETURN(TBACKGND);
10123 case '|':
10124 if (pgetc() == '|')
10125 RETURN(TOR);
10126 pungetc();
10127 RETURN(TPIPE);
10128 case ';':
10129 if (pgetc() == ';')
10130 RETURN(TENDCASE);
10131 pungetc();
10132 RETURN(TSEMI);
10133 case '(':
10134 RETURN(TLP);
10135 case ')':
10136 RETURN(TRP);
10137 default:
10138 goto breakloop;
10139 }
10140 }
Eric Andersenc470f442003-07-28 09:56:35 +000010141breakloop:
10142 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010143#undef RETURN
10144}
Eric Andersen81fe1232003-07-29 06:38:40 +000010145#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010146
Eric Andersencb57d552001-06-28 07:25:16 +000010147
Eric Andersencb57d552001-06-28 07:25:16 +000010148/*
10149 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10150 * is not NULL, read a here document. In the latter case, eofmark is the
10151 * word which marks the end of the document and striptabs is true if
10152 * leading tabs should be stripped from the document. The argument firstc
10153 * is the first character of the input token or document.
10154 *
10155 * Because C does not have internal subroutines, I have simulated them
10156 * using goto's to implement the subroutine linkage. The following macros
10157 * will run code that appears at the end of readtoken1.
10158 */
10159
Eric Andersen2870d962001-07-02 17:27:21 +000010160#define CHECKEND() {goto checkend; checkend_return:;}
10161#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10162#define PARSESUB() {goto parsesub; parsesub_return:;}
10163#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10164#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10165#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010166
10167static int
Eric Andersenc470f442003-07-28 09:56:35 +000010168readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010169{
Eric Andersencb57d552001-06-28 07:25:16 +000010170 int c = firstc;
10171 char *out;
10172 int len;
10173 char line[EOFMARKLEN + 1];
Eric Andersena68ea1c2006-01-30 22:48:39 +000010174 struct nodelist *bqlist = 0;
10175 int quotef = 0;
10176 int dblquote = 0;
10177 int varnest = 0; /* levels of variables expansion */
10178 int arinest = 0; /* levels of arithmetic expansion */
10179 int parenlevel = 0; /* levels of parens in arithmetic */
10180 int dqvarnest = 0; /* levels of variables expansion within double quotes */
10181 int oldstyle = 0;
10182 int prevsyntax = 0; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010183#if __GNUC__
10184 /* Avoid longjmp clobbering */
10185 (void) &out;
10186 (void) &quotef;
10187 (void) &dblquote;
10188 (void) &varnest;
10189 (void) &arinest;
10190 (void) &parenlevel;
10191 (void) &dqvarnest;
10192 (void) &oldstyle;
10193 (void) &prevsyntax;
10194 (void) &syntax;
10195#endif
10196
10197 startlinno = plinno;
10198 dblquote = 0;
10199 if (syntax == DQSYNTAX)
10200 dblquote = 1;
10201 quotef = 0;
10202 bqlist = NULL;
10203 varnest = 0;
10204 arinest = 0;
10205 parenlevel = 0;
10206 dqvarnest = 0;
10207
10208 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010209 loop: { /* for each line, until end of word */
10210 CHECKEND(); /* set c to PEOF if at end of here document */
10211 for (;;) { /* until end of line or end of word */
10212 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10213 switch(SIT(c, syntax)) {
10214 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010215 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010216 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010217 USTPUTC(c, out);
10218 plinno++;
10219 if (doprompt)
10220 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010221 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010222 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010223 case CWORD:
10224 USTPUTC(c, out);
10225 break;
10226 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010227 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010228 USTPUTC(CTLESC, out);
10229 USTPUTC(c, out);
10230 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010231 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010232 c = pgetc2();
10233 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010234 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010235 USTPUTC('\\', out);
10236 pungetc();
10237 } else if (c == '\n') {
10238 if (doprompt)
10239 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010240 } else {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010241 if (dblquote &&
Eric Andersenc470f442003-07-28 09:56:35 +000010242 c != '\\' && c != '`' &&
10243 c != '$' && (
10244 c != '"' ||
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010245 eofmark != NULL)
Eric Andersenc470f442003-07-28 09:56:35 +000010246 ) {
10247 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010248 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010249 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010250 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010251 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010252 USTPUTC(c, out);
10253 quotef++;
10254 }
10255 break;
10256 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010257 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010258quotemark:
10259 if (eofmark == NULL) {
10260 USTPUTC(CTLQUOTEMARK, out);
10261 }
Eric Andersencb57d552001-06-28 07:25:16 +000010262 break;
10263 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010264 syntax = DQSYNTAX;
10265 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010266 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010267 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010268 if (eofmark != NULL && arinest == 0 &&
10269 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010270 USTPUTC(c, out);
10271 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010272 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010273 syntax = BASESYNTAX;
10274 dblquote = 0;
10275 }
10276 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010277 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010278 }
10279 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010280 case CVAR: /* '$' */
10281 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010282 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010283 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010284 if (varnest > 0) {
10285 varnest--;
10286 if (dqvarnest > 0) {
10287 dqvarnest--;
10288 }
10289 USTPUTC(CTLENDVAR, out);
10290 } else {
10291 USTPUTC(c, out);
10292 }
10293 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010294#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010295 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010296 parenlevel++;
10297 USTPUTC(c, out);
10298 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010299 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010300 if (parenlevel > 0) {
10301 USTPUTC(c, out);
10302 --parenlevel;
10303 } else {
10304 if (pgetc() == ')') {
10305 if (--arinest == 0) {
10306 USTPUTC(CTLENDARI, out);
10307 syntax = prevsyntax;
10308 if (syntax == DQSYNTAX)
10309 dblquote = 1;
10310 else
10311 dblquote = 0;
10312 } else
10313 USTPUTC(')', out);
10314 } else {
10315 /*
10316 * unbalanced parens
10317 * (don't 2nd guess - no error)
10318 */
10319 pungetc();
10320 USTPUTC(')', out);
10321 }
10322 }
10323 break;
10324#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010325 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010326 PARSEBACKQOLD();
10327 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010328 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010329 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010330 case CIGN:
10331 break;
10332 default:
10333 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010334 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010335#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010336 if (c != PEOA)
10337#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010338 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010339
Eric Andersencb57d552001-06-28 07:25:16 +000010340 }
10341 c = pgetc_macro();
10342 }
10343 }
Eric Andersenc470f442003-07-28 09:56:35 +000010344endword:
10345#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010346 if (syntax == ARISYNTAX)
10347 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010348#endif
10349 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010350 synerror("Unterminated quoted string");
10351 if (varnest != 0) {
10352 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010353 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010354 synerror("Missing '}'");
10355 }
10356 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010357 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010358 out = stackblock();
10359 if (eofmark == NULL) {
10360 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010361 && quotef == 0
10362 && len <= 2
10363 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010364 PARSEREDIR();
10365 return lasttoken = TREDIR;
10366 } else {
10367 pungetc();
10368 }
10369 }
10370 quoteflag = quotef;
10371 backquotelist = bqlist;
10372 grabstackblock(len);
10373 wordtext = out;
10374 return lasttoken = TWORD;
10375/* end of readtoken routine */
10376
10377
10378
10379/*
10380 * Check to see whether we are at the end of the here document. When this
10381 * is called, c is set to the first character of the next input line. If
10382 * we are at the end of the here document, this routine sets the c to PEOF.
10383 */
10384
Eric Andersenc470f442003-07-28 09:56:35 +000010385checkend: {
10386 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010387#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010388 if (c == PEOA) {
10389 c = pgetc2();
10390 }
10391#endif
10392 if (striptabs) {
10393 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010394 c = pgetc2();
10395 }
Eric Andersenc470f442003-07-28 09:56:35 +000010396 }
10397 if (c == *eofmark) {
10398 if (pfgets(line, sizeof line) != NULL) {
10399 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010400
Eric Andersenc470f442003-07-28 09:56:35 +000010401 p = line;
10402 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10403 if (*p == '\n' && *q == '\0') {
10404 c = PEOF;
10405 plinno++;
10406 needprompt = doprompt;
10407 } else {
10408 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010409 }
10410 }
10411 }
10412 }
Eric Andersenc470f442003-07-28 09:56:35 +000010413 goto checkend_return;
10414}
Eric Andersencb57d552001-06-28 07:25:16 +000010415
10416
10417/*
10418 * Parse a redirection operator. The variable "out" points to a string
10419 * specifying the fd to be redirected. The variable "c" contains the
10420 * first character of the redirection operator.
10421 */
10422
Eric Andersenc470f442003-07-28 09:56:35 +000010423parseredir: {
10424 char fd = *out;
10425 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010426
Eric Andersenc470f442003-07-28 09:56:35 +000010427 np = (union node *)stalloc(sizeof (struct nfile));
10428 if (c == '>') {
10429 np->nfile.fd = 1;
10430 c = pgetc();
10431 if (c == '>')
10432 np->type = NAPPEND;
10433 else if (c == '|')
10434 np->type = NCLOBBER;
10435 else if (c == '&')
10436 np->type = NTOFD;
10437 else {
10438 np->type = NTO;
10439 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010440 }
Eric Andersenc470f442003-07-28 09:56:35 +000010441 } else { /* c == '<' */
10442 np->nfile.fd = 0;
10443 switch (c = pgetc()) {
10444 case '<':
10445 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10446 np = (union node *)stalloc(sizeof (struct nhere));
10447 np->nfile.fd = 0;
10448 }
10449 np->type = NHERE;
10450 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10451 heredoc->here = np;
10452 if ((c = pgetc()) == '-') {
10453 heredoc->striptabs = 1;
10454 } else {
10455 heredoc->striptabs = 0;
10456 pungetc();
10457 }
10458 break;
10459
10460 case '&':
10461 np->type = NFROMFD;
10462 break;
10463
10464 case '>':
10465 np->type = NFROMTO;
10466 break;
10467
10468 default:
10469 np->type = NFROM;
10470 pungetc();
10471 break;
10472 }
Eric Andersencb57d552001-06-28 07:25:16 +000010473 }
Eric Andersenc470f442003-07-28 09:56:35 +000010474 if (fd != '\0')
10475 np->nfile.fd = digit_val(fd);
10476 redirnode = np;
10477 goto parseredir_return;
10478}
Eric Andersencb57d552001-06-28 07:25:16 +000010479
10480
10481/*
10482 * Parse a substitution. At this point, we have read the dollar sign
10483 * and nothing else.
10484 */
10485
Eric Andersenc470f442003-07-28 09:56:35 +000010486parsesub: {
10487 int subtype;
10488 int typeloc;
10489 int flags;
10490 char *p;
10491 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010492
Eric Andersenc470f442003-07-28 09:56:35 +000010493 c = pgetc();
10494 if (
10495 c <= PEOA_OR_PEOF ||
10496 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10497 ) {
10498 USTPUTC('$', out);
10499 pungetc();
10500 } else if (c == '(') { /* $(command) or $((arith)) */
10501 if (pgetc() == '(') {
10502#ifdef CONFIG_ASH_MATH_SUPPORT
10503 PARSEARITH();
10504#else
10505 synerror("We unsupport $((arith))");
10506#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010507 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010508 pungetc();
10509 PARSEBACKQNEW();
10510 }
10511 } else {
10512 USTPUTC(CTLVAR, out);
10513 typeloc = out - (char *)stackblock();
10514 USTPUTC(VSNORMAL, out);
10515 subtype = VSNORMAL;
10516 if (c == '{') {
10517 c = pgetc();
10518 if (c == '#') {
10519 if ((c = pgetc()) == '}')
10520 c = '#';
10521 else
10522 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010523 }
Eric Andersenc470f442003-07-28 09:56:35 +000010524 else
10525 subtype = 0;
10526 }
10527 if (c > PEOA_OR_PEOF && is_name(c)) {
10528 do {
10529 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010530 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010531 } while (c > PEOA_OR_PEOF && is_in_name(c));
10532 } else if (is_digit(c)) {
10533 do {
10534 STPUTC(c, out);
10535 c = pgetc();
10536 } while (is_digit(c));
10537 }
10538 else if (is_special(c)) {
10539 USTPUTC(c, out);
10540 c = pgetc();
10541 }
10542 else
10543badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010544
Eric Andersenc470f442003-07-28 09:56:35 +000010545 STPUTC('=', out);
10546 flags = 0;
10547 if (subtype == 0) {
10548 switch (c) {
10549 case ':':
10550 flags = VSNUL;
10551 c = pgetc();
10552 /*FALLTHROUGH*/
10553 default:
10554 p = strchr(types, c);
10555 if (p == NULL)
10556 goto badsub;
10557 subtype = p - types + VSNORMAL;
10558 break;
10559 case '%':
10560 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010561 {
10562 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010563 subtype = c == '#' ? VSTRIMLEFT :
10564 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010565 c = pgetc();
10566 if (c == cc)
10567 subtype++;
10568 else
10569 pungetc();
10570 break;
10571 }
10572 }
Eric Andersenc470f442003-07-28 09:56:35 +000010573 } else {
10574 pungetc();
10575 }
10576 if (dblquote || arinest)
10577 flags |= VSQUOTE;
10578 *((char *)stackblock() + typeloc) = subtype | flags;
10579 if (subtype != VSNORMAL) {
10580 varnest++;
10581 if (dblquote || arinest) {
10582 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010583 }
10584 }
10585 }
Eric Andersenc470f442003-07-28 09:56:35 +000010586 goto parsesub_return;
10587}
Eric Andersencb57d552001-06-28 07:25:16 +000010588
10589
10590/*
10591 * Called to parse command substitutions. Newstyle is set if the command
10592 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10593 * list of commands (passed by reference), and savelen is the number of
10594 * characters on the top of the stack which must be preserved.
10595 */
10596
Eric Andersenc470f442003-07-28 09:56:35 +000010597parsebackq: {
10598 struct nodelist **nlpp;
10599 int savepbq;
10600 union node *n;
10601 char *volatile str;
10602 struct jmploc jmploc;
10603 struct jmploc *volatile savehandler;
10604 size_t savelen;
Eric Andersena68ea1c2006-01-30 22:48:39 +000010605 int saveprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010606#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010607 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010608#endif
10609
Eric Andersenc470f442003-07-28 09:56:35 +000010610 savepbq = parsebackquote;
10611 if (setjmp(jmploc.loc)) {
10612 if (str)
10613 ckfree(str);
10614 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010615 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010616 longjmp(handler->loc, 1);
10617 }
10618 INTOFF;
10619 str = NULL;
10620 savelen = out - (char *)stackblock();
10621 if (savelen > 0) {
10622 str = ckmalloc(savelen);
10623 memcpy(str, stackblock(), savelen);
10624 }
10625 savehandler = handler;
10626 handler = &jmploc;
10627 INTON;
10628 if (oldstyle) {
10629 /* We must read until the closing backquote, giving special
10630 treatment to some slashes, and then push the string and
10631 reread it as input, interpreting it normally. */
10632 char *pout;
10633 int pc;
10634 size_t psavelen;
10635 char *pstr;
10636
10637
10638 STARTSTACKSTR(pout);
10639 for (;;) {
10640 if (needprompt) {
10641 setprompt(2);
Eric Andersenc470f442003-07-28 09:56:35 +000010642 }
10643 switch (pc = pgetc()) {
10644 case '`':
10645 goto done;
10646
10647 case '\\':
10648 if ((pc = pgetc()) == '\n') {
10649 plinno++;
10650 if (doprompt)
10651 setprompt(2);
10652 /*
10653 * If eating a newline, avoid putting
10654 * the newline into the new character
10655 * stream (via the STPUTC after the
10656 * switch).
10657 */
10658 continue;
10659 }
10660 if (pc != '\\' && pc != '`' && pc != '$'
10661 && (!dblquote || pc != '"'))
10662 STPUTC('\\', pout);
10663 if (pc > PEOA_OR_PEOF) {
10664 break;
10665 }
10666 /* fall through */
10667
10668 case PEOF:
10669#ifdef CONFIG_ASH_ALIAS
10670 case PEOA:
10671#endif
10672 startlinno = plinno;
10673 synerror("EOF in backquote substitution");
10674
10675 case '\n':
10676 plinno++;
10677 needprompt = doprompt;
10678 break;
10679
10680 default:
10681 break;
10682 }
10683 STPUTC(pc, pout);
10684 }
10685done:
10686 STPUTC('\0', pout);
10687 psavelen = pout - (char *)stackblock();
10688 if (psavelen > 0) {
10689 pstr = grabstackstr(pout);
10690 setinputstring(pstr);
10691 }
10692 }
10693 nlpp = &bqlist;
10694 while (*nlpp)
10695 nlpp = &(*nlpp)->next;
10696 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10697 (*nlpp)->next = NULL;
10698 parsebackquote = oldstyle;
10699
10700 if (oldstyle) {
10701 saveprompt = doprompt;
10702 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010703 }
10704
Eric Andersenc470f442003-07-28 09:56:35 +000010705 n = list(2);
10706
10707 if (oldstyle)
10708 doprompt = saveprompt;
10709 else {
10710 if (readtoken() != TRP)
10711 synexpect(TRP);
10712 }
10713
10714 (*nlpp)->n = n;
10715 if (oldstyle) {
10716 /*
10717 * Start reading from old file again, ignoring any pushed back
10718 * tokens left from the backquote parsing
10719 */
10720 popfile();
10721 tokpushback = 0;
10722 }
10723 while (stackblocksize() <= savelen)
10724 growstackblock();
10725 STARTSTACKSTR(out);
10726 if (str) {
10727 memcpy(out, str, savelen);
10728 STADJUST(savelen, out);
10729 INTOFF;
10730 ckfree(str);
10731 str = NULL;
10732 INTON;
10733 }
10734 parsebackquote = savepbq;
10735 handler = savehandler;
10736 if (arinest || dblquote)
10737 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10738 else
10739 USTPUTC(CTLBACKQ, out);
10740 if (oldstyle)
10741 goto parsebackq_oldreturn;
10742 else
10743 goto parsebackq_newreturn;
10744}
10745
10746#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010747/*
10748 * Parse an arithmetic expansion (indicate start of one and set state)
10749 */
Eric Andersenc470f442003-07-28 09:56:35 +000010750parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010751
Eric Andersenc470f442003-07-28 09:56:35 +000010752 if (++arinest == 1) {
10753 prevsyntax = syntax;
10754 syntax = ARISYNTAX;
10755 USTPUTC(CTLARI, out);
10756 if (dblquote)
10757 USTPUTC('"',out);
10758 else
10759 USTPUTC(' ',out);
10760 } else {
10761 /*
10762 * we collapse embedded arithmetic expansion to
10763 * parenthesis, which should be equivalent
10764 */
10765 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010766 }
Eric Andersenc470f442003-07-28 09:56:35 +000010767 goto parsearith_return;
10768}
10769#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010770
Eric Andersenc470f442003-07-28 09:56:35 +000010771} /* end of readtoken */
10772
Eric Andersencb57d552001-06-28 07:25:16 +000010773
10774
Eric Andersencb57d552001-06-28 07:25:16 +000010775/*
10776 * Returns true if the text contains nothing to expand (no dollar signs
10777 * or backquotes).
10778 */
10779
Eric Andersenc470f442003-07-28 09:56:35 +000010780static int
10781noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010782{
Eric Andersencb57d552001-06-28 07:25:16 +000010783 char *p;
10784 char c;
10785
10786 p = text;
10787 while ((c = *p++) != '\0') {
10788 if (c == CTLQUOTEMARK)
10789 continue;
10790 if (c == CTLESC)
10791 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010792 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010793 return 0;
10794 }
10795 return 1;
10796}
10797
10798
10799/*
Eric Andersenc470f442003-07-28 09:56:35 +000010800 * Return of a legal variable name (a letter or underscore followed by zero or
10801 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010802 */
10803
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010804static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010805endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010806{
Eric Andersenc470f442003-07-28 09:56:35 +000010807 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010808
Eric Andersenc470f442003-07-28 09:56:35 +000010809 p = (char *) name;
10810 if (! is_name(*p))
10811 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010812 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010813 if (! is_in_name(*p))
10814 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010815 }
Eric Andersenc470f442003-07-28 09:56:35 +000010816 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010817}
10818
10819
10820/*
10821 * Called when an unexpected token is read during the parse. The argument
10822 * is the token that is expected, or -1 if more than one type of token can
10823 * occur at this point.
10824 */
10825
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010826static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010827{
10828 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010829 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010830
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010831 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10832 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010833 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010834 synerror(msg);
10835 /* NOTREACHED */
10836}
10837
Eric Andersenc470f442003-07-28 09:56:35 +000010838static void
10839synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010840{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010841 sh_error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010842 /* NOTREACHED */
10843}
10844
Eric Andersencb57d552001-06-28 07:25:16 +000010845
10846/*
10847 * called by editline -- any expansions to the prompt
10848 * should be added here.
10849 */
Eric Andersenc470f442003-07-28 09:56:35 +000010850
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010851#ifdef CONFIG_ASH_EXPAND_PRMT
10852static const char *
10853expandstr(const char *ps)
10854{
10855 union node n;
10856
10857 /* XXX Fix (char *) cast. */
10858 setinputstring((char *)ps);
10859 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10860 popfile();
10861
10862 n.narg.type = NARG;
10863 n.narg.next = NULL;
10864 n.narg.text = wordtext;
10865 n.narg.backquote = backquotelist;
10866
10867 expandarg(&n, NULL, 0);
10868 return stackblock();
10869}
10870#endif
10871
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010872static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010873{
Eric Andersenc470f442003-07-28 09:56:35 +000010874 const char *prompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010875#ifdef CONFIG_ASH_EXPAND_PRMT
10876 struct stackmark smark;
10877#endif
10878
10879 needprompt = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010880
10881 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010882 case 1:
10883 prompt = ps1val();
10884 break;
10885 case 2:
10886 prompt = ps2val();
10887 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010888 default: /* 0 */
10889 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010890 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010891#ifdef CONFIG_ASH_EXPAND_PRMT
10892 setstackmark(&smark);
10893 stalloc(stackblocksize());
10894#endif
10895 putprompt(expandstr(prompt));
10896#ifdef CONFIG_ASH_EXPAND_PRMT
10897 popstackmark(&smark);
10898#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010899}
10900
Eric Andersencb57d552001-06-28 07:25:16 +000010901
Eric Andersenc470f442003-07-28 09:56:35 +000010902static const char *const *findkwd(const char *s)
10903{
10904 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010905 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010906 sizeof(const char *), pstrcmp);
10907}
10908
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010909/* redir.c */
Eric Andersenc470f442003-07-28 09:56:35 +000010910
Eric Andersencb57d552001-06-28 07:25:16 +000010911/*
10912 * Code for dealing with input/output redirection.
10913 */
10914
Eric Andersenc470f442003-07-28 09:56:35 +000010915#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010916#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010917# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010918#else
10919# define PIPESIZE PIPE_BUF
10920#endif
10921
Eric Andersen62483552001-07-10 06:09:16 +000010922/*
10923 * Open a file in noclobber mode.
10924 * The code was copied from bash.
10925 */
Rob Landley88621d72006-08-29 19:41:06 +000010926static int noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010927{
10928 int r, fd;
10929 struct stat finfo, finfo2;
10930
10931 /*
10932 * If the file exists and is a regular file, return an error
10933 * immediately.
10934 */
10935 r = stat(fname, &finfo);
10936 if (r == 0 && S_ISREG(finfo.st_mode)) {
10937 errno = EEXIST;
10938 return -1;
10939 }
10940
10941 /*
10942 * If the file was not present (r != 0), make sure we open it
10943 * exclusively so that if it is created before we open it, our open
10944 * will fail. Make sure that we do not truncate an existing file.
10945 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10946 * file was not a regular file, we leave O_EXCL off.
10947 */
10948 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010949 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10950 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010951
10952 /* If the open failed, return the file descriptor right away. */
10953 if (fd < 0)
10954 return fd;
10955
10956 /*
10957 * OK, the open succeeded, but the file may have been changed from a
10958 * non-regular file to a regular file between the stat and the open.
10959 * We are assuming that the O_EXCL open handles the case where FILENAME
10960 * did not exist and is symlinked to an existing file between the stat
10961 * and open.
10962 */
10963
10964 /*
10965 * If we can open it and fstat the file descriptor, and neither check
10966 * revealed that it was a regular file, and the file has not been
10967 * replaced, return the file descriptor.
10968 */
Eric Andersenc470f442003-07-28 09:56:35 +000010969 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10970 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010971 return fd;
10972
10973 /* The file has been replaced. badness. */
10974 close(fd);
10975 errno = EEXIST;
10976 return -1;
10977}
Eric Andersencb57d552001-06-28 07:25:16 +000010978
10979/*
Eric Andersen62483552001-07-10 06:09:16 +000010980 * Handle here documents. Normally we fork off a process to write the
10981 * data to a pipe. If the document is short, we can stuff the data in
10982 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010983 */
10984
Rob Landley88621d72006-08-29 19:41:06 +000010985static int openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010986{
10987 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010988 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010989
Eric Andersen62483552001-07-10 06:09:16 +000010990 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010991 sh_error("Pipe call failed");
Eric Andersen62483552001-07-10 06:09:16 +000010992 if (redir->type == NHERE) {
10993 len = strlen(redir->nhere.doc->narg.text);
10994 if (len <= PIPESIZE) {
Rob Landley53437472006-07-16 08:14:35 +000010995 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010996 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010997 }
Eric Andersencb57d552001-06-28 07:25:16 +000010998 }
Eric Andersenc470f442003-07-28 09:56:35 +000010999 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000011000 close(pip[0]);
11001 signal(SIGINT, SIG_IGN);
11002 signal(SIGQUIT, SIG_IGN);
11003 signal(SIGHUP, SIG_IGN);
11004#ifdef SIGTSTP
11005 signal(SIGTSTP, SIG_IGN);
11006#endif
11007 signal(SIGPIPE, SIG_DFL);
11008 if (redir->type == NHERE)
Rob Landley53437472006-07-16 08:14:35 +000011009 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000011010 else
11011 expandhere(redir->nhere.doc, pip[1]);
11012 _exit(0);
11013 }
Eric Andersenc470f442003-07-28 09:56:35 +000011014out:
Eric Andersen62483552001-07-10 06:09:16 +000011015 close(pip[1]);
11016 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011017}
11018
Eric Andersenc470f442003-07-28 09:56:35 +000011019static int
11020openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011021{
Eric Andersencb57d552001-06-28 07:25:16 +000011022 char *fname;
11023 int f;
11024
11025 switch (redir->nfile.type) {
11026 case NFROM:
11027 fname = redir->nfile.expfname;
11028 if ((f = open(fname, O_RDONLY)) < 0)
11029 goto eopen;
11030 break;
11031 case NFROMTO:
11032 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011033 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011034 goto ecreate;
11035 break;
11036 case NTO:
11037 /* Take care of noclobber mode. */
11038 if (Cflag) {
11039 fname = redir->nfile.expfname;
11040 if ((f = noclobberopen(fname)) < 0)
11041 goto ecreate;
11042 break;
11043 }
Eric Andersenc470f442003-07-28 09:56:35 +000011044 /* FALLTHROUGH */
11045 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011046 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011047 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011048 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011049 break;
11050 case NAPPEND:
11051 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011052 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011053 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011054 break;
11055 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011056#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011057 abort();
11058#endif
11059 /* Fall through to eliminate warning. */
11060 case NTOFD:
11061 case NFROMFD:
11062 f = -1;
11063 break;
11064 case NHERE:
11065 case NXHERE:
11066 f = openhere(redir);
11067 break;
11068 }
11069
11070 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011071ecreate:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011072 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011073eopen:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011074 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
Eric Andersencb57d552001-06-28 07:25:16 +000011075}
11076
Rob Landley88621d72006-08-29 19:41:06 +000011077static void dupredirect(union node *redir, int f)
Eric Andersenc470f442003-07-28 09:56:35 +000011078{
11079 int fd = redir->nfile.fd;
11080
11081 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11082 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11083 copyfd(redir->ndup.dupfd, fd);
11084 }
11085 return;
11086 }
11087
11088 if (f != fd) {
11089 copyfd(f, fd);
11090 close(f);
11091 }
11092 return;
11093}
Eric Andersencb57d552001-06-28 07:25:16 +000011094
Eric Andersen62483552001-07-10 06:09:16 +000011095/*
11096 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11097 * old file descriptors are stashed away so that the redirection can be
11098 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11099 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011100 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011101 */
11102
Eric Andersenc470f442003-07-28 09:56:35 +000011103static void
11104redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011105{
11106 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011107 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011108 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011109 int fd;
11110 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011111 int *p;
11112 nullredirs++;
11113 if (!redir) {
11114 return;
Eric Andersen62483552001-07-10 06:09:16 +000011115 }
Eric Andersenc470f442003-07-28 09:56:35 +000011116 sv = NULL;
11117 INTOFF;
11118 if (flags & REDIR_PUSH) {
11119 struct redirtab *q;
11120 q = ckmalloc(sizeof (struct redirtab));
11121 q->next = redirlist;
11122 redirlist = q;
11123 q->nullredirs = nullredirs - 1;
11124 for (i = 0 ; i < 10 ; i++)
11125 q->renamed[i] = EMPTY;
11126 nullredirs = 0;
11127 sv = q;
11128 }
11129 n = redir;
11130 do {
Eric Andersen62483552001-07-10 06:09:16 +000011131 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011132 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011133 n->ndup.dupfd == fd)
11134 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011135
Eric Andersen62483552001-07-10 06:09:16 +000011136 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011137 if (fd == newfd)
11138 continue;
11139 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11140 i = fcntl(fd, F_DUPFD, 10);
11141
11142 if (i == -1) {
11143 i = errno;
11144 if (i != EBADF) {
11145 close(newfd);
11146 errno = i;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011147 sh_error("%d: %m", fd);
Eric Andersen62483552001-07-10 06:09:16 +000011148 /* NOTREACHED */
11149 }
Eric Andersenc470f442003-07-28 09:56:35 +000011150 } else {
11151 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011152 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011153 }
Eric Andersenc470f442003-07-28 09:56:35 +000011154 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011155 close(fd);
11156 }
Eric Andersenc470f442003-07-28 09:56:35 +000011157 dupredirect(n, newfd);
11158 } while ((n = n->nfile.next));
11159 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011160 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11161 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011162}
11163
11164
Eric Andersencb57d552001-06-28 07:25:16 +000011165/*
11166 * Undo the effects of the last redirection.
11167 */
11168
Eric Andersenc470f442003-07-28 09:56:35 +000011169void
11170popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011171{
Eric Andersenc470f442003-07-28 09:56:35 +000011172 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011173 int i;
11174
Eric Andersenc470f442003-07-28 09:56:35 +000011175 if (--nullredirs >= 0)
11176 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011177 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011178 rp = redirlist;
11179 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011180 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011181 if (!drop) {
11182 close(i);
11183 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011184 }
Eric Andersenc470f442003-07-28 09:56:35 +000011185 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011186 }
11187 }
11188 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011189 nullredirs = rp->nullredirs;
11190 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011191 INTON;
11192}
11193
11194/*
Eric Andersenc470f442003-07-28 09:56:35 +000011195 * Undo all redirections. Called on error or interrupt.
11196 */
11197
11198/*
Eric Andersencb57d552001-06-28 07:25:16 +000011199 * Discard all saved file descriptors.
11200 */
11201
Eric Andersenc470f442003-07-28 09:56:35 +000011202void
11203clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011204{
Eric Andersenc470f442003-07-28 09:56:35 +000011205 for (;;) {
11206 nullredirs = 0;
11207 if (!redirlist)
11208 break;
11209 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011210 }
Eric Andersencb57d552001-06-28 07:25:16 +000011211}
11212
11213
Eric Andersencb57d552001-06-28 07:25:16 +000011214/*
11215 * Copy a file descriptor to be >= to. Returns -1
11216 * if the source file descriptor is closed, EMPTY if there are no unused
11217 * file descriptors left.
11218 */
11219
Eric Andersenc470f442003-07-28 09:56:35 +000011220int
11221copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011222{
11223 int newfd;
11224
11225 newfd = fcntl(from, F_DUPFD, to);
11226 if (newfd < 0) {
11227 if (errno == EMFILE)
11228 return EMPTY;
11229 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011230 sh_error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011231 }
11232 return newfd;
11233}
11234
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011235
Eric Andersenc470f442003-07-28 09:56:35 +000011236int
11237redirectsafe(union node *redir, int flags)
11238{
11239 int err;
11240 volatile int saveint;
11241 struct jmploc *volatile savehandler = handler;
11242 struct jmploc jmploc;
11243
11244 SAVEINT(saveint);
11245 if (!(err = setjmp(jmploc.loc) * 2)) {
11246 handler = &jmploc;
11247 redirect(redir, flags);
11248 }
11249 handler = savehandler;
11250 if (err && exception != EXERROR)
11251 longjmp(handler->loc, 1);
11252 RESTOREINT(saveint);
11253 return err;
11254}
11255
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011256/* show.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011257
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011258#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +000011259static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011260static void shcmd(union node *, FILE *);
11261static void sharg(union node *, FILE *);
11262static void indent(int, char *, FILE *);
11263static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011264
11265
Eric Andersenc470f442003-07-28 09:56:35 +000011266void
11267showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011268{
11269 trputs("showtree called\n");
11270 shtree(n, 1, NULL, stdout);
11271}
Eric Andersencb57d552001-06-28 07:25:16 +000011272
Eric Andersenc470f442003-07-28 09:56:35 +000011273
11274static void
11275shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011276{
11277 struct nodelist *lp;
11278 const char *s;
11279
11280 if (n == NULL)
11281 return;
11282
11283 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011284 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011285 case NSEMI:
11286 s = "; ";
11287 goto binop;
11288 case NAND:
11289 s = " && ";
11290 goto binop;
11291 case NOR:
11292 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011293binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011294 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011295 /* if (ind < 0) */
11296 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011297 shtree(n->nbinary.ch2, ind, NULL, fp);
11298 break;
11299 case NCMD:
11300 shcmd(n, fp);
11301 if (ind >= 0)
11302 putc('\n', fp);
11303 break;
11304 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011305 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011306 shcmd(lp->n, fp);
11307 if (lp->next)
11308 fputs(" | ", fp);
11309 }
11310 if (n->npipe.backgnd)
11311 fputs(" &", fp);
11312 if (ind >= 0)
11313 putc('\n', fp);
11314 break;
11315 default:
11316 fprintf(fp, "<node type %d>", n->type);
11317 if (ind >= 0)
11318 putc('\n', fp);
11319 break;
11320 }
11321}
11322
11323
Eric Andersenc470f442003-07-28 09:56:35 +000011324static void
11325shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011326{
11327 union node *np;
11328 int first;
11329 const char *s;
11330 int dftfd;
11331
11332 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011333 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11334 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011335 putchar(' ');
11336 sharg(np, fp);
11337 first = 0;
11338 }
Eric Andersenc470f442003-07-28 09:56:35 +000011339 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11340 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011341 putchar(' ');
11342 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011343 case NTO: s = ">"; dftfd = 1; break;
11344 case NCLOBBER: s = ">|"; dftfd = 1; break;
11345 case NAPPEND: s = ">>"; dftfd = 1; break;
11346 case NTOFD: s = ">&"; dftfd = 1; break;
11347 case NFROM: s = "<"; dftfd = 0; break;
11348 case NFROMFD: s = "<&"; dftfd = 0; break;
11349 case NFROMTO: s = "<>"; dftfd = 0; break;
11350 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011351 }
11352 if (np->nfile.fd != dftfd)
11353 fprintf(fp, "%d", np->nfile.fd);
11354 fputs(s, fp);
11355 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11356 fprintf(fp, "%d", np->ndup.dupfd);
11357 } else {
11358 sharg(np->nfile.fname, fp);
11359 }
11360 first = 0;
11361 }
11362}
11363
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011364
Eric Andersenc470f442003-07-28 09:56:35 +000011365
11366static void
11367sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011368{
Eric Andersencb57d552001-06-28 07:25:16 +000011369 char *p;
11370 struct nodelist *bqlist;
11371 int subtype;
11372
11373 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011374 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011375 abort();
11376 }
11377 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011378 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011379 switch (*p) {
11380 case CTLESC:
11381 putc(*++p, fp);
11382 break;
11383 case CTLVAR:
11384 putc('$', fp);
11385 putc('{', fp);
11386 subtype = *++p;
11387 if (subtype == VSLENGTH)
11388 putc('#', fp);
11389
11390 while (*p != '=')
11391 putc(*p++, fp);
11392
11393 if (subtype & VSNUL)
11394 putc(':', fp);
11395
11396 switch (subtype & VSTYPE) {
11397 case VSNORMAL:
11398 putc('}', fp);
11399 break;
11400 case VSMINUS:
11401 putc('-', fp);
11402 break;
11403 case VSPLUS:
11404 putc('+', fp);
11405 break;
11406 case VSQUESTION:
11407 putc('?', fp);
11408 break;
11409 case VSASSIGN:
11410 putc('=', fp);
11411 break;
11412 case VSTRIMLEFT:
11413 putc('#', fp);
11414 break;
11415 case VSTRIMLEFTMAX:
11416 putc('#', fp);
11417 putc('#', fp);
11418 break;
11419 case VSTRIMRIGHT:
11420 putc('%', fp);
11421 break;
11422 case VSTRIMRIGHTMAX:
11423 putc('%', fp);
11424 putc('%', fp);
11425 break;
11426 case VSLENGTH:
11427 break;
11428 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011429 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011430 }
11431 break;
11432 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011433 putc('}', fp);
11434 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011435 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011436 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011437 putc('$', fp);
11438 putc('(', fp);
11439 shtree(bqlist->n, -1, NULL, fp);
11440 putc(')', fp);
11441 break;
11442 default:
11443 putc(*p, fp);
11444 break;
11445 }
11446 }
11447}
11448
11449
Eric Andersenc470f442003-07-28 09:56:35 +000011450static void
11451indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011452{
11453 int i;
11454
Eric Andersenc470f442003-07-28 09:56:35 +000011455 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011456 if (pfx && i == amount - 1)
11457 fputs(pfx, fp);
11458 putc('\t', fp);
11459 }
11460}
Eric Andersencb57d552001-06-28 07:25:16 +000011461
Eric Andersenc470f442003-07-28 09:56:35 +000011462
11463
11464/*
11465 * Debugging stuff.
11466 */
11467
11468
Eric Andersencb57d552001-06-28 07:25:16 +000011469FILE *tracefile;
11470
Eric Andersencb57d552001-06-28 07:25:16 +000011471
Eric Andersenc470f442003-07-28 09:56:35 +000011472void
11473trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011474{
Eric Andersenc470f442003-07-28 09:56:35 +000011475 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011476 return;
11477 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011478}
11479
Eric Andersenc470f442003-07-28 09:56:35 +000011480void
11481trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011482{
11483 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011484
Eric Andersenc470f442003-07-28 09:56:35 +000011485 if (debug != 1)
11486 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011487 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011488 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011489 va_end(va);
11490}
11491
Eric Andersenc470f442003-07-28 09:56:35 +000011492void
11493tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011494{
Eric Andersenc470f442003-07-28 09:56:35 +000011495 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011496 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011497 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011498}
11499
11500
Eric Andersenc470f442003-07-28 09:56:35 +000011501void
11502trputs(const char *s)
11503{
11504 if (debug != 1)
11505 return;
11506 fputs(s, tracefile);
11507}
11508
11509
11510static void
11511trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011512{
11513 char *p;
11514 char c;
11515
Eric Andersenc470f442003-07-28 09:56:35 +000011516 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011517 return;
11518 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011519 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011520 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011521 case '\n': c = 'n'; goto backslash;
11522 case '\t': c = 't'; goto backslash;
11523 case '\r': c = 'r'; goto backslash;
11524 case '"': c = '"'; goto backslash;
11525 case '\\': c = '\\'; goto backslash;
11526 case CTLESC: c = 'e'; goto backslash;
11527 case CTLVAR: c = 'v'; goto backslash;
11528 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11529 case CTLBACKQ: c = 'q'; goto backslash;
11530 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11531backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011532 putc(c, tracefile);
11533 break;
11534 default:
11535 if (*p >= ' ' && *p <= '~')
11536 putc(*p, tracefile);
11537 else {
11538 putc('\\', tracefile);
11539 putc(*p >> 6 & 03, tracefile);
11540 putc(*p >> 3 & 07, tracefile);
11541 putc(*p & 07, tracefile);
11542 }
11543 break;
11544 }
11545 }
11546 putc('"', tracefile);
11547}
11548
11549
Eric Andersenc470f442003-07-28 09:56:35 +000011550void
11551trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011552{
Eric Andersenc470f442003-07-28 09:56:35 +000011553 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011554 return;
11555 while (*ap) {
11556 trstring(*ap++);
11557 if (*ap)
11558 putc(' ', tracefile);
11559 else
11560 putc('\n', tracefile);
11561 }
Eric Andersencb57d552001-06-28 07:25:16 +000011562}
11563
11564
Eric Andersenc470f442003-07-28 09:56:35 +000011565void
11566opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011567{
Eric Andersencb57d552001-06-28 07:25:16 +000011568 char s[100];
11569#ifdef O_APPEND
11570 int flags;
11571#endif
11572
Eric Andersenc470f442003-07-28 09:56:35 +000011573 if (debug != 1) {
11574 if (tracefile)
11575 fflush(tracefile);
11576 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011577 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011578 }
Eric Andersenc470f442003-07-28 09:56:35 +000011579 scopy("./trace", s);
11580 if (tracefile) {
11581 if (!freopen(s, "a", tracefile)) {
11582 fprintf(stderr, "Can't re-open %s\n", s);
11583 debug = 0;
11584 return;
11585 }
11586 } else {
11587 if ((tracefile = fopen(s, "a")) == NULL) {
11588 fprintf(stderr, "Can't open %s\n", s);
11589 debug = 0;
11590 return;
11591 }
11592 }
Eric Andersencb57d552001-06-28 07:25:16 +000011593#ifdef O_APPEND
11594 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11595 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11596#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011597 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011598 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011599}
Eric Andersenc470f442003-07-28 09:56:35 +000011600#endif /* DEBUG */
11601
11602
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011603/* trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011604
11605/*
11606 * Sigmode records the current value of the signal handlers for the various
11607 * modes. A value of zero means that the current handler is not known.
11608 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11609 */
11610
11611#define S_DFL 1 /* default signal handling (SIG_DFL) */
11612#define S_CATCH 2 /* signal is caught */
11613#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11614#define S_HARD_IGN 4 /* signal is ignored permenantly */
11615#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11616
Eric Andersencb57d552001-06-28 07:25:16 +000011617
11618
11619/*
Eric Andersencb57d552001-06-28 07:25:16 +000011620 * The trap builtin.
11621 */
11622
Eric Andersenc470f442003-07-28 09:56:35 +000011623int
11624trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011625{
11626 char *action;
11627 char **ap;
11628 int signo;
11629
Eric Andersenc470f442003-07-28 09:56:35 +000011630 nextopt(nullstr);
11631 ap = argptr;
11632 if (!*ap) {
11633 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011634 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011635 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011636
Rob Landleyc9c1a412006-07-12 19:17:55 +000011637 sn = get_signame(signo);
Eric Andersenc470f442003-07-28 09:56:35 +000011638 out1fmt("trap -- %s %s\n",
11639 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011640 }
11641 }
11642 return 0;
11643 }
Eric Andersenc470f442003-07-28 09:56:35 +000011644 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011645 action = NULL;
11646 else
11647 action = *ap++;
11648 while (*ap) {
Rob Landleyc9c1a412006-07-12 19:17:55 +000011649 if ((signo = get_signum(*ap)) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011650 sh_error("%s: bad trap", *ap);
Eric Andersencb57d552001-06-28 07:25:16 +000011651 INTOFF;
11652 if (action) {
11653 if (action[0] == '-' && action[1] == '\0')
11654 action = NULL;
11655 else
Eric Andersenc470f442003-07-28 09:56:35 +000011656 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011657 }
Eric Andersenc470f442003-07-28 09:56:35 +000011658 if (trap[signo])
11659 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011660 trap[signo] = action;
11661 if (signo != 0)
11662 setsignal(signo);
11663 INTON;
11664 ap++;
11665 }
11666 return 0;
11667}
11668
11669
Eric Andersenc470f442003-07-28 09:56:35 +000011670/*
11671 * Clear traps on a fork.
11672 */
11673
11674void
11675clear_traps(void)
11676{
11677 char **tp;
11678
11679 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11680 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11681 INTOFF;
11682 ckfree(*tp);
11683 *tp = NULL;
11684 if (tp != &trap[0])
11685 setsignal(tp - trap);
11686 INTON;
11687 }
11688 }
11689}
11690
11691
Eric Andersencb57d552001-06-28 07:25:16 +000011692/*
11693 * Set the signal handler for the specified signal. The routine figures
11694 * out what it should be set to.
11695 */
11696
Eric Andersenc470f442003-07-28 09:56:35 +000011697void
11698setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011699{
11700 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011701 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011702 struct sigaction act;
11703
11704 if ((t = trap[signo]) == NULL)
11705 action = S_DFL;
11706 else if (*t != '\0')
11707 action = S_CATCH;
11708 else
11709 action = S_IGN;
11710 if (rootshell && action == S_DFL) {
11711 switch (signo) {
11712 case SIGINT:
11713 if (iflag || minusc || sflag == 0)
11714 action = S_CATCH;
11715 break;
11716 case SIGQUIT:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011717#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011718 if (debug)
11719 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011720#endif
11721 /* FALLTHROUGH */
11722 case SIGTERM:
11723 if (iflag)
11724 action = S_IGN;
11725 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011726#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011727 case SIGTSTP:
11728 case SIGTTOU:
11729 if (mflag)
11730 action = S_IGN;
11731 break;
11732#endif
11733 }
11734 }
11735
11736 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011737 tsig = *t;
11738 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011739 /*
11740 * current setting unknown
11741 */
11742 if (sigaction(signo, 0, &act) == -1) {
11743 /*
11744 * Pretend it worked; maybe we should give a warning
11745 * here, but other shells don't. We don't alter
11746 * sigmode, so that we retry every time.
11747 */
11748 return;
11749 }
11750 if (act.sa_handler == SIG_IGN) {
11751 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011752 signo == SIGTTIN || signo == SIGTTOU)) {
11753 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011754 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011755 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011756 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011757 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011758 }
11759 }
Eric Andersenc470f442003-07-28 09:56:35 +000011760 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011761 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011762 switch (action) {
11763 case S_CATCH:
11764 act.sa_handler = onsig;
11765 break;
11766 case S_IGN:
11767 act.sa_handler = SIG_IGN;
11768 break;
11769 default:
11770 act.sa_handler = SIG_DFL;
11771 }
Eric Andersencb57d552001-06-28 07:25:16 +000011772 *t = action;
11773 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011774 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011775 sigaction(signo, &act, 0);
11776}
11777
11778/*
11779 * Ignore a signal.
11780 */
11781
Eric Andersenc470f442003-07-28 09:56:35 +000011782void
11783ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011784{
11785 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11786 signal(signo, SIG_IGN);
11787 }
11788 sigmode[signo - 1] = S_HARD_IGN;
11789}
11790
11791
Eric Andersencb57d552001-06-28 07:25:16 +000011792/*
11793 * Signal handler.
11794 */
11795
Eric Andersenc470f442003-07-28 09:56:35 +000011796void
11797onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011798{
Eric Andersencb57d552001-06-28 07:25:16 +000011799 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011800 pendingsigs = signo;
11801
11802 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11803 if (!suppressint)
11804 onint();
11805 intpending = 1;
11806 }
Eric Andersencb57d552001-06-28 07:25:16 +000011807}
11808
11809
Eric Andersencb57d552001-06-28 07:25:16 +000011810/*
11811 * Called to execute a trap. Perhaps we should avoid entering new trap
11812 * handlers while we are executing a trap handler.
11813 */
11814
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011815int
Eric Andersenc470f442003-07-28 09:56:35 +000011816dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011817{
Eric Andersenc470f442003-07-28 09:56:35 +000011818 char *p;
11819 char *q;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011820 int i;
Eric Andersencb57d552001-06-28 07:25:16 +000011821 int savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011822 int skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011823
Eric Andersenc470f442003-07-28 09:56:35 +000011824 savestatus = exitstatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011825 pendingsigs = 0;
11826 xbarrier();
11827
11828 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11829 if (!*q)
11830 continue;
11831 *q = 0;
11832
11833 p = trap[i + 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011834 if (!p)
11835 continue;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011836 skip = evalstring(p, SKIPEVAL);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011837 exitstatus = savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011838 if (skip)
11839 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011840 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011841
11842 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +000011843}
11844
Eric Andersenc470f442003-07-28 09:56:35 +000011845
Eric Andersenc470f442003-07-28 09:56:35 +000011846/*
11847 * Controls whether the shell is interactive or not.
11848 */
11849
Eric Andersenc470f442003-07-28 09:56:35 +000011850void
11851setinteractive(int on)
11852{
11853 static int is_interactive;
11854
11855 if (++on == is_interactive)
11856 return;
11857 is_interactive = on;
11858 setsignal(SIGINT);
11859 setsignal(SIGQUIT);
11860 setsignal(SIGTERM);
11861#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11862 if(is_interactive > 1) {
11863 /* Looks like they want an interactive shell */
11864 static int do_banner;
11865
11866 if(!do_banner) {
11867 out1fmt(
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +000011868 "\n\n%s Built-in shell (ash)\n"
11869 "Enter 'help' for a list of built-in commands.\n\n",
11870 BB_BANNER);
Eric Andersenc470f442003-07-28 09:56:35 +000011871 do_banner++;
11872 }
11873 }
11874#endif
11875}
11876
11877
11878#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11879/*** List the available builtins ***/
11880
11881static int helpcmd(int argc, char **argv)
11882{
11883 int col, i;
11884
11885 out1fmt("\nBuilt-in commands:\n-------------------\n");
11886 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11887 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11888 builtincmd[i].name + 1);
11889 if (col > 60) {
11890 out1fmt("\n");
11891 col = 0;
11892 }
11893 }
11894#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11895 {
11896 extern const struct BB_applet applets[];
11897 extern const size_t NUM_APPLETS;
11898
11899 for (i = 0; i < NUM_APPLETS; i++) {
11900
11901 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11902 if (col > 60) {
11903 out1fmt("\n");
11904 col = 0;
11905 }
11906 }
11907 }
11908#endif
11909 out1fmt("\n\n");
11910 return EXIT_SUCCESS;
11911}
11912#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11913
Eric Andersencb57d552001-06-28 07:25:16 +000011914/*
11915 * Called to exit the shell.
11916 */
11917
Eric Andersenc470f442003-07-28 09:56:35 +000011918void
11919exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011920{
Eric Andersenc470f442003-07-28 09:56:35 +000011921 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011922 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011923 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011924
Eric Andersenc470f442003-07-28 09:56:35 +000011925 status = exitstatus;
11926 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011927 if (setjmp(loc.loc)) {
11928 if (exception == EXEXIT)
11929 _exit(exitstatus);
Eric Andersenc470f442003-07-28 09:56:35 +000011930 goto out;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011931 }
Eric Andersenc470f442003-07-28 09:56:35 +000011932 handler = &loc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011933 if ((p = trap[0])) {
Eric Andersencb57d552001-06-28 07:25:16 +000011934 trap[0] = NULL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011935 evalstring(p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011936 }
Eric Andersencb57d552001-06-28 07:25:16 +000011937 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011938 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011939#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11940 if (iflag && rootshell) {
11941 const char *hp = lookupvar("HISTFILE");
11942
11943 if(hp != NULL )
11944 save_history ( hp );
11945 }
11946#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011947out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011948 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011949 /* NOTREACHED */
11950}
11951
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011952/* var.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011953
11954static struct var *vartab[VTABSIZE];
11955
11956static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011957static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011958
11959/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011960 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011961 */
11962
Eric Andersenc470f442003-07-28 09:56:35 +000011963
11964#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011965/*
Eric Andersenc470f442003-07-28 09:56:35 +000011966 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011967 */
11968
Eric Andersenc470f442003-07-28 09:56:35 +000011969int
11970setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011971{
Eric Andersenc470f442003-07-28 09:56:35 +000011972 int err;
11973 volatile int saveint;
11974 struct jmploc *volatile savehandler = handler;
11975 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011976
Eric Andersenc470f442003-07-28 09:56:35 +000011977 SAVEINT(saveint);
11978 if (setjmp(jmploc.loc))
11979 err = 1;
11980 else {
11981 handler = &jmploc;
11982 setvar(name, val, flags);
11983 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011984 }
Eric Andersenc470f442003-07-28 09:56:35 +000011985 handler = savehandler;
11986 RESTOREINT(saveint);
11987 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011988}
Eric Andersenc470f442003-07-28 09:56:35 +000011989#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011990
11991/*
11992 * Set the value of a variable. The flags argument is ored with the
11993 * flags of the variable. If val is NULL, the variable is unset.
11994 */
11995
Eric Andersenc470f442003-07-28 09:56:35 +000011996static void
11997setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011998{
Eric Andersenc470f442003-07-28 09:56:35 +000011999 char *p, *q;
12000 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000012001 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000012002 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000012003
Eric Andersenc470f442003-07-28 09:56:35 +000012004 q = endofname(name);
12005 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012006 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000012007 if (!namelen || p != q)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012008 sh_error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012009 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012010 if (val == NULL) {
12011 flags |= VUNSET;
12012 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012013 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000012014 }
12015 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012016 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
Paul Fox8de331d2005-07-21 12:03:05 +000012017 if (val) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012018 *p++ = '=';
Eric Andersenc470f442003-07-28 09:56:35 +000012019 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000012020 }
Eric Andersenc470f442003-07-28 09:56:35 +000012021 *p = '\0';
12022 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012023 INTON;
12024}
12025
12026
Eric Andersencb57d552001-06-28 07:25:16 +000012027/*
12028 * Same as setvar except that the variable and value are passed in
12029 * the first argument as name=value. Since the first argument will
12030 * be actually stored in the table, it should not be a string that
12031 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012032 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012033 */
12034
Eric Andersenc470f442003-07-28 09:56:35 +000012035void
12036setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012037{
12038 struct var *vp, **vpp;
12039
12040 vpp = hashvar(s);
12041 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012042 vp = *findvar(vpp, s);
12043 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012044 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12045 const char *n;
12046
Eric Andersenc470f442003-07-28 09:56:35 +000012047 if (flags & VNOSAVE)
12048 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012049 n = vp->text;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012050 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012051 }
Eric Andersenc470f442003-07-28 09:56:35 +000012052
12053 if (flags & VNOSET)
12054 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012055
12056 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012057 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012058
Eric Andersenc470f442003-07-28 09:56:35 +000012059 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12060 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012061
Eric Andersenc470f442003-07-28 09:56:35 +000012062 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12063 } else {
12064 if (flags & VNOSET)
12065 return;
12066 /* not found */
12067 vp = ckmalloc(sizeof (*vp));
12068 vp->next = *vpp;
12069 vp->func = NULL;
12070 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012071 }
Eric Andersenc470f442003-07-28 09:56:35 +000012072 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12073 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012074 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012075 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012076}
12077
12078
Eric Andersencb57d552001-06-28 07:25:16 +000012079/*
12080 * Process a linked list of variable assignments.
12081 */
12082
Eric Andersenc470f442003-07-28 09:56:35 +000012083static void
12084listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012085{
Eric Andersenc470f442003-07-28 09:56:35 +000012086 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012087
Eric Andersenc470f442003-07-28 09:56:35 +000012088 if (!lp)
12089 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012090 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012091 do {
12092 setvareq(lp->text, flags);
12093 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012094 INTON;
12095}
12096
12097
Eric Andersencb57d552001-06-28 07:25:16 +000012098/*
12099 * Find the value of a variable. Returns NULL if not set.
12100 */
12101
Eric Andersenc470f442003-07-28 09:56:35 +000012102static char *
12103lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012104{
Eric Andersencb57d552001-06-28 07:25:16 +000012105 struct var *v;
12106
Eric Andersen16767e22004-03-16 05:14:10 +000012107 if ((v = *findvar(hashvar(name), name))) {
12108#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012109 /*
12110 * Dynamic variables are implemented roughly the same way they are
12111 * in bash. Namely, they're "special" so long as they aren't unset.
12112 * As soon as they're unset, they're no longer dynamic, and dynamic
12113 * lookup will no longer happen at that point. -- PFM.
12114 */
Eric Andersen16767e22004-03-16 05:14:10 +000012115 if((v->flags & VDYNAMIC))
12116 (*v->func)(NULL);
12117#endif
12118 if(!(v->flags & VUNSET))
12119 return strchrnul(v->text, '=') + 1;
12120 }
Eric Andersenef02f822004-03-11 13:34:24 +000012121
Eric Andersencb57d552001-06-28 07:25:16 +000012122 return NULL;
12123}
12124
12125
Eric Andersencb57d552001-06-28 07:25:16 +000012126/*
12127 * Search the environment of a builtin command.
12128 */
12129
Eric Andersenc470f442003-07-28 09:56:35 +000012130static char *
12131bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012132{
Eric Andersenc470f442003-07-28 09:56:35 +000012133 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012134
Eric Andersenc470f442003-07-28 09:56:35 +000012135 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012136 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012137 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012138 }
12139 return lookupvar(name);
12140}
12141
12142
Eric Andersencb57d552001-06-28 07:25:16 +000012143/*
Eric Andersenc470f442003-07-28 09:56:35 +000012144 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012145 */
12146
Eric Andersenc470f442003-07-28 09:56:35 +000012147static char **
12148listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012149{
Eric Andersencb57d552001-06-28 07:25:16 +000012150 struct var **vpp;
12151 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012152 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012153 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012154
Eric Andersenc470f442003-07-28 09:56:35 +000012155 STARTSTACKSTR(ep);
12156 vpp = vartab;
12157 mask = on | off;
12158 do {
12159 for (vp = *vpp ; vp ; vp = vp->next)
12160 if ((vp->flags & mask) == on) {
12161 if (ep == stackstrend())
12162 ep = growstackstr();
12163 *ep++ = (char *) vp->text;
12164 }
12165 } while (++vpp < vartab + VTABSIZE);
12166 if (ep == stackstrend())
12167 ep = growstackstr();
12168 if (end)
12169 *end = ep;
12170 *ep++ = NULL;
12171 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012172}
12173
12174
12175/*
Eric Andersenc470f442003-07-28 09:56:35 +000012176 * POSIX requires that 'set' (but not export or readonly) output the
12177 * variables in lexicographic order - by the locale's collating order (sigh).
12178 * Maybe we could keep them in an ordered balanced binary tree
12179 * instead of hashed lists.
12180 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012181 */
12182
Eric Andersenc470f442003-07-28 09:56:35 +000012183static int
12184showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012185{
Eric Andersenc470f442003-07-28 09:56:35 +000012186 const char *sep;
12187 char **ep, **epend;
12188
12189 ep = listvars(on, off, &epend);
12190 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12191
12192 sep = *sep_prefix ? spcstr : sep_prefix;
12193
12194 for (; ep < epend; ep++) {
12195 const char *p;
12196 const char *q;
12197
12198 p = strchrnul(*ep, '=');
12199 q = nullstr;
12200 if (*p)
12201 q = single_quote(++p);
12202
12203 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12204 }
12205
Eric Andersencb57d552001-06-28 07:25:16 +000012206 return 0;
12207}
12208
12209
12210
12211/*
12212 * The export and readonly commands.
12213 */
12214
Eric Andersenc470f442003-07-28 09:56:35 +000012215static int
12216exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012217{
12218 struct var *vp;
12219 char *name;
12220 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012221 char **aptr;
12222 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12223 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012224
Eric Andersenc470f442003-07-28 09:56:35 +000012225 notp = nextopt("p") - 'p';
12226 if (notp && ((name = *(aptr = argptr)))) {
12227 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012228 if ((p = strchr(name, '=')) != NULL) {
12229 p++;
12230 } else {
12231 if ((vp = *findvar(hashvar(name), name))) {
12232 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012233 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012234 }
12235 }
12236 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012237 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012238 } else {
12239 showvars(argv[0], flag, 0);
12240 }
12241 return 0;
12242}
12243
Eric Andersen34506362001-08-02 05:02:46 +000012244
Eric Andersencb57d552001-06-28 07:25:16 +000012245/*
Eric Andersencb57d552001-06-28 07:25:16 +000012246 * Make a variable a local variable. When a variable is made local, it's
12247 * value and flags are saved in a localvar structure. The saved values
12248 * will be restored when the shell function returns. We handle the name
12249 * "-" as a special case.
12250 */
12251
Rob Landley88621d72006-08-29 19:41:06 +000012252static void mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012253{
Eric Andersencb57d552001-06-28 07:25:16 +000012254 struct localvar *lvp;
12255 struct var **vpp;
12256 struct var *vp;
12257
12258 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012259 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012260 if (name[0] == '-' && name[1] == '\0') {
12261 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012262 p = ckmalloc(sizeof(optlist));
12263 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012264 vp = NULL;
12265 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012266 char *eq;
12267
Eric Andersencb57d552001-06-28 07:25:16 +000012268 vpp = hashvar(name);
12269 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012270 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012271 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012272 if (eq)
12273 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012274 else
12275 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012276 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012277 lvp->flags = VUNSET;
12278 } else {
12279 lvp->text = vp->text;
12280 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012281 vp->flags |= VSTRFIXED|VTEXTFIXED;
12282 if (eq)
12283 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012284 }
12285 }
12286 lvp->vp = vp;
12287 lvp->next = localvars;
12288 localvars = lvp;
12289 INTON;
12290}
12291
Eric Andersenc470f442003-07-28 09:56:35 +000012292/*
12293 * The "local" command.
12294 */
12295
12296static int
12297localcmd(int argc, char **argv)
12298{
12299 char *name;
12300
12301 argv = argptr;
12302 while ((name = *argv++) != NULL) {
12303 mklocal(name);
12304 }
12305 return 0;
12306}
12307
12308
Eric Andersencb57d552001-06-28 07:25:16 +000012309/*
12310 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012311 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012312 */
12313
Eric Andersenc470f442003-07-28 09:56:35 +000012314static void
12315poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012316{
Eric Andersencb57d552001-06-28 07:25:16 +000012317 struct localvar *lvp;
12318 struct var *vp;
12319
12320 while ((lvp = localvars) != NULL) {
12321 localvars = lvp->next;
12322 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012323 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12324 if (vp == NULL) { /* $- saved */
12325 memcpy(optlist, lvp->text, sizeof(optlist));
12326 ckfree(lvp->text);
12327 optschanged();
12328 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12329 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012330 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012331 if (vp->func)
12332 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12333 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12334 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012335 vp->flags = lvp->flags;
12336 vp->text = lvp->text;
12337 }
Eric Andersenc470f442003-07-28 09:56:35 +000012338 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012339 }
12340}
12341
12342
Eric Andersencb57d552001-06-28 07:25:16 +000012343/*
12344 * The unset builtin command. We unset the function before we unset the
12345 * variable to allow a function to be unset when there is a readonly variable
12346 * with the same name.
12347 */
12348
Eric Andersenc470f442003-07-28 09:56:35 +000012349int
12350unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012351{
12352 char **ap;
12353 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012354 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012355 int ret = 0;
12356
12357 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012358 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012359 }
Eric Andersencb57d552001-06-28 07:25:16 +000012360
Eric Andersenc470f442003-07-28 09:56:35 +000012361 for (ap = argptr; *ap ; ap++) {
12362 if (flag != 'f') {
12363 i = unsetvar(*ap);
12364 ret |= i;
12365 if (!(i & 2))
12366 continue;
12367 }
12368 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012369 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012370 }
Eric Andersenc470f442003-07-28 09:56:35 +000012371 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012372}
12373
12374
12375/*
12376 * Unset the specified variable.
12377 */
12378
Eric Andersenc470f442003-07-28 09:56:35 +000012379int
12380unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012381{
Eric Andersencb57d552001-06-28 07:25:16 +000012382 struct var **vpp;
12383 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012384 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012385
12386 vpp = findvar(hashvar(s), s);
12387 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012388 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012389 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012390 int flags = vp->flags;
12391
12392 retval = 1;
12393 if (flags & VREADONLY)
12394 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012395#ifdef DYNAMIC_VAR
12396 vp->flags &= ~VDYNAMIC;
12397#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012398 if (flags & VUNSET)
12399 goto ok;
12400 if ((flags & VSTRFIXED) == 0) {
12401 INTOFF;
12402 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12403 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012404 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012405 ckfree(vp);
12406 INTON;
12407 } else {
12408 setvar(s, 0, 0);
12409 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012410 }
Eric Andersenc470f442003-07-28 09:56:35 +000012411ok:
12412 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012413 }
12414
Eric Andersenc470f442003-07-28 09:56:35 +000012415out:
12416 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012417}
12418
12419
12420
12421/*
12422 * Find the appropriate entry in the hash table from the name.
12423 */
12424
Eric Andersenc470f442003-07-28 09:56:35 +000012425static struct var **
12426hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012427{
Eric Andersencb57d552001-06-28 07:25:16 +000012428 unsigned int hashval;
12429
12430 hashval = ((unsigned char) *p) << 4;
12431 while (*p && *p != '=')
12432 hashval += (unsigned char) *p++;
12433 return &vartab[hashval % VTABSIZE];
12434}
12435
12436
12437
12438/*
Eric Andersenc470f442003-07-28 09:56:35 +000012439 * Compares two strings up to the first = or '\0'. The first
12440 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012441 * either '=' or '\0'.
12442 */
12443
Eric Andersenc470f442003-07-28 09:56:35 +000012444int
12445varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012446{
Eric Andersenc470f442003-07-28 09:56:35 +000012447 int c, d;
12448
12449 while ((c = *p) == (d = *q)) {
12450 if (!c || c == '=')
12451 goto out;
12452 p++;
12453 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012454 }
Eric Andersenc470f442003-07-28 09:56:35 +000012455 if (c == '=')
12456 c = 0;
12457 if (d == '=')
12458 d = 0;
12459out:
12460 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012461}
12462
Eric Andersenc470f442003-07-28 09:56:35 +000012463static int
12464vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012465{
Eric Andersenc470f442003-07-28 09:56:35 +000012466 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012467}
12468
Eric Andersenc470f442003-07-28 09:56:35 +000012469static struct var **
12470findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012471{
12472 for (; *vpp; vpp = &(*vpp)->next) {
12473 if (varequal((*vpp)->text, name)) {
12474 break;
12475 }
12476 }
12477 return vpp;
12478}
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012479/* setmode.c */
Eric Andersencb57d552001-06-28 07:25:16 +000012480
Eric Andersenc470f442003-07-28 09:56:35 +000012481#include <sys/times.h>
12482
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012483static const unsigned char timescmd_str[] = {
12484 ' ', offsetof(struct tms, tms_utime),
12485 '\n', offsetof(struct tms, tms_stime),
12486 ' ', offsetof(struct tms, tms_cutime),
12487 '\n', offsetof(struct tms, tms_cstime),
12488 0
12489};
Eric Andersencb57d552001-06-28 07:25:16 +000012490
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012491static int timescmd(int ac, char **av)
12492{
12493 long int clk_tck, s, t;
12494 const unsigned char *p;
12495 struct tms buf;
12496
12497 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012498 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012499
12500 p = timescmd_str;
12501 do {
12502 t = *(clock_t *)(((char *) &buf) + p[1]);
12503 s = t / clk_tck;
12504 out1fmt("%ldm%ld.%.3lds%c",
12505 s/60, s%60,
12506 ((t - s * clk_tck) * 1000) / clk_tck,
12507 p[0]);
12508 } while (*(p += 2));
12509
Eric Andersencb57d552001-06-28 07:25:16 +000012510 return 0;
12511}
12512
Eric Andersend35c5df2002-01-09 15:37:36 +000012513#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012514static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012515dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012516{
Eric Andersened9ecf72004-06-22 08:29:45 +000012517 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012518 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012519
Eric Andersenc470f442003-07-28 09:56:35 +000012520 INTOFF;
12521 result = arith(s, &errcode);
12522 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012523 if (errcode == -3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012524 sh_error("exponent less than 0");
Eric Andersen90898442003-08-06 11:20:52 +000012525 else if (errcode == -2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012526 sh_error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012527 else if (errcode == -5)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012528 sh_error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012529 else
12530 synerror(s);
12531 }
12532 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012533
Eric Andersenc470f442003-07-28 09:56:35 +000012534 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012535}
Eric Andersenc470f442003-07-28 09:56:35 +000012536
12537
12538/*
Eric Andersen90898442003-08-06 11:20:52 +000012539 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12540 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12541 *
12542 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012543 */
Eric Andersen90898442003-08-06 11:20:52 +000012544
Eric Andersenc470f442003-07-28 09:56:35 +000012545static int
Eric Andersen90898442003-08-06 11:20:52 +000012546letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012547{
Eric Andersenc470f442003-07-28 09:56:35 +000012548 char **ap;
Denis Vlasenkocba9ef52006-10-10 21:00:47 +000012549 arith_t i = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012550
Eric Andersen90898442003-08-06 11:20:52 +000012551 ap = argv + 1;
12552 if(!*ap)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012553 sh_error("expression expected");
Eric Andersen90898442003-08-06 11:20:52 +000012554 for (ap = argv + 1; *ap; ap++) {
12555 i = dash_arith(*ap);
12556 }
Eric Andersenc470f442003-07-28 09:56:35 +000012557
Eric Andersen90898442003-08-06 11:20:52 +000012558 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012559}
12560#endif /* CONFIG_ASH_MATH_SUPPORT */
12561
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012562/* miscbltin.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012563
12564/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012565 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012566 */
12567
12568#undef rflag
12569
12570#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012571#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012572typedef enum __rlimit_resource rlim_t;
12573#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012574#endif
12575
12576
Eric Andersenc470f442003-07-28 09:56:35 +000012577/*
12578 * The read builtin. The -e option causes backslashes to escape the
12579 * following character.
12580 *
12581 * This uses unbuffered input, which may be avoidable in some cases.
12582 */
12583
12584static int
12585readcmd(int argc, char **argv)
12586{
12587 char **ap;
12588 int backslash;
12589 char c;
12590 int rflag;
12591 char *prompt;
12592 const char *ifs;
12593 char *p;
12594 int startword;
12595 int status;
12596 int i;
Paul Fox02eb9342005-09-07 16:56:02 +000012597#if defined(CONFIG_ASH_READ_NCHARS)
12598 int nch_flag = 0;
12599 int nchars = 0;
12600 int silent = 0;
12601 struct termios tty, old_tty;
12602#endif
12603#if defined(CONFIG_ASH_READ_TIMEOUT)
12604 fd_set set;
12605 struct timeval ts;
12606
12607 ts.tv_sec = ts.tv_usec = 0;
12608#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012609
12610 rflag = 0;
12611 prompt = NULL;
Paul Fox02eb9342005-09-07 16:56:02 +000012612#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12613 while ((i = nextopt("p:rt:n:s")) != '\0')
12614#elif defined(CONFIG_ASH_READ_NCHARS)
12615 while ((i = nextopt("p:rn:s")) != '\0')
12616#elif defined(CONFIG_ASH_READ_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012617 while ((i = nextopt("p:rt:")) != '\0')
12618#else
12619 while ((i = nextopt("p:r")) != '\0')
12620#endif
12621 {
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012622 switch(i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012623 case 'p':
Eric Andersenc470f442003-07-28 09:56:35 +000012624 prompt = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012625 break;
12626#if defined(CONFIG_ASH_READ_NCHARS)
12627 case 'n':
12628 nchars = strtol(optionarg, &p, 10);
12629 if (*p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012630 sh_error("invalid count");
Paul Fox02eb9342005-09-07 16:56:02 +000012631 nch_flag = (nchars > 0);
12632 break;
12633 case 's':
12634 silent = 1;
12635 break;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012636#endif
Paul Fox02eb9342005-09-07 16:56:02 +000012637#if defined(CONFIG_ASH_READ_TIMEOUT)
12638 case 't':
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012639 ts.tv_sec = strtol(optionarg, &p, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012640 ts.tv_usec = 0;
12641 if (*p == '.') {
12642 char *p2;
12643 if (*++p) {
12644 int scale;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012645 ts.tv_usec = strtol(p, &p2, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012646 if (*p2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012647 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012648 scale = p2 - p;
12649 /* normalize to usec */
12650 if (scale > 6)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012651 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012652 while (scale++ < 6)
12653 ts.tv_usec *= 10;
12654 }
12655 } else if (*p) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012656 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012657 }
12658 if ( ! ts.tv_sec && ! ts.tv_usec)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012659 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012660 break;
12661#endif
12662 case 'r':
12663 rflag = 1;
12664 break;
12665 default:
12666 break;
12667 }
Eric Andersenc470f442003-07-28 09:56:35 +000012668 }
12669 if (prompt && isatty(0)) {
12670 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012671 }
12672 if (*(ap = argptr) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012673 sh_error("arg count");
Eric Andersenc470f442003-07-28 09:56:35 +000012674 if ((ifs = bltinlookup("IFS")) == NULL)
12675 ifs = defifs;
Paul Fox02eb9342005-09-07 16:56:02 +000012676#if defined(CONFIG_ASH_READ_NCHARS)
12677 if (nch_flag || silent) {
12678 tcgetattr(0, &tty);
12679 old_tty = tty;
12680 if (nch_flag) {
12681 tty.c_lflag &= ~ICANON;
12682 tty.c_cc[VMIN] = nchars;
12683 }
12684 if (silent) {
12685 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12686
12687 }
12688 tcsetattr(0, TCSANOW, &tty);
12689 }
12690#endif
12691#if defined(CONFIG_ASH_READ_TIMEOUT)
12692 if (ts.tv_sec || ts.tv_usec) {
12693 FD_ZERO (&set);
12694 FD_SET (0, &set);
12695
12696 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12697 if (!i) {
12698#if defined(CONFIG_ASH_READ_NCHARS)
12699 if (nch_flag)
12700 tcsetattr(0, TCSANOW, &old_tty);
12701#endif
12702 return 1;
12703 }
12704 }
Ned Ludd2123b7c2005-02-09 21:07:23 +000012705#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012706 status = 0;
12707 startword = 1;
12708 backslash = 0;
12709 STARTSTACKSTR(p);
Paul Fox02eb9342005-09-07 16:56:02 +000012710#if defined(CONFIG_ASH_READ_NCHARS)
12711 while (!nch_flag || nchars--)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012712#else
12713 for (;;)
12714#endif
12715 {
Eric Andersenc470f442003-07-28 09:56:35 +000012716 if (read(0, &c, 1) != 1) {
12717 status = 1;
12718 break;
12719 }
12720 if (c == '\0')
12721 continue;
12722 if (backslash) {
12723 backslash = 0;
12724 if (c != '\n')
12725 goto put;
12726 continue;
12727 }
12728 if (!rflag && c == '\\') {
12729 backslash++;
12730 continue;
12731 }
12732 if (c == '\n')
12733 break;
12734 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12735 continue;
12736 }
12737 startword = 0;
12738 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12739 STACKSTRNUL(p);
12740 setvar(*ap, stackblock(), 0);
12741 ap++;
12742 startword = 1;
12743 STARTSTACKSTR(p);
12744 } else {
12745put:
12746 STPUTC(c, p);
12747 }
12748 }
Paul Fox02eb9342005-09-07 16:56:02 +000012749#if defined(CONFIG_ASH_READ_NCHARS)
12750 if (nch_flag || silent)
12751 tcsetattr(0, TCSANOW, &old_tty);
12752#endif
12753
Eric Andersenc470f442003-07-28 09:56:35 +000012754 STACKSTRNUL(p);
12755 /* Remove trailing blanks */
12756 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12757 *p = '\0';
12758 setvar(*ap, stackblock(), 0);
12759 while (*++ap != NULL)
12760 setvar(*ap, nullstr, 0);
12761 return status;
12762}
12763
12764
12765static int umaskcmd(int argc, char **argv)
12766{
12767 static const char permuser[3] = "ugo";
12768 static const char permmode[3] = "rwx";
12769 static const short int permmask[] = {
12770 S_IRUSR, S_IWUSR, S_IXUSR,
12771 S_IRGRP, S_IWGRP, S_IXGRP,
12772 S_IROTH, S_IWOTH, S_IXOTH
12773 };
12774
12775 char *ap;
12776 mode_t mask;
12777 int i;
12778 int symbolic_mode = 0;
12779
12780 while (nextopt("S") != '\0') {
12781 symbolic_mode = 1;
12782 }
12783
12784 INTOFF;
12785 mask = umask(0);
12786 umask(mask);
12787 INTON;
12788
12789 if ((ap = *argptr) == NULL) {
12790 if (symbolic_mode) {
12791 char buf[18];
12792 char *p = buf;
12793
12794 for (i = 0; i < 3; i++) {
12795 int j;
12796
12797 *p++ = permuser[i];
12798 *p++ = '=';
12799 for (j = 0; j < 3; j++) {
12800 if ((mask & permmask[3 * i + j]) == 0) {
12801 *p++ = permmode[j];
12802 }
12803 }
12804 *p++ = ',';
12805 }
12806 *--p = 0;
12807 puts(buf);
12808 } else {
12809 out1fmt("%.4o\n", mask);
12810 }
12811 } else {
12812 if (is_digit((unsigned char) *ap)) {
12813 mask = 0;
12814 do {
12815 if (*ap >= '8' || *ap < '0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012816 sh_error(illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012817 mask = (mask << 3) + (*ap - '0');
12818 } while (*++ap != '\0');
12819 umask(mask);
12820 } else {
12821 mask = ~mask & 0777;
12822 if (!bb_parse_mode(ap, &mask)) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012823 sh_error("Illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012824 }
12825 umask(~mask & 0777);
12826 }
12827 }
12828 return 0;
12829}
12830
12831/*
12832 * ulimit builtin
12833 *
12834 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12835 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12836 * ash by J.T. Conklin.
12837 *
12838 * Public domain.
12839 */
12840
12841struct limits {
12842 const char *name;
12843 int cmd;
12844 int factor; /* multiply by to get rlim_{cur,max} values */
12845 char option;
12846};
12847
12848static const struct limits limits[] = {
12849#ifdef RLIMIT_CPU
12850 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12851#endif
12852#ifdef RLIMIT_FSIZE
12853 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12854#endif
12855#ifdef RLIMIT_DATA
12856 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12857#endif
12858#ifdef RLIMIT_STACK
12859 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12860#endif
12861#ifdef RLIMIT_CORE
12862 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12863#endif
12864#ifdef RLIMIT_RSS
12865 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12866#endif
12867#ifdef RLIMIT_MEMLOCK
12868 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12869#endif
12870#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012871 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012872#endif
12873#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012874 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012875#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012876#ifdef RLIMIT_AS
12877 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012878#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012879#ifdef RLIMIT_LOCKS
12880 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012881#endif
12882 { (char *) 0, 0, 0, '\0' }
12883};
12884
Glenn L McGrath76620622004-01-13 10:19:37 +000012885enum limtype { SOFT = 0x1, HARD = 0x2 };
12886
12887static void printlim(enum limtype how, const struct rlimit *limit,
12888 const struct limits *l)
12889{
12890 rlim_t val;
12891
12892 val = limit->rlim_max;
12893 if (how & SOFT)
12894 val = limit->rlim_cur;
12895
12896 if (val == RLIM_INFINITY)
12897 out1fmt("unlimited\n");
12898 else {
12899 val /= l->factor;
12900 out1fmt("%lld\n", (long long) val);
12901 }
12902}
12903
Eric Andersenc470f442003-07-28 09:56:35 +000012904int
12905ulimitcmd(int argc, char **argv)
12906{
12907 int c;
12908 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012909 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012910 const struct limits *l;
12911 int set, all = 0;
12912 int optc, what;
12913 struct rlimit limit;
12914
12915 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012916 while ((optc = nextopt("HSa"
12917#ifdef RLIMIT_CPU
12918 "t"
12919#endif
12920#ifdef RLIMIT_FSIZE
12921 "f"
12922#endif
12923#ifdef RLIMIT_DATA
12924 "d"
12925#endif
12926#ifdef RLIMIT_STACK
12927 "s"
12928#endif
12929#ifdef RLIMIT_CORE
12930 "c"
12931#endif
12932#ifdef RLIMIT_RSS
12933 "m"
12934#endif
12935#ifdef RLIMIT_MEMLOCK
12936 "l"
12937#endif
12938#ifdef RLIMIT_NPROC
12939 "p"
12940#endif
12941#ifdef RLIMIT_NOFILE
12942 "n"
12943#endif
12944#ifdef RLIMIT_AS
12945 "v"
12946#endif
12947#ifdef RLIMIT_LOCKS
12948 "w"
12949#endif
12950 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012951 switch (optc) {
12952 case 'H':
12953 how = HARD;
12954 break;
12955 case 'S':
12956 how = SOFT;
12957 break;
12958 case 'a':
12959 all = 1;
12960 break;
12961 default:
12962 what = optc;
12963 }
12964
Glenn L McGrath76620622004-01-13 10:19:37 +000012965 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012966 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012967
12968 set = *argptr ? 1 : 0;
12969 if (set) {
12970 char *p = *argptr;
12971
12972 if (all || argptr[1])
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012973 sh_error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012974 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012975 val = RLIM_INFINITY;
12976 else {
12977 val = (rlim_t) 0;
12978
12979 while ((c = *p++) >= '0' && c <= '9')
12980 {
12981 val = (val * 10) + (long)(c - '0');
12982 if (val < (rlim_t) 0)
12983 break;
12984 }
12985 if (c)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012986 sh_error("bad number");
Eric Andersenc470f442003-07-28 09:56:35 +000012987 val *= l->factor;
12988 }
12989 }
12990 if (all) {
12991 for (l = limits; l->name; l++) {
12992 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012993 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012994 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012995 }
12996 return 0;
12997 }
12998
12999 getrlimit(l->cmd, &limit);
13000 if (set) {
13001 if (how & HARD)
13002 limit.rlim_max = val;
13003 if (how & SOFT)
13004 limit.rlim_cur = val;
13005 if (setrlimit(l->cmd, &limit) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000013006 sh_error("error setting limit (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +000013007 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000013008 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000013009 }
13010 return 0;
13011}
13012
Eric Andersen90898442003-08-06 11:20:52 +000013013
13014#ifdef CONFIG_ASH_MATH_SUPPORT
13015
13016/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
13017
13018 Permission is hereby granted, free of charge, to any person obtaining
13019 a copy of this software and associated documentation files (the
13020 "Software"), to deal in the Software without restriction, including
13021 without limitation the rights to use, copy, modify, merge, publish,
13022 distribute, sublicense, and/or sell copies of the Software, and to
13023 permit persons to whom the Software is furnished to do so, subject to
13024 the following conditions:
13025
13026 The above copyright notice and this permission notice shall be
13027 included in all copies or substantial portions of the Software.
13028
13029 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13030 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13031 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13032 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13033 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13034 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13035 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13036*/
13037
13038/* This is my infix parser/evaluator. It is optimized for size, intended
13039 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000013040 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000013041 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000013042 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000013043 * be that which POSIX specifies for shells. */
13044
13045/* The code uses a simple two-stack algorithm. See
13046 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000013047 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000013048 * this is based (this code differs in that it applies operators immediately
13049 * to the stack instead of adding them to a queue to end up with an
13050 * expression). */
13051
13052/* To use the routine, call it with an expression string and error return
13053 * pointer */
13054
13055/*
13056 * Aug 24, 2001 Manuel Novoa III
13057 *
13058 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13059 *
13060 * 1) In arith_apply():
13061 * a) Cached values of *numptr and &(numptr[-1]).
13062 * b) Removed redundant test for zero denominator.
13063 *
13064 * 2) In arith():
13065 * a) Eliminated redundant code for processing operator tokens by moving
13066 * to a table-based implementation. Also folded handling of parens
13067 * into the table.
13068 * b) Combined all 3 loops which called arith_apply to reduce generated
13069 * code size at the cost of speed.
13070 *
13071 * 3) The following expressions were treated as valid by the original code:
13072 * 1() , 0! , 1 ( *3 ) .
13073 * These bugs have been fixed by internally enclosing the expression in
13074 * parens and then checking that all binary ops and right parens are
13075 * preceded by a valid expression (NUM_TOKEN).
13076 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013077 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013078 * ctype's isspace() if it is used by another busybox applet or if additional
13079 * whitespace chars should be considered. Look below the "#include"s for a
13080 * precompiler test.
13081 */
13082
13083/*
13084 * Aug 26, 2001 Manuel Novoa III
13085 *
13086 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13087 *
13088 * Merge in Aaron's comments previously posted to the busybox list,
13089 * modified slightly to take account of my changes to the code.
13090 *
13091 */
13092
13093/*
13094 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13095 *
13096 * - allow access to variable,
13097 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13098 * - realize assign syntax (VAR=expr, +=, *= etc)
13099 * - realize exponentiation (** operator)
13100 * - realize comma separated - expr, expr
13101 * - realise ++expr --expr expr++ expr--
13102 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013103 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013104 * - was restored loses XOR operator
13105 * - remove one goto label, added three ;-)
13106 * - protect $((num num)) as true zero expr (Manuel`s error)
13107 * - always use special isspace(), see comment from bash ;-)
13108 */
13109
13110
13111#define arith_isspace(arithval) \
13112 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13113
13114
13115typedef unsigned char operator;
13116
13117/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013118 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013119 * precedence. The ID portion is so that multiple operators can have the
13120 * same precedence, ensuring that the leftmost one is evaluated first.
13121 * Consider * and /. */
13122
13123#define tok_decl(prec,id) (((id)<<5)|(prec))
13124#define PREC(op) ((op) & 0x1F)
13125
13126#define TOK_LPAREN tok_decl(0,0)
13127
13128#define TOK_COMMA tok_decl(1,0)
13129
13130#define TOK_ASSIGN tok_decl(2,0)
13131#define TOK_AND_ASSIGN tok_decl(2,1)
13132#define TOK_OR_ASSIGN tok_decl(2,2)
13133#define TOK_XOR_ASSIGN tok_decl(2,3)
13134#define TOK_PLUS_ASSIGN tok_decl(2,4)
13135#define TOK_MINUS_ASSIGN tok_decl(2,5)
13136#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13137#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13138
13139#define TOK_MUL_ASSIGN tok_decl(3,0)
13140#define TOK_DIV_ASSIGN tok_decl(3,1)
13141#define TOK_REM_ASSIGN tok_decl(3,2)
13142
13143/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13144#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13145
13146/* conditional is right associativity too */
13147#define TOK_CONDITIONAL tok_decl(4,0)
13148#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13149
13150#define TOK_OR tok_decl(5,0)
13151
13152#define TOK_AND tok_decl(6,0)
13153
13154#define TOK_BOR tok_decl(7,0)
13155
13156#define TOK_BXOR tok_decl(8,0)
13157
13158#define TOK_BAND tok_decl(9,0)
13159
13160#define TOK_EQ tok_decl(10,0)
13161#define TOK_NE tok_decl(10,1)
13162
13163#define TOK_LT tok_decl(11,0)
13164#define TOK_GT tok_decl(11,1)
13165#define TOK_GE tok_decl(11,2)
13166#define TOK_LE tok_decl(11,3)
13167
13168#define TOK_LSHIFT tok_decl(12,0)
13169#define TOK_RSHIFT tok_decl(12,1)
13170
13171#define TOK_ADD tok_decl(13,0)
13172#define TOK_SUB tok_decl(13,1)
13173
13174#define TOK_MUL tok_decl(14,0)
13175#define TOK_DIV tok_decl(14,1)
13176#define TOK_REM tok_decl(14,2)
13177
13178/* exponent is right associativity */
13179#define TOK_EXPONENT tok_decl(15,1)
13180
13181/* For now unary operators. */
13182#define UNARYPREC 16
13183#define TOK_BNOT tok_decl(UNARYPREC,0)
13184#define TOK_NOT tok_decl(UNARYPREC,1)
13185
13186#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13187#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13188
13189#define PREC_PRE (UNARYPREC+2)
13190
13191#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13192#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13193
13194#define PREC_POST (UNARYPREC+3)
13195
13196#define TOK_POST_INC tok_decl(PREC_POST, 0)
13197#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13198
13199#define SPEC_PREC (UNARYPREC+4)
13200
13201#define TOK_NUM tok_decl(SPEC_PREC, 0)
13202#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13203
13204#define NUMPTR (*numstackptr)
13205
Rob Landley88621d72006-08-29 19:41:06 +000013206static int tok_have_assign(operator op)
Eric Andersen90898442003-08-06 11:20:52 +000013207{
13208 operator prec = PREC(op);
13209
13210 convert_prec_is_assing(prec);
13211 return (prec == PREC(TOK_ASSIGN) ||
13212 prec == PREC_PRE || prec == PREC_POST);
13213}
13214
Rob Landley88621d72006-08-29 19:41:06 +000013215static int is_right_associativity(operator prec)
Eric Andersen90898442003-08-06 11:20:52 +000013216{
13217 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13218 prec == PREC(TOK_CONDITIONAL));
13219}
13220
13221
13222typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013223 arith_t val;
13224 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013225 char contidional_second_val_initialized;
13226 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013227 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013228} v_n_t;
13229
13230
13231typedef struct CHK_VAR_RECURSIVE_LOOPED {
13232 const char *var;
13233 struct CHK_VAR_RECURSIVE_LOOPED *next;
13234} chk_var_recursive_looped_t;
13235
13236static chk_var_recursive_looped_t *prev_chk_var_recursive;
13237
13238
13239static int arith_lookup_val(v_n_t *t)
13240{
13241 if(t->var) {
13242 const char * p = lookupvar(t->var);
13243
13244 if(p) {
13245 int errcode;
13246
13247 /* recursive try as expression */
13248 chk_var_recursive_looped_t *cur;
13249 chk_var_recursive_looped_t cur_save;
13250
13251 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13252 if(strcmp(cur->var, t->var) == 0) {
13253 /* expression recursion loop detected */
13254 return -5;
13255 }
13256 }
13257 /* save current lookuped var name */
13258 cur = prev_chk_var_recursive;
13259 cur_save.var = t->var;
13260 cur_save.next = cur;
13261 prev_chk_var_recursive = &cur_save;
13262
13263 t->val = arith (p, &errcode);
13264 /* restore previous ptr after recursiving */
13265 prev_chk_var_recursive = cur;
13266 return errcode;
13267 } else {
13268 /* allow undefined var as 0 */
13269 t->val = 0;
13270 }
13271 }
13272 return 0;
13273}
13274
13275/* "applying" a token means performing it on the top elements on the integer
13276 * stack. For a unary operator it will only change the top element, but a
13277 * binary operator will pop two arguments and push a result */
Rob Landley88621d72006-08-29 19:41:06 +000013278static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
Eric Andersen90898442003-08-06 11:20:52 +000013279{
Eric Andersen90898442003-08-06 11:20:52 +000013280 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013281 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013282 int ret_arith_lookup_val;
13283
13284 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13285 without arguments */
13286 numptr_m1 = NUMPTR - 1;
13287
13288 /* check operand is var with noninteger value */
13289 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13290 if(ret_arith_lookup_val)
13291 return ret_arith_lookup_val;
13292
13293 rez = numptr_m1->val;
13294 if (op == TOK_UMINUS)
13295 rez *= -1;
13296 else if (op == TOK_NOT)
13297 rez = !rez;
13298 else if (op == TOK_BNOT)
13299 rez = ~rez;
13300 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13301 rez++;
13302 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13303 rez--;
13304 else if (op != TOK_UPLUS) {
13305 /* Binary operators */
13306
13307 /* check and binary operators need two arguments */
13308 if (numptr_m1 == numstack) goto err;
13309
13310 /* ... and they pop one */
13311 --NUMPTR;
13312 numptr_val = rez;
13313 if (op == TOK_CONDITIONAL) {
13314 if(! numptr_m1->contidional_second_val_initialized) {
13315 /* protect $((expr1 ? expr2)) without ": expr" */
13316 goto err;
13317 }
13318 rez = numptr_m1->contidional_second_val;
13319 } else if(numptr_m1->contidional_second_val_initialized) {
13320 /* protect $((expr1 : expr2)) without "expr ? " */
13321 goto err;
13322 }
13323 numptr_m1 = NUMPTR - 1;
13324 if(op != TOK_ASSIGN) {
13325 /* check operand is var with noninteger value for not '=' */
13326 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13327 if(ret_arith_lookup_val)
13328 return ret_arith_lookup_val;
13329 }
13330 if (op == TOK_CONDITIONAL) {
13331 numptr_m1->contidional_second_val = rez;
13332 }
13333 rez = numptr_m1->val;
13334 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13335 rez |= numptr_val;
13336 else if (op == TOK_OR)
13337 rez = numptr_val || rez;
13338 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13339 rez &= numptr_val;
13340 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13341 rez ^= numptr_val;
13342 else if (op == TOK_AND)
13343 rez = rez && numptr_val;
13344 else if (op == TOK_EQ)
13345 rez = (rez == numptr_val);
13346 else if (op == TOK_NE)
13347 rez = (rez != numptr_val);
13348 else if (op == TOK_GE)
13349 rez = (rez >= numptr_val);
13350 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13351 rez >>= numptr_val;
13352 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13353 rez <<= numptr_val;
13354 else if (op == TOK_GT)
13355 rez = (rez > numptr_val);
13356 else if (op == TOK_LT)
13357 rez = (rez < numptr_val);
13358 else if (op == TOK_LE)
13359 rez = (rez <= numptr_val);
13360 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13361 rez *= numptr_val;
13362 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13363 rez += numptr_val;
13364 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13365 rez -= numptr_val;
13366 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13367 rez = numptr_val;
13368 else if (op == TOK_CONDITIONAL_SEP) {
13369 if (numptr_m1 == numstack) {
13370 /* protect $((expr : expr)) without "expr ? " */
13371 goto err;
13372 }
13373 numptr_m1->contidional_second_val_initialized = op;
13374 numptr_m1->contidional_second_val = numptr_val;
13375 }
13376 else if (op == TOK_CONDITIONAL) {
13377 rez = rez ?
13378 numptr_val : numptr_m1->contidional_second_val;
13379 }
13380 else if(op == TOK_EXPONENT) {
13381 if(numptr_val < 0)
13382 return -3; /* exponent less than 0 */
13383 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013384 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013385
13386 if(numptr_val)
13387 while(numptr_val--)
13388 c *= rez;
13389 rez = c;
13390 }
13391 }
13392 else if(numptr_val==0) /* zero divisor check */
13393 return -2;
13394 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13395 rez /= numptr_val;
13396 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13397 rez %= numptr_val;
13398 }
13399 if(tok_have_assign(op)) {
13400 char buf[32];
13401
13402 if(numptr_m1->var == NULL) {
13403 /* Hmm, 1=2 ? */
13404 goto err;
13405 }
13406 /* save to shell variable */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013407#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersena68ea1c2006-01-30 22:48:39 +000013408 snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013409#else
Eric Andersena68ea1c2006-01-30 22:48:39 +000013410 snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013411#endif
Eric Andersen90898442003-08-06 11:20:52 +000013412 setvar(numptr_m1->var, buf, 0);
13413 /* after saving, make previous value for v++ or v-- */
13414 if(op == TOK_POST_INC)
13415 rez--;
13416 else if(op == TOK_POST_DEC)
13417 rez++;
13418 }
13419 numptr_m1->val = rez;
13420 /* protect geting var value, is number now */
13421 numptr_m1->var = NULL;
13422 return 0;
13423err: return(-1);
13424}
13425
13426/* longest must first */
13427static const char op_tokens[] = {
13428 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13429 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13430 '<','<', 0, TOK_LSHIFT,
13431 '>','>', 0, TOK_RSHIFT,
13432 '|','|', 0, TOK_OR,
13433 '&','&', 0, TOK_AND,
13434 '!','=', 0, TOK_NE,
13435 '<','=', 0, TOK_LE,
13436 '>','=', 0, TOK_GE,
13437 '=','=', 0, TOK_EQ,
13438 '|','=', 0, TOK_OR_ASSIGN,
13439 '&','=', 0, TOK_AND_ASSIGN,
13440 '*','=', 0, TOK_MUL_ASSIGN,
13441 '/','=', 0, TOK_DIV_ASSIGN,
13442 '%','=', 0, TOK_REM_ASSIGN,
13443 '+','=', 0, TOK_PLUS_ASSIGN,
13444 '-','=', 0, TOK_MINUS_ASSIGN,
13445 '-','-', 0, TOK_POST_DEC,
13446 '^','=', 0, TOK_XOR_ASSIGN,
13447 '+','+', 0, TOK_POST_INC,
13448 '*','*', 0, TOK_EXPONENT,
13449 '!', 0, TOK_NOT,
13450 '<', 0, TOK_LT,
13451 '>', 0, TOK_GT,
13452 '=', 0, TOK_ASSIGN,
13453 '|', 0, TOK_BOR,
13454 '&', 0, TOK_BAND,
13455 '*', 0, TOK_MUL,
13456 '/', 0, TOK_DIV,
13457 '%', 0, TOK_REM,
13458 '+', 0, TOK_ADD,
13459 '-', 0, TOK_SUB,
13460 '^', 0, TOK_BXOR,
13461 /* uniq */
13462 '~', 0, TOK_BNOT,
13463 ',', 0, TOK_COMMA,
13464 '?', 0, TOK_CONDITIONAL,
13465 ':', 0, TOK_CONDITIONAL_SEP,
13466 ')', 0, TOK_RPAREN,
13467 '(', 0, TOK_LPAREN,
13468 0
13469};
13470/* ptr to ")" */
13471#define endexpression &op_tokens[sizeof(op_tokens)-7]
13472
13473
Eric Andersened9ecf72004-06-22 08:29:45 +000013474static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013475{
"Robert P. J. Day"68229832006-07-01 13:08:46 +000013476 char arithval; /* Current character under analysis */
Eric Andersen90898442003-08-06 11:20:52 +000013477 operator lasttok, op;
13478 operator prec;
13479
13480 const char *p = endexpression;
13481 int errcode;
13482
13483 size_t datasizes = strlen(expr) + 2;
13484
13485 /* Stack of integers */
13486 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013487 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013488 * the reader. */
13489 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13490 *numstackptr = numstack;
13491 /* Stack of operator tokens */
13492 operator *stack = alloca((datasizes) * sizeof(operator)),
13493 *stackptr = stack;
13494
13495 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13496 *perrcode = errcode = 0;
13497
13498 while(1) {
13499 if ((arithval = *expr) == 0) {
13500 if (p == endexpression) {
13501 /* Null expression. */
13502 return 0;
13503 }
13504
13505 /* This is only reached after all tokens have been extracted from the
13506 * input stream. If there are still tokens on the operator stack, they
13507 * are to be applied in order. At the end, there should be a final
13508 * result on the integer stack */
13509
13510 if (expr != endexpression + 1) {
13511 /* If we haven't done so already, */
13512 /* append a closing right paren */
13513 expr = endexpression;
13514 /* and let the loop process it. */
13515 continue;
13516 }
13517 /* At this point, we're done with the expression. */
13518 if (numstackptr != numstack+1) {
13519 /* ... but if there isn't, it's bad */
13520 err:
13521 return (*perrcode = -1);
13522 }
13523 if(numstack->var) {
13524 /* expression is $((var)) only, lookup now */
13525 errcode = arith_lookup_val(numstack);
13526 }
13527 ret:
13528 *perrcode = errcode;
13529 return numstack->val;
13530 } else {
13531 /* Continue processing the expression. */
13532 if (arith_isspace(arithval)) {
13533 /* Skip whitespace */
13534 goto prologue;
13535 }
13536 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013537 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013538
13539 numstackptr->var = alloca(var_name_size);
13540 safe_strncpy(numstackptr->var, expr, var_name_size);
13541 expr = p;
13542 num:
13543 numstackptr->contidional_second_val_initialized = 0;
13544 numstackptr++;
13545 lasttok = TOK_NUM;
13546 continue;
13547 } else if (is_digit(arithval)) {
13548 numstackptr->var = NULL;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013549#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersenad63cb22004-10-08 09:43:34 +000013550 numstackptr->val = strtoll(expr, (char **) &expr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013551#else
13552 numstackptr->val = strtol(expr, (char **) &expr, 0);
13553#endif
Eric Andersen90898442003-08-06 11:20:52 +000013554 goto num;
13555 }
13556 for(p = op_tokens; ; p++) {
13557 const char *o;
13558
13559 if(*p == 0) {
13560 /* strange operator not found */
13561 goto err;
13562 }
13563 for(o = expr; *p && *o == *p; p++)
13564 o++;
13565 if(! *p) {
13566 /* found */
13567 expr = o - 1;
13568 break;
13569 }
13570 /* skip tail uncompared token */
13571 while(*p)
13572 p++;
13573 /* skip zero delim */
13574 p++;
13575 }
13576 op = p[1];
13577
13578 /* post grammar: a++ reduce to num */
13579 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13580 lasttok = TOK_NUM;
13581
13582 /* Plus and minus are binary (not unary) _only_ if the last
13583 * token was as number, or a right paren (which pretends to be
13584 * a number, since it evaluates to one). Think about it.
13585 * It makes sense. */
13586 if (lasttok != TOK_NUM) {
13587 switch(op) {
13588 case TOK_ADD:
13589 op = TOK_UPLUS;
13590 break;
13591 case TOK_SUB:
13592 op = TOK_UMINUS;
13593 break;
13594 case TOK_POST_INC:
13595 op = TOK_PRE_INC;
13596 break;
13597 case TOK_POST_DEC:
13598 op = TOK_PRE_DEC;
13599 break;
13600 }
13601 }
13602 /* We don't want a unary operator to cause recursive descent on the
13603 * stack, because there can be many in a row and it could cause an
13604 * operator to be evaluated before its argument is pushed onto the
13605 * integer stack. */
13606 /* But for binary operators, "apply" everything on the operator
13607 * stack until we find an operator with a lesser priority than the
13608 * one we have just extracted. */
13609 /* Left paren is given the lowest priority so it will never be
13610 * "applied" in this way.
13611 * if associativity is right and priority eq, applied also skip
13612 */
13613 prec = PREC(op);
13614 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13615 /* not left paren or unary */
13616 if (lasttok != TOK_NUM) {
13617 /* binary op must be preceded by a num */
13618 goto err;
13619 }
13620 while (stackptr != stack) {
13621 if (op == TOK_RPAREN) {
13622 /* The algorithm employed here is simple: while we don't
13623 * hit an open paren nor the bottom of the stack, pop
13624 * tokens and apply them */
13625 if (stackptr[-1] == TOK_LPAREN) {
13626 --stackptr;
13627 /* Any operator directly after a */
13628 lasttok = TOK_NUM;
13629 /* close paren should consider itself binary */
13630 goto prologue;
13631 }
13632 } else {
13633 operator prev_prec = PREC(stackptr[-1]);
13634
13635 convert_prec_is_assing(prec);
13636 convert_prec_is_assing(prev_prec);
13637 if (prev_prec < prec)
13638 break;
13639 /* check right assoc */
13640 if(prev_prec == prec && is_right_associativity(prec))
13641 break;
13642 }
13643 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13644 if(errcode) goto ret;
13645 }
13646 if (op == TOK_RPAREN) {
13647 goto err;
13648 }
13649 }
13650
13651 /* Push this operator to the stack and remember it. */
13652 *stackptr++ = lasttok = op;
13653
13654 prologue:
13655 ++expr;
13656 }
13657 }
13658}
13659#endif /* CONFIG_ASH_MATH_SUPPORT */
13660
13661
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000013662#if DEBUG
Denis Vlasenko8f8f2682006-10-03 21:00:43 +000013663const char *applet_name = "debug stuff usage";
Eric Andersenc470f442003-07-28 09:56:35 +000013664int main(int argc, char **argv)
13665{
13666 return ash_main(argc, argv);
13667}
13668#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013669
Eric Andersendf82f612001-06-28 07:46:40 +000013670/*-
13671 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013672 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013673 *
13674 * This code is derived from software contributed to Berkeley by
13675 * Kenneth Almquist.
13676 *
13677 * Redistribution and use in source and binary forms, with or without
13678 * modification, are permitted provided that the following conditions
13679 * are met:
13680 * 1. Redistributions of source code must retain the above copyright
13681 * notice, this list of conditions and the following disclaimer.
13682 * 2. Redistributions in binary form must reproduce the above copyright
13683 * notice, this list of conditions and the following disclaimer in the
13684 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013685 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013686 * may be used to endorse or promote products derived from this software
13687 * without specific prior written permission.
13688 *
13689 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13690 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13691 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13692 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13693 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13694 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13695 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13696 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13697 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13698 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13699 * SUCH DAMAGE.
13700 */