blob: 591e0a658e3b0252d464a1a87178df2c654e0693 [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;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002132 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002133 }
2134
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002135 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00002136}
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))
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002163 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 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002184 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002185 }
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
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002199 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00002200}
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();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002210 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002211 }
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
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002220 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00002221}
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);
Denis Vlasenko9f739442006-12-16 23:49:13 +00002318 else if (LONE_DASH(dest)) {
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:
Denis Vlasenko097c3242006-11-27 16:59:15 +00004807 return startp;
Eric Andersenc470f442003-07-28 09:56:35 +00004808 case CTLQUOTEMARK:
Denis Vlasenko097c3242006-11-27 16:59:15 +00004809 return startp;
Eric Andersenc470f442003-07-28 09:56:35 +00004810 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);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004834 return p;
Eric Andersenc470f442003-07-28 09:56:35 +00004835lose:
4836 *p = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004837 return startp;
Eric Andersenc470f442003-07-28 09:56:35 +00004838}
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) {
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00005854 q = memcpy(q, str, len) + 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{
Denis Vlasenkobf66fbc2006-12-21 13:23:14 +00008175 return bb_echo(argv);
Paul Fox0b621582005-08-09 19:38:05 +00008176}
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);
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008436 p = memcpy(p, s, n) + n;
Eric Andersenc470f442003-07-28 09:56:35 +00008437 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++ = '\'';
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008520 q = memcpy(q, s, len) + len;
Eric Andersenc470f442003-07-28 09:56:35 +00008521 *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++ = '"';
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008533 q = memcpy(q, s, len) + len;
Eric Andersenc470f442003-07-28 09:56:35 +00008534 *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 *
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008757nodesavestr(char *s)
Eric Andersenc470f442003-07-28 09:56:35 +00008758{
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008759 char *rtn = funcstring;
Eric Andersenc470f442003-07-28 09:56:35 +00008760
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008761 strcpy(funcstring, s);
8762 funcstring += strlen(s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008763 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008764}
8765
Eric Andersenc470f442003-07-28 09:56:35 +00008766
Eric Andersenc470f442003-07-28 09:56:35 +00008767/*
8768 * Free a parse tree.
8769 */
8770
8771static void
8772freefunc(struct funcnode *f)
8773{
8774 if (f && --f->count < 0)
8775 ckfree(f);
8776}
8777
8778
8779static void options(int);
8780static void setoption(int, int);
8781
Eric Andersencb57d552001-06-28 07:25:16 +00008782
Eric Andersencb57d552001-06-28 07:25:16 +00008783/*
8784 * Process the shell command line arguments.
8785 */
8786
Eric Andersenc470f442003-07-28 09:56:35 +00008787void
8788procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008789{
8790 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008791 const char *xminusc;
8792 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008793
Eric Andersenc470f442003-07-28 09:56:35 +00008794 xargv = argv;
8795 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008796 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008797 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008798 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008799 optlist[i] = 2;
8800 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008801 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008802 xargv = argptr;
8803 xminusc = minusc;
8804 if (*xargv == NULL) {
8805 if (xminusc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +00008806 sh_error(bb_msg_requires_arg, "-c");
Eric Andersencb57d552001-06-28 07:25:16 +00008807 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008808 }
Eric Andersencb57d552001-06-28 07:25:16 +00008809 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8810 iflag = 1;
8811 if (mflag == 2)
8812 mflag = iflag;
8813 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008814 if (optlist[i] == 2)
8815 optlist[i] = 0;
8816#if DEBUG == 2
8817 debug = 1;
8818#endif
8819 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8820 if (xminusc) {
8821 minusc = *xargv++;
8822 if (*xargv)
8823 goto setarg0;
8824 } else if (!sflag) {
8825 setinputfile(*xargv, 0);
8826setarg0:
8827 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008828 commandname = arg0;
8829 }
Eric Andersencb57d552001-06-28 07:25:16 +00008830
Eric Andersenc470f442003-07-28 09:56:35 +00008831 shellparam.p = xargv;
8832#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008833 shellparam.optind = 1;
8834 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008835#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008836 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008837 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008838 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008839 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008840 }
8841 optschanged();
8842}
8843
8844
Eric Andersenc470f442003-07-28 09:56:35 +00008845void
8846optschanged(void)
8847{
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008848#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008849 opentrace();
8850#endif
8851 setinteractive(iflag);
8852 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008853 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008854}
Eric Andersencb57d552001-06-28 07:25:16 +00008855
Rob Landley88621d72006-08-29 19:41:06 +00008856static void minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008857{
8858 int i;
8859
8860 if (name == NULL) {
8861 out1str("Current option settings\n");
8862 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008863 out1fmt("%-16s%s\n", optnames(i),
8864 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008865 } else {
8866 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008867 if (equal(name, optnames(i))) {
8868 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008869 return;
8870 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008871 sh_error("Illegal option -o %s", name);
Eric Andersen62483552001-07-10 06:09:16 +00008872 }
8873}
8874
Eric Andersenc470f442003-07-28 09:56:35 +00008875/*
8876 * Process shell options. The global variable argptr contains a pointer
8877 * to the argument list; we advance it past the options.
8878 */
Eric Andersen62483552001-07-10 06:09:16 +00008879
Eric Andersenc470f442003-07-28 09:56:35 +00008880static void
8881options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008882{
8883 char *p;
8884 int val;
8885 int c;
8886
8887 if (cmdline)
8888 minusc = NULL;
8889 while ((p = *argptr) != NULL) {
8890 argptr++;
8891 if ((c = *p++) == '-') {
8892 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +00008893 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +00008894 if (!cmdline) {
8895 /* "-" means turn off -x and -v */
8896 if (p[0] == '\0')
8897 xflag = vflag = 0;
8898 /* "--" means reset params */
8899 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008900 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008901 }
Eric Andersenc470f442003-07-28 09:56:35 +00008902 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008903 }
8904 } else if (c == '+') {
8905 val = 0;
8906 } else {
8907 argptr--;
8908 break;
8909 }
8910 while ((c = *p++) != '\0') {
8911 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008912 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008913 } else if (c == 'o') {
8914 minus_o(*argptr, val);
8915 if (*argptr)
8916 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008917 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008918 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008919 isloginsh = 1;
8920 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008921 } else {
8922 setoption(c, val);
8923 }
8924 }
8925 }
8926}
8927
Eric Andersencb57d552001-06-28 07:25:16 +00008928
Eric Andersenc470f442003-07-28 09:56:35 +00008929static void
8930setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008931{
Eric Andersencb57d552001-06-28 07:25:16 +00008932 int i;
8933
8934 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008935 if (optletters(i) == flag) {
8936 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008937 return;
8938 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008939 sh_error("Illegal option -%c", flag);
Eric Andersencb57d552001-06-28 07:25:16 +00008940 /* NOTREACHED */
8941}
8942
8943
8944
Eric Andersencb57d552001-06-28 07:25:16 +00008945/*
8946 * Set the shell parameters.
8947 */
8948
Eric Andersenc470f442003-07-28 09:56:35 +00008949void
8950setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008951{
Eric Andersencb57d552001-06-28 07:25:16 +00008952 char **newparam;
8953 char **ap;
8954 int nparam;
8955
Eric Andersenc470f442003-07-28 09:56:35 +00008956 for (nparam = 0 ; argv[nparam] ; nparam++);
8957 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008958 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008959 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008960 }
8961 *ap = NULL;
8962 freeparam(&shellparam);
8963 shellparam.malloc = 1;
8964 shellparam.nparam = nparam;
8965 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008966#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008967 shellparam.optind = 1;
8968 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008969#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008970}
8971
8972
8973/*
8974 * Free the list of positional parameters.
8975 */
8976
Eric Andersenc470f442003-07-28 09:56:35 +00008977void
8978freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008979{
Eric Andersencb57d552001-06-28 07:25:16 +00008980 char **ap;
8981
8982 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008983 for (ap = param->p ; *ap ; ap++)
8984 ckfree(*ap);
8985 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008986 }
8987}
8988
8989
8990
8991/*
8992 * The shift builtin command.
8993 */
8994
Eric Andersenc470f442003-07-28 09:56:35 +00008995int
8996shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008997{
8998 int n;
8999 char **ap1, **ap2;
9000
9001 n = 1;
9002 if (argc > 1)
9003 n = number(argv[1]);
9004 if (n > shellparam.nparam)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009005 sh_error("can't shift that many");
Eric Andersencb57d552001-06-28 07:25:16 +00009006 INTOFF;
9007 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009008 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009009 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009010 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009011 }
9012 ap2 = shellparam.p;
9013 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009014#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009015 shellparam.optind = 1;
9016 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009017#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009018 INTON;
9019 return 0;
9020}
9021
9022
9023
9024/*
9025 * The set command builtin.
9026 */
9027
Eric Andersenc470f442003-07-28 09:56:35 +00009028int
9029setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009030{
9031 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009032 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009033 INTOFF;
9034 options(0);
9035 optschanged();
9036 if (*argptr != NULL) {
9037 setparam(argptr);
9038 }
9039 INTON;
9040 return 0;
9041}
9042
9043
Eric Andersenc470f442003-07-28 09:56:35 +00009044#ifdef CONFIG_ASH_GETOPTS
9045static void
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00009046getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009047{
9048 shellparam.optind = number(value);
9049 shellparam.optoff = -1;
9050}
Eric Andersenc470f442003-07-28 09:56:35 +00009051#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009052
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009053#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009054static void change_lc_all(const char *value)
9055{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009056 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009057 setlocale(LC_ALL, value);
9058}
9059
9060static void change_lc_ctype(const char *value)
9061{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009062 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009063 setlocale(LC_CTYPE, value);
9064}
9065
9066#endif
9067
Eric Andersen16767e22004-03-16 05:14:10 +00009068#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009069/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009070static void change_random(const char *value)
9071{
Eric Andersen16767e22004-03-16 05:14:10 +00009072 if(value == NULL) {
9073 /* "get", generate */
9074 char buf[16];
9075
9076 rseed = rseed * 1103515245 + 12345;
9077 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9078 /* set without recursion */
9079 setvar(vrandom.text, buf, VNOFUNC);
9080 vrandom.flags &= ~VNOFUNC;
9081 } else {
9082 /* set/reset */
9083 rseed = strtoul(value, (char **)NULL, 10);
9084 }
Eric Andersenef02f822004-03-11 13:34:24 +00009085}
Eric Andersen16767e22004-03-16 05:14:10 +00009086#endif
9087
Eric Andersenef02f822004-03-11 13:34:24 +00009088
Eric Andersend35c5df2002-01-09 15:37:36 +00009089#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009090static int
Eric Andersenc470f442003-07-28 09:56:35 +00009091getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009092{
9093 char *p, *q;
9094 char c = '?';
9095 int done = 0;
9096 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009097 char s[12];
9098 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009099
Eric Andersena48b0a32003-10-22 10:56:47 +00009100 if(*param_optind < 1)
9101 return 1;
9102 optnext = optfirst + *param_optind - 1;
9103
9104 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009105 p = NULL;
9106 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009107 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009108 if (p == NULL || *p == '\0') {
9109 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009110 p = *optnext;
9111 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009112atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009113 p = NULL;
9114 done = 1;
9115 goto out;
9116 }
9117 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +00009118 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009119 goto atend;
9120 }
9121
9122 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009123 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009124 if (*q == '\0') {
9125 if (optstr[0] == ':') {
9126 s[0] = c;
9127 s[1] = '\0';
9128 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009129 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009130 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009131 (void) unsetvar("OPTARG");
9132 }
9133 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009134 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009135 }
9136 if (*++q == ':')
9137 q++;
9138 }
9139
9140 if (*++q == ':') {
9141 if (*p == '\0' && (p = *optnext) == NULL) {
9142 if (optstr[0] == ':') {
9143 s[0] = c;
9144 s[1] = '\0';
9145 err |= setvarsafe("OPTARG", s, 0);
9146 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009147 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009148 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009149 (void) unsetvar("OPTARG");
9150 c = '?';
9151 }
Eric Andersenc470f442003-07-28 09:56:35 +00009152 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009153 }
9154
9155 if (p == *optnext)
9156 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009157 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009158 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009159 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009160 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009161
Eric Andersenc470f442003-07-28 09:56:35 +00009162out:
Eric Andersencb57d552001-06-28 07:25:16 +00009163 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009164 *param_optind = optnext - optfirst + 1;
9165 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009166 err |= setvarsafe("OPTIND", s, VNOFUNC);
9167 s[0] = c;
9168 s[1] = '\0';
9169 err |= setvarsafe(optvar, s, 0);
9170 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009171 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009172 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009173 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009174 exraise(EXERROR);
9175 }
9176 return done;
9177}
Eric Andersenc470f442003-07-28 09:56:35 +00009178
9179/*
9180 * The getopts builtin. Shellparam.optnext points to the next argument
9181 * to be processed. Shellparam.optptr points to the next character to
9182 * be processed in the current argument. If shellparam.optnext is NULL,
9183 * then it's the first time getopts has been called.
9184 */
9185
9186int
9187getoptscmd(int argc, char **argv)
9188{
9189 char **optbase;
9190
9191 if (argc < 3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009192 sh_error("Usage: getopts optstring var [arg]");
Eric Andersenc470f442003-07-28 09:56:35 +00009193 else if (argc == 3) {
9194 optbase = shellparam.p;
9195 if (shellparam.optind > shellparam.nparam + 1) {
9196 shellparam.optind = 1;
9197 shellparam.optoff = -1;
9198 }
9199 }
9200 else {
9201 optbase = &argv[3];
9202 if (shellparam.optind > argc - 2) {
9203 shellparam.optind = 1;
9204 shellparam.optoff = -1;
9205 }
9206 }
9207
9208 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9209 &shellparam.optoff);
9210}
9211#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009212
9213/*
9214 * XXX - should get rid of. have all builtins use getopt(3). the
9215 * library getopt must have the BSD extension static variable "optreset"
9216 * otherwise it can't be used within the shell safely.
9217 *
9218 * Standard option processing (a la getopt) for builtin routines. The
9219 * only argument that is passed to nextopt is the option string; the
9220 * other arguments are unnecessary. It return the character, or '\0' on
9221 * end of input.
9222 */
9223
Eric Andersenc470f442003-07-28 09:56:35 +00009224static int
9225nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009226{
Eric Andersencb57d552001-06-28 07:25:16 +00009227 char *p;
9228 const char *q;
9229 char c;
9230
9231 if ((p = optptr) == NULL || *p == '\0') {
9232 p = *argptr;
9233 if (p == NULL || *p != '-' || *++p == '\0')
9234 return '\0';
9235 argptr++;
Denis Vlasenko9f739442006-12-16 23:49:13 +00009236 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009237 return '\0';
9238 }
9239 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009240 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009241 if (*q == '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009242 sh_error("Illegal option -%c", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009243 if (*++q == ':')
9244 q++;
9245 }
9246 if (*++q == ':') {
9247 if (*p == '\0' && (p = *argptr++) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009248 sh_error("No arg for -%c option", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009249 optionarg = p;
9250 p = NULL;
9251 }
9252 optptr = p;
9253 return c;
9254}
9255
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009256
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009257/* output.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009258
Eric Andersenc470f442003-07-28 09:56:35 +00009259void
9260outstr(const char *p, FILE *file)
9261{
9262 INTOFF;
9263 fputs(p, file);
9264 INTON;
9265}
9266
9267void
9268flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009269{
Eric Andersencb57d552001-06-28 07:25:16 +00009270 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009271 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009272 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009273 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009274}
9275
Eric Andersenc470f442003-07-28 09:56:35 +00009276void
Eric Andersen16767e22004-03-16 05:14:10 +00009277flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009278{
9279 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009280 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009281 INTON;
9282}
9283
9284static void
9285outcslow(int c, FILE *dest)
9286{
9287 INTOFF;
9288 putc(c, dest);
9289 fflush(dest);
9290 INTON;
9291}
9292
9293
9294static int
9295out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009296{
9297 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009298 int r;
9299
9300 INTOFF;
9301 va_start(ap, fmt);
9302 r = vprintf(fmt, ap);
9303 va_end(ap);
9304 INTON;
9305 return r;
9306}
9307
9308
9309int
9310fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9311{
9312 va_list ap;
9313 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009314
Eric Andersencb57d552001-06-28 07:25:16 +00009315 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009316 INTOFF;
9317 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009318 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009319 INTON;
9320 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009321}
9322
Eric Andersenc470f442003-07-28 09:56:35 +00009323
Eric Andersencb57d552001-06-28 07:25:16 +00009324
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009325/* parser.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009326
9327
Eric Andersencb57d552001-06-28 07:25:16 +00009328/*
9329 * Shell command parser.
9330 */
9331
9332#define EOFMARKLEN 79
9333
9334
Eric Andersencb57d552001-06-28 07:25:16 +00009335struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009336 struct heredoc *next; /* next here document in list */
9337 union node *here; /* redirection node */
9338 char *eofmark; /* string indicating end of input */
9339 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009340};
9341
9342
9343
Eric Andersenc470f442003-07-28 09:56:35 +00009344static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009345
9346
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009347static union node *list(int);
9348static union node *andor(void);
9349static union node *pipeline(void);
9350static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009351static union node *simplecmd(void);
9352static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009353static void parsefname(void);
9354static void parseheredoc(void);
9355static char peektoken(void);
9356static int readtoken(void);
9357static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009358static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009359static int noexpand(char *);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00009360static void synexpect(int) ATTRIBUTE_NORETURN;
9361static void synerror(const char *) ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009362static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009363
9364
Eric Andersenc470f442003-07-28 09:56:35 +00009365
Eric Andersenc470f442003-07-28 09:56:35 +00009366
Eric Andersencb57d552001-06-28 07:25:16 +00009367/*
9368 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9369 * valid parse tree indicating a blank line.)
9370 */
9371
Eric Andersenc470f442003-07-28 09:56:35 +00009372union node *
9373parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009374{
9375 int t;
9376
9377 tokpushback = 0;
9378 doprompt = interact;
9379 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009380 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009381 needprompt = 0;
9382 t = readtoken();
9383 if (t == TEOF)
9384 return NEOF;
9385 if (t == TNL)
9386 return NULL;
9387 tokpushback++;
9388 return list(1);
9389}
9390
9391
Eric Andersenc470f442003-07-28 09:56:35 +00009392static union node *
9393list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009394{
9395 union node *n1, *n2, *n3;
9396 int tok;
9397
Eric Andersenc470f442003-07-28 09:56:35 +00009398 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9399 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009400 return NULL;
9401 n1 = NULL;
9402 for (;;) {
9403 n2 = andor();
9404 tok = readtoken();
9405 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009406 if (n2->type == NPIPE) {
9407 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009408 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009409 if (n2->type != NREDIR) {
9410 n3 = stalloc(sizeof(struct nredir));
9411 n3->nredir.n = n2;
9412 n3->nredir.redirect = NULL;
9413 n2 = n3;
9414 }
9415 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009416 }
9417 }
9418 if (n1 == NULL) {
9419 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009420 }
9421 else {
9422 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009423 n3->type = NSEMI;
9424 n3->nbinary.ch1 = n1;
9425 n3->nbinary.ch2 = n2;
9426 n1 = n3;
9427 }
9428 switch (tok) {
9429 case TBACKGND:
9430 case TSEMI:
9431 tok = readtoken();
9432 /* fall through */
9433 case TNL:
9434 if (tok == TNL) {
9435 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009436 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009437 return n1;
9438 } else {
9439 tokpushback++;
9440 }
Eric Andersenc470f442003-07-28 09:56:35 +00009441 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009442 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009443 return n1;
9444 break;
9445 case TEOF:
9446 if (heredoclist)
9447 parseheredoc();
9448 else
Eric Andersenc470f442003-07-28 09:56:35 +00009449 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009450 return n1;
9451 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009452 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009453 synexpect(-1);
9454 tokpushback++;
9455 return n1;
9456 }
9457 }
9458}
9459
9460
9461
Eric Andersenc470f442003-07-28 09:56:35 +00009462static union node *
9463andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009464{
Eric Andersencb57d552001-06-28 07:25:16 +00009465 union node *n1, *n2, *n3;
9466 int t;
9467
Eric Andersencb57d552001-06-28 07:25:16 +00009468 n1 = pipeline();
9469 for (;;) {
9470 if ((t = readtoken()) == TAND) {
9471 t = NAND;
9472 } else if (t == TOR) {
9473 t = NOR;
9474 } else {
9475 tokpushback++;
9476 return n1;
9477 }
Eric Andersenc470f442003-07-28 09:56:35 +00009478 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009479 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009480 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009481 n3->type = t;
9482 n3->nbinary.ch1 = n1;
9483 n3->nbinary.ch2 = n2;
9484 n1 = n3;
9485 }
9486}
9487
9488
9489
Eric Andersenc470f442003-07-28 09:56:35 +00009490static union node *
9491pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009492{
Eric Andersencb57d552001-06-28 07:25:16 +00009493 union node *n1, *n2, *pipenode;
9494 struct nodelist *lp, *prev;
9495 int negate;
9496
9497 negate = 0;
9498 TRACE(("pipeline: entered\n"));
9499 if (readtoken() == TNOT) {
9500 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009501 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009502 } else
9503 tokpushback++;
9504 n1 = command();
9505 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009506 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009507 pipenode->type = NPIPE;
9508 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009509 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009510 pipenode->npipe.cmdlist = lp;
9511 lp->n = n1;
9512 do {
9513 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009514 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9515 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009516 lp->n = command();
9517 prev->next = lp;
9518 } while (readtoken() == TPIPE);
9519 lp->next = NULL;
9520 n1 = pipenode;
9521 }
9522 tokpushback++;
9523 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009524 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009525 n2->type = NNOT;
9526 n2->nnot.com = n1;
9527 return n2;
9528 } else
9529 return n1;
9530}
9531
9532
9533
Eric Andersenc470f442003-07-28 09:56:35 +00009534static union node *
9535command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009536{
Eric Andersencb57d552001-06-28 07:25:16 +00009537 union node *n1, *n2;
9538 union node *ap, **app;
9539 union node *cp, **cpp;
9540 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009541 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009542 int t;
9543
9544 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009545 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009546
Eric Andersencb57d552001-06-28 07:25:16 +00009547 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009548 default:
9549 synexpect(-1);
9550 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009551 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009552 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009553 n1->type = NIF;
9554 n1->nif.test = list(0);
9555 if (readtoken() != TTHEN)
9556 synexpect(TTHEN);
9557 n1->nif.ifpart = list(0);
9558 n2 = n1;
9559 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009560 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009561 n2 = n2->nif.elsepart;
9562 n2->type = NIF;
9563 n2->nif.test = list(0);
9564 if (readtoken() != TTHEN)
9565 synexpect(TTHEN);
9566 n2->nif.ifpart = list(0);
9567 }
9568 if (lasttoken == TELSE)
9569 n2->nif.elsepart = list(0);
9570 else {
9571 n2->nif.elsepart = NULL;
9572 tokpushback++;
9573 }
Eric Andersenc470f442003-07-28 09:56:35 +00009574 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009575 break;
9576 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009577 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009578 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009579 n1 = (union node *)stalloc(sizeof (struct nbinary));
9580 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009581 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009582 if ((got=readtoken()) != TDO) {
9583TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009584 synexpect(TDO);
9585 }
9586 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009587 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009588 break;
9589 }
9590 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009591 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009592 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009593 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009594 n1->type = NFOR;
9595 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009596 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009597 if (readtoken() == TIN) {
9598 app = &ap;
9599 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009600 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009601 n2->type = NARG;
9602 n2->narg.text = wordtext;
9603 n2->narg.backquote = backquotelist;
9604 *app = n2;
9605 app = &n2->narg.next;
9606 }
9607 *app = NULL;
9608 n1->nfor.args = ap;
9609 if (lasttoken != TNL && lasttoken != TSEMI)
9610 synexpect(-1);
9611 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009612 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009613 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009614 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009615 n2->narg.backquote = NULL;
9616 n2->narg.next = NULL;
9617 n1->nfor.args = n2;
9618 /*
9619 * Newline or semicolon here is optional (but note
9620 * that the original Bourne shell only allowed NL).
9621 */
9622 if (lasttoken != TNL && lasttoken != TSEMI)
9623 tokpushback++;
9624 }
Eric Andersenc470f442003-07-28 09:56:35 +00009625 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009626 if (readtoken() != TDO)
9627 synexpect(TDO);
9628 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009629 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009630 break;
9631 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009632 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009633 n1->type = NCASE;
9634 if (readtoken() != TWORD)
9635 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009636 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009637 n2->type = NARG;
9638 n2->narg.text = wordtext;
9639 n2->narg.backquote = backquotelist;
9640 n2->narg.next = NULL;
9641 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009642 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009643 } while (readtoken() == TNL);
9644 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009645 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009646 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009647next_case:
9648 checkkwd = CHKNL | CHKKWD;
9649 t = readtoken();
9650 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009651 if (lasttoken == TLP)
9652 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009653 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009654 cp->type = NCLIST;
9655 app = &cp->nclist.pattern;
9656 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009657 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009658 ap->type = NARG;
9659 ap->narg.text = wordtext;
9660 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009661 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009662 break;
9663 app = &ap->narg.next;
9664 readtoken();
9665 }
9666 ap->narg.next = NULL;
9667 if (lasttoken != TRP)
9668 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009669 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009670
Eric Andersenc470f442003-07-28 09:56:35 +00009671 cpp = &cp->nclist.next;
9672
9673 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009674 if ((t = readtoken()) != TESAC) {
9675 if (t != TENDCASE)
9676 synexpect(TENDCASE);
9677 else
Eric Andersenc470f442003-07-28 09:56:35 +00009678 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009679 }
Eric Andersenc470f442003-07-28 09:56:35 +00009680 }
Eric Andersencb57d552001-06-28 07:25:16 +00009681 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009682 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009683 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009684 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009685 n1->type = NSUBSHELL;
9686 n1->nredir.n = list(0);
9687 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009688 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009689 break;
9690 case TBEGIN:
9691 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009692 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009693 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009694 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009695 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009696 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009697 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009698 }
9699
Eric Andersenc470f442003-07-28 09:56:35 +00009700 if (readtoken() != t)
9701 synexpect(t);
9702
9703redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009704 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009705 checkkwd = CHKKWD | CHKALIAS;
9706 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009707 while (readtoken() == TREDIR) {
9708 *rpp = n2 = redirnode;
9709 rpp = &n2->nfile.next;
9710 parsefname();
9711 }
9712 tokpushback++;
9713 *rpp = NULL;
9714 if (redir) {
9715 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009716 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009717 n2->type = NREDIR;
9718 n2->nredir.n = n1;
9719 n1 = n2;
9720 }
9721 n1->nredir.redirect = redir;
9722 }
9723
9724 return n1;
9725}
9726
9727
Eric Andersenc470f442003-07-28 09:56:35 +00009728static union node *
9729simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009730 union node *args, **app;
9731 union node *n = NULL;
9732 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009733 union node **rpp, *redir;
9734 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009735
9736 args = NULL;
9737 app = &args;
9738 vars = NULL;
9739 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009740 redir = NULL;
9741 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009742
Eric Andersenc470f442003-07-28 09:56:35 +00009743 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009744 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009745 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009746 switch (readtoken()) {
9747 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009748 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009749 n->type = NARG;
9750 n->narg.text = wordtext;
9751 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009752 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009753 *vpp = n;
9754 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009755 } else {
9756 *app = n;
9757 app = &n->narg.next;
9758 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009759 }
9760 break;
9761 case TREDIR:
9762 *rpp = n = redirnode;
9763 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009764 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009765 break;
9766 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009767 if (
9768 args && app == &args->narg.next &&
9769 !vars && !redir
9770 ) {
9771 struct builtincmd *bcmd;
9772 const char *name;
9773
Eric Andersencb57d552001-06-28 07:25:16 +00009774 /* We have a function */
9775 if (readtoken() != TRP)
9776 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009777 name = n->narg.text;
9778 if (
9779 !goodname(name) || (
9780 (bcmd = find_builtin(name)) &&
9781 IS_BUILTIN_SPECIAL(bcmd)
9782 )
9783 )
9784 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009785 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009786 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009787 n->narg.next = command();
9788 return n;
9789 }
9790 /* fall through */
9791 default:
9792 tokpushback++;
9793 goto out;
9794 }
9795 }
Eric Andersenc470f442003-07-28 09:56:35 +00009796out:
Eric Andersencb57d552001-06-28 07:25:16 +00009797 *app = NULL;
9798 *vpp = NULL;
9799 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009800 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009801 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009802 n->ncmd.args = args;
9803 n->ncmd.assign = vars;
9804 n->ncmd.redirect = redir;
9805 return n;
9806}
9807
Eric Andersenc470f442003-07-28 09:56:35 +00009808static union node *
9809makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009810{
Eric Andersencb57d552001-06-28 07:25:16 +00009811 union node *n;
9812
Eric Andersenc470f442003-07-28 09:56:35 +00009813 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009814 n->type = NARG;
9815 n->narg.next = NULL;
9816 n->narg.text = wordtext;
9817 n->narg.backquote = backquotelist;
9818 return n;
9819}
9820
Eric Andersenc470f442003-07-28 09:56:35 +00009821void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009822{
Eric Andersencb57d552001-06-28 07:25:16 +00009823 TRACE(("Fix redir %s %d\n", text, err));
9824 if (!err)
9825 n->ndup.vname = NULL;
9826
9827 if (is_digit(text[0]) && text[1] == '\0')
9828 n->ndup.dupfd = digit_val(text[0]);
Denis Vlasenko9f739442006-12-16 23:49:13 +00009829 else if (LONE_DASH(text))
Eric Andersencb57d552001-06-28 07:25:16 +00009830 n->ndup.dupfd = -1;
9831 else {
9832
9833 if (err)
9834 synerror("Bad fd number");
9835 else
9836 n->ndup.vname = makename();
9837 }
9838}
9839
9840
Eric Andersenc470f442003-07-28 09:56:35 +00009841static void
9842parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009843{
Eric Andersencb57d552001-06-28 07:25:16 +00009844 union node *n = redirnode;
9845
9846 if (readtoken() != TWORD)
9847 synexpect(-1);
9848 if (n->type == NHERE) {
9849 struct heredoc *here = heredoc;
9850 struct heredoc *p;
9851 int i;
9852
9853 if (quoteflag == 0)
9854 n->type = NXHERE;
9855 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009856 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009857 synerror("Illegal eof marker for << redirection");
9858 rmescapes(wordtext);
9859 here->eofmark = wordtext;
9860 here->next = NULL;
9861 if (heredoclist == NULL)
9862 heredoclist = here;
9863 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009864 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009865 p->next = here;
9866 }
9867 } else if (n->type == NTOFD || n->type == NFROMFD) {
9868 fixredir(n, wordtext, 0);
9869 } else {
9870 n->nfile.fname = makename();
9871 }
9872}
9873
9874
9875/*
9876 * Input any here documents.
9877 */
9878
Eric Andersenc470f442003-07-28 09:56:35 +00009879static void
9880parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009881{
Eric Andersencb57d552001-06-28 07:25:16 +00009882 struct heredoc *here;
9883 union node *n;
9884
Eric Andersenc470f442003-07-28 09:56:35 +00009885 here = heredoclist;
9886 heredoclist = 0;
9887
9888 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009889 if (needprompt) {
9890 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009891 }
Eric Andersenc470f442003-07-28 09:56:35 +00009892 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9893 here->eofmark, here->striptabs);
9894 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009895 n->narg.type = NARG;
9896 n->narg.next = NULL;
9897 n->narg.text = wordtext;
9898 n->narg.backquote = backquotelist;
9899 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009900 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009901 }
9902}
9903
Eric Andersenc470f442003-07-28 09:56:35 +00009904static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009905{
Eric Andersencb57d552001-06-28 07:25:16 +00009906 int t;
9907
9908 t = readtoken();
9909 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009910 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009911}
9912
Eric Andersenc470f442003-07-28 09:56:35 +00009913static int
9914readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009915{
Eric Andersencb57d552001-06-28 07:25:16 +00009916 int t;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009917#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00009918 int alreadyseen = tokpushback;
9919#endif
9920
Eric Andersend35c5df2002-01-09 15:37:36 +00009921#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009922top:
Eric Andersen2870d962001-07-02 17:27:21 +00009923#endif
9924
Eric Andersencb57d552001-06-28 07:25:16 +00009925 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009926
Eric Andersenc470f442003-07-28 09:56:35 +00009927 /*
9928 * eat newlines
9929 */
9930 if (checkkwd & CHKNL) {
9931 while (t == TNL) {
9932 parseheredoc();
9933 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009934 }
9935 }
9936
Eric Andersenc470f442003-07-28 09:56:35 +00009937 if (t != TWORD || quoteflag) {
9938 goto out;
9939 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009940
Eric Andersenc470f442003-07-28 09:56:35 +00009941 /*
9942 * check for keywords
9943 */
9944 if (checkkwd & CHKKWD) {
9945 const char *const *pp;
9946
9947 if ((pp = findkwd(wordtext))) {
9948 lasttoken = t = pp - tokname_array;
9949 TRACE(("keyword %s recognized\n", tokname(t)));
9950 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009951 }
Eric Andersenc470f442003-07-28 09:56:35 +00009952 }
9953
9954 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009955#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009956 struct alias *ap;
9957 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009958 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009959 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009960 }
Eric Andersencb57d552001-06-28 07:25:16 +00009961 goto top;
9962 }
Eric Andersen2870d962001-07-02 17:27:21 +00009963#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009964 }
Eric Andersenc470f442003-07-28 09:56:35 +00009965out:
9966 checkkwd = 0;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009967#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00009968 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009969 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009970 else
Eric Andersenc470f442003-07-28 09:56:35 +00009971 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009972#endif
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00009973 return t;
Eric Andersencb57d552001-06-28 07:25:16 +00009974}
9975
9976
9977/*
9978 * Read the next input token.
9979 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009980 * backquotes. We set quoteflag to true if any part of the word was
9981 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009982 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009983 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009984 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009985 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009986 *
9987 * [Change comment: here documents and internal procedures]
9988 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9989 * word parsing code into a separate routine. In this case, readtoken
9990 * doesn't need to have any internal procedures, but parseword does.
9991 * We could also make parseoperator in essence the main routine, and
9992 * have parseword (readtoken1?) handle both words and redirection.]
9993 */
9994
Eric Andersen81fe1232003-07-29 06:38:40 +00009995#define NEW_xxreadtoken
9996#ifdef NEW_xxreadtoken
9997
9998/* singles must be first! */
9999static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10000
10001static const char xxreadtoken_tokens[] = {
10002 TNL, TLP, TRP, /* only single occurrence allowed */
10003 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10004 TEOF, /* corresponds to trailing nul */
10005 TAND, TOR, TENDCASE, /* if double occurrence */
10006};
10007
10008#define xxreadtoken_doubles \
10009 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10010#define xxreadtoken_singles \
10011 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10012
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +000010013static int xxreadtoken(void)
Eric Andersen81fe1232003-07-29 06:38:40 +000010014{
10015 int c;
10016
10017 if (tokpushback) {
10018 tokpushback = 0;
10019 return lasttoken;
10020 }
10021 if (needprompt) {
10022 setprompt(2);
Eric Andersen81fe1232003-07-29 06:38:40 +000010023 }
10024 startlinno = plinno;
10025 for (;;) { /* until token or start of word found */
10026 c = pgetc_macro();
10027
10028 if ((c != ' ') && (c != '\t')
10029#ifdef CONFIG_ASH_ALIAS
10030 && (c != PEOA)
10031#endif
10032 ) {
10033 if (c == '#') {
10034 while ((c = pgetc()) != '\n' && c != PEOF);
10035 pungetc();
10036 } else if (c == '\\') {
10037 if (pgetc() != '\n') {
10038 pungetc();
10039 goto READTOKEN1;
10040 }
10041 startlinno = ++plinno;
10042 if (doprompt)
10043 setprompt(2);
10044 } else {
10045 const char *p
10046 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10047
10048 if (c != PEOF) {
10049 if (c == '\n') {
10050 plinno++;
10051 needprompt = doprompt;
10052 }
10053
10054 p = strchr(xxreadtoken_chars, c);
10055 if (p == NULL) {
10056 READTOKEN1:
10057 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10058 }
10059
10060 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10061 if (pgetc() == *p) { /* double occurrence? */
10062 p += xxreadtoken_doubles + 1;
10063 } else {
10064 pungetc();
10065 }
10066 }
10067 }
10068
10069 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10070 }
10071 }
10072 }
10073}
10074
10075
10076#else
Eric Andersen2870d962001-07-02 17:27:21 +000010077#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010078
Eric Andersenc470f442003-07-28 09:56:35 +000010079static int
10080xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010081{
Eric Andersencb57d552001-06-28 07:25:16 +000010082 int c;
10083
10084 if (tokpushback) {
10085 tokpushback = 0;
10086 return lasttoken;
10087 }
10088 if (needprompt) {
10089 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010090 }
10091 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010092 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010093 c = pgetc_macro();
10094 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010095 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010096#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010097 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010098#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010099 continue;
10100 case '#':
10101 while ((c = pgetc()) != '\n' && c != PEOF);
10102 pungetc();
10103 continue;
10104 case '\\':
10105 if (pgetc() == '\n') {
10106 startlinno = ++plinno;
10107 if (doprompt)
10108 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010109 continue;
10110 }
10111 pungetc();
10112 goto breakloop;
10113 case '\n':
10114 plinno++;
10115 needprompt = doprompt;
10116 RETURN(TNL);
10117 case PEOF:
10118 RETURN(TEOF);
10119 case '&':
10120 if (pgetc() == '&')
10121 RETURN(TAND);
10122 pungetc();
10123 RETURN(TBACKGND);
10124 case '|':
10125 if (pgetc() == '|')
10126 RETURN(TOR);
10127 pungetc();
10128 RETURN(TPIPE);
10129 case ';':
10130 if (pgetc() == ';')
10131 RETURN(TENDCASE);
10132 pungetc();
10133 RETURN(TSEMI);
10134 case '(':
10135 RETURN(TLP);
10136 case ')':
10137 RETURN(TRP);
10138 default:
10139 goto breakloop;
10140 }
10141 }
Eric Andersenc470f442003-07-28 09:56:35 +000010142breakloop:
10143 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010144#undef RETURN
10145}
Eric Andersen81fe1232003-07-29 06:38:40 +000010146#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010147
Eric Andersencb57d552001-06-28 07:25:16 +000010148
Eric Andersencb57d552001-06-28 07:25:16 +000010149/*
10150 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10151 * is not NULL, read a here document. In the latter case, eofmark is the
10152 * word which marks the end of the document and striptabs is true if
10153 * leading tabs should be stripped from the document. The argument firstc
10154 * is the first character of the input token or document.
10155 *
10156 * Because C does not have internal subroutines, I have simulated them
10157 * using goto's to implement the subroutine linkage. The following macros
10158 * will run code that appears at the end of readtoken1.
10159 */
10160
Eric Andersen2870d962001-07-02 17:27:21 +000010161#define CHECKEND() {goto checkend; checkend_return:;}
10162#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10163#define PARSESUB() {goto parsesub; parsesub_return:;}
10164#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10165#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10166#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010167
10168static int
Eric Andersenc470f442003-07-28 09:56:35 +000010169readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010170{
Eric Andersencb57d552001-06-28 07:25:16 +000010171 int c = firstc;
10172 char *out;
10173 int len;
10174 char line[EOFMARKLEN + 1];
Eric Andersena68ea1c2006-01-30 22:48:39 +000010175 struct nodelist *bqlist = 0;
10176 int quotef = 0;
10177 int dblquote = 0;
10178 int varnest = 0; /* levels of variables expansion */
10179 int arinest = 0; /* levels of arithmetic expansion */
10180 int parenlevel = 0; /* levels of parens in arithmetic */
10181 int dqvarnest = 0; /* levels of variables expansion within double quotes */
10182 int oldstyle = 0;
10183 int prevsyntax = 0; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010184#if __GNUC__
10185 /* Avoid longjmp clobbering */
10186 (void) &out;
10187 (void) &quotef;
10188 (void) &dblquote;
10189 (void) &varnest;
10190 (void) &arinest;
10191 (void) &parenlevel;
10192 (void) &dqvarnest;
10193 (void) &oldstyle;
10194 (void) &prevsyntax;
10195 (void) &syntax;
10196#endif
10197
10198 startlinno = plinno;
10199 dblquote = 0;
10200 if (syntax == DQSYNTAX)
10201 dblquote = 1;
10202 quotef = 0;
10203 bqlist = NULL;
10204 varnest = 0;
10205 arinest = 0;
10206 parenlevel = 0;
10207 dqvarnest = 0;
10208
10209 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010210 loop: { /* for each line, until end of word */
10211 CHECKEND(); /* set c to PEOF if at end of here document */
10212 for (;;) { /* until end of line or end of word */
10213 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10214 switch(SIT(c, syntax)) {
10215 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010216 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010217 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010218 USTPUTC(c, out);
10219 plinno++;
10220 if (doprompt)
10221 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010222 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010223 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010224 case CWORD:
10225 USTPUTC(c, out);
10226 break;
10227 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010228 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010229 USTPUTC(CTLESC, out);
10230 USTPUTC(c, out);
10231 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010232 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010233 c = pgetc2();
10234 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010235 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010236 USTPUTC('\\', out);
10237 pungetc();
10238 } else if (c == '\n') {
10239 if (doprompt)
10240 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010241 } else {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010242 if (dblquote &&
Eric Andersenc470f442003-07-28 09:56:35 +000010243 c != '\\' && c != '`' &&
10244 c != '$' && (
10245 c != '"' ||
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010246 eofmark != NULL)
Eric Andersenc470f442003-07-28 09:56:35 +000010247 ) {
10248 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010249 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010250 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010251 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010252 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010253 USTPUTC(c, out);
10254 quotef++;
10255 }
10256 break;
10257 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010258 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010259quotemark:
10260 if (eofmark == NULL) {
10261 USTPUTC(CTLQUOTEMARK, out);
10262 }
Eric Andersencb57d552001-06-28 07:25:16 +000010263 break;
10264 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010265 syntax = DQSYNTAX;
10266 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010267 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010268 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010269 if (eofmark != NULL && arinest == 0 &&
10270 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010271 USTPUTC(c, out);
10272 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010273 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010274 syntax = BASESYNTAX;
10275 dblquote = 0;
10276 }
10277 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010278 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010279 }
10280 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010281 case CVAR: /* '$' */
10282 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010283 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010284 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010285 if (varnest > 0) {
10286 varnest--;
10287 if (dqvarnest > 0) {
10288 dqvarnest--;
10289 }
10290 USTPUTC(CTLENDVAR, out);
10291 } else {
10292 USTPUTC(c, out);
10293 }
10294 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010295#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010296 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010297 parenlevel++;
10298 USTPUTC(c, out);
10299 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010300 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010301 if (parenlevel > 0) {
10302 USTPUTC(c, out);
10303 --parenlevel;
10304 } else {
10305 if (pgetc() == ')') {
10306 if (--arinest == 0) {
10307 USTPUTC(CTLENDARI, out);
10308 syntax = prevsyntax;
10309 if (syntax == DQSYNTAX)
10310 dblquote = 1;
10311 else
10312 dblquote = 0;
10313 } else
10314 USTPUTC(')', out);
10315 } else {
10316 /*
10317 * unbalanced parens
10318 * (don't 2nd guess - no error)
10319 */
10320 pungetc();
10321 USTPUTC(')', out);
10322 }
10323 }
10324 break;
10325#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010326 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010327 PARSEBACKQOLD();
10328 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010329 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010330 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010331 case CIGN:
10332 break;
10333 default:
10334 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010335 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010336#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010337 if (c != PEOA)
10338#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010339 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010340
Eric Andersencb57d552001-06-28 07:25:16 +000010341 }
10342 c = pgetc_macro();
10343 }
10344 }
Eric Andersenc470f442003-07-28 09:56:35 +000010345endword:
10346#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010347 if (syntax == ARISYNTAX)
10348 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010349#endif
10350 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010351 synerror("Unterminated quoted string");
10352 if (varnest != 0) {
10353 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010354 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010355 synerror("Missing '}'");
10356 }
10357 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010358 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010359 out = stackblock();
10360 if (eofmark == NULL) {
10361 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010362 && quotef == 0
10363 && len <= 2
10364 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010365 PARSEREDIR();
10366 return lasttoken = TREDIR;
10367 } else {
10368 pungetc();
10369 }
10370 }
10371 quoteflag = quotef;
10372 backquotelist = bqlist;
10373 grabstackblock(len);
10374 wordtext = out;
10375 return lasttoken = TWORD;
10376/* end of readtoken routine */
10377
10378
10379
10380/*
10381 * Check to see whether we are at the end of the here document. When this
10382 * is called, c is set to the first character of the next input line. If
10383 * we are at the end of the here document, this routine sets the c to PEOF.
10384 */
10385
Eric Andersenc470f442003-07-28 09:56:35 +000010386checkend: {
10387 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010388#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010389 if (c == PEOA) {
10390 c = pgetc2();
10391 }
10392#endif
10393 if (striptabs) {
10394 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010395 c = pgetc2();
10396 }
Eric Andersenc470f442003-07-28 09:56:35 +000010397 }
10398 if (c == *eofmark) {
10399 if (pfgets(line, sizeof line) != NULL) {
10400 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010401
Eric Andersenc470f442003-07-28 09:56:35 +000010402 p = line;
10403 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10404 if (*p == '\n' && *q == '\0') {
10405 c = PEOF;
10406 plinno++;
10407 needprompt = doprompt;
10408 } else {
10409 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010410 }
10411 }
10412 }
10413 }
Eric Andersenc470f442003-07-28 09:56:35 +000010414 goto checkend_return;
10415}
Eric Andersencb57d552001-06-28 07:25:16 +000010416
10417
10418/*
10419 * Parse a redirection operator. The variable "out" points to a string
10420 * specifying the fd to be redirected. The variable "c" contains the
10421 * first character of the redirection operator.
10422 */
10423
Eric Andersenc470f442003-07-28 09:56:35 +000010424parseredir: {
10425 char fd = *out;
10426 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010427
Eric Andersenc470f442003-07-28 09:56:35 +000010428 np = (union node *)stalloc(sizeof (struct nfile));
10429 if (c == '>') {
10430 np->nfile.fd = 1;
10431 c = pgetc();
10432 if (c == '>')
10433 np->type = NAPPEND;
10434 else if (c == '|')
10435 np->type = NCLOBBER;
10436 else if (c == '&')
10437 np->type = NTOFD;
10438 else {
10439 np->type = NTO;
10440 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010441 }
Eric Andersenc470f442003-07-28 09:56:35 +000010442 } else { /* c == '<' */
10443 np->nfile.fd = 0;
10444 switch (c = pgetc()) {
10445 case '<':
10446 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10447 np = (union node *)stalloc(sizeof (struct nhere));
10448 np->nfile.fd = 0;
10449 }
10450 np->type = NHERE;
10451 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10452 heredoc->here = np;
10453 if ((c = pgetc()) == '-') {
10454 heredoc->striptabs = 1;
10455 } else {
10456 heredoc->striptabs = 0;
10457 pungetc();
10458 }
10459 break;
10460
10461 case '&':
10462 np->type = NFROMFD;
10463 break;
10464
10465 case '>':
10466 np->type = NFROMTO;
10467 break;
10468
10469 default:
10470 np->type = NFROM;
10471 pungetc();
10472 break;
10473 }
Eric Andersencb57d552001-06-28 07:25:16 +000010474 }
Eric Andersenc470f442003-07-28 09:56:35 +000010475 if (fd != '\0')
10476 np->nfile.fd = digit_val(fd);
10477 redirnode = np;
10478 goto parseredir_return;
10479}
Eric Andersencb57d552001-06-28 07:25:16 +000010480
10481
10482/*
10483 * Parse a substitution. At this point, we have read the dollar sign
10484 * and nothing else.
10485 */
10486
Eric Andersenc470f442003-07-28 09:56:35 +000010487parsesub: {
10488 int subtype;
10489 int typeloc;
10490 int flags;
10491 char *p;
10492 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010493
Eric Andersenc470f442003-07-28 09:56:35 +000010494 c = pgetc();
10495 if (
10496 c <= PEOA_OR_PEOF ||
10497 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10498 ) {
10499 USTPUTC('$', out);
10500 pungetc();
10501 } else if (c == '(') { /* $(command) or $((arith)) */
10502 if (pgetc() == '(') {
10503#ifdef CONFIG_ASH_MATH_SUPPORT
10504 PARSEARITH();
10505#else
10506 synerror("We unsupport $((arith))");
10507#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010508 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010509 pungetc();
10510 PARSEBACKQNEW();
10511 }
10512 } else {
10513 USTPUTC(CTLVAR, out);
10514 typeloc = out - (char *)stackblock();
10515 USTPUTC(VSNORMAL, out);
10516 subtype = VSNORMAL;
10517 if (c == '{') {
10518 c = pgetc();
10519 if (c == '#') {
10520 if ((c = pgetc()) == '}')
10521 c = '#';
10522 else
10523 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010524 }
Eric Andersenc470f442003-07-28 09:56:35 +000010525 else
10526 subtype = 0;
10527 }
10528 if (c > PEOA_OR_PEOF && is_name(c)) {
10529 do {
10530 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010531 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010532 } while (c > PEOA_OR_PEOF && is_in_name(c));
10533 } else if (is_digit(c)) {
10534 do {
10535 STPUTC(c, out);
10536 c = pgetc();
10537 } while (is_digit(c));
10538 }
10539 else if (is_special(c)) {
10540 USTPUTC(c, out);
10541 c = pgetc();
10542 }
10543 else
10544badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010545
Eric Andersenc470f442003-07-28 09:56:35 +000010546 STPUTC('=', out);
10547 flags = 0;
10548 if (subtype == 0) {
10549 switch (c) {
10550 case ':':
10551 flags = VSNUL;
10552 c = pgetc();
10553 /*FALLTHROUGH*/
10554 default:
10555 p = strchr(types, c);
10556 if (p == NULL)
10557 goto badsub;
10558 subtype = p - types + VSNORMAL;
10559 break;
10560 case '%':
10561 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010562 {
10563 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010564 subtype = c == '#' ? VSTRIMLEFT :
10565 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010566 c = pgetc();
10567 if (c == cc)
10568 subtype++;
10569 else
10570 pungetc();
10571 break;
10572 }
10573 }
Eric Andersenc470f442003-07-28 09:56:35 +000010574 } else {
10575 pungetc();
10576 }
10577 if (dblquote || arinest)
10578 flags |= VSQUOTE;
10579 *((char *)stackblock() + typeloc) = subtype | flags;
10580 if (subtype != VSNORMAL) {
10581 varnest++;
10582 if (dblquote || arinest) {
10583 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010584 }
10585 }
10586 }
Eric Andersenc470f442003-07-28 09:56:35 +000010587 goto parsesub_return;
10588}
Eric Andersencb57d552001-06-28 07:25:16 +000010589
10590
10591/*
10592 * Called to parse command substitutions. Newstyle is set if the command
10593 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10594 * list of commands (passed by reference), and savelen is the number of
10595 * characters on the top of the stack which must be preserved.
10596 */
10597
Eric Andersenc470f442003-07-28 09:56:35 +000010598parsebackq: {
10599 struct nodelist **nlpp;
10600 int savepbq;
10601 union node *n;
10602 char *volatile str;
10603 struct jmploc jmploc;
10604 struct jmploc *volatile savehandler;
10605 size_t savelen;
Eric Andersena68ea1c2006-01-30 22:48:39 +000010606 int saveprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010607#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010608 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010609#endif
10610
Eric Andersenc470f442003-07-28 09:56:35 +000010611 savepbq = parsebackquote;
10612 if (setjmp(jmploc.loc)) {
10613 if (str)
10614 ckfree(str);
10615 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010616 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010617 longjmp(handler->loc, 1);
10618 }
10619 INTOFF;
10620 str = NULL;
10621 savelen = out - (char *)stackblock();
10622 if (savelen > 0) {
10623 str = ckmalloc(savelen);
10624 memcpy(str, stackblock(), savelen);
10625 }
10626 savehandler = handler;
10627 handler = &jmploc;
10628 INTON;
10629 if (oldstyle) {
10630 /* We must read until the closing backquote, giving special
10631 treatment to some slashes, and then push the string and
10632 reread it as input, interpreting it normally. */
10633 char *pout;
10634 int pc;
10635 size_t psavelen;
10636 char *pstr;
10637
10638
10639 STARTSTACKSTR(pout);
10640 for (;;) {
10641 if (needprompt) {
10642 setprompt(2);
Eric Andersenc470f442003-07-28 09:56:35 +000010643 }
10644 switch (pc = pgetc()) {
10645 case '`':
10646 goto done;
10647
10648 case '\\':
10649 if ((pc = pgetc()) == '\n') {
10650 plinno++;
10651 if (doprompt)
10652 setprompt(2);
10653 /*
10654 * If eating a newline, avoid putting
10655 * the newline into the new character
10656 * stream (via the STPUTC after the
10657 * switch).
10658 */
10659 continue;
10660 }
10661 if (pc != '\\' && pc != '`' && pc != '$'
10662 && (!dblquote || pc != '"'))
10663 STPUTC('\\', pout);
10664 if (pc > PEOA_OR_PEOF) {
10665 break;
10666 }
10667 /* fall through */
10668
10669 case PEOF:
10670#ifdef CONFIG_ASH_ALIAS
10671 case PEOA:
10672#endif
10673 startlinno = plinno;
10674 synerror("EOF in backquote substitution");
10675
10676 case '\n':
10677 plinno++;
10678 needprompt = doprompt;
10679 break;
10680
10681 default:
10682 break;
10683 }
10684 STPUTC(pc, pout);
10685 }
10686done:
10687 STPUTC('\0', pout);
10688 psavelen = pout - (char *)stackblock();
10689 if (psavelen > 0) {
10690 pstr = grabstackstr(pout);
10691 setinputstring(pstr);
10692 }
10693 }
10694 nlpp = &bqlist;
10695 while (*nlpp)
10696 nlpp = &(*nlpp)->next;
10697 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10698 (*nlpp)->next = NULL;
10699 parsebackquote = oldstyle;
10700
10701 if (oldstyle) {
10702 saveprompt = doprompt;
10703 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010704 }
10705
Eric Andersenc470f442003-07-28 09:56:35 +000010706 n = list(2);
10707
10708 if (oldstyle)
10709 doprompt = saveprompt;
10710 else {
10711 if (readtoken() != TRP)
10712 synexpect(TRP);
10713 }
10714
10715 (*nlpp)->n = n;
10716 if (oldstyle) {
10717 /*
10718 * Start reading from old file again, ignoring any pushed back
10719 * tokens left from the backquote parsing
10720 */
10721 popfile();
10722 tokpushback = 0;
10723 }
10724 while (stackblocksize() <= savelen)
10725 growstackblock();
10726 STARTSTACKSTR(out);
10727 if (str) {
10728 memcpy(out, str, savelen);
10729 STADJUST(savelen, out);
10730 INTOFF;
10731 ckfree(str);
10732 str = NULL;
10733 INTON;
10734 }
10735 parsebackquote = savepbq;
10736 handler = savehandler;
10737 if (arinest || dblquote)
10738 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10739 else
10740 USTPUTC(CTLBACKQ, out);
10741 if (oldstyle)
10742 goto parsebackq_oldreturn;
10743 else
10744 goto parsebackq_newreturn;
10745}
10746
10747#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010748/*
10749 * Parse an arithmetic expansion (indicate start of one and set state)
10750 */
Eric Andersenc470f442003-07-28 09:56:35 +000010751parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010752
Eric Andersenc470f442003-07-28 09:56:35 +000010753 if (++arinest == 1) {
10754 prevsyntax = syntax;
10755 syntax = ARISYNTAX;
10756 USTPUTC(CTLARI, out);
10757 if (dblquote)
10758 USTPUTC('"',out);
10759 else
10760 USTPUTC(' ',out);
10761 } else {
10762 /*
10763 * we collapse embedded arithmetic expansion to
10764 * parenthesis, which should be equivalent
10765 */
10766 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010767 }
Eric Andersenc470f442003-07-28 09:56:35 +000010768 goto parsearith_return;
10769}
10770#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010771
Eric Andersenc470f442003-07-28 09:56:35 +000010772} /* end of readtoken */
10773
Eric Andersencb57d552001-06-28 07:25:16 +000010774
10775
Eric Andersencb57d552001-06-28 07:25:16 +000010776/*
10777 * Returns true if the text contains nothing to expand (no dollar signs
10778 * or backquotes).
10779 */
10780
Eric Andersenc470f442003-07-28 09:56:35 +000010781static int
10782noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010783{
Eric Andersencb57d552001-06-28 07:25:16 +000010784 char *p;
10785 char c;
10786
10787 p = text;
10788 while ((c = *p++) != '\0') {
10789 if (c == CTLQUOTEMARK)
10790 continue;
10791 if (c == CTLESC)
10792 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010793 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010794 return 0;
10795 }
10796 return 1;
10797}
10798
10799
10800/*
Eric Andersenc470f442003-07-28 09:56:35 +000010801 * Return of a legal variable name (a letter or underscore followed by zero or
10802 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010803 */
10804
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010805static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010806endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010807{
Eric Andersenc470f442003-07-28 09:56:35 +000010808 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010809
Eric Andersenc470f442003-07-28 09:56:35 +000010810 p = (char *) name;
10811 if (! is_name(*p))
10812 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010813 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010814 if (! is_in_name(*p))
10815 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010816 }
Eric Andersenc470f442003-07-28 09:56:35 +000010817 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010818}
10819
10820
10821/*
10822 * Called when an unexpected token is read during the parse. The argument
10823 * is the token that is expected, or -1 if more than one type of token can
10824 * occur at this point.
10825 */
10826
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010827static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010828{
10829 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010830 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010831
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010832 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10833 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010834 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010835 synerror(msg);
10836 /* NOTREACHED */
10837}
10838
Eric Andersenc470f442003-07-28 09:56:35 +000010839static void
10840synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010841{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010842 sh_error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010843 /* NOTREACHED */
10844}
10845
Eric Andersencb57d552001-06-28 07:25:16 +000010846
10847/*
10848 * called by editline -- any expansions to the prompt
10849 * should be added here.
10850 */
Eric Andersenc470f442003-07-28 09:56:35 +000010851
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010852#ifdef CONFIG_ASH_EXPAND_PRMT
10853static const char *
10854expandstr(const char *ps)
10855{
10856 union node n;
10857
10858 /* XXX Fix (char *) cast. */
10859 setinputstring((char *)ps);
10860 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10861 popfile();
10862
10863 n.narg.type = NARG;
10864 n.narg.next = NULL;
10865 n.narg.text = wordtext;
10866 n.narg.backquote = backquotelist;
10867
10868 expandarg(&n, NULL, 0);
10869 return stackblock();
10870}
10871#endif
10872
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010873static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010874{
Eric Andersenc470f442003-07-28 09:56:35 +000010875 const char *prompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010876#ifdef CONFIG_ASH_EXPAND_PRMT
10877 struct stackmark smark;
10878#endif
10879
10880 needprompt = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010881
10882 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010883 case 1:
10884 prompt = ps1val();
10885 break;
10886 case 2:
10887 prompt = ps2val();
10888 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010889 default: /* 0 */
10890 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010891 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010892#ifdef CONFIG_ASH_EXPAND_PRMT
10893 setstackmark(&smark);
10894 stalloc(stackblocksize());
10895#endif
10896 putprompt(expandstr(prompt));
10897#ifdef CONFIG_ASH_EXPAND_PRMT
10898 popstackmark(&smark);
10899#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010900}
10901
Eric Andersencb57d552001-06-28 07:25:16 +000010902
Eric Andersenc470f442003-07-28 09:56:35 +000010903static const char *const *findkwd(const char *s)
10904{
10905 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010906 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010907 sizeof(const char *), pstrcmp);
10908}
10909
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010910/* redir.c */
Eric Andersenc470f442003-07-28 09:56:35 +000010911
Eric Andersencb57d552001-06-28 07:25:16 +000010912/*
10913 * Code for dealing with input/output redirection.
10914 */
10915
Eric Andersenc470f442003-07-28 09:56:35 +000010916#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010917#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010918# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010919#else
10920# define PIPESIZE PIPE_BUF
10921#endif
10922
Eric Andersen62483552001-07-10 06:09:16 +000010923/*
10924 * Open a file in noclobber mode.
10925 * The code was copied from bash.
10926 */
Rob Landley88621d72006-08-29 19:41:06 +000010927static int noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010928{
10929 int r, fd;
10930 struct stat finfo, finfo2;
10931
10932 /*
10933 * If the file exists and is a regular file, return an error
10934 * immediately.
10935 */
10936 r = stat(fname, &finfo);
10937 if (r == 0 && S_ISREG(finfo.st_mode)) {
10938 errno = EEXIST;
10939 return -1;
10940 }
10941
10942 /*
10943 * If the file was not present (r != 0), make sure we open it
10944 * exclusively so that if it is created before we open it, our open
10945 * will fail. Make sure that we do not truncate an existing file.
10946 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10947 * file was not a regular file, we leave O_EXCL off.
10948 */
10949 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010950 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10951 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010952
10953 /* If the open failed, return the file descriptor right away. */
10954 if (fd < 0)
10955 return fd;
10956
10957 /*
10958 * OK, the open succeeded, but the file may have been changed from a
10959 * non-regular file to a regular file between the stat and the open.
10960 * We are assuming that the O_EXCL open handles the case where FILENAME
10961 * did not exist and is symlinked to an existing file between the stat
10962 * and open.
10963 */
10964
10965 /*
10966 * If we can open it and fstat the file descriptor, and neither check
10967 * revealed that it was a regular file, and the file has not been
10968 * replaced, return the file descriptor.
10969 */
Eric Andersenc470f442003-07-28 09:56:35 +000010970 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10971 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010972 return fd;
10973
10974 /* The file has been replaced. badness. */
10975 close(fd);
10976 errno = EEXIST;
10977 return -1;
10978}
Eric Andersencb57d552001-06-28 07:25:16 +000010979
10980/*
Eric Andersen62483552001-07-10 06:09:16 +000010981 * Handle here documents. Normally we fork off a process to write the
10982 * data to a pipe. If the document is short, we can stuff the data in
10983 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010984 */
10985
Rob Landley88621d72006-08-29 19:41:06 +000010986static int openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010987{
10988 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010989 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010990
Eric Andersen62483552001-07-10 06:09:16 +000010991 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010992 sh_error("Pipe call failed");
Eric Andersen62483552001-07-10 06:09:16 +000010993 if (redir->type == NHERE) {
10994 len = strlen(redir->nhere.doc->narg.text);
10995 if (len <= PIPESIZE) {
Rob Landley53437472006-07-16 08:14:35 +000010996 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010997 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010998 }
Eric Andersencb57d552001-06-28 07:25:16 +000010999 }
Eric Andersenc470f442003-07-28 09:56:35 +000011000 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000011001 close(pip[0]);
11002 signal(SIGINT, SIG_IGN);
11003 signal(SIGQUIT, SIG_IGN);
11004 signal(SIGHUP, SIG_IGN);
11005#ifdef SIGTSTP
11006 signal(SIGTSTP, SIG_IGN);
11007#endif
11008 signal(SIGPIPE, SIG_DFL);
11009 if (redir->type == NHERE)
Rob Landley53437472006-07-16 08:14:35 +000011010 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000011011 else
11012 expandhere(redir->nhere.doc, pip[1]);
11013 _exit(0);
11014 }
Eric Andersenc470f442003-07-28 09:56:35 +000011015out:
Eric Andersen62483552001-07-10 06:09:16 +000011016 close(pip[1]);
11017 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011018}
11019
Eric Andersenc470f442003-07-28 09:56:35 +000011020static int
11021openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011022{
Eric Andersencb57d552001-06-28 07:25:16 +000011023 char *fname;
11024 int f;
11025
11026 switch (redir->nfile.type) {
11027 case NFROM:
11028 fname = redir->nfile.expfname;
11029 if ((f = open(fname, O_RDONLY)) < 0)
11030 goto eopen;
11031 break;
11032 case NFROMTO:
11033 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011034 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011035 goto ecreate;
11036 break;
11037 case NTO:
11038 /* Take care of noclobber mode. */
11039 if (Cflag) {
11040 fname = redir->nfile.expfname;
11041 if ((f = noclobberopen(fname)) < 0)
11042 goto ecreate;
11043 break;
11044 }
Eric Andersenc470f442003-07-28 09:56:35 +000011045 /* FALLTHROUGH */
11046 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011047 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011048 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011049 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011050 break;
11051 case NAPPEND:
11052 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011053 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011054 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011055 break;
11056 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011057#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011058 abort();
11059#endif
11060 /* Fall through to eliminate warning. */
11061 case NTOFD:
11062 case NFROMFD:
11063 f = -1;
11064 break;
11065 case NHERE:
11066 case NXHERE:
11067 f = openhere(redir);
11068 break;
11069 }
11070
11071 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011072ecreate:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011073 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011074eopen:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011075 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
Eric Andersencb57d552001-06-28 07:25:16 +000011076}
11077
Rob Landley88621d72006-08-29 19:41:06 +000011078static void dupredirect(union node *redir, int f)
Eric Andersenc470f442003-07-28 09:56:35 +000011079{
11080 int fd = redir->nfile.fd;
11081
11082 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11083 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11084 copyfd(redir->ndup.dupfd, fd);
11085 }
11086 return;
11087 }
11088
11089 if (f != fd) {
11090 copyfd(f, fd);
11091 close(f);
11092 }
11093 return;
11094}
Eric Andersencb57d552001-06-28 07:25:16 +000011095
Eric Andersen62483552001-07-10 06:09:16 +000011096/*
11097 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11098 * old file descriptors are stashed away so that the redirection can be
11099 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11100 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011101 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011102 */
11103
Eric Andersenc470f442003-07-28 09:56:35 +000011104static void
11105redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011106{
11107 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011108 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011109 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011110 int fd;
11111 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011112 int *p;
11113 nullredirs++;
11114 if (!redir) {
11115 return;
Eric Andersen62483552001-07-10 06:09:16 +000011116 }
Eric Andersenc470f442003-07-28 09:56:35 +000011117 sv = NULL;
11118 INTOFF;
11119 if (flags & REDIR_PUSH) {
11120 struct redirtab *q;
11121 q = ckmalloc(sizeof (struct redirtab));
11122 q->next = redirlist;
11123 redirlist = q;
11124 q->nullredirs = nullredirs - 1;
11125 for (i = 0 ; i < 10 ; i++)
11126 q->renamed[i] = EMPTY;
11127 nullredirs = 0;
11128 sv = q;
11129 }
11130 n = redir;
11131 do {
Eric Andersen62483552001-07-10 06:09:16 +000011132 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011133 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011134 n->ndup.dupfd == fd)
11135 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011136
Eric Andersen62483552001-07-10 06:09:16 +000011137 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011138 if (fd == newfd)
11139 continue;
11140 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11141 i = fcntl(fd, F_DUPFD, 10);
11142
11143 if (i == -1) {
11144 i = errno;
11145 if (i != EBADF) {
11146 close(newfd);
11147 errno = i;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011148 sh_error("%d: %m", fd);
Eric Andersen62483552001-07-10 06:09:16 +000011149 /* NOTREACHED */
11150 }
Eric Andersenc470f442003-07-28 09:56:35 +000011151 } else {
11152 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011153 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011154 }
Eric Andersenc470f442003-07-28 09:56:35 +000011155 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011156 close(fd);
11157 }
Eric Andersenc470f442003-07-28 09:56:35 +000011158 dupredirect(n, newfd);
11159 } while ((n = n->nfile.next));
11160 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011161 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11162 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011163}
11164
11165
Eric Andersencb57d552001-06-28 07:25:16 +000011166/*
11167 * Undo the effects of the last redirection.
11168 */
11169
Eric Andersenc470f442003-07-28 09:56:35 +000011170void
11171popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011172{
Eric Andersenc470f442003-07-28 09:56:35 +000011173 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011174 int i;
11175
Eric Andersenc470f442003-07-28 09:56:35 +000011176 if (--nullredirs >= 0)
11177 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011178 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011179 rp = redirlist;
11180 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011181 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011182 if (!drop) {
11183 close(i);
11184 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011185 }
Eric Andersenc470f442003-07-28 09:56:35 +000011186 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011187 }
11188 }
11189 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011190 nullredirs = rp->nullredirs;
11191 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011192 INTON;
11193}
11194
11195/*
Eric Andersenc470f442003-07-28 09:56:35 +000011196 * Undo all redirections. Called on error or interrupt.
11197 */
11198
11199/*
Eric Andersencb57d552001-06-28 07:25:16 +000011200 * Discard all saved file descriptors.
11201 */
11202
Eric Andersenc470f442003-07-28 09:56:35 +000011203void
11204clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011205{
Eric Andersenc470f442003-07-28 09:56:35 +000011206 for (;;) {
11207 nullredirs = 0;
11208 if (!redirlist)
11209 break;
11210 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011211 }
Eric Andersencb57d552001-06-28 07:25:16 +000011212}
11213
11214
Eric Andersencb57d552001-06-28 07:25:16 +000011215/*
11216 * Copy a file descriptor to be >= to. Returns -1
11217 * if the source file descriptor is closed, EMPTY if there are no unused
11218 * file descriptors left.
11219 */
11220
Eric Andersenc470f442003-07-28 09:56:35 +000011221int
11222copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011223{
11224 int newfd;
11225
11226 newfd = fcntl(from, F_DUPFD, to);
11227 if (newfd < 0) {
11228 if (errno == EMFILE)
11229 return EMPTY;
11230 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011231 sh_error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011232 }
11233 return newfd;
11234}
11235
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011236
Eric Andersenc470f442003-07-28 09:56:35 +000011237int
11238redirectsafe(union node *redir, int flags)
11239{
11240 int err;
11241 volatile int saveint;
11242 struct jmploc *volatile savehandler = handler;
11243 struct jmploc jmploc;
11244
11245 SAVEINT(saveint);
11246 if (!(err = setjmp(jmploc.loc) * 2)) {
11247 handler = &jmploc;
11248 redirect(redir, flags);
11249 }
11250 handler = savehandler;
11251 if (err && exception != EXERROR)
11252 longjmp(handler->loc, 1);
11253 RESTOREINT(saveint);
11254 return err;
11255}
11256
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011257/* show.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011258
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011259#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +000011260static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011261static void shcmd(union node *, FILE *);
11262static void sharg(union node *, FILE *);
11263static void indent(int, char *, FILE *);
11264static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011265
11266
Eric Andersenc470f442003-07-28 09:56:35 +000011267void
11268showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011269{
11270 trputs("showtree called\n");
11271 shtree(n, 1, NULL, stdout);
11272}
Eric Andersencb57d552001-06-28 07:25:16 +000011273
Eric Andersenc470f442003-07-28 09:56:35 +000011274
11275static void
11276shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011277{
11278 struct nodelist *lp;
11279 const char *s;
11280
11281 if (n == NULL)
11282 return;
11283
11284 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011285 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011286 case NSEMI:
11287 s = "; ";
11288 goto binop;
11289 case NAND:
11290 s = " && ";
11291 goto binop;
11292 case NOR:
11293 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011294binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011295 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011296 /* if (ind < 0) */
11297 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011298 shtree(n->nbinary.ch2, ind, NULL, fp);
11299 break;
11300 case NCMD:
11301 shcmd(n, fp);
11302 if (ind >= 0)
11303 putc('\n', fp);
11304 break;
11305 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011306 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011307 shcmd(lp->n, fp);
11308 if (lp->next)
11309 fputs(" | ", fp);
11310 }
11311 if (n->npipe.backgnd)
11312 fputs(" &", fp);
11313 if (ind >= 0)
11314 putc('\n', fp);
11315 break;
11316 default:
11317 fprintf(fp, "<node type %d>", n->type);
11318 if (ind >= 0)
11319 putc('\n', fp);
11320 break;
11321 }
11322}
11323
11324
Eric Andersenc470f442003-07-28 09:56:35 +000011325static void
11326shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011327{
11328 union node *np;
11329 int first;
11330 const char *s;
11331 int dftfd;
11332
11333 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011334 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11335 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011336 putchar(' ');
11337 sharg(np, fp);
11338 first = 0;
11339 }
Eric Andersenc470f442003-07-28 09:56:35 +000011340 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11341 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011342 putchar(' ');
11343 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011344 case NTO: s = ">"; dftfd = 1; break;
11345 case NCLOBBER: s = ">|"; dftfd = 1; break;
11346 case NAPPEND: s = ">>"; dftfd = 1; break;
11347 case NTOFD: s = ">&"; dftfd = 1; break;
11348 case NFROM: s = "<"; dftfd = 0; break;
11349 case NFROMFD: s = "<&"; dftfd = 0; break;
11350 case NFROMTO: s = "<>"; dftfd = 0; break;
11351 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011352 }
11353 if (np->nfile.fd != dftfd)
11354 fprintf(fp, "%d", np->nfile.fd);
11355 fputs(s, fp);
11356 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11357 fprintf(fp, "%d", np->ndup.dupfd);
11358 } else {
11359 sharg(np->nfile.fname, fp);
11360 }
11361 first = 0;
11362 }
11363}
11364
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011365
Eric Andersenc470f442003-07-28 09:56:35 +000011366
11367static void
11368sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011369{
Eric Andersencb57d552001-06-28 07:25:16 +000011370 char *p;
11371 struct nodelist *bqlist;
11372 int subtype;
11373
11374 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011375 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011376 abort();
11377 }
11378 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011379 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011380 switch (*p) {
11381 case CTLESC:
11382 putc(*++p, fp);
11383 break;
11384 case CTLVAR:
11385 putc('$', fp);
11386 putc('{', fp);
11387 subtype = *++p;
11388 if (subtype == VSLENGTH)
11389 putc('#', fp);
11390
11391 while (*p != '=')
11392 putc(*p++, fp);
11393
11394 if (subtype & VSNUL)
11395 putc(':', fp);
11396
11397 switch (subtype & VSTYPE) {
11398 case VSNORMAL:
11399 putc('}', fp);
11400 break;
11401 case VSMINUS:
11402 putc('-', fp);
11403 break;
11404 case VSPLUS:
11405 putc('+', fp);
11406 break;
11407 case VSQUESTION:
11408 putc('?', fp);
11409 break;
11410 case VSASSIGN:
11411 putc('=', fp);
11412 break;
11413 case VSTRIMLEFT:
11414 putc('#', fp);
11415 break;
11416 case VSTRIMLEFTMAX:
11417 putc('#', fp);
11418 putc('#', fp);
11419 break;
11420 case VSTRIMRIGHT:
11421 putc('%', fp);
11422 break;
11423 case VSTRIMRIGHTMAX:
11424 putc('%', fp);
11425 putc('%', fp);
11426 break;
11427 case VSLENGTH:
11428 break;
11429 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011430 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011431 }
11432 break;
11433 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011434 putc('}', fp);
11435 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011436 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011437 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011438 putc('$', fp);
11439 putc('(', fp);
11440 shtree(bqlist->n, -1, NULL, fp);
11441 putc(')', fp);
11442 break;
11443 default:
11444 putc(*p, fp);
11445 break;
11446 }
11447 }
11448}
11449
11450
Eric Andersenc470f442003-07-28 09:56:35 +000011451static void
11452indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011453{
11454 int i;
11455
Eric Andersenc470f442003-07-28 09:56:35 +000011456 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011457 if (pfx && i == amount - 1)
11458 fputs(pfx, fp);
11459 putc('\t', fp);
11460 }
11461}
Eric Andersencb57d552001-06-28 07:25:16 +000011462
Eric Andersenc470f442003-07-28 09:56:35 +000011463
11464
11465/*
11466 * Debugging stuff.
11467 */
11468
11469
Eric Andersencb57d552001-06-28 07:25:16 +000011470FILE *tracefile;
11471
Eric Andersencb57d552001-06-28 07:25:16 +000011472
Eric Andersenc470f442003-07-28 09:56:35 +000011473void
11474trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011475{
Eric Andersenc470f442003-07-28 09:56:35 +000011476 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011477 return;
11478 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011479}
11480
Eric Andersenc470f442003-07-28 09:56:35 +000011481void
11482trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011483{
11484 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011485
Eric Andersenc470f442003-07-28 09:56:35 +000011486 if (debug != 1)
11487 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011488 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011489 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011490 va_end(va);
11491}
11492
Eric Andersenc470f442003-07-28 09:56:35 +000011493void
11494tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011495{
Eric Andersenc470f442003-07-28 09:56:35 +000011496 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011497 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011498 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011499}
11500
11501
Eric Andersenc470f442003-07-28 09:56:35 +000011502void
11503trputs(const char *s)
11504{
11505 if (debug != 1)
11506 return;
11507 fputs(s, tracefile);
11508}
11509
11510
11511static void
11512trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011513{
11514 char *p;
11515 char c;
11516
Eric Andersenc470f442003-07-28 09:56:35 +000011517 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011518 return;
11519 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011520 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011521 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011522 case '\n': c = 'n'; goto backslash;
11523 case '\t': c = 't'; goto backslash;
11524 case '\r': c = 'r'; goto backslash;
11525 case '"': c = '"'; goto backslash;
11526 case '\\': c = '\\'; goto backslash;
11527 case CTLESC: c = 'e'; goto backslash;
11528 case CTLVAR: c = 'v'; goto backslash;
11529 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11530 case CTLBACKQ: c = 'q'; goto backslash;
11531 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11532backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011533 putc(c, tracefile);
11534 break;
11535 default:
11536 if (*p >= ' ' && *p <= '~')
11537 putc(*p, tracefile);
11538 else {
11539 putc('\\', tracefile);
11540 putc(*p >> 6 & 03, tracefile);
11541 putc(*p >> 3 & 07, tracefile);
11542 putc(*p & 07, tracefile);
11543 }
11544 break;
11545 }
11546 }
11547 putc('"', tracefile);
11548}
11549
11550
Eric Andersenc470f442003-07-28 09:56:35 +000011551void
11552trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011553{
Eric Andersenc470f442003-07-28 09:56:35 +000011554 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011555 return;
11556 while (*ap) {
11557 trstring(*ap++);
11558 if (*ap)
11559 putc(' ', tracefile);
11560 else
11561 putc('\n', tracefile);
11562 }
Eric Andersencb57d552001-06-28 07:25:16 +000011563}
11564
11565
Eric Andersenc470f442003-07-28 09:56:35 +000011566void
11567opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011568{
Eric Andersencb57d552001-06-28 07:25:16 +000011569 char s[100];
11570#ifdef O_APPEND
11571 int flags;
11572#endif
11573
Eric Andersenc470f442003-07-28 09:56:35 +000011574 if (debug != 1) {
11575 if (tracefile)
11576 fflush(tracefile);
11577 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011578 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011579 }
Eric Andersenc470f442003-07-28 09:56:35 +000011580 scopy("./trace", s);
11581 if (tracefile) {
11582 if (!freopen(s, "a", tracefile)) {
11583 fprintf(stderr, "Can't re-open %s\n", s);
11584 debug = 0;
11585 return;
11586 }
11587 } else {
11588 if ((tracefile = fopen(s, "a")) == NULL) {
11589 fprintf(stderr, "Can't open %s\n", s);
11590 debug = 0;
11591 return;
11592 }
11593 }
Eric Andersencb57d552001-06-28 07:25:16 +000011594#ifdef O_APPEND
11595 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11596 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11597#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011598 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011599 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011600}
Eric Andersenc470f442003-07-28 09:56:35 +000011601#endif /* DEBUG */
11602
11603
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011604/* trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011605
11606/*
11607 * Sigmode records the current value of the signal handlers for the various
11608 * modes. A value of zero means that the current handler is not known.
11609 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11610 */
11611
11612#define S_DFL 1 /* default signal handling (SIG_DFL) */
11613#define S_CATCH 2 /* signal is caught */
11614#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11615#define S_HARD_IGN 4 /* signal is ignored permenantly */
11616#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11617
Eric Andersencb57d552001-06-28 07:25:16 +000011618
11619
11620/*
Eric Andersencb57d552001-06-28 07:25:16 +000011621 * The trap builtin.
11622 */
11623
Eric Andersenc470f442003-07-28 09:56:35 +000011624int
11625trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011626{
11627 char *action;
11628 char **ap;
11629 int signo;
11630
Eric Andersenc470f442003-07-28 09:56:35 +000011631 nextopt(nullstr);
11632 ap = argptr;
11633 if (!*ap) {
11634 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011635 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011636 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011637
Rob Landleyc9c1a412006-07-12 19:17:55 +000011638 sn = get_signame(signo);
Eric Andersenc470f442003-07-28 09:56:35 +000011639 out1fmt("trap -- %s %s\n",
11640 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011641 }
11642 }
11643 return 0;
11644 }
Eric Andersenc470f442003-07-28 09:56:35 +000011645 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011646 action = NULL;
11647 else
11648 action = *ap++;
11649 while (*ap) {
Rob Landleyc9c1a412006-07-12 19:17:55 +000011650 if ((signo = get_signum(*ap)) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011651 sh_error("%s: bad trap", *ap);
Eric Andersencb57d552001-06-28 07:25:16 +000011652 INTOFF;
11653 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000011654 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000011655 action = NULL;
11656 else
Eric Andersenc470f442003-07-28 09:56:35 +000011657 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011658 }
Eric Andersenc470f442003-07-28 09:56:35 +000011659 if (trap[signo])
11660 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011661 trap[signo] = action;
11662 if (signo != 0)
11663 setsignal(signo);
11664 INTON;
11665 ap++;
11666 }
11667 return 0;
11668}
11669
11670
Eric Andersenc470f442003-07-28 09:56:35 +000011671/*
11672 * Clear traps on a fork.
11673 */
11674
11675void
11676clear_traps(void)
11677{
11678 char **tp;
11679
11680 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11681 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11682 INTOFF;
11683 ckfree(*tp);
11684 *tp = NULL;
11685 if (tp != &trap[0])
11686 setsignal(tp - trap);
11687 INTON;
11688 }
11689 }
11690}
11691
11692
Eric Andersencb57d552001-06-28 07:25:16 +000011693/*
11694 * Set the signal handler for the specified signal. The routine figures
11695 * out what it should be set to.
11696 */
11697
Eric Andersenc470f442003-07-28 09:56:35 +000011698void
11699setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011700{
11701 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011702 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011703 struct sigaction act;
11704
11705 if ((t = trap[signo]) == NULL)
11706 action = S_DFL;
11707 else if (*t != '\0')
11708 action = S_CATCH;
11709 else
11710 action = S_IGN;
11711 if (rootshell && action == S_DFL) {
11712 switch (signo) {
11713 case SIGINT:
11714 if (iflag || minusc || sflag == 0)
11715 action = S_CATCH;
11716 break;
11717 case SIGQUIT:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011718#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011719 if (debug)
11720 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011721#endif
11722 /* FALLTHROUGH */
11723 case SIGTERM:
11724 if (iflag)
11725 action = S_IGN;
11726 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011727#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011728 case SIGTSTP:
11729 case SIGTTOU:
11730 if (mflag)
11731 action = S_IGN;
11732 break;
11733#endif
11734 }
11735 }
11736
11737 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011738 tsig = *t;
11739 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011740 /*
11741 * current setting unknown
11742 */
11743 if (sigaction(signo, 0, &act) == -1) {
11744 /*
11745 * Pretend it worked; maybe we should give a warning
11746 * here, but other shells don't. We don't alter
11747 * sigmode, so that we retry every time.
11748 */
11749 return;
11750 }
11751 if (act.sa_handler == SIG_IGN) {
11752 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011753 signo == SIGTTIN || signo == SIGTTOU)) {
11754 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011755 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011756 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011757 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011758 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011759 }
11760 }
Eric Andersenc470f442003-07-28 09:56:35 +000011761 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011762 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011763 switch (action) {
11764 case S_CATCH:
11765 act.sa_handler = onsig;
11766 break;
11767 case S_IGN:
11768 act.sa_handler = SIG_IGN;
11769 break;
11770 default:
11771 act.sa_handler = SIG_DFL;
11772 }
Eric Andersencb57d552001-06-28 07:25:16 +000011773 *t = action;
11774 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011775 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011776 sigaction(signo, &act, 0);
11777}
11778
11779/*
11780 * Ignore a signal.
11781 */
11782
Eric Andersenc470f442003-07-28 09:56:35 +000011783void
11784ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011785{
11786 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11787 signal(signo, SIG_IGN);
11788 }
11789 sigmode[signo - 1] = S_HARD_IGN;
11790}
11791
11792
Eric Andersencb57d552001-06-28 07:25:16 +000011793/*
11794 * Signal handler.
11795 */
11796
Eric Andersenc470f442003-07-28 09:56:35 +000011797void
11798onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011799{
Eric Andersencb57d552001-06-28 07:25:16 +000011800 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011801 pendingsigs = signo;
11802
11803 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11804 if (!suppressint)
11805 onint();
11806 intpending = 1;
11807 }
Eric Andersencb57d552001-06-28 07:25:16 +000011808}
11809
11810
Eric Andersencb57d552001-06-28 07:25:16 +000011811/*
11812 * Called to execute a trap. Perhaps we should avoid entering new trap
11813 * handlers while we are executing a trap handler.
11814 */
11815
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011816int
Eric Andersenc470f442003-07-28 09:56:35 +000011817dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011818{
Eric Andersenc470f442003-07-28 09:56:35 +000011819 char *p;
11820 char *q;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011821 int i;
Eric Andersencb57d552001-06-28 07:25:16 +000011822 int savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011823 int skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011824
Eric Andersenc470f442003-07-28 09:56:35 +000011825 savestatus = exitstatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011826 pendingsigs = 0;
11827 xbarrier();
11828
11829 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11830 if (!*q)
11831 continue;
11832 *q = 0;
11833
11834 p = trap[i + 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011835 if (!p)
11836 continue;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011837 skip = evalstring(p, SKIPEVAL);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011838 exitstatus = savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011839 if (skip)
11840 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011841 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011842
11843 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +000011844}
11845
Eric Andersenc470f442003-07-28 09:56:35 +000011846
Eric Andersenc470f442003-07-28 09:56:35 +000011847/*
11848 * Controls whether the shell is interactive or not.
11849 */
11850
Eric Andersenc470f442003-07-28 09:56:35 +000011851void
11852setinteractive(int on)
11853{
11854 static int is_interactive;
11855
11856 if (++on == is_interactive)
11857 return;
11858 is_interactive = on;
11859 setsignal(SIGINT);
11860 setsignal(SIGQUIT);
11861 setsignal(SIGTERM);
11862#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11863 if(is_interactive > 1) {
11864 /* Looks like they want an interactive shell */
11865 static int do_banner;
11866
11867 if(!do_banner) {
11868 out1fmt(
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +000011869 "\n\n%s Built-in shell (ash)\n"
11870 "Enter 'help' for a list of built-in commands.\n\n",
11871 BB_BANNER);
Eric Andersenc470f442003-07-28 09:56:35 +000011872 do_banner++;
11873 }
11874 }
11875#endif
11876}
11877
11878
11879#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11880/*** List the available builtins ***/
11881
11882static int helpcmd(int argc, char **argv)
11883{
11884 int col, i;
11885
11886 out1fmt("\nBuilt-in commands:\n-------------------\n");
11887 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11888 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11889 builtincmd[i].name + 1);
11890 if (col > 60) {
11891 out1fmt("\n");
11892 col = 0;
11893 }
11894 }
11895#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11896 {
11897 extern const struct BB_applet applets[];
11898 extern const size_t NUM_APPLETS;
11899
11900 for (i = 0; i < NUM_APPLETS; i++) {
11901
11902 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11903 if (col > 60) {
11904 out1fmt("\n");
11905 col = 0;
11906 }
11907 }
11908 }
11909#endif
11910 out1fmt("\n\n");
11911 return EXIT_SUCCESS;
11912}
11913#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11914
Eric Andersencb57d552001-06-28 07:25:16 +000011915/*
11916 * Called to exit the shell.
11917 */
11918
Eric Andersenc470f442003-07-28 09:56:35 +000011919void
11920exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011921{
Eric Andersenc470f442003-07-28 09:56:35 +000011922 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011923 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011924 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011925
Eric Andersenc470f442003-07-28 09:56:35 +000011926 status = exitstatus;
11927 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011928 if (setjmp(loc.loc)) {
11929 if (exception == EXEXIT)
11930 _exit(exitstatus);
Eric Andersenc470f442003-07-28 09:56:35 +000011931 goto out;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011932 }
Eric Andersenc470f442003-07-28 09:56:35 +000011933 handler = &loc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011934 if ((p = trap[0])) {
Eric Andersencb57d552001-06-28 07:25:16 +000011935 trap[0] = NULL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011936 evalstring(p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011937 }
Eric Andersencb57d552001-06-28 07:25:16 +000011938 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011939 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011940#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11941 if (iflag && rootshell) {
11942 const char *hp = lookupvar("HISTFILE");
11943
11944 if(hp != NULL )
11945 save_history ( hp );
11946 }
11947#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011948out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011949 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011950 /* NOTREACHED */
11951}
11952
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011953/* var.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011954
11955static struct var *vartab[VTABSIZE];
11956
11957static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011958static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011959
11960/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011961 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011962 */
11963
Eric Andersenc470f442003-07-28 09:56:35 +000011964
11965#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011966/*
Eric Andersenc470f442003-07-28 09:56:35 +000011967 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011968 */
11969
Eric Andersenc470f442003-07-28 09:56:35 +000011970int
11971setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011972{
Eric Andersenc470f442003-07-28 09:56:35 +000011973 int err;
11974 volatile int saveint;
11975 struct jmploc *volatile savehandler = handler;
11976 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011977
Eric Andersenc470f442003-07-28 09:56:35 +000011978 SAVEINT(saveint);
11979 if (setjmp(jmploc.loc))
11980 err = 1;
11981 else {
11982 handler = &jmploc;
11983 setvar(name, val, flags);
11984 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011985 }
Eric Andersenc470f442003-07-28 09:56:35 +000011986 handler = savehandler;
11987 RESTOREINT(saveint);
11988 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011989}
Eric Andersenc470f442003-07-28 09:56:35 +000011990#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011991
11992/*
11993 * Set the value of a variable. The flags argument is ored with the
11994 * flags of the variable. If val is NULL, the variable is unset.
11995 */
11996
Eric Andersenc470f442003-07-28 09:56:35 +000011997static void
11998setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011999{
Eric Andersenc470f442003-07-28 09:56:35 +000012000 char *p, *q;
12001 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000012002 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000012003 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000012004
Eric Andersenc470f442003-07-28 09:56:35 +000012005 q = endofname(name);
12006 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012007 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000012008 if (!namelen || p != q)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012009 sh_error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012010 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012011 if (val == NULL) {
12012 flags |= VUNSET;
12013 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012014 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000012015 }
12016 INTOFF;
Denis Vlasenko15b213e2006-12-19 00:20:20 +000012017 nameeq = ckmalloc(namelen + vallen + 2);
Denis Vlasenko7cfecc42006-12-18 22:32:45 +000012018 p = memcpy(nameeq, name, namelen) + namelen;
Paul Fox8de331d2005-07-21 12:03:05 +000012019 if (val) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012020 *p++ = '=';
Denis Vlasenko7cfecc42006-12-18 22:32:45 +000012021 p = memcpy(p, val, vallen) + vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000012022 }
Eric Andersenc470f442003-07-28 09:56:35 +000012023 *p = '\0';
12024 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012025 INTON;
12026}
12027
12028
Eric Andersencb57d552001-06-28 07:25:16 +000012029/*
12030 * Same as setvar except that the variable and value are passed in
12031 * the first argument as name=value. Since the first argument will
12032 * be actually stored in the table, it should not be a string that
12033 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012034 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012035 */
12036
Eric Andersenc470f442003-07-28 09:56:35 +000012037void
12038setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012039{
12040 struct var *vp, **vpp;
12041
12042 vpp = hashvar(s);
12043 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012044 vp = *findvar(vpp, s);
12045 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012046 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12047 const char *n;
12048
Eric Andersenc470f442003-07-28 09:56:35 +000012049 if (flags & VNOSAVE)
12050 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012051 n = vp->text;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012052 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012053 }
Eric Andersenc470f442003-07-28 09:56:35 +000012054
12055 if (flags & VNOSET)
12056 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012057
12058 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012059 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012060
Eric Andersenc470f442003-07-28 09:56:35 +000012061 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12062 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012063
Eric Andersenc470f442003-07-28 09:56:35 +000012064 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12065 } else {
12066 if (flags & VNOSET)
12067 return;
12068 /* not found */
12069 vp = ckmalloc(sizeof (*vp));
12070 vp->next = *vpp;
12071 vp->func = NULL;
12072 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012073 }
Eric Andersenc470f442003-07-28 09:56:35 +000012074 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12075 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012076 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012077 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012078}
12079
12080
Eric Andersencb57d552001-06-28 07:25:16 +000012081/*
12082 * Process a linked list of variable assignments.
12083 */
12084
Eric Andersenc470f442003-07-28 09:56:35 +000012085static void
12086listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012087{
Eric Andersenc470f442003-07-28 09:56:35 +000012088 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012089
Eric Andersenc470f442003-07-28 09:56:35 +000012090 if (!lp)
12091 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012092 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012093 do {
12094 setvareq(lp->text, flags);
12095 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012096 INTON;
12097}
12098
12099
Eric Andersencb57d552001-06-28 07:25:16 +000012100/*
12101 * Find the value of a variable. Returns NULL if not set.
12102 */
12103
Eric Andersenc470f442003-07-28 09:56:35 +000012104static char *
12105lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012106{
Eric Andersencb57d552001-06-28 07:25:16 +000012107 struct var *v;
12108
Eric Andersen16767e22004-03-16 05:14:10 +000012109 if ((v = *findvar(hashvar(name), name))) {
12110#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012111 /*
12112 * Dynamic variables are implemented roughly the same way they are
12113 * in bash. Namely, they're "special" so long as they aren't unset.
12114 * As soon as they're unset, they're no longer dynamic, and dynamic
12115 * lookup will no longer happen at that point. -- PFM.
12116 */
Eric Andersen16767e22004-03-16 05:14:10 +000012117 if((v->flags & VDYNAMIC))
12118 (*v->func)(NULL);
12119#endif
12120 if(!(v->flags & VUNSET))
12121 return strchrnul(v->text, '=') + 1;
12122 }
Eric Andersenef02f822004-03-11 13:34:24 +000012123
Eric Andersencb57d552001-06-28 07:25:16 +000012124 return NULL;
12125}
12126
12127
Eric Andersencb57d552001-06-28 07:25:16 +000012128/*
12129 * Search the environment of a builtin command.
12130 */
12131
Eric Andersenc470f442003-07-28 09:56:35 +000012132static char *
12133bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012134{
Eric Andersenc470f442003-07-28 09:56:35 +000012135 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012136
Eric Andersenc470f442003-07-28 09:56:35 +000012137 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012138 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012139 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012140 }
12141 return lookupvar(name);
12142}
12143
12144
Eric Andersencb57d552001-06-28 07:25:16 +000012145/*
Eric Andersenc470f442003-07-28 09:56:35 +000012146 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012147 */
12148
Eric Andersenc470f442003-07-28 09:56:35 +000012149static char **
12150listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012151{
Eric Andersencb57d552001-06-28 07:25:16 +000012152 struct var **vpp;
12153 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012154 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012155 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012156
Eric Andersenc470f442003-07-28 09:56:35 +000012157 STARTSTACKSTR(ep);
12158 vpp = vartab;
12159 mask = on | off;
12160 do {
12161 for (vp = *vpp ; vp ; vp = vp->next)
12162 if ((vp->flags & mask) == on) {
12163 if (ep == stackstrend())
12164 ep = growstackstr();
12165 *ep++ = (char *) vp->text;
12166 }
12167 } while (++vpp < vartab + VTABSIZE);
12168 if (ep == stackstrend())
12169 ep = growstackstr();
12170 if (end)
12171 *end = ep;
12172 *ep++ = NULL;
12173 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012174}
12175
12176
12177/*
Eric Andersenc470f442003-07-28 09:56:35 +000012178 * POSIX requires that 'set' (but not export or readonly) output the
12179 * variables in lexicographic order - by the locale's collating order (sigh).
12180 * Maybe we could keep them in an ordered balanced binary tree
12181 * instead of hashed lists.
12182 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012183 */
12184
Eric Andersenc470f442003-07-28 09:56:35 +000012185static int
12186showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012187{
Eric Andersenc470f442003-07-28 09:56:35 +000012188 const char *sep;
12189 char **ep, **epend;
12190
12191 ep = listvars(on, off, &epend);
12192 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12193
12194 sep = *sep_prefix ? spcstr : sep_prefix;
12195
12196 for (; ep < epend; ep++) {
12197 const char *p;
12198 const char *q;
12199
12200 p = strchrnul(*ep, '=');
12201 q = nullstr;
12202 if (*p)
12203 q = single_quote(++p);
12204
12205 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12206 }
12207
Eric Andersencb57d552001-06-28 07:25:16 +000012208 return 0;
12209}
12210
12211
12212
12213/*
12214 * The export and readonly commands.
12215 */
12216
Eric Andersenc470f442003-07-28 09:56:35 +000012217static int
12218exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012219{
12220 struct var *vp;
12221 char *name;
12222 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012223 char **aptr;
12224 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12225 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012226
Eric Andersenc470f442003-07-28 09:56:35 +000012227 notp = nextopt("p") - 'p';
12228 if (notp && ((name = *(aptr = argptr)))) {
12229 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012230 if ((p = strchr(name, '=')) != NULL) {
12231 p++;
12232 } else {
12233 if ((vp = *findvar(hashvar(name), name))) {
12234 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012235 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012236 }
12237 }
12238 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012239 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012240 } else {
12241 showvars(argv[0], flag, 0);
12242 }
12243 return 0;
12244}
12245
Eric Andersen34506362001-08-02 05:02:46 +000012246
Eric Andersencb57d552001-06-28 07:25:16 +000012247/*
Eric Andersencb57d552001-06-28 07:25:16 +000012248 * Make a variable a local variable. When a variable is made local, it's
12249 * value and flags are saved in a localvar structure. The saved values
12250 * will be restored when the shell function returns. We handle the name
12251 * "-" as a special case.
12252 */
12253
Rob Landley88621d72006-08-29 19:41:06 +000012254static void mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012255{
Eric Andersencb57d552001-06-28 07:25:16 +000012256 struct localvar *lvp;
12257 struct var **vpp;
12258 struct var *vp;
12259
12260 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012261 lvp = ckmalloc(sizeof (struct localvar));
Denis Vlasenko9f739442006-12-16 23:49:13 +000012262 if (LONE_DASH(name)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012263 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012264 p = ckmalloc(sizeof(optlist));
12265 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012266 vp = NULL;
12267 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012268 char *eq;
12269
Eric Andersencb57d552001-06-28 07:25:16 +000012270 vpp = hashvar(name);
12271 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012272 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012273 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012274 if (eq)
12275 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012276 else
12277 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012278 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012279 lvp->flags = VUNSET;
12280 } else {
12281 lvp->text = vp->text;
12282 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012283 vp->flags |= VSTRFIXED|VTEXTFIXED;
12284 if (eq)
12285 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012286 }
12287 }
12288 lvp->vp = vp;
12289 lvp->next = localvars;
12290 localvars = lvp;
12291 INTON;
12292}
12293
Eric Andersenc470f442003-07-28 09:56:35 +000012294/*
12295 * The "local" command.
12296 */
12297
12298static int
12299localcmd(int argc, char **argv)
12300{
12301 char *name;
12302
12303 argv = argptr;
12304 while ((name = *argv++) != NULL) {
12305 mklocal(name);
12306 }
12307 return 0;
12308}
12309
12310
Eric Andersencb57d552001-06-28 07:25:16 +000012311/*
12312 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012313 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012314 */
12315
Eric Andersenc470f442003-07-28 09:56:35 +000012316static void
12317poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012318{
Eric Andersencb57d552001-06-28 07:25:16 +000012319 struct localvar *lvp;
12320 struct var *vp;
12321
12322 while ((lvp = localvars) != NULL) {
12323 localvars = lvp->next;
12324 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012325 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12326 if (vp == NULL) { /* $- saved */
12327 memcpy(optlist, lvp->text, sizeof(optlist));
12328 ckfree(lvp->text);
12329 optschanged();
12330 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12331 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012332 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012333 if (vp->func)
12334 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12335 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12336 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012337 vp->flags = lvp->flags;
12338 vp->text = lvp->text;
12339 }
Eric Andersenc470f442003-07-28 09:56:35 +000012340 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012341 }
12342}
12343
12344
Eric Andersencb57d552001-06-28 07:25:16 +000012345/*
12346 * The unset builtin command. We unset the function before we unset the
12347 * variable to allow a function to be unset when there is a readonly variable
12348 * with the same name.
12349 */
12350
Eric Andersenc470f442003-07-28 09:56:35 +000012351int
12352unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012353{
12354 char **ap;
12355 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012356 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012357 int ret = 0;
12358
12359 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012360 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012361 }
Eric Andersencb57d552001-06-28 07:25:16 +000012362
Eric Andersenc470f442003-07-28 09:56:35 +000012363 for (ap = argptr; *ap ; ap++) {
12364 if (flag != 'f') {
12365 i = unsetvar(*ap);
12366 ret |= i;
12367 if (!(i & 2))
12368 continue;
12369 }
12370 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012371 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012372 }
Eric Andersenc470f442003-07-28 09:56:35 +000012373 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012374}
12375
12376
12377/*
12378 * Unset the specified variable.
12379 */
12380
Eric Andersenc470f442003-07-28 09:56:35 +000012381int
12382unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012383{
Eric Andersencb57d552001-06-28 07:25:16 +000012384 struct var **vpp;
12385 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012386 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012387
12388 vpp = findvar(hashvar(s), s);
12389 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012390 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012391 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012392 int flags = vp->flags;
12393
12394 retval = 1;
12395 if (flags & VREADONLY)
12396 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012397#ifdef DYNAMIC_VAR
12398 vp->flags &= ~VDYNAMIC;
12399#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012400 if (flags & VUNSET)
12401 goto ok;
12402 if ((flags & VSTRFIXED) == 0) {
12403 INTOFF;
12404 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12405 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012406 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012407 ckfree(vp);
12408 INTON;
12409 } else {
12410 setvar(s, 0, 0);
12411 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012412 }
Eric Andersenc470f442003-07-28 09:56:35 +000012413ok:
12414 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012415 }
12416
Eric Andersenc470f442003-07-28 09:56:35 +000012417out:
12418 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012419}
12420
12421
12422
12423/*
12424 * Find the appropriate entry in the hash table from the name.
12425 */
12426
Eric Andersenc470f442003-07-28 09:56:35 +000012427static struct var **
12428hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012429{
Eric Andersencb57d552001-06-28 07:25:16 +000012430 unsigned int hashval;
12431
12432 hashval = ((unsigned char) *p) << 4;
12433 while (*p && *p != '=')
12434 hashval += (unsigned char) *p++;
12435 return &vartab[hashval % VTABSIZE];
12436}
12437
12438
12439
12440/*
Eric Andersenc470f442003-07-28 09:56:35 +000012441 * Compares two strings up to the first = or '\0'. The first
12442 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012443 * either '=' or '\0'.
12444 */
12445
Eric Andersenc470f442003-07-28 09:56:35 +000012446int
12447varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012448{
Eric Andersenc470f442003-07-28 09:56:35 +000012449 int c, d;
12450
12451 while ((c = *p) == (d = *q)) {
12452 if (!c || c == '=')
12453 goto out;
12454 p++;
12455 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012456 }
Eric Andersenc470f442003-07-28 09:56:35 +000012457 if (c == '=')
12458 c = 0;
12459 if (d == '=')
12460 d = 0;
12461out:
12462 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012463}
12464
Eric Andersenc470f442003-07-28 09:56:35 +000012465static int
12466vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012467{
Eric Andersenc470f442003-07-28 09:56:35 +000012468 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012469}
12470
Eric Andersenc470f442003-07-28 09:56:35 +000012471static struct var **
12472findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012473{
12474 for (; *vpp; vpp = &(*vpp)->next) {
12475 if (varequal((*vpp)->text, name)) {
12476 break;
12477 }
12478 }
12479 return vpp;
12480}
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012481/* setmode.c */
Eric Andersencb57d552001-06-28 07:25:16 +000012482
Eric Andersenc470f442003-07-28 09:56:35 +000012483#include <sys/times.h>
12484
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012485static const unsigned char timescmd_str[] = {
12486 ' ', offsetof(struct tms, tms_utime),
12487 '\n', offsetof(struct tms, tms_stime),
12488 ' ', offsetof(struct tms, tms_cutime),
12489 '\n', offsetof(struct tms, tms_cstime),
12490 0
12491};
Eric Andersencb57d552001-06-28 07:25:16 +000012492
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012493static int timescmd(int ac, char **av)
12494{
12495 long int clk_tck, s, t;
12496 const unsigned char *p;
12497 struct tms buf;
12498
12499 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012500 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012501
12502 p = timescmd_str;
12503 do {
12504 t = *(clock_t *)(((char *) &buf) + p[1]);
12505 s = t / clk_tck;
12506 out1fmt("%ldm%ld.%.3lds%c",
12507 s/60, s%60,
12508 ((t - s * clk_tck) * 1000) / clk_tck,
12509 p[0]);
12510 } while (*(p += 2));
12511
Eric Andersencb57d552001-06-28 07:25:16 +000012512 return 0;
12513}
12514
Eric Andersend35c5df2002-01-09 15:37:36 +000012515#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012516static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012517dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012518{
Eric Andersened9ecf72004-06-22 08:29:45 +000012519 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012520 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012521
Eric Andersenc470f442003-07-28 09:56:35 +000012522 INTOFF;
12523 result = arith(s, &errcode);
12524 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012525 if (errcode == -3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012526 sh_error("exponent less than 0");
Eric Andersen90898442003-08-06 11:20:52 +000012527 else if (errcode == -2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012528 sh_error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012529 else if (errcode == -5)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012530 sh_error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012531 else
12532 synerror(s);
12533 }
12534 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012535
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012536 return result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012537}
Eric Andersenc470f442003-07-28 09:56:35 +000012538
12539
12540/*
Eric Andersen90898442003-08-06 11:20:52 +000012541 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12542 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12543 *
12544 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012545 */
Eric Andersen90898442003-08-06 11:20:52 +000012546
Eric Andersenc470f442003-07-28 09:56:35 +000012547static int
Eric Andersen90898442003-08-06 11:20:52 +000012548letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012549{
Eric Andersenc470f442003-07-28 09:56:35 +000012550 char **ap;
Denis Vlasenkocba9ef52006-10-10 21:00:47 +000012551 arith_t i = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012552
Eric Andersen90898442003-08-06 11:20:52 +000012553 ap = argv + 1;
12554 if(!*ap)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012555 sh_error("expression expected");
Eric Andersen90898442003-08-06 11:20:52 +000012556 for (ap = argv + 1; *ap; ap++) {
12557 i = dash_arith(*ap);
12558 }
Eric Andersenc470f442003-07-28 09:56:35 +000012559
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012560 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012561}
12562#endif /* CONFIG_ASH_MATH_SUPPORT */
12563
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012564/* miscbltin.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012565
12566/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012567 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012568 */
12569
12570#undef rflag
12571
Denis Vlasenko83e5d6f2006-12-18 21:49:06 +000012572#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012573typedef enum __rlimit_resource rlim_t;
12574#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012575
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;
Denis Vlasenko079f8af2006-11-27 16:49:31 +000013423 err:
13424 return -1;
Eric Andersen90898442003-08-06 11:20:52 +000013425}
13426
13427/* longest must first */
13428static const char op_tokens[] = {
13429 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13430 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13431 '<','<', 0, TOK_LSHIFT,
13432 '>','>', 0, TOK_RSHIFT,
13433 '|','|', 0, TOK_OR,
13434 '&','&', 0, TOK_AND,
13435 '!','=', 0, TOK_NE,
13436 '<','=', 0, TOK_LE,
13437 '>','=', 0, TOK_GE,
13438 '=','=', 0, TOK_EQ,
13439 '|','=', 0, TOK_OR_ASSIGN,
13440 '&','=', 0, TOK_AND_ASSIGN,
13441 '*','=', 0, TOK_MUL_ASSIGN,
13442 '/','=', 0, TOK_DIV_ASSIGN,
13443 '%','=', 0, TOK_REM_ASSIGN,
13444 '+','=', 0, TOK_PLUS_ASSIGN,
13445 '-','=', 0, TOK_MINUS_ASSIGN,
13446 '-','-', 0, TOK_POST_DEC,
13447 '^','=', 0, TOK_XOR_ASSIGN,
13448 '+','+', 0, TOK_POST_INC,
13449 '*','*', 0, TOK_EXPONENT,
13450 '!', 0, TOK_NOT,
13451 '<', 0, TOK_LT,
13452 '>', 0, TOK_GT,
13453 '=', 0, TOK_ASSIGN,
13454 '|', 0, TOK_BOR,
13455 '&', 0, TOK_BAND,
13456 '*', 0, TOK_MUL,
13457 '/', 0, TOK_DIV,
13458 '%', 0, TOK_REM,
13459 '+', 0, TOK_ADD,
13460 '-', 0, TOK_SUB,
13461 '^', 0, TOK_BXOR,
13462 /* uniq */
13463 '~', 0, TOK_BNOT,
13464 ',', 0, TOK_COMMA,
13465 '?', 0, TOK_CONDITIONAL,
13466 ':', 0, TOK_CONDITIONAL_SEP,
13467 ')', 0, TOK_RPAREN,
13468 '(', 0, TOK_LPAREN,
13469 0
13470};
13471/* ptr to ")" */
13472#define endexpression &op_tokens[sizeof(op_tokens)-7]
13473
13474
Eric Andersened9ecf72004-06-22 08:29:45 +000013475static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013476{
"Robert P. J. Day"68229832006-07-01 13:08:46 +000013477 char arithval; /* Current character under analysis */
Eric Andersen90898442003-08-06 11:20:52 +000013478 operator lasttok, op;
13479 operator prec;
13480
13481 const char *p = endexpression;
13482 int errcode;
13483
13484 size_t datasizes = strlen(expr) + 2;
13485
13486 /* Stack of integers */
13487 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013488 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013489 * the reader. */
13490 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13491 *numstackptr = numstack;
13492 /* Stack of operator tokens */
13493 operator *stack = alloca((datasizes) * sizeof(operator)),
13494 *stackptr = stack;
13495
13496 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13497 *perrcode = errcode = 0;
13498
13499 while(1) {
13500 if ((arithval = *expr) == 0) {
13501 if (p == endexpression) {
13502 /* Null expression. */
13503 return 0;
13504 }
13505
13506 /* This is only reached after all tokens have been extracted from the
13507 * input stream. If there are still tokens on the operator stack, they
13508 * are to be applied in order. At the end, there should be a final
13509 * result on the integer stack */
13510
13511 if (expr != endexpression + 1) {
13512 /* If we haven't done so already, */
13513 /* append a closing right paren */
13514 expr = endexpression;
13515 /* and let the loop process it. */
13516 continue;
13517 }
13518 /* At this point, we're done with the expression. */
13519 if (numstackptr != numstack+1) {
13520 /* ... but if there isn't, it's bad */
13521 err:
13522 return (*perrcode = -1);
13523 }
13524 if(numstack->var) {
13525 /* expression is $((var)) only, lookup now */
13526 errcode = arith_lookup_val(numstack);
13527 }
13528 ret:
13529 *perrcode = errcode;
13530 return numstack->val;
13531 } else {
13532 /* Continue processing the expression. */
13533 if (arith_isspace(arithval)) {
13534 /* Skip whitespace */
13535 goto prologue;
13536 }
13537 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013538 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013539
13540 numstackptr->var = alloca(var_name_size);
13541 safe_strncpy(numstackptr->var, expr, var_name_size);
13542 expr = p;
13543 num:
13544 numstackptr->contidional_second_val_initialized = 0;
13545 numstackptr++;
13546 lasttok = TOK_NUM;
13547 continue;
13548 } else if (is_digit(arithval)) {
13549 numstackptr->var = NULL;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013550#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersenad63cb22004-10-08 09:43:34 +000013551 numstackptr->val = strtoll(expr, (char **) &expr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013552#else
13553 numstackptr->val = strtol(expr, (char **) &expr, 0);
13554#endif
Eric Andersen90898442003-08-06 11:20:52 +000013555 goto num;
13556 }
13557 for(p = op_tokens; ; p++) {
13558 const char *o;
13559
13560 if(*p == 0) {
13561 /* strange operator not found */
13562 goto err;
13563 }
13564 for(o = expr; *p && *o == *p; p++)
13565 o++;
13566 if(! *p) {
13567 /* found */
13568 expr = o - 1;
13569 break;
13570 }
13571 /* skip tail uncompared token */
13572 while(*p)
13573 p++;
13574 /* skip zero delim */
13575 p++;
13576 }
13577 op = p[1];
13578
13579 /* post grammar: a++ reduce to num */
13580 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13581 lasttok = TOK_NUM;
13582
13583 /* Plus and minus are binary (not unary) _only_ if the last
13584 * token was as number, or a right paren (which pretends to be
13585 * a number, since it evaluates to one). Think about it.
13586 * It makes sense. */
13587 if (lasttok != TOK_NUM) {
13588 switch(op) {
13589 case TOK_ADD:
13590 op = TOK_UPLUS;
13591 break;
13592 case TOK_SUB:
13593 op = TOK_UMINUS;
13594 break;
13595 case TOK_POST_INC:
13596 op = TOK_PRE_INC;
13597 break;
13598 case TOK_POST_DEC:
13599 op = TOK_PRE_DEC;
13600 break;
13601 }
13602 }
13603 /* We don't want a unary operator to cause recursive descent on the
13604 * stack, because there can be many in a row and it could cause an
13605 * operator to be evaluated before its argument is pushed onto the
13606 * integer stack. */
13607 /* But for binary operators, "apply" everything on the operator
13608 * stack until we find an operator with a lesser priority than the
13609 * one we have just extracted. */
13610 /* Left paren is given the lowest priority so it will never be
13611 * "applied" in this way.
13612 * if associativity is right and priority eq, applied also skip
13613 */
13614 prec = PREC(op);
13615 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13616 /* not left paren or unary */
13617 if (lasttok != TOK_NUM) {
13618 /* binary op must be preceded by a num */
13619 goto err;
13620 }
13621 while (stackptr != stack) {
13622 if (op == TOK_RPAREN) {
13623 /* The algorithm employed here is simple: while we don't
13624 * hit an open paren nor the bottom of the stack, pop
13625 * tokens and apply them */
13626 if (stackptr[-1] == TOK_LPAREN) {
13627 --stackptr;
13628 /* Any operator directly after a */
13629 lasttok = TOK_NUM;
13630 /* close paren should consider itself binary */
13631 goto prologue;
13632 }
13633 } else {
13634 operator prev_prec = PREC(stackptr[-1]);
13635
13636 convert_prec_is_assing(prec);
13637 convert_prec_is_assing(prev_prec);
13638 if (prev_prec < prec)
13639 break;
13640 /* check right assoc */
13641 if(prev_prec == prec && is_right_associativity(prec))
13642 break;
13643 }
13644 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13645 if(errcode) goto ret;
13646 }
13647 if (op == TOK_RPAREN) {
13648 goto err;
13649 }
13650 }
13651
13652 /* Push this operator to the stack and remember it. */
13653 *stackptr++ = lasttok = op;
13654
13655 prologue:
13656 ++expr;
13657 }
13658 }
13659}
13660#endif /* CONFIG_ASH_MATH_SUPPORT */
13661
13662
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000013663#if DEBUG
Denis Vlasenko8f8f2682006-10-03 21:00:43 +000013664const char *applet_name = "debug stuff usage";
Eric Andersenc470f442003-07-28 09:56:35 +000013665int main(int argc, char **argv)
13666{
13667 return ash_main(argc, argv);
13668}
13669#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013670
Eric Andersendf82f612001-06-28 07:46:40 +000013671/*-
13672 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013673 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013674 *
13675 * This code is derived from software contributed to Berkeley by
13676 * Kenneth Almquist.
13677 *
13678 * Redistribution and use in source and binary forms, with or without
13679 * modification, are permitted provided that the following conditions
13680 * are met:
13681 * 1. Redistributions of source code must retain the above copyright
13682 * notice, this list of conditions and the following disclaimer.
13683 * 2. Redistributions in binary form must reproduce the above copyright
13684 * notice, this list of conditions and the following disclaimer in the
13685 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013686 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013687 * may be used to endorse or promote products derived from this software
13688 * without specific prior written permission.
13689 *
13690 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13691 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13692 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13693 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13694 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13695 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13696 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13697 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13698 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13699 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13700 * SUCH DAMAGE.
13701 */