blob: 0f9b3288b73aaa65223ffb6f26110622f0846276 [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
Denis Vlasenko666da5e2006-12-26 18:17:42 +000088#define JOBS 0
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
Eric Andersenc470f442003-07-28 09:56:35 +000096#ifdef __GLIBC__
97/* glibc sucks */
98static int *dash_errno;
99#undef errno
100#define errno (*dash_errno)
101#endif
102
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000103#if defined(__uClinux__)
104#error "Do not even bother, ash will not run on uClinux"
105#endif
106
Denis Vlasenkoa7189f02006-11-17 20:29:00 +0000107#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +0000108#define _DIAGASSERT(assert_expr) assert(assert_expr)
109#else
110#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000111#endif
112
Eric Andersen2870d962001-07-02 17:27:21 +0000113
Eric Andersenc470f442003-07-28 09:56:35 +0000114#ifdef CONFIG_ASH_ALIAS
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000115/* alias.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000116
117#define ALIASINUSE 1
118#define ALIASDEAD 2
119
120struct alias {
121 struct alias *next;
122 char *name;
123 char *val;
124 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000125};
126
Eric Andersenc470f442003-07-28 09:56:35 +0000127static struct alias *lookupalias(const char *, int);
128static int aliascmd(int, char **);
129static int unaliascmd(int, char **);
130static void rmaliases(void);
131static int unalias(const char *);
132static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000133#endif
134
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000135/* cd.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000136
137
138static void setpwd(const char *, int);
139
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000140/* error.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000141
142
143/*
144 * Types of operations (passed to the errmsg routine).
145 */
146
147
148static const char not_found_msg[] = "%s: not found";
149
150
151#define E_OPEN "No such file" /* opening a file */
152#define E_CREAT "Directory nonexistent" /* creating a file */
153#define E_EXEC not_found_msg+4 /* executing a program */
154
155/*
156 * We enclose jmp_buf in a structure so that we can declare pointers to
157 * jump locations. The global variable handler contains the location to
158 * jump to when an exception occurs, and the global variable exception
Eric Andersenaff114c2004-04-14 17:51:38 +0000159 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000160 * exception handlers, the user should save the value of handler on entry
161 * to an inner scope, set handler to point to a jmploc structure for the
162 * inner scope, and restore handler on exit from the scope.
163 */
164
165struct jmploc {
166 jmp_buf loc;
167};
168
169static struct jmploc *handler;
170static int exception;
171static volatile int suppressint;
172static volatile sig_atomic_t intpending;
173
Eric Andersenc470f442003-07-28 09:56:35 +0000174/* exceptions */
175#define EXINT 0 /* SIGINT received */
176#define EXERROR 1 /* a generic error */
177#define EXSHELLPROC 2 /* execute a shell procedure */
178#define EXEXEC 3 /* command execution failed */
179#define EXEXIT 4 /* exit the shell */
180#define EXSIG 5 /* trapped signal in wait(1) */
181
182
183/* do we generate EXSIG events */
184static int exsig;
185/* last pending signal */
186static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000187
188/*
189 * These macros allow the user to suspend the handling of interrupt signals
190 * over a period of time. This is similar to SIGHOLD to or sigblock, but
191 * much more efficient and portable. (But hacking the kernel is so much
192 * more fun than worrying about efficiency and portability. :-))
193 */
194
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000195#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
Eric Andersenc470f442003-07-28 09:56:35 +0000196#define INTOFF \
197 ({ \
198 suppressint++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000199 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000200 0; \
201 })
202#define SAVEINT(v) ((v) = suppressint)
203#define RESTOREINT(v) \
204 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000205 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000206 if ((suppressint = (v)) == 0 && intpending) onint(); \
207 0; \
208 })
209#define EXSIGON() \
210 ({ \
211 exsig++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000212 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000213 if (pendingsigs) \
214 exraise(EXSIG); \
215 0; \
216 })
217/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000218
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000219
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000220static void exraise(int) ATTRIBUTE_NORETURN;
221static void onint(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000222
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000223static void sh_error(const char *, ...) ATTRIBUTE_NORETURN;
224static void exerror(int, const char *, ...) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000225
226static void sh_warnx(const char *, ...);
227
228#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
229static void
230inton(void) {
231 if (--suppressint == 0 && intpending) {
232 onint();
233 }
234}
235#define INTON inton()
236static void forceinton(void)
237{
238 suppressint = 0;
239 if (intpending)
240 onint();
241}
Eric Andersen3102ac42001-07-06 04:26:23 +0000242#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000243#else
Eric Andersenc470f442003-07-28 09:56:35 +0000244#define INTON \
245 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000246 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000247 if (--suppressint == 0 && intpending) onint(); \
248 0; \
249 })
250#define FORCEINTON \
251 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000252 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000253 suppressint = 0; \
254 if (intpending) onint(); \
255 0; \
256 })
257#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000258
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000259/* expand.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000260
261struct strlist {
262 struct strlist *next;
263 char *text;
264};
265
266
267struct arglist {
268 struct strlist *list;
269 struct strlist **lastp;
270};
271
Eric Andersenc470f442003-07-28 09:56:35 +0000272/*
273 * expandarg() flags
274 */
275#define EXP_FULL 0x1 /* perform word splitting & file globbing */
276#define EXP_TILDE 0x2 /* do normal tilde expansion */
277#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
278#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
279#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
280#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
281#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
282#define EXP_WORD 0x80 /* expand word in parameter expansion */
283#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
284
285
286union node;
287static void expandarg(union node *, struct arglist *, int);
288#define rmescapes(p) _rmescapes((p), 0)
289static char *_rmescapes(char *, int);
290static int casematch(union node *, char *);
291
292#ifdef CONFIG_ASH_MATH_SUPPORT
293static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000294#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000295
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000296/* eval.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000297
Eric Andersenc470f442003-07-28 09:56:35 +0000298static char *commandname; /* currently executing command */
299static struct strlist *cmdenviron; /* environment for builtin command */
300static int exitstatus; /* exit status of last command */
301static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000302
Eric Andersenc470f442003-07-28 09:56:35 +0000303
304struct backcmd { /* result of evalbackcmd */
305 int fd; /* file descriptor to read from */
306 char *buf; /* buffer */
307 int nleft; /* number of chars in buffer */
308 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000309};
310
Eric Andersen62483552001-07-10 06:09:16 +0000311/*
Eric Andersenc470f442003-07-28 09:56:35 +0000312 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000313 */
Eric Andersenc470f442003-07-28 09:56:35 +0000314
315#define NCMD 0
316#define NPIPE 1
317#define NREDIR 2
318#define NBACKGND 3
319#define NSUBSHELL 4
320#define NAND 5
321#define NOR 6
322#define NSEMI 7
323#define NIF 8
324#define NWHILE 9
325#define NUNTIL 10
326#define NFOR 11
327#define NCASE 12
328#define NCLIST 13
329#define NDEFUN 14
330#define NARG 15
331#define NTO 16
332#define NCLOBBER 17
333#define NFROM 18
334#define NFROMTO 19
335#define NAPPEND 20
336#define NTOFD 21
337#define NFROMFD 22
338#define NHERE 23
339#define NXHERE 24
340#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000341
342
343
Eric Andersenc470f442003-07-28 09:56:35 +0000344struct ncmd {
345 int type;
346 union node *assign;
347 union node *args;
348 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000349};
350
351
Eric Andersenc470f442003-07-28 09:56:35 +0000352struct npipe {
353 int type;
354 int backgnd;
355 struct nodelist *cmdlist;
356};
Eric Andersen62483552001-07-10 06:09:16 +0000357
358
Eric Andersenc470f442003-07-28 09:56:35 +0000359struct nredir {
360 int type;
361 union node *n;
362 union node *redirect;
363};
Eric Andersen62483552001-07-10 06:09:16 +0000364
365
Eric Andersenc470f442003-07-28 09:56:35 +0000366struct nbinary {
367 int type;
368 union node *ch1;
369 union node *ch2;
370};
Eric Andersen2870d962001-07-02 17:27:21 +0000371
Eric Andersen2870d962001-07-02 17:27:21 +0000372
Eric Andersenc470f442003-07-28 09:56:35 +0000373struct nif {
374 int type;
375 union node *test;
376 union node *ifpart;
377 union node *elsepart;
378};
379
380
381struct nfor {
382 int type;
383 union node *args;
384 union node *body;
385 char *var;
386};
387
388
389struct ncase {
390 int type;
391 union node *expr;
392 union node *cases;
393};
394
395
396struct nclist {
397 int type;
398 union node *next;
399 union node *pattern;
400 union node *body;
401};
402
403
404struct narg {
405 int type;
406 union node *next;
407 char *text;
408 struct nodelist *backquote;
409};
410
411
412struct nfile {
413 int type;
414 union node *next;
415 int fd;
416 union node *fname;
417 char *expfname;
418};
419
420
421struct ndup {
422 int type;
423 union node *next;
424 int fd;
425 int dupfd;
426 union node *vname;
427};
428
429
430struct nhere {
431 int type;
432 union node *next;
433 int fd;
434 union node *doc;
435};
436
437
438struct nnot {
439 int type;
440 union node *com;
441};
442
443
444union node {
445 int type;
446 struct ncmd ncmd;
447 struct npipe npipe;
448 struct nredir nredir;
449 struct nbinary nbinary;
450 struct nif nif;
451 struct nfor nfor;
452 struct ncase ncase;
453 struct nclist nclist;
454 struct narg narg;
455 struct nfile nfile;
456 struct ndup ndup;
457 struct nhere nhere;
458 struct nnot nnot;
459};
460
461
462struct nodelist {
463 struct nodelist *next;
464 union node *n;
465};
466
467
468struct funcnode {
469 int count;
470 union node n;
471};
472
473
474static void freefunc(struct funcnode *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000475/* parser.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000476
477/* control characters in argument strings */
478#define CTL_FIRST '\201' /* first 'special' character */
479#define CTLESC '\201' /* escape next character */
480#define CTLVAR '\202' /* variable defn */
481#define CTLENDVAR '\203'
482#define CTLBACKQ '\204'
483#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
484/* CTLBACKQ | CTLQUOTE == '\205' */
485#define CTLARI '\206' /* arithmetic expression */
486#define CTLENDARI '\207'
487#define CTLQUOTEMARK '\210'
488#define CTL_LAST '\210' /* last 'special' character */
489
490/* variable substitution byte (follows CTLVAR) */
491#define VSTYPE 0x0f /* type of variable substitution */
492#define VSNUL 0x10 /* colon--treat the empty string as unset */
493#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
494
495/* values of VSTYPE field */
496#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
497#define VSMINUS 0x2 /* ${var-text} */
498#define VSPLUS 0x3 /* ${var+text} */
499#define VSQUESTION 0x4 /* ${var?message} */
500#define VSASSIGN 0x5 /* ${var=text} */
501#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
502#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
503#define VSTRIMLEFT 0x8 /* ${var#pattern} */
504#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
505#define VSLENGTH 0xa /* ${#var} */
506
507/* values of checkkwd variable */
508#define CHKALIAS 0x1
509#define CHKKWD 0x2
510#define CHKNL 0x4
511
512#define IBUFSIZ (BUFSIZ + 1)
513
514/*
515 * NEOF is returned by parsecmd when it encounters an end of file. It
516 * must be distinct from NULL, so we use the address of a variable that
517 * happens to be handy.
518 */
519static int plinno = 1; /* input line number */
520
521/* number of characters left in input buffer */
522static int parsenleft; /* copy of parsefile->nleft */
523static int parselleft; /* copy of parsefile->lleft */
524
525/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000526static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000527
528struct strpush {
529 struct strpush *prev; /* preceding string on stack */
530 char *prevstring;
531 int prevnleft;
532#ifdef CONFIG_ASH_ALIAS
533 struct alias *ap; /* if push was associated with an alias */
534#endif
535 char *string; /* remember the string since it may change */
536};
537
538struct parsefile {
539 struct parsefile *prev; /* preceding file on stack */
540 int linno; /* current line */
541 int fd; /* file descriptor (or -1 if string) */
542 int nleft; /* number of chars left in this line */
543 int lleft; /* number of chars left in this buffer */
544 char *nextc; /* next char in buffer */
545 char *buf; /* input buffer */
546 struct strpush *strpush; /* for pushing strings at this level */
547 struct strpush basestrpush; /* so pushing one is fast */
548};
549
Eric Andersenc470f442003-07-28 09:56:35 +0000550static struct parsefile basepf; /* top level input file */
"Vladimir N. Oleynik"6f347ef2005-10-15 10:23:55 +0000551#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
Eric Andersenc470f442003-07-28 09:56:35 +0000552static struct parsefile *parsefile = &basepf; /* current input file */
553
554
555static int tokpushback; /* last token pushed back */
556#define NEOF ((union node *)&tokpushback)
557static int parsebackquote; /* nonzero if we are inside backquotes */
558static int doprompt; /* if set, prompt the user */
559static int needprompt; /* true if interactive and at start of line */
560static int lasttoken; /* last token read */
561static char *wordtext; /* text of last word returned by readtoken */
562static int checkkwd;
563static struct nodelist *backquotelist;
564static union node *redirnode;
565static struct heredoc *heredoc;
566static int quoteflag; /* set if (part of) last token was quoted */
567static int startlinno; /* line # where last token started */
568
569static union node *parsecmd(int);
570static void fixredir(union node *, const char *, int);
571static const char *const *findkwd(const char *);
572static char *endofname(const char *);
573
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000574/* shell.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000575
576typedef void *pointer;
577
578static char nullstr[1]; /* zero length string */
579static const char spcstr[] = " ";
580static const char snlfmt[] = "%s\n";
581static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
582static const char illnum[] = "Illegal number: %s";
583static const char homestr[] = "HOME";
584
Denis Vlasenkoa7189f02006-11-17 20:29:00 +0000585#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +0000586#define TRACE(param) trace param
587#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000588#else
Eric Andersenc470f442003-07-28 09:56:35 +0000589#define TRACE(param)
590#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000591#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000592
Eric Andersenc470f442003-07-28 09:56:35 +0000593#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
594#define __builtin_expect(x, expected_value) (x)
595#endif
596
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000597#define xlikely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000598
Eric Andersenc470f442003-07-28 09:56:35 +0000599
600#define TEOF 0
601#define TNL 1
602#define TREDIR 2
603#define TWORD 3
604#define TSEMI 4
605#define TBACKGND 5
606#define TAND 6
607#define TOR 7
608#define TPIPE 8
609#define TLP 9
610#define TRP 10
611#define TENDCASE 11
612#define TENDBQUOTE 12
613#define TNOT 13
614#define TCASE 14
615#define TDO 15
616#define TDONE 16
617#define TELIF 17
618#define TELSE 18
619#define TESAC 19
620#define TFI 20
621#define TFOR 21
622#define TIF 22
623#define TIN 23
624#define TTHEN 24
625#define TUNTIL 25
626#define TWHILE 26
627#define TBEGIN 27
628#define TEND 28
629
630/* first char is indicating which tokens mark the end of a list */
631static const char *const tokname_array[] = {
632 "\1end of file",
633 "\0newline",
634 "\0redirection",
635 "\0word",
636 "\0;",
637 "\0&",
638 "\0&&",
639 "\0||",
640 "\0|",
641 "\0(",
642 "\1)",
643 "\1;;",
644 "\1`",
645#define KWDOFFSET 13
646 /* the following are keywords */
647 "\0!",
648 "\0case",
649 "\1do",
650 "\1done",
651 "\1elif",
652 "\1else",
653 "\1esac",
654 "\1fi",
655 "\0for",
656 "\0if",
657 "\0in",
658 "\1then",
659 "\0until",
660 "\0while",
661 "\0{",
662 "\1}",
663};
664
665static const char *tokname(int tok)
666{
667 static char buf[16];
668
669 if (tok >= TSEMI)
670 buf[0] = '"';
671 sprintf(buf + (tok >= TSEMI), "%s%c",
672 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
673 return buf;
674}
675
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000676/* machdep.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000677
678/*
679 * Most machines require the value returned from malloc to be aligned
680 * in some way. The following macro will get this right on many machines.
681 */
682
683#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
684/*
685 * It appears that grabstackstr() will barf with such alignments
686 * because stalloc() will return a string allocated in a new stackblock.
687 */
688#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
689
690/*
691 * This file was generated by the mksyntax program.
692 */
693
694
695/* Syntax classes */
696#define CWORD 0 /* character is nothing special */
697#define CNL 1 /* newline character */
698#define CBACK 2 /* a backslash character */
699#define CSQUOTE 3 /* single quote */
700#define CDQUOTE 4 /* double quote */
701#define CENDQUOTE 5 /* a terminating quote */
702#define CBQUOTE 6 /* backwards single quote */
703#define CVAR 7 /* a dollar sign */
704#define CENDVAR 8 /* a '}' character */
705#define CLP 9 /* a left paren in arithmetic */
706#define CRP 10 /* a right paren in arithmetic */
707#define CENDFILE 11 /* end of file */
708#define CCTL 12 /* like CWORD, except it must be escaped */
709#define CSPCL 13 /* these terminate a word */
710#define CIGN 14 /* character should be ignored */
711
712#ifdef CONFIG_ASH_ALIAS
713#define SYNBASE 130
714#define PEOF -130
715#define PEOA -129
716#define PEOA_OR_PEOF PEOA
717#else
718#define SYNBASE 129
719#define PEOF -129
720#define PEOA_OR_PEOF PEOF
721#endif
722
723#define is_digit(c) ((unsigned)((c) - '0') <= 9)
724#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
725#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
726
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000727/* C99 say: "char" declaration may be signed or unsigned default */
728#define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int)
729
Eric Andersenc470f442003-07-28 09:56:35 +0000730/*
731 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
732 * (assuming ascii char codes, as the original implementation did)
733 */
734#define is_special(c) \
735 ( (((unsigned int)c) - 33 < 32) \
736 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
737
738#define digit_val(c) ((c) - '0')
739
740/*
741 * This file was generated by the mksyntax program.
742 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000743
Eric Andersend35c5df2002-01-09 15:37:36 +0000744#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000745#define USE_SIT_FUNCTION
746#endif
747
748/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000749#define BASESYNTAX 0 /* not in quotes */
750#define DQSYNTAX 1 /* in double quotes */
751#define SQSYNTAX 2 /* in single quotes */
752#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000753
Eric Andersenc470f442003-07-28 09:56:35 +0000754#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000755static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000756#ifdef CONFIG_ASH_ALIAS
757 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
758#endif
759 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
760 {CNL, CNL, CNL, CNL}, /* 2, \n */
761 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
762 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
763 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
764 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
765 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
766 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
767 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
768 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
769 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000770#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000771 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
772 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
773 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000774#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000775};
Eric Andersenc470f442003-07-28 09:56:35 +0000776#else
777static const char S_I_T[][3] = {
778#ifdef CONFIG_ASH_ALIAS
779 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
780#endif
781 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
782 {CNL, CNL, CNL}, /* 2, \n */
783 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
784 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
785 {CVAR, CVAR, CWORD}, /* 5, $ */
786 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
787 {CSPCL, CWORD, CWORD}, /* 7, ( */
788 {CSPCL, CWORD, CWORD}, /* 8, ) */
789 {CBACK, CBACK, CCTL}, /* 9, \ */
790 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
791 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
792#ifndef USE_SIT_FUNCTION
793 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
794 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
795 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
796#endif
797};
798#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000799
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000800#ifdef USE_SIT_FUNCTION
801
802#define U_C(c) ((unsigned char)(c))
803
804static int SIT(int c, int syntax)
805{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000806 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000807#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000808 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000809 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
810 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
811 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
812 11, 3 /* "}~" */
813 };
814#else
815 static const char syntax_index_table[] = {
816 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
817 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
818 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
819 10, 2 /* "}~" */
820 };
821#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000822 const char *s;
823 int indx;
824
Eric Andersenc470f442003-07-28 09:56:35 +0000825 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000826 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000827#ifdef CONFIG_ASH_ALIAS
828 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000829 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000830 else
831#endif
832 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
833 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000834 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000835 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000836 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000837 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000838 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000839 }
840 return S_I_T[indx][syntax];
841}
842
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000843#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000844
845#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
846
Eric Andersenc470f442003-07-28 09:56:35 +0000847#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000848#define CSPCL_CIGN_CIGN_CIGN 0
849#define CSPCL_CWORD_CWORD_CWORD 1
850#define CNL_CNL_CNL_CNL 2
851#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000852#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000853#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000854#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000855#define CSPCL_CWORD_CWORD_CLP 7
856#define CSPCL_CWORD_CWORD_CRP 8
857#define CBACK_CBACK_CCTL_CBACK 9
858#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
859#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
860#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
861#define CWORD_CWORD_CWORD_CWORD 13
862#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000863#else
864#define CSPCL_CWORD_CWORD_CWORD 0
865#define CNL_CNL_CNL_CNL 1
866#define CWORD_CCTL_CCTL_CWORD 2
867#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
868#define CVAR_CVAR_CWORD_CVAR 4
869#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
870#define CSPCL_CWORD_CWORD_CLP 6
871#define CSPCL_CWORD_CWORD_CRP 7
872#define CBACK_CBACK_CCTL_CBACK 8
873#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
874#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
875#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
876#define CWORD_CWORD_CWORD_CWORD 12
877#define CCTL_CCTL_CCTL_CCTL 13
878#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000879
880static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000881 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000882 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
883#ifdef CONFIG_ASH_ALIAS
884 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
885#endif
886 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
887 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
888 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
889 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
890 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
891 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
892 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
893 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
894 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000895 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
896 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
897 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
898 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
899 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
900 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
901 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
902 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
903 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
904 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
905 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
906 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
907 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
908 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
909 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
910 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
911 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
912 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
913 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
914 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
915 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
916 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
917 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
918 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
919 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
920 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
921 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
922 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
923 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
924 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
925 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
926 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
927 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
928 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
929 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
930 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
931 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
932 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
933 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
934 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
935 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
936 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
937 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
938 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
939 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
940 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
941 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
942 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
943 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
944 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
945 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
946 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
947 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
948 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
949 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
950 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
951 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
952 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
953 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
954 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
955 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
956 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
957 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
958 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
959 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
960 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
961 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
962 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
963 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
964 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
965 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
966 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
967 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
968 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
969 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
970 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
971 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
972 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
973 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
974 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
975 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
976 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
977 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
978 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
979 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
980 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
981 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
982 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
983 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
984 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
985 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
986 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
987 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
988 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
989 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
990 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
991 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
992 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
993 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
994 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
995 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
996 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
997 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
998 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
999 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1024 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1025 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1047 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001048 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001049 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1050 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1051 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1052 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001053 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001054 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1055 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1056 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1057 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1058 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1059 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1060 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1061 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1062 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1063 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1064 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1072 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1073 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1075 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1076 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1077 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1078 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1106 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1107 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1108 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1111 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1139 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1140 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1141 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001142};
1143
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001144#endif /* USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00001145
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001146/* alias.c */
Eric Andersen2870d962001-07-02 17:27:21 +00001147
Eric Andersen2870d962001-07-02 17:27:21 +00001148
Eric Andersenc470f442003-07-28 09:56:35 +00001149#define ATABSIZE 39
1150
1151static int funcblocksize; /* size of structures in function */
1152static int funcstringsize; /* size of strings in node */
1153static pointer funcblock; /* block to allocate function from */
1154static char *funcstring; /* block to allocate strings from */
1155
1156static const short nodesize[26] = {
1157 SHELL_ALIGN(sizeof (struct ncmd)),
1158 SHELL_ALIGN(sizeof (struct npipe)),
1159 SHELL_ALIGN(sizeof (struct nredir)),
1160 SHELL_ALIGN(sizeof (struct nredir)),
1161 SHELL_ALIGN(sizeof (struct nredir)),
1162 SHELL_ALIGN(sizeof (struct nbinary)),
1163 SHELL_ALIGN(sizeof (struct nbinary)),
1164 SHELL_ALIGN(sizeof (struct nbinary)),
1165 SHELL_ALIGN(sizeof (struct nif)),
1166 SHELL_ALIGN(sizeof (struct nbinary)),
1167 SHELL_ALIGN(sizeof (struct nbinary)),
1168 SHELL_ALIGN(sizeof (struct nfor)),
1169 SHELL_ALIGN(sizeof (struct ncase)),
1170 SHELL_ALIGN(sizeof (struct nclist)),
1171 SHELL_ALIGN(sizeof (struct narg)),
1172 SHELL_ALIGN(sizeof (struct narg)),
1173 SHELL_ALIGN(sizeof (struct nfile)),
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 ndup)),
1179 SHELL_ALIGN(sizeof (struct ndup)),
1180 SHELL_ALIGN(sizeof (struct nhere)),
1181 SHELL_ALIGN(sizeof (struct nhere)),
1182 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001183};
1184
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001185
Eric Andersenc470f442003-07-28 09:56:35 +00001186static void calcsize(union node *);
1187static void sizenodelist(struct nodelist *);
1188static union node *copynode(union node *);
1189static struct nodelist *copynodelist(struct nodelist *);
1190static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001191
1192
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001193static int evalstring(char *, int mask);
Eric Andersenc470f442003-07-28 09:56:35 +00001194union node; /* BLETCH for ansi C */
1195static void evaltree(union node *, int);
1196static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001197
Eric Andersenc470f442003-07-28 09:56:35 +00001198static int evalskip; /* set if we are skipping commands */
1199static int skipcount; /* number of levels to skip */
1200static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001201
1202/* reasons for skipping commands (see comment on breakcmd routine) */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001203#define SKIPBREAK (1 << 0)
1204#define SKIPCONT (1 << 1)
1205#define SKIPFUNC (1 << 2)
1206#define SKIPFILE (1 << 3)
1207#define SKIPEVAL (1 << 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001208
Eric Andersenc470f442003-07-28 09:56:35 +00001209/*
1210 * This file was generated by the mkbuiltins program.
1211 */
Eric Andersen2870d962001-07-02 17:27:21 +00001212
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001213#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001214static int bgcmd(int, char **);
1215#endif
1216static int breakcmd(int, char **);
1217static int cdcmd(int, char **);
1218#ifdef CONFIG_ASH_CMDCMD
1219static int commandcmd(int, char **);
1220#endif
1221static int dotcmd(int, char **);
1222static int evalcmd(int, char **);
Paul Fox0b621582005-08-09 19:38:05 +00001223#ifdef CONFIG_ASH_BUILTIN_ECHO
1224static int echocmd(int, char **);
1225#endif
Paul Fox6ab03782006-06-08 21:37:26 +00001226#ifdef CONFIG_ASH_BUILTIN_TEST
1227static int testcmd(int, char **);
1228#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001229static int execcmd(int, char **);
1230static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001231static int exportcmd(int, char **);
1232static int falsecmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001233#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001234static int fgcmd(int, char **);
1235#endif
1236#ifdef CONFIG_ASH_GETOPTS
1237static int getoptscmd(int, char **);
1238#endif
1239static int hashcmd(int, char **);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00001240#if !ENABLE_FEATURE_SH_EXTRA_QUIET
Eric Andersenc470f442003-07-28 09:56:35 +00001241static int helpcmd(int argc, char **argv);
1242#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001243#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001244static int jobscmd(int, char **);
1245#endif
Eric Andersen90898442003-08-06 11:20:52 +00001246#ifdef CONFIG_ASH_MATH_SUPPORT
1247static int letcmd(int, char **);
1248#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001249static int localcmd(int, char **);
1250static int pwdcmd(int, char **);
1251static int readcmd(int, char **);
1252static int returncmd(int, char **);
1253static int setcmd(int, char **);
1254static int shiftcmd(int, char **);
1255static int timescmd(int, char **);
1256static int trapcmd(int, char **);
1257static int truecmd(int, char **);
1258static int typecmd(int, char **);
1259static int umaskcmd(int, char **);
1260static int unsetcmd(int, char **);
1261static int waitcmd(int, char **);
1262static int ulimitcmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001263#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001264static int killcmd(int, char **);
1265#endif
1266
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001267/* mail.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001268
1269#ifdef CONFIG_ASH_MAIL
1270static void chkmail(void);
1271static void changemail(const char *);
1272#endif
1273
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001274/* exec.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001275
1276/* values of cmdtype */
1277#define CMDUNKNOWN -1 /* no entry in table for command */
1278#define CMDNORMAL 0 /* command is an executable program */
1279#define CMDFUNCTION 1 /* command is a shell function */
1280#define CMDBUILTIN 2 /* command is a shell builtin */
1281
1282struct builtincmd {
1283 const char *name;
1284 int (*builtin)(int, char **);
1285 /* unsigned flags; */
1286};
1287
Paul Fox0b621582005-08-09 19:38:05 +00001288
1289#define COMMANDCMD (builtincmd + 5 + \
Paul Fox6ab03782006-06-08 21:37:26 +00001290 2 * ENABLE_ASH_BUILTIN_TEST + \
1291 ENABLE_ASH_ALIAS + \
1292 ENABLE_ASH_JOB_CONTROL)
Paul Fox0b621582005-08-09 19:38:05 +00001293#define EXECCMD (builtincmd + 7 + \
Paul Fox6ab03782006-06-08 21:37:26 +00001294 2 * ENABLE_ASH_BUILTIN_TEST + \
1295 ENABLE_ASH_ALIAS + \
1296 ENABLE_ASH_JOB_CONTROL + \
1297 ENABLE_ASH_CMDCMD + \
1298 ENABLE_ASH_BUILTIN_ECHO)
Eric Andersenc470f442003-07-28 09:56:35 +00001299
1300#define BUILTIN_NOSPEC "0"
1301#define BUILTIN_SPECIAL "1"
1302#define BUILTIN_REGULAR "2"
1303#define BUILTIN_SPEC_REG "3"
1304#define BUILTIN_ASSIGN "4"
1305#define BUILTIN_SPEC_ASSG "5"
1306#define BUILTIN_REG_ASSG "6"
1307#define BUILTIN_SPEC_REG_ASSG "7"
1308
1309#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1310#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
Paul Foxc3850c82005-07-20 18:23:39 +00001311#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001312
Bernhard Reutner-Fischer35492132006-06-21 18:19:53 +00001313/* make sure to keep these in proper order since it is searched via bsearch() */
Eric Andersenc470f442003-07-28 09:56:35 +00001314static const struct builtincmd builtincmd[] = {
1315 { BUILTIN_SPEC_REG ".", dotcmd },
1316 { BUILTIN_SPEC_REG ":", truecmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001317#ifdef CONFIG_ASH_BUILTIN_TEST
1318 { BUILTIN_REGULAR "[", testcmd },
1319 { BUILTIN_REGULAR "[[", testcmd },
1320#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001321#ifdef CONFIG_ASH_ALIAS
1322 { BUILTIN_REG_ASSG "alias", aliascmd },
1323#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001324#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001325 { BUILTIN_REGULAR "bg", bgcmd },
1326#endif
1327 { BUILTIN_SPEC_REG "break", breakcmd },
1328 { BUILTIN_REGULAR "cd", cdcmd },
1329 { BUILTIN_NOSPEC "chdir", cdcmd },
1330#ifdef CONFIG_ASH_CMDCMD
1331 { BUILTIN_REGULAR "command", commandcmd },
1332#endif
1333 { BUILTIN_SPEC_REG "continue", breakcmd },
Paul Fox0b621582005-08-09 19:38:05 +00001334#ifdef CONFIG_ASH_BUILTIN_ECHO
1335 { BUILTIN_REGULAR "echo", echocmd },
1336#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001337 { BUILTIN_SPEC_REG "eval", evalcmd },
1338 { BUILTIN_SPEC_REG "exec", execcmd },
1339 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001340 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1341 { BUILTIN_REGULAR "false", falsecmd },
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001342#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001343 { BUILTIN_REGULAR "fg", fgcmd },
1344#endif
1345#ifdef CONFIG_ASH_GETOPTS
1346 { BUILTIN_REGULAR "getopts", getoptscmd },
1347#endif
1348 { BUILTIN_NOSPEC "hash", hashcmd },
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00001349#if !ENABLE_FEATURE_SH_EXTRA_QUIET
Eric Andersenc470f442003-07-28 09:56:35 +00001350 { BUILTIN_NOSPEC "help", helpcmd },
1351#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001352#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001353 { BUILTIN_REGULAR "jobs", jobscmd },
1354 { BUILTIN_REGULAR "kill", killcmd },
1355#endif
1356#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001357 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001358#endif
1359 { BUILTIN_ASSIGN "local", localcmd },
1360 { BUILTIN_NOSPEC "pwd", pwdcmd },
1361 { BUILTIN_REGULAR "read", readcmd },
1362 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1363 { BUILTIN_SPEC_REG "return", returncmd },
1364 { BUILTIN_SPEC_REG "set", setcmd },
1365 { BUILTIN_SPEC_REG "shift", shiftcmd },
Mike Frysingerc2ad4f52006-06-21 18:04:49 +00001366 { BUILTIN_SPEC_REG "source", dotcmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001367#ifdef CONFIG_ASH_BUILTIN_TEST
1368 { BUILTIN_REGULAR "test", testcmd },
1369#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001370 { BUILTIN_SPEC_REG "times", timescmd },
1371 { BUILTIN_SPEC_REG "trap", trapcmd },
1372 { BUILTIN_REGULAR "true", truecmd },
1373 { BUILTIN_NOSPEC "type", typecmd },
1374 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1375 { BUILTIN_REGULAR "umask", umaskcmd },
1376#ifdef CONFIG_ASH_ALIAS
1377 { BUILTIN_REGULAR "unalias", unaliascmd },
1378#endif
1379 { BUILTIN_SPEC_REG "unset", unsetcmd },
1380 { BUILTIN_REGULAR "wait", waitcmd },
1381};
1382
Denis Vlasenko8f27c342006-12-26 21:31:11 +00001383#define NUMBUILTINS (sizeof(builtincmd) / sizeof(builtincmd[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001384
1385
1386struct cmdentry {
1387 int cmdtype;
1388 union param {
1389 int index;
1390 const struct builtincmd *cmd;
1391 struct funcnode *func;
1392 } u;
1393};
1394
1395
1396/* action to find_command() */
1397#define DO_ERR 0x01 /* prints errors */
1398#define DO_ABS 0x02 /* checks absolute paths */
1399#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1400#define DO_ALTPATH 0x08 /* using alternate path */
1401#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1402
1403static const char *pathopt; /* set by padvance */
1404
1405static void shellexec(char **, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001406 ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00001407static char *padvance(const char **, const char *);
1408static void find_command(char *, struct cmdentry *, int, const char *);
1409static struct builtincmd *find_builtin(const char *);
1410static void hashcd(void);
1411static void changepath(const char *);
1412static void defun(char *, union node *);
1413static void unsetfunc(const char *);
1414
Eric Andersened9ecf72004-06-22 08:29:45 +00001415#ifdef CONFIG_ASH_MATH_SUPPORT_64
1416typedef int64_t arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001417#define arith_t_type (long long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001418#else
1419typedef long arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001420#define arith_t_type (long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001421#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001422
1423#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001424static arith_t dash_arith(const char *);
1425static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001426#endif
1427
Eric Andersen16767e22004-03-16 05:14:10 +00001428#ifdef CONFIG_ASH_RANDOM_SUPPORT
1429static unsigned long rseed;
1430static void change_random(const char *);
1431# ifndef DYNAMIC_VAR
1432# define DYNAMIC_VAR
1433# endif
1434#endif
1435
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001436/* init.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001437
1438static void reset(void);
1439
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001440/* var.h */
Eric Andersen2870d962001-07-02 17:27:21 +00001441
1442/*
1443 * Shell variables.
1444 */
1445
1446/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001447#define VEXPORT 0x01 /* variable is exported */
1448#define VREADONLY 0x02 /* variable cannot be modified */
1449#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1450#define VTEXTFIXED 0x08 /* text is statically allocated */
1451#define VSTACK 0x10 /* text is allocated on the stack */
1452#define VUNSET 0x20 /* the variable is not set */
1453#define VNOFUNC 0x40 /* don't call the callback function */
1454#define VNOSET 0x80 /* do not set variable - just readonly test */
1455#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001456#ifdef DYNAMIC_VAR
1457# define VDYNAMIC 0x200 /* dynamic variable */
1458# else
1459# define VDYNAMIC 0
1460#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001461
1462struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001463 struct var *next; /* next entry in hash list */
1464 int flags; /* flags are defined above */
1465 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001466 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001467 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001468};
1469
1470struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001471 struct localvar *next; /* next local variable in list */
1472 struct var *vp; /* the variable that was made local */
1473 int flags; /* saved flags */
1474 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001475};
1476
1477
Eric Andersen2870d962001-07-02 17:27:21 +00001478static struct localvar *localvars;
1479
Eric Andersenc470f442003-07-28 09:56:35 +00001480/*
1481 * Shell variables.
1482 */
1483
1484#ifdef CONFIG_ASH_GETOPTS
1485static void getoptsreset(const char *);
1486#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001487
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001488#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001489static void change_lc_all(const char *value);
1490static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001491#endif
1492
Eric Andersenef02f822004-03-11 13:34:24 +00001493
Eric Andersen2870d962001-07-02 17:27:21 +00001494#define VTABSIZE 39
1495
Eric Andersen90898442003-08-06 11:20:52 +00001496static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001497#ifdef IFS_BROKEN
1498static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001499#define defifs (defifsvar + 4)
1500#else
Eric Andersenc470f442003-07-28 09:56:35 +00001501static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001502#endif
1503
Eric Andersenc470f442003-07-28 09:56:35 +00001504
1505static struct var varinit[] = {
1506#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001507 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001508#else
Eric Andersen16767e22004-03-16 05:14:10 +00001509 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001510#endif
1511
1512#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001513 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1514 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001515#endif
1516
Eric Andersen16767e22004-03-16 05:14:10 +00001517 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1518 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1519 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1520 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001521#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001522 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1523#endif
1524#ifdef CONFIG_ASH_RANDOM_SUPPORT
1525 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001526#endif
1527#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001528 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1529 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001530#endif
Denis Vlasenko38f63192007-01-22 09:03:07 +00001531#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001532 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001533#endif
1534};
1535
1536#define vifs varinit[0]
1537#ifdef CONFIG_ASH_MAIL
1538#define vmail (&vifs)[1]
1539#define vmpath (&vmail)[1]
1540#else
1541#define vmpath vifs
1542#endif
1543#define vpath (&vmpath)[1]
1544#define vps1 (&vpath)[1]
1545#define vps2 (&vps1)[1]
1546#define vps4 (&vps2)[1]
1547#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001548#ifdef CONFIG_ASH_GETOPTS
1549#define vrandom (&voptind)[1]
1550#else
1551#define vrandom (&vps4)[1]
1552#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001553#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001554
1555/*
1556 * The following macros access the values of the above variables.
1557 * They have to skip over the name. They return the null string
1558 * for unset variables.
1559 */
1560
1561#define ifsval() (vifs.text + 4)
1562#define ifsset() ((vifs.flags & VUNSET) == 0)
1563#define mailval() (vmail.text + 5)
1564#define mpathval() (vmpath.text + 9)
1565#define pathval() (vpath.text + 5)
1566#define ps1val() (vps1.text + 4)
1567#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001568#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001569#define optindval() (voptind.text + 7)
1570
1571#define mpathset() ((vmpath.flags & VUNSET) == 0)
1572
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001573static void setvar(const char *, const char *, int);
1574static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001575static void listsetvar(struct strlist *, int);
1576static char *lookupvar(const char *);
1577static char *bltinlookup(const char *);
1578static char **listvars(int, int, char ***);
1579#define environment() listvars(VEXPORT, VUNSET, 0)
1580static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001581static void poplocalvars(void);
1582static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001583#ifdef CONFIG_ASH_GETOPTS
1584static int setvarsafe(const char *, const char *, int);
1585#endif
1586static int varcmp(const char *, const char *);
1587static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001588
1589
Rob Landley88621d72006-08-29 19:41:06 +00001590static int varequal(const char *a, const char *b) {
Eric Andersenc470f442003-07-28 09:56:35 +00001591 return !varcmp(a, b);
1592}
Eric Andersen2870d962001-07-02 17:27:21 +00001593
1594
Eric Andersenc470f442003-07-28 09:56:35 +00001595static int loopnest; /* current loop nesting level */
1596
Eric Andersenc470f442003-07-28 09:56:35 +00001597/*
1598 * The parsefile structure pointed to by the global variable parsefile
1599 * contains information about the current file being read.
1600 */
1601
1602
1603struct redirtab {
1604 struct redirtab *next;
1605 int renamed[10];
1606 int nullredirs;
1607};
1608
1609static struct redirtab *redirlist;
1610static int nullredirs;
1611
1612extern char **environ;
1613
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001614/* output.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001615
1616
1617static void outstr(const char *, FILE *);
1618static void outcslow(int, FILE *);
1619static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001620static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001621static int out1fmt(const char *, ...)
1622 __attribute__((__format__(__printf__,1,2)));
1623static int fmtstr(char *, size_t, const char *, ...)
1624 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001625
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001626static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001627
Eric Andersenc470f442003-07-28 09:56:35 +00001628
1629static void out1str(const char *p)
1630{
1631 outstr(p, stdout);
1632}
1633
1634static void out2str(const char *p)
1635{
1636 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001637 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001638}
1639
1640/*
1641 * Initialization code.
1642 */
1643
1644/*
1645 * This routine initializes the builtin variables.
1646 */
1647
Rob Landley88621d72006-08-29 19:41:06 +00001648static void initvar(void)
Eric Andersenc470f442003-07-28 09:56:35 +00001649{
1650 struct var *vp;
1651 struct var *end;
1652 struct var **vpp;
1653
1654 /*
1655 * PS1 depends on uid
1656 */
Denis Vlasenko38f63192007-01-22 09:03:07 +00001657#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Eric Andersenc470f442003-07-28 09:56:35 +00001658 vps1.text = "PS1=\\w \\$ ";
1659#else
1660 if (!geteuid())
1661 vps1.text = "PS1=# ";
1662#endif
1663 vp = varinit;
1664 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1665 do {
1666 vpp = hashvar(vp->text);
1667 vp->next = *vpp;
1668 *vpp = vp;
1669 } while (++vp < end);
1670}
1671
Rob Landley88621d72006-08-29 19:41:06 +00001672static void init(void)
Eric Andersenc470f442003-07-28 09:56:35 +00001673{
1674
1675 /* from input.c: */
1676 {
1677 basepf.nextc = basepf.buf = basebuf;
1678 }
1679
1680 /* from trap.c: */
1681 {
1682 signal(SIGCHLD, SIG_DFL);
1683 }
1684
1685 /* from var.c: */
1686 {
1687 char **envp;
1688 char ppid[32];
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001689 const char *p;
1690 struct stat st1, st2;
Eric Andersenc470f442003-07-28 09:56:35 +00001691
1692 initvar();
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001693 for (envp = environ ; envp && *envp ; envp++) {
Eric Andersenc470f442003-07-28 09:56:35 +00001694 if (strchr(*envp, '=')) {
1695 setvareq(*envp, VEXPORT|VTEXTFIXED);
1696 }
1697 }
1698
1699 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1700 setvar("PPID", ppid, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001701
1702 p = lookupvar("PWD");
1703 if (p)
1704 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1705 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1706 p = 0;
1707 setpwd(p, 0);
Eric Andersenc470f442003-07-28 09:56:35 +00001708 }
1709}
1710
1711/* PEOF (the end of file marker) */
1712
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001713enum {
1714 INPUT_PUSH_FILE = 1,
1715 INPUT_NOFILE_OK = 2,
1716};
1717
Eric Andersenc470f442003-07-28 09:56:35 +00001718/*
1719 * The input line number. Input.c just defines this variable, and saves
1720 * and restores it when files are pushed and popped. The user of this
1721 * package must set its value.
1722 */
1723
1724static int pgetc(void);
1725static int pgetc2(void);
1726static int preadbuffer(void);
1727static void pungetc(void);
1728static void pushstring(char *, void *);
1729static void popstring(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001730static void setinputfd(int, int);
1731static void setinputstring(char *);
1732static void popfile(void);
1733static void popallfiles(void);
1734static void closescript(void);
1735
1736
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001737/* jobs.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001738
1739
1740/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1741#define FORK_FG 0
1742#define FORK_BG 1
1743#define FORK_NOJOB 2
1744
1745/* mode flags for showjob(s) */
1746#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1747#define SHOW_PID 0x04 /* include process pid */
1748#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1749
1750
1751/*
1752 * A job structure contains information about a job. A job is either a
1753 * single process or a set of processes contained in a pipeline. In the
1754 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1755 * array of pids.
1756 */
1757
1758struct procstat {
1759 pid_t pid; /* process id */
1760 int status; /* last process status from wait() */
1761 char *cmd; /* text of command being run */
1762};
1763
1764struct job {
1765 struct procstat ps0; /* status of process */
1766 struct procstat *ps; /* status or processes when more than one */
1767#if JOBS
1768 int stopstatus; /* status of a stopped job */
1769#endif
1770 uint32_t
1771 nprocs: 16, /* number of processes */
1772 state: 8,
1773#define JOBRUNNING 0 /* at least one proc running */
1774#define JOBSTOPPED 1 /* all procs are stopped */
1775#define JOBDONE 2 /* all procs are completed */
1776#if JOBS
1777 sigint: 1, /* job was killed by SIGINT */
1778 jobctl: 1, /* job running under job control */
1779#endif
1780 waited: 1, /* true if this entry has been waited for */
1781 used: 1, /* true if this entry is in used */
1782 changed: 1; /* true if status has changed */
1783 struct job *prev_job; /* previous job */
1784};
1785
1786static pid_t backgndpid; /* pid of last background process */
1787static int job_warning; /* user was warned about stopped jobs */
1788#if JOBS
1789static int jobctl; /* true if doing job control */
1790#endif
1791
1792static struct job *makejob(union node *, int);
1793static int forkshell(struct job *, union node *, int);
1794static int waitforjob(struct job *);
1795static int stoppedjobs(void);
1796
1797#if ! JOBS
1798#define setjobctl(on) /* do nothing */
1799#else
1800static void setjobctl(int);
1801static void showjobs(FILE *, int);
1802#endif
1803
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001804/* main.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001805
1806
1807/* pid of main shell */
1808static int rootpid;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001809/* shell level: 0 for the main shell, 1 for its children, and so on */
1810static int shlvl;
1811#define rootshell (!shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00001812
1813static void readcmdfile(char *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001814static int cmdloop(int);
Eric Andersenc470f442003-07-28 09:56:35 +00001815
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001816/* memalloc.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001817
1818
1819struct stackmark {
1820 struct stack_block *stackp;
1821 char *stacknxt;
1822 size_t stacknleft;
1823 struct stackmark *marknext;
1824};
1825
1826/* minimum size of a block */
1827#define MINSIZE SHELL_ALIGN(504)
1828
1829struct stack_block {
1830 struct stack_block *prev;
1831 char space[MINSIZE];
1832};
1833
1834static struct stack_block stackbase;
1835static struct stack_block *stackp = &stackbase;
1836static struct stackmark *markp;
1837static char *stacknxt = stackbase.space;
1838static size_t stacknleft = MINSIZE;
1839static char *sstrend = stackbase.space + MINSIZE;
1840static int herefd = -1;
1841
1842
1843static pointer ckmalloc(size_t);
1844static pointer ckrealloc(pointer, size_t);
1845static char *savestr(const char *);
1846static pointer stalloc(size_t);
1847static void stunalloc(pointer);
1848static void setstackmark(struct stackmark *);
1849static void popstackmark(struct stackmark *);
1850static void growstackblock(void);
1851static void *growstackstr(void);
1852static char *makestrspace(size_t, char *);
1853static char *stnputs(const char *, size_t, char *);
1854static char *stputs(const char *, char *);
1855
1856
Rob Landley88621d72006-08-29 19:41:06 +00001857static char *_STPUTC(int c, char *p) {
Eric Andersenc470f442003-07-28 09:56:35 +00001858 if (p == sstrend)
1859 p = growstackstr();
1860 *p++ = c;
1861 return p;
1862}
1863
1864#define stackblock() ((void *)stacknxt)
1865#define stackblocksize() stacknleft
1866#define STARTSTACKSTR(p) ((p) = stackblock())
1867#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1868#define CHECKSTRSPACE(n, p) \
1869 ({ \
1870 char *q = (p); \
1871 size_t l = (n); \
1872 size_t m = sstrend - q; \
1873 if (l > m) \
1874 (p) = makestrspace(l, q); \
1875 0; \
1876 })
1877#define USTPUTC(c, p) (*p++ = (c))
1878#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1879#define STUNPUTC(p) (--p)
1880#define STTOPC(p) p[-1]
1881#define STADJUST(amount, p) (p += (amount))
1882
1883#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1884#define ungrabstackstr(s, p) stunalloc((s))
1885#define stackstrend() ((void *)sstrend)
1886
1887#define ckfree(p) free((pointer)(p))
1888
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001889/* mystring.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001890
1891
1892#define DOLATSTRLEN 4
1893
1894static char *prefix(const char *, const char *);
1895static int number(const char *);
1896static int is_number(const char *);
1897static char *single_quote(const char *);
1898static char *sstrdup(const char *);
1899
1900#define equal(s1, s2) (strcmp(s1, s2) == 0)
1901#define scopy(s1, s2) ((void)strcpy(s2, s1))
1902
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001903/* options.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001904
1905struct shparam {
1906 int nparam; /* # of positional parameters (without $0) */
1907 unsigned char malloc; /* if parameter list dynamically allocated */
1908 char **p; /* parameter list */
1909#ifdef CONFIG_ASH_GETOPTS
1910 int optind; /* next parameter to be processed by getopts */
1911 int optoff; /* used by getopts */
1912#endif
1913};
1914
1915
1916#define eflag optlist[0]
1917#define fflag optlist[1]
1918#define Iflag optlist[2]
1919#define iflag optlist[3]
1920#define mflag optlist[4]
1921#define nflag optlist[5]
1922#define sflag optlist[6]
1923#define xflag optlist[7]
1924#define vflag optlist[8]
1925#define Cflag optlist[9]
1926#define aflag optlist[10]
1927#define bflag optlist[11]
1928#define uflag optlist[12]
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001929#define viflag optlist[13]
Eric Andersenc470f442003-07-28 09:56:35 +00001930
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00001931#if DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001932#define nolog optlist[14]
1933#define debug optlist[15]
Paul Fox3f11b1b2005-08-04 19:04:46 +00001934#endif
1935
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001936/* options.c */
Eric Andersenc470f442003-07-28 09:56:35 +00001937
1938
Paul Fox3f11b1b2005-08-04 19:04:46 +00001939static const char *const optletters_optnames[] = {
Eric Andersenc470f442003-07-28 09:56:35 +00001940 "e" "errexit",
1941 "f" "noglob",
1942 "I" "ignoreeof",
1943 "i" "interactive",
1944 "m" "monitor",
1945 "n" "noexec",
1946 "s" "stdin",
1947 "x" "xtrace",
1948 "v" "verbose",
1949 "C" "noclobber",
1950 "a" "allexport",
1951 "b" "notify",
1952 "u" "nounset",
Paul Fox3f11b1b2005-08-04 19:04:46 +00001953 "\0" "vi",
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00001954#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00001955 "\0" "nolog",
1956 "\0" "debug",
1957#endif
1958};
1959
1960#define optletters(n) optletters_optnames[(n)][0]
1961#define optnames(n) (&optletters_optnames[(n)][1])
1962
Paul Fox3f11b1b2005-08-04 19:04:46 +00001963#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001964
1965static char optlist[NOPTS];
1966
1967
1968static char *arg0; /* value of $0 */
1969static struct shparam shellparam; /* $@ current positional parameters */
1970static char **argptr; /* argument list for builtin commands */
1971static char *optionarg; /* set by nextopt (like getopt) */
1972static char *optptr; /* used by nextopt */
1973
1974static char *minusc; /* argument to -c option */
1975
1976
1977static void procargs(int, char **);
1978static void optschanged(void);
1979static void setparam(char **);
1980static void freeparam(volatile struct shparam *);
1981static int shiftcmd(int, char **);
1982static int setcmd(int, char **);
1983static int nextopt(const char *);
1984
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001985/* redir.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001986
1987/* flags passed to redirect */
1988#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001989#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00001990
1991union node;
1992static void redirect(union node *, int);
1993static void popredir(int);
1994static void clearredir(int);
1995static int copyfd(int, int);
1996static int redirectsafe(union node *, int);
1997
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001998/* show.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001999
2000
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00002001#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00002002static void showtree(union node *);
2003static void trace(const char *, ...);
2004static void tracev(const char *, va_list);
2005static void trargs(char **);
2006static void trputc(int);
2007static void trputs(const char *);
2008static void opentrace(void);
2009#endif
2010
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002011/* trap.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002012
2013
2014/* trap handler commands */
2015static char *trap[NSIG];
2016/* current value of signal */
2017static char sigmode[NSIG - 1];
2018/* indicates specified signal received */
2019static char gotsig[NSIG - 1];
2020
2021static void clear_traps(void);
2022static void setsignal(int);
2023static void ignoresig(int);
2024static void onsig(int);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002025static int dotrap(void);
Eric Andersenc470f442003-07-28 09:56:35 +00002026static void setinteractive(int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002027static void exitshell(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00002028
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002029
2030static int is_safe_applet(char *name)
2031{
Denis Vlasenko8f27c342006-12-26 21:31:11 +00002032 /* It isn't a bug to have non-existent applet here... */
2033 /* ...just a waste of space... */
Denis Vlasenkof7996f32007-01-11 17:20:00 +00002034 static const char safe_applets[][8] = {
Denis Vlasenko8f27c342006-12-26 21:31:11 +00002035 "["
2036 USE_AWK (, "awk" )
2037 USE_CAT (, "cat" )
2038 USE_CHMOD (, "chmod" )
2039 USE_CHOWN (, "chown" )
2040 USE_CP (, "cp" )
2041 USE_CUT (, "cut" )
2042 USE_DD (, "dd" )
2043 USE_ECHO (, "echo" )
2044 USE_FIND (, "find" )
2045 USE_HEXDUMP(, "hexdump")
2046 USE_LN (, "ln" )
2047 USE_LS (, "ls" )
2048 USE_MKDIR (, "mkdir" )
2049 USE_RM (, "rm" )
2050 USE_SORT (, "sort" )
2051 USE_TEST (, "test" )
2052 USE_TOUCH (, "touch" )
2053 USE_XARGS (, "xargs" )
2054 };
2055 int n = sizeof(safe_applets) / sizeof(safe_applets[0]);
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00002056 int i;
2057 for (i = 0; i < n; i++)
2058 if (strcmp(safe_applets[i], name) == 0)
2059 return 1;
2060
2061 return 0;
2062}
2063
2064
Eric Andersenc470f442003-07-28 09:56:35 +00002065/*
2066 * This routine is called when an error or an interrupt occurs in an
2067 * interactive shell and control is returned to the main command loop.
2068 */
2069
2070static void
2071reset(void)
2072{
2073 /* from eval.c: */
2074 {
2075 evalskip = 0;
2076 loopnest = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002077 }
2078
2079 /* from input.c: */
2080 {
2081 parselleft = parsenleft = 0; /* clear input buffer */
2082 popallfiles();
2083 }
2084
2085 /* from parser.c: */
2086 {
2087 tokpushback = 0;
2088 checkkwd = 0;
2089 }
2090
2091 /* from redir.c: */
2092 {
2093 clearredir(0);
2094 }
2095
2096}
2097
2098#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002099static struct alias *atab[ATABSIZE];
2100
Eric Andersenc470f442003-07-28 09:56:35 +00002101static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002102static struct alias *freealias(struct alias *);
2103static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002104
Eric Andersenc470f442003-07-28 09:56:35 +00002105static void
2106setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002107{
2108 struct alias *ap, **app;
2109
2110 app = __lookupalias(name);
2111 ap = *app;
2112 INTOFF;
2113 if (ap) {
2114 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002115 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002116 }
Eric Andersenc470f442003-07-28 09:56:35 +00002117 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002118 ap->flag &= ~ALIASDEAD;
2119 } else {
2120 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002121 ap = ckmalloc(sizeof (struct alias));
2122 ap->name = savestr(name);
2123 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002124 ap->flag = 0;
2125 ap->next = 0;
2126 *app = ap;
2127 }
2128 INTON;
2129}
2130
Eric Andersenc470f442003-07-28 09:56:35 +00002131static int
2132unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002133{
Eric Andersencb57d552001-06-28 07:25:16 +00002134 struct alias **app;
2135
2136 app = __lookupalias(name);
2137
2138 if (*app) {
2139 INTOFF;
2140 *app = freealias(*app);
2141 INTON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002142 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002143 }
2144
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002145 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00002146}
2147
Eric Andersenc470f442003-07-28 09:56:35 +00002148static void
2149rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002150{
Eric Andersencb57d552001-06-28 07:25:16 +00002151 struct alias *ap, **app;
2152 int i;
2153
2154 INTOFF;
2155 for (i = 0; i < ATABSIZE; i++) {
2156 app = &atab[i];
2157 for (ap = *app; ap; ap = *app) {
2158 *app = freealias(*app);
2159 if (ap == *app) {
2160 app = &ap->next;
2161 }
2162 }
2163 }
2164 INTON;
2165}
2166
Eric Andersenc470f442003-07-28 09:56:35 +00002167static struct alias *
2168lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002169{
Eric Andersenc470f442003-07-28 09:56:35 +00002170 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002171
Eric Andersenc470f442003-07-28 09:56:35 +00002172 if (check && ap && (ap->flag & ALIASINUSE))
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002173 return NULL;
2174 return ap;
Eric Andersen2870d962001-07-02 17:27:21 +00002175}
2176
Eric Andersencb57d552001-06-28 07:25:16 +00002177/*
2178 * TODO - sort output
2179 */
Eric Andersenc470f442003-07-28 09:56:35 +00002180static int
2181aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002182{
2183 char *n, *v;
2184 int ret = 0;
2185 struct alias *ap;
2186
2187 if (argc == 1) {
2188 int i;
2189
2190 for (i = 0; i < ATABSIZE; i++)
2191 for (ap = atab[i]; ap; ap = ap->next) {
2192 printalias(ap);
2193 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002194 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002195 }
2196 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002197 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002198 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002199 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002200 ret = 1;
2201 } else
2202 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002203 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002204 *v++ = '\0';
2205 setalias(n, v);
2206 }
2207 }
2208
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002209 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00002210}
2211
Eric Andersenc470f442003-07-28 09:56:35 +00002212static int
2213unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002214{
2215 int i;
2216
2217 while ((i = nextopt("a")) != '\0') {
2218 if (i == 'a') {
2219 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002220 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002221 }
2222 }
2223 for (i = 0; *argptr; argptr++) {
2224 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002225 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002226 i = 1;
2227 }
2228 }
2229
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002230 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00002231}
2232
Eric Andersenc470f442003-07-28 09:56:35 +00002233static struct alias *
2234freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002235 struct alias *next;
2236
2237 if (ap->flag & ALIASINUSE) {
2238 ap->flag |= ALIASDEAD;
2239 return ap;
2240 }
2241
2242 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002243 ckfree(ap->name);
2244 ckfree(ap->val);
2245 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002246 return next;
2247}
2248
Eric Andersenc470f442003-07-28 09:56:35 +00002249static void
2250printalias(const struct alias *ap) {
2251 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2252}
Eric Andersencb57d552001-06-28 07:25:16 +00002253
Eric Andersenc470f442003-07-28 09:56:35 +00002254static struct alias **
2255__lookupalias(const char *name) {
2256 unsigned int hashval;
2257 struct alias **app;
2258 const char *p;
2259 unsigned int ch;
2260
2261 p = name;
2262
2263 ch = (unsigned char)*p;
2264 hashval = ch << 4;
2265 while (ch) {
2266 hashval += ch;
2267 ch = (unsigned char)*++p;
2268 }
2269 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002270
2271 for (; *app; app = &(*app)->next) {
2272 if (equal(name, (*app)->name)) {
2273 break;
2274 }
2275 }
2276
2277 return app;
2278}
Eric Andersenc470f442003-07-28 09:56:35 +00002279#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002280
Eric Andersencb57d552001-06-28 07:25:16 +00002281
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002282/* cd.c */
Eric Andersen2870d962001-07-02 17:27:21 +00002283
Eric Andersencb57d552001-06-28 07:25:16 +00002284/*
Eric Andersenc470f442003-07-28 09:56:35 +00002285 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002286 */
2287
Eric Andersenc470f442003-07-28 09:56:35 +00002288#define CD_PHYSICAL 1
2289#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002290
Eric Andersenc470f442003-07-28 09:56:35 +00002291static int docd(const char *, int);
2292static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002293
Eric Andersenc470f442003-07-28 09:56:35 +00002294static char *curdir = nullstr; /* current working directory */
2295static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002296
Eric Andersenc470f442003-07-28 09:56:35 +00002297static int
2298cdopt(void)
2299{
2300 int flags = 0;
2301 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002302
Eric Andersenc470f442003-07-28 09:56:35 +00002303 j = 'L';
2304 while ((i = nextopt("LP"))) {
2305 if (i != j) {
2306 flags ^= CD_PHYSICAL;
2307 j = i;
2308 }
2309 }
Eric Andersencb57d552001-06-28 07:25:16 +00002310
Eric Andersenc470f442003-07-28 09:56:35 +00002311 return flags;
2312}
Eric Andersen2870d962001-07-02 17:27:21 +00002313
Eric Andersenc470f442003-07-28 09:56:35 +00002314static int
2315cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002316{
2317 const char *dest;
2318 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002319 const char *p;
2320 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002321 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002322 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002323
Eric Andersenc470f442003-07-28 09:56:35 +00002324 flags = cdopt();
2325 dest = *argptr;
2326 if (!dest)
2327 dest = bltinlookup(homestr);
Denis Vlasenko9f739442006-12-16 23:49:13 +00002328 else if (LONE_DASH(dest)) {
Eric Andersencb57d552001-06-28 07:25:16 +00002329 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002330 flags |= CD_PRINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002331 }
Eric Andersenc470f442003-07-28 09:56:35 +00002332 if (!dest)
2333 dest = nullstr;
2334 if (*dest == '/')
2335 goto step7;
2336 if (*dest == '.') {
2337 c = dest[1];
2338dotdot:
2339 switch (c) {
2340 case '\0':
2341 case '/':
2342 goto step6;
2343 case '.':
2344 c = dest[2];
2345 if (c != '.')
2346 goto dotdot;
2347 }
2348 }
2349 if (!*dest)
2350 dest = ".";
2351 if (!(path = bltinlookup("CDPATH"))) {
2352step6:
2353step7:
2354 p = dest;
2355 goto docd;
2356 }
2357 do {
2358 c = *path;
2359 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002360 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002361 if (c && c != ':')
2362 flags |= CD_PRINT;
2363docd:
2364 if (!docd(p, flags))
2365 goto out;
2366 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002367 }
Eric Andersenc470f442003-07-28 09:56:35 +00002368 } while (path);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002369 sh_error("can't cd to %s", dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002370 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002371out:
2372 if (flags & CD_PRINT)
2373 out1fmt(snlfmt, curdir);
2374 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002375}
2376
2377
2378/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002379 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002380 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002381 */
2382
Rob Landley88621d72006-08-29 19:41:06 +00002383static const char * updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002384{
Eric Andersenc470f442003-07-28 09:56:35 +00002385 char *new;
2386 char *p;
2387 char *cdcomppath;
2388 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002389
Eric Andersenc470f442003-07-28 09:56:35 +00002390 cdcomppath = sstrdup(dir);
2391 STARTSTACKSTR(new);
2392 if (*dir != '/') {
2393 if (curdir == nullstr)
2394 return 0;
2395 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002396 }
Eric Andersenc470f442003-07-28 09:56:35 +00002397 new = makestrspace(strlen(dir) + 2, new);
2398 lim = stackblock() + 1;
2399 if (*dir != '/') {
2400 if (new[-1] != '/')
2401 USTPUTC('/', new);
2402 if (new > lim && *lim == '/')
2403 lim++;
2404 } else {
2405 USTPUTC('/', new);
2406 cdcomppath++;
2407 if (dir[1] == '/' && dir[2] != '/') {
2408 USTPUTC('/', new);
2409 cdcomppath++;
2410 lim++;
2411 }
2412 }
2413 p = strtok(cdcomppath, "/");
2414 while (p) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00002415 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +00002416 case '.':
2417 if (p[1] == '.' && p[2] == '\0') {
2418 while (new > lim) {
2419 STUNPUTC(new);
2420 if (new[-1] == '/')
2421 break;
2422 }
2423 break;
2424 } else if (p[1] == '\0')
2425 break;
2426 /* fall through */
2427 default:
2428 new = stputs(p, new);
2429 USTPUTC('/', new);
2430 }
2431 p = strtok(0, "/");
2432 }
2433 if (new > lim)
2434 STUNPUTC(new);
2435 *new = 0;
2436 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002437}
2438
2439/*
Eric Andersenc470f442003-07-28 09:56:35 +00002440 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2441 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002442 */
2443
Eric Andersenc470f442003-07-28 09:56:35 +00002444static int
2445docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002446{
Eric Andersenc470f442003-07-28 09:56:35 +00002447 const char *dir = 0;
2448 int err;
2449
2450 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2451
Eric Andersencb57d552001-06-28 07:25:16 +00002452 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002453 if (!(flags & CD_PHYSICAL)) {
2454 dir = updatepwd(dest);
2455 if (dir)
2456 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002457 }
Eric Andersenc470f442003-07-28 09:56:35 +00002458 err = chdir(dest);
2459 if (err)
2460 goto out;
2461 setpwd(dir, 1);
2462 hashcd();
2463out:
Eric Andersencb57d552001-06-28 07:25:16 +00002464 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002465 return err;
2466}
2467
2468/*
2469 * Find out what the current directory is. If we already know the current
2470 * directory, this routine returns immediately.
2471 */
Rob Landley88621d72006-08-29 19:41:06 +00002472static char * getpwd(void)
Eric Andersenc470f442003-07-28 09:56:35 +00002473{
2474 char *dir = getcwd(0, 0);
2475 return dir ? dir : nullstr;
2476}
2477
2478static int
2479pwdcmd(int argc, char **argv)
2480{
2481 int flags;
2482 const char *dir = curdir;
2483
2484 flags = cdopt();
2485 if (flags) {
2486 if (physdir == nullstr)
2487 setpwd(dir, 0);
2488 dir = physdir;
2489 }
2490 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002491 return 0;
2492}
2493
Eric Andersenc470f442003-07-28 09:56:35 +00002494static void
2495setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002496{
Eric Andersenc470f442003-07-28 09:56:35 +00002497 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002498
Eric Andersenc470f442003-07-28 09:56:35 +00002499 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002500
Eric Andersencb57d552001-06-28 07:25:16 +00002501 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002502 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002503 }
2504 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002505 if (physdir != nullstr) {
2506 if (physdir != oldcur)
2507 free(physdir);
2508 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002509 }
Eric Andersenc470f442003-07-28 09:56:35 +00002510 if (oldcur == val || !val) {
2511 char *s = getpwd();
2512 physdir = s;
2513 if (!val)
2514 dir = s;
2515 } else
2516 dir = savestr(val);
2517 if (oldcur != dir && oldcur != nullstr) {
2518 free(oldcur);
2519 }
2520 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002521 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002522 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002523}
2524
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002525/* error.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002526
Eric Andersencb57d552001-06-28 07:25:16 +00002527/*
2528 * Errors and exceptions.
2529 */
2530
2531/*
2532 * Code to handle exceptions in C.
2533 */
2534
Eric Andersen2870d962001-07-02 17:27:21 +00002535
Eric Andersencb57d552001-06-28 07:25:16 +00002536
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002537static void exverror(int, const char *, va_list)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002538 ATTRIBUTE_NORETURN;
Eric Andersencb57d552001-06-28 07:25:16 +00002539
2540/*
2541 * Called to raise an exception. Since C doesn't include exceptions, we
2542 * just do a longjmp to the exception handler. The type of exception is
2543 * stored in the global variable "exception".
2544 */
2545
Eric Andersenc470f442003-07-28 09:56:35 +00002546static void
2547exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002548{
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00002549#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002550 if (handler == NULL)
2551 abort();
2552#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002553 INTOFF;
2554
Eric Andersencb57d552001-06-28 07:25:16 +00002555 exception = e;
2556 longjmp(handler->loc, 1);
2557}
2558
2559
2560/*
2561 * Called from trap.c when a SIGINT is received. (If the user specifies
2562 * that SIGINT is to be trapped or ignored using the trap builtin, then
2563 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002564 * are held using the INTOFF macro. (The test for iflag is just
2565 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002566 */
2567
Eric Andersenc470f442003-07-28 09:56:35 +00002568static void
2569onint(void) {
2570 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002571
Eric Andersencb57d552001-06-28 07:25:16 +00002572 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002573 i = EXSIG;
2574 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2575 if (!(rootshell && iflag)) {
2576 signal(SIGINT, SIG_DFL);
2577 raise(SIGINT);
2578 }
2579 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002580 }
Eric Andersenc470f442003-07-28 09:56:35 +00002581 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002582 /* NOTREACHED */
2583}
2584
Eric Andersenc470f442003-07-28 09:56:35 +00002585static void
2586exvwarning(const char *msg, va_list ap)
2587{
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002588 FILE *errs;
Eric Andersencb57d552001-06-28 07:25:16 +00002589
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002590 errs = stderr;
2591 fprintf(errs, "%s: ", arg0);
2592 if (commandname) {
2593 const char *fmt = (!iflag || parsefile->fd) ?
2594 "%s: %d: " : "%s: ";
2595 fprintf(errs, fmt, commandname, startlinno);
2596 }
2597 vfprintf(errs, msg, ap);
2598 outcslow('\n', errs);
Eric Andersenc470f442003-07-28 09:56:35 +00002599}
Eric Andersen2870d962001-07-02 17:27:21 +00002600
Eric Andersencb57d552001-06-28 07:25:16 +00002601/*
Eric Andersenc470f442003-07-28 09:56:35 +00002602 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002603 * is not NULL then error prints an error message using printf style
2604 * formatting. It then raises the error exception.
2605 */
Eric Andersenc470f442003-07-28 09:56:35 +00002606static void
2607exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002608{
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00002609#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002610 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002611 TRACE(("exverror(%d, \"", cond));
2612 TRACEV((msg, ap));
2613 TRACE(("\") pid=%d\n", getpid()));
2614 } else
2615 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2616 if (msg)
2617#endif
2618 exvwarning(msg, ap);
2619
2620 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002621 exraise(cond);
2622 /* NOTREACHED */
2623}
2624
2625
Eric Andersenc470f442003-07-28 09:56:35 +00002626static void
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002627sh_error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002628{
Eric Andersencb57d552001-06-28 07:25:16 +00002629 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002630
Eric Andersencb57d552001-06-28 07:25:16 +00002631 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002632 exverror(EXERROR, msg, ap);
2633 /* NOTREACHED */
2634 va_end(ap);
2635}
2636
2637
Eric Andersenc470f442003-07-28 09:56:35 +00002638static void
2639exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002640{
Eric Andersencb57d552001-06-28 07:25:16 +00002641 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002642
Eric Andersencb57d552001-06-28 07:25:16 +00002643 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002644 exverror(cond, msg, ap);
2645 /* NOTREACHED */
2646 va_end(ap);
2647}
2648
Eric Andersencb57d552001-06-28 07:25:16 +00002649/*
Eric Andersenc470f442003-07-28 09:56:35 +00002650 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002651 */
2652
Eric Andersenc470f442003-07-28 09:56:35 +00002653static void
2654sh_warnx(const char *fmt, ...)
2655{
2656 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002657
Eric Andersenc470f442003-07-28 09:56:35 +00002658 va_start(ap, fmt);
2659 exvwarning(fmt, ap);
2660 va_end(ap);
2661}
Eric Andersen2870d962001-07-02 17:27:21 +00002662
Eric Andersencb57d552001-06-28 07:25:16 +00002663
2664/*
2665 * Return a string describing an error. The returned string may be a
2666 * pointer to a static buffer that will be overwritten on the next call.
2667 * Action describes the operation that got the error.
2668 */
2669
Eric Andersenc470f442003-07-28 09:56:35 +00002670static const char *
2671errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002672{
Eric Andersenc470f442003-07-28 09:56:35 +00002673 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002674
Eric Andersenc470f442003-07-28 09:56:35 +00002675 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002676 }
Eric Andersenc470f442003-07-28 09:56:35 +00002677 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002678}
2679
2680
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002681/* eval.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002682
2683/*
2684 * Evaluate a command.
2685 */
Eric Andersencb57d552001-06-28 07:25:16 +00002686
2687/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002688#define EV_EXIT 01 /* exit after evaluating tree */
2689#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2690#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002691
2692
Eric Andersenc470f442003-07-28 09:56:35 +00002693static void evalloop(union node *, int);
2694static void evalfor(union node *, int);
2695static void evalcase(union node *, int);
2696static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002697static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002698static void evalpipe(union node *, int);
2699static void evalcommand(union node *, int);
2700static int evalbltin(const struct builtincmd *, int, char **);
2701static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002702static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002703static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002704
Eric Andersenc470f442003-07-28 09:56:35 +00002705
2706static const struct builtincmd bltin = {
2707 "\0\0", bltincmd
2708};
2709
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002710
Eric Andersencb57d552001-06-28 07:25:16 +00002711/*
2712 * Called to reset things after an exception.
2713 */
2714
Eric Andersencb57d552001-06-28 07:25:16 +00002715/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002716 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002717 */
2718
Eric Andersenc470f442003-07-28 09:56:35 +00002719static int
2720evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002721{
Eric Andersen2870d962001-07-02 17:27:21 +00002722 char *p;
2723 char *concat;
2724 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002725
Eric Andersen2870d962001-07-02 17:27:21 +00002726 if (argc > 1) {
2727 p = argv[1];
2728 if (argc > 2) {
2729 STARTSTACKSTR(concat);
2730 ap = argv + 2;
2731 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002732 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002733 if ((p = *ap++) == NULL)
2734 break;
2735 STPUTC(' ', concat);
2736 }
2737 STPUTC('\0', concat);
2738 p = grabstackstr(concat);
2739 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002740 evalstring(p, ~SKIPEVAL);
2741
Eric Andersen2870d962001-07-02 17:27:21 +00002742 }
2743 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002744}
2745
Eric Andersenc470f442003-07-28 09:56:35 +00002746
Eric Andersencb57d552001-06-28 07:25:16 +00002747/*
2748 * Execute a command or commands contained in a string.
2749 */
2750
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002751static int
2752evalstring(char *s, int mask)
Eric Andersen2870d962001-07-02 17:27:21 +00002753{
Eric Andersencb57d552001-06-28 07:25:16 +00002754 union node *n;
2755 struct stackmark smark;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002756 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002757
Eric Andersencb57d552001-06-28 07:25:16 +00002758 setinputstring(s);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002759 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002760
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002761 skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002762 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002763 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002764 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002765 skip = evalskip;
2766 if (skip)
Eric Andersenc470f442003-07-28 09:56:35 +00002767 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002768 }
2769 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002770
2771 skip &= mask;
2772 evalskip = skip;
2773 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002774}
2775
Eric Andersenc470f442003-07-28 09:56:35 +00002776
Eric Andersen62483552001-07-10 06:09:16 +00002777
2778/*
Eric Andersenc470f442003-07-28 09:56:35 +00002779 * Evaluate a parse tree. The value is left in the global variable
2780 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002781 */
2782
Eric Andersenc470f442003-07-28 09:56:35 +00002783static void
2784evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002785{
Eric Andersenc470f442003-07-28 09:56:35 +00002786 int checkexit = 0;
2787 void (*evalfn)(union node *, int);
2788 unsigned isor;
2789 int status;
2790 if (n == NULL) {
2791 TRACE(("evaltree(NULL) called\n"));
2792 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002793 }
Eric Andersenc470f442003-07-28 09:56:35 +00002794 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2795 getpid(), n, n->type, flags));
2796 switch (n->type) {
2797 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00002798#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00002799 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002800 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002801 break;
2802#endif
2803 case NNOT:
2804 evaltree(n->nnot.com, EV_TESTED);
2805 status = !exitstatus;
2806 goto setstatus;
2807 case NREDIR:
2808 expredir(n->nredir.redirect);
2809 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2810 if (!status) {
2811 evaltree(n->nredir.n, flags & EV_TESTED);
2812 status = exitstatus;
2813 }
2814 popredir(0);
2815 goto setstatus;
2816 case NCMD:
2817 evalfn = evalcommand;
2818checkexit:
2819 if (eflag && !(flags & EV_TESTED))
2820 checkexit = ~0;
2821 goto calleval;
2822 case NFOR:
2823 evalfn = evalfor;
2824 goto calleval;
2825 case NWHILE:
2826 case NUNTIL:
2827 evalfn = evalloop;
2828 goto calleval;
2829 case NSUBSHELL:
2830 case NBACKGND:
2831 evalfn = evalsubshell;
2832 goto calleval;
2833 case NPIPE:
2834 evalfn = evalpipe;
2835 goto checkexit;
2836 case NCASE:
2837 evalfn = evalcase;
2838 goto calleval;
2839 case NAND:
2840 case NOR:
2841 case NSEMI:
2842#if NAND + 1 != NOR
2843#error NAND + 1 != NOR
2844#endif
2845#if NOR + 1 != NSEMI
2846#error NOR + 1 != NSEMI
2847#endif
2848 isor = n->type - NAND;
2849 evaltree(
2850 n->nbinary.ch1,
2851 (flags | ((isor >> 1) - 1)) & EV_TESTED
2852 );
2853 if (!exitstatus == isor)
2854 break;
2855 if (!evalskip) {
2856 n = n->nbinary.ch2;
2857evaln:
2858 evalfn = evaltree;
2859calleval:
2860 evalfn(n, flags);
2861 break;
2862 }
2863 break;
2864 case NIF:
2865 evaltree(n->nif.test, EV_TESTED);
2866 if (evalskip)
2867 break;
2868 if (exitstatus == 0) {
2869 n = n->nif.ifpart;
2870 goto evaln;
2871 } else if (n->nif.elsepart) {
2872 n = n->nif.elsepart;
2873 goto evaln;
2874 }
2875 goto success;
2876 case NDEFUN:
2877 defun(n->narg.text, n->narg.next);
2878success:
2879 status = 0;
2880setstatus:
2881 exitstatus = status;
2882 break;
2883 }
2884out:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002885 if ((checkexit & exitstatus))
2886 evalskip |= SKIPEVAL;
2887 else if (pendingsigs && dotrap())
2888 goto exexit;
2889
2890 if (flags & EV_EXIT) {
2891exexit:
Eric Andersenc470f442003-07-28 09:56:35 +00002892 exraise(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002893 }
Eric Andersen62483552001-07-10 06:09:16 +00002894}
2895
Eric Andersenc470f442003-07-28 09:56:35 +00002896
2897#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2898static
2899#endif
2900void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2901
2902
2903static void
2904evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002905{
2906 int status;
2907
2908 loopnest++;
2909 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002910 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002911 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002912 int i;
2913
Eric Andersencb57d552001-06-28 07:25:16 +00002914 evaltree(n->nbinary.ch1, EV_TESTED);
2915 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002916skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002917 evalskip = 0;
2918 continue;
2919 }
2920 if (evalskip == SKIPBREAK && --skipcount <= 0)
2921 evalskip = 0;
2922 break;
2923 }
Eric Andersenc470f442003-07-28 09:56:35 +00002924 i = exitstatus;
2925 if (n->type != NWHILE)
2926 i = !i;
2927 if (i != 0)
2928 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002929 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002930 status = exitstatus;
2931 if (evalskip)
2932 goto skipping;
2933 }
2934 loopnest--;
2935 exitstatus = status;
2936}
2937
Eric Andersenc470f442003-07-28 09:56:35 +00002938
2939
2940static void
2941evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002942{
2943 struct arglist arglist;
2944 union node *argp;
2945 struct strlist *sp;
2946 struct stackmark smark;
2947
2948 setstackmark(&smark);
2949 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002950 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002951 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002952 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002953 if (evalskip)
2954 goto out;
2955 }
2956 *arglist.lastp = NULL;
2957
2958 exitstatus = 0;
2959 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002960 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002961 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002962 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002963 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002964 if (evalskip) {
2965 if (evalskip == SKIPCONT && --skipcount <= 0) {
2966 evalskip = 0;
2967 continue;
2968 }
2969 if (evalskip == SKIPBREAK && --skipcount <= 0)
2970 evalskip = 0;
2971 break;
2972 }
2973 }
2974 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002975out:
Eric Andersencb57d552001-06-28 07:25:16 +00002976 popstackmark(&smark);
2977}
2978
Eric Andersenc470f442003-07-28 09:56:35 +00002979
2980
2981static void
2982evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002983{
2984 union node *cp;
2985 union node *patp;
2986 struct arglist arglist;
2987 struct stackmark smark;
2988
2989 setstackmark(&smark);
2990 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002991 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002992 exitstatus = 0;
2993 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2994 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002995 if (casematch(patp, arglist.list->text)) {
2996 if (evalskip == 0) {
2997 evaltree(cp->nclist.body, flags);
2998 }
2999 goto out;
3000 }
3001 }
3002 }
Eric Andersenc470f442003-07-28 09:56:35 +00003003out:
Eric Andersencb57d552001-06-28 07:25:16 +00003004 popstackmark(&smark);
3005}
3006
Eric Andersenc470f442003-07-28 09:56:35 +00003007
3008
3009/*
3010 * Kick off a subshell to evaluate a tree.
3011 */
3012
3013static void
3014evalsubshell(union node *n, int flags)
3015{
3016 struct job *jp;
3017 int backgnd = (n->type == NBACKGND);
3018 int status;
3019
3020 expredir(n->nredir.redirect);
3021 if (!backgnd && flags & EV_EXIT && !trap[0])
3022 goto nofork;
3023 INTOFF;
3024 jp = makejob(n, 1);
3025 if (forkshell(jp, n, backgnd) == 0) {
3026 INTON;
3027 flags |= EV_EXIT;
3028 if (backgnd)
3029 flags &=~ EV_TESTED;
3030nofork:
3031 redirect(n->nredir.redirect, 0);
3032 evaltreenr(n->nredir.n, flags);
3033 /* never returns */
3034 }
3035 status = 0;
3036 if (! backgnd)
3037 status = waitforjob(jp);
3038 exitstatus = status;
3039 INTON;
3040}
3041
3042
3043
3044/*
3045 * Compute the names of the files in a redirection list.
3046 */
3047
3048static void
3049expredir(union node *n)
3050{
3051 union node *redir;
3052
3053 for (redir = n ; redir ; redir = redir->nfile.next) {
3054 struct arglist fn;
Denis Vlasenko5f031582006-10-16 01:33:16 +00003055 memset(&fn, 0, sizeof(struct arglist));
Eric Andersenc470f442003-07-28 09:56:35 +00003056 fn.lastp = &fn.list;
3057 switch (redir->type) {
3058 case NFROMTO:
3059 case NFROM:
3060 case NTO:
3061 case NCLOBBER:
3062 case NAPPEND:
3063 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3064 redir->nfile.expfname = fn.list->text;
3065 break;
3066 case NFROMFD:
3067 case NTOFD:
3068 if (redir->ndup.vname) {
3069 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko5f031582006-10-16 01:33:16 +00003070 if (fn.list != NULL)
3071 fixredir(redir, fn.list->text, 1);
3072 else
3073 sh_error("redir error");
Eric Andersenc470f442003-07-28 09:56:35 +00003074 }
3075 break;
3076 }
3077 }
3078}
3079
3080
3081
Eric Andersencb57d552001-06-28 07:25:16 +00003082/*
Eric Andersencb57d552001-06-28 07:25:16 +00003083 * Evaluate a pipeline. All the processes in the pipeline are children
3084 * of the process creating the pipeline. (This differs from some versions
3085 * of the shell, which make the last process in a pipeline the parent
3086 * of all the rest.)
3087 */
3088
Eric Andersenc470f442003-07-28 09:56:35 +00003089static void
3090evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003091{
3092 struct job *jp;
3093 struct nodelist *lp;
3094 int pipelen;
3095 int prevfd;
3096 int pip[2];
3097
Eric Andersenc470f442003-07-28 09:56:35 +00003098 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003099 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003100 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003101 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003102 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003103 INTOFF;
3104 jp = makejob(n, pipelen);
3105 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003106 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003107 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003108 pip[1] = -1;
3109 if (lp->next) {
3110 if (pipe(pip) < 0) {
3111 close(prevfd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003112 sh_error("Pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00003113 }
3114 }
3115 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3116 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003117 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003118 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003119 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003120 if (prevfd > 0) {
3121 dup2(prevfd, 0);
3122 close(prevfd);
3123 }
3124 if (pip[1] > 1) {
3125 dup2(pip[1], 1);
3126 close(pip[1]);
3127 }
Eric Andersenc470f442003-07-28 09:56:35 +00003128 evaltreenr(lp->n, flags);
3129 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003130 }
3131 if (prevfd >= 0)
3132 close(prevfd);
3133 prevfd = pip[0];
3134 close(pip[1]);
3135 }
Eric Andersencb57d552001-06-28 07:25:16 +00003136 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003137 exitstatus = waitforjob(jp);
3138 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003139 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003140 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003141}
3142
Eric Andersen62483552001-07-10 06:09:16 +00003143
3144
3145/*
3146 * Execute a command inside back quotes. If it's a builtin command, we
3147 * want to save its output in a block obtained from malloc. Otherwise
3148 * we fork off a subprocess and get the output of the command via a pipe.
3149 * Should be called with interrupts off.
3150 */
3151
Eric Andersenc470f442003-07-28 09:56:35 +00003152static void
3153evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003154{
Eric Andersenc470f442003-07-28 09:56:35 +00003155 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003156
Eric Andersen62483552001-07-10 06:09:16 +00003157 result->fd = -1;
3158 result->buf = NULL;
3159 result->nleft = 0;
3160 result->jp = NULL;
3161 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003162 goto out;
3163 }
Eric Andersenc470f442003-07-28 09:56:35 +00003164
3165 saveherefd = herefd;
3166 herefd = -1;
3167
3168 {
3169 int pip[2];
3170 struct job *jp;
3171
3172 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003173 sh_error("Pipe call failed");
Eric Andersenc470f442003-07-28 09:56:35 +00003174 jp = makejob(n, 1);
3175 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3176 FORCEINTON;
3177 close(pip[0]);
3178 if (pip[1] != 1) {
3179 close(1);
3180 copyfd(pip[1], 1);
3181 close(pip[1]);
3182 }
3183 eflag = 0;
3184 evaltreenr(n, EV_EXIT);
3185 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003186 }
Eric Andersenc470f442003-07-28 09:56:35 +00003187 close(pip[1]);
3188 result->fd = pip[0];
3189 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003190 }
Eric Andersenc470f442003-07-28 09:56:35 +00003191 herefd = saveherefd;
3192out:
Eric Andersen62483552001-07-10 06:09:16 +00003193 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003194 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003195}
3196
Eric Andersenc470f442003-07-28 09:56:35 +00003197#ifdef CONFIG_ASH_CMDCMD
Rob Landley88621d72006-08-29 19:41:06 +00003198static char ** parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00003199{
3200 char *cp, c;
3201
3202 for (;;) {
3203 cp = *++argv;
3204 if (!cp)
3205 return 0;
3206 if (*cp++ != '-')
3207 break;
3208 if (!(c = *cp++))
3209 break;
3210 if (c == '-' && !*cp) {
3211 argv++;
3212 break;
3213 }
3214 do {
3215 switch (c) {
3216 case 'p':
3217 *path = defpath;
3218 break;
3219 default:
3220 /* run 'typecmd' for other options */
3221 return 0;
3222 }
3223 } while ((c = *cp++));
3224 }
3225 return argv;
3226}
3227#endif
3228
Rob Landley88621d72006-08-29 19:41:06 +00003229static int isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00003230{
3231 const char *q = endofname(p);
3232 if (p == q)
3233 return 0;
3234 return *q == '=';
3235}
Eric Andersen62483552001-07-10 06:09:16 +00003236
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003237#ifdef CONFIG_ASH_EXPAND_PRMT
3238static const char *expandstr(const char *ps);
3239#else
3240#define expandstr(s) s
3241#endif
3242
Eric Andersen62483552001-07-10 06:09:16 +00003243/*
3244 * Execute a simple command.
3245 */
Eric Andersencb57d552001-06-28 07:25:16 +00003246
Eric Andersenc470f442003-07-28 09:56:35 +00003247static void
3248evalcommand(union node *cmd, int flags)
3249{
3250 struct stackmark smark;
3251 union node *argp;
3252 struct arglist arglist;
3253 struct arglist varlist;
3254 char **argv;
3255 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003256 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003257 struct cmdentry cmdentry;
3258 struct job *jp;
3259 char *lastarg;
3260 const char *path;
3261 int spclbltin;
3262 int cmd_is_exec;
3263 int status;
3264 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003265 struct builtincmd *bcmd;
3266 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003267
3268 /* First expand the arguments. */
3269 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3270 setstackmark(&smark);
3271 back_exitstatus = 0;
3272
3273 cmdentry.cmdtype = CMDBUILTIN;
3274 cmdentry.u.cmd = &bltin;
3275 varlist.lastp = &varlist.list;
3276 *varlist.lastp = NULL;
3277 arglist.lastp = &arglist.list;
3278 *arglist.lastp = NULL;
3279
3280 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003281 if (cmd->ncmd.args)
3282 {
3283 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3284 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3285 }
3286
Eric Andersenc470f442003-07-28 09:56:35 +00003287 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3288 struct strlist **spp;
3289
3290 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003291 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00003292 expandarg(argp, &arglist, EXP_VARTILDE);
3293 else
3294 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3295
Eric Andersenc470f442003-07-28 09:56:35 +00003296 for (sp = *spp; sp; sp = sp->next)
3297 argc++;
3298 }
3299
3300 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3301 for (sp = arglist.list ; sp ; sp = sp->next) {
3302 TRACE(("evalcommand arg: %s\n", sp->text));
3303 *nargv++ = sp->text;
3304 }
3305 *nargv = NULL;
3306
3307 lastarg = NULL;
3308 if (iflag && funcnest == 0 && argc > 0)
3309 lastarg = nargv[-1];
3310
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003311 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003312 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003313 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003314
3315 path = vpath.text;
3316 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3317 struct strlist **spp;
3318 char *p;
3319
3320 spp = varlist.lastp;
3321 expandarg(argp, &varlist, EXP_VARTILDE);
3322
3323 /*
3324 * Modify the command lookup path, if a PATH= assignment
3325 * is present
3326 */
3327 p = (*spp)->text;
3328 if (varequal(p, path))
3329 path = p;
3330 }
3331
3332 /* Print the command if xflag is set. */
3333 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003334 int n;
3335 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003336
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003337 p++;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003338 dprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003339
3340 sp = varlist.list;
3341 for(n = 0; n < 2; n++) {
3342 while (sp) {
3343 dprintf(preverrout_fd, p, sp->text);
3344 sp = sp->next;
3345 if(*p == '%') {
3346 p--;
3347 }
3348 }
3349 sp = arglist.list;
3350 }
Rob Landley53437472006-07-16 08:14:35 +00003351 full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003352 }
3353
3354 cmd_is_exec = 0;
3355 spclbltin = -1;
3356
3357 /* Now locate the command. */
3358 if (argc) {
3359 const char *oldpath;
3360 int cmd_flag = DO_ERR;
3361
3362 path += 5;
3363 oldpath = path;
3364 for (;;) {
3365 find_command(argv[0], &cmdentry, cmd_flag, path);
3366 if (cmdentry.cmdtype == CMDUNKNOWN) {
3367 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003368 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003369 goto bail;
3370 }
3371
3372 /* implement bltin and command here */
3373 if (cmdentry.cmdtype != CMDBUILTIN)
3374 break;
3375 if (spclbltin < 0)
3376 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3377 if (cmdentry.u.cmd == EXECCMD)
3378 cmd_is_exec++;
3379#ifdef CONFIG_ASH_CMDCMD
3380 if (cmdentry.u.cmd == COMMANDCMD) {
3381
3382 path = oldpath;
3383 nargv = parse_command_args(argv, &path);
3384 if (!nargv)
3385 break;
3386 argc -= nargv - argv;
3387 argv = nargv;
3388 cmd_flag |= DO_NOFUNC;
3389 } else
3390#endif
3391 break;
3392 }
3393 }
3394
3395 if (status) {
3396 /* We have a redirection error. */
3397 if (spclbltin > 0)
3398 exraise(EXERROR);
3399bail:
3400 exitstatus = status;
3401 goto out;
3402 }
3403
3404 /* Execute the command. */
3405 switch (cmdentry.cmdtype) {
3406 default:
3407 /* Fork off a child process if necessary. */
3408 if (!(flags & EV_EXIT) || trap[0]) {
3409 INTOFF;
3410 jp = makejob(cmd, 1);
3411 if (forkshell(jp, cmd, FORK_FG) != 0) {
3412 exitstatus = waitforjob(jp);
3413 INTON;
3414 break;
3415 }
3416 FORCEINTON;
3417 }
3418 listsetvar(varlist.list, VEXPORT|VSTACK);
3419 shellexec(argv, path, cmdentry.u.index);
3420 /* NOTREACHED */
3421
3422 case CMDBUILTIN:
3423 cmdenviron = varlist.list;
3424 if (cmdenviron) {
3425 struct strlist *list = cmdenviron;
3426 int i = VNOSET;
3427 if (spclbltin > 0 || argc == 0) {
3428 i = 0;
3429 if (cmd_is_exec && argc > 1)
3430 i = VEXPORT;
3431 }
3432 listsetvar(list, i);
3433 }
3434 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3435 int exit_status;
3436 int i, j;
3437
3438 i = exception;
3439 if (i == EXEXIT)
3440 goto raise;
3441
3442 exit_status = 2;
3443 j = 0;
3444 if (i == EXINT)
3445 j = SIGINT;
3446 if (i == EXSIG)
3447 j = pendingsigs;
3448 if (j)
3449 exit_status = j + 128;
3450 exitstatus = exit_status;
3451
3452 if (i == EXINT || spclbltin > 0) {
3453raise:
3454 longjmp(handler->loc, 1);
3455 }
3456 FORCEINTON;
3457 }
3458 break;
3459
3460 case CMDFUNCTION:
3461 listsetvar(varlist.list, 0);
3462 if (evalfun(cmdentry.u.func, argc, argv, flags))
3463 goto raise;
3464 break;
3465 }
3466
3467out:
3468 popredir(cmd_is_exec);
3469 if (lastarg)
3470 /* dsl: I think this is intended to be used to support
3471 * '_' in 'vi' command mode during line editing...
3472 * However I implemented that within libedit itself.
3473 */
3474 setvar("_", lastarg, 0);
3475 popstackmark(&smark);
3476}
3477
3478static int
3479evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3480 char *volatile savecmdname;
3481 struct jmploc *volatile savehandler;
3482 struct jmploc jmploc;
3483 int i;
3484
3485 savecmdname = commandname;
3486 if ((i = setjmp(jmploc.loc)))
3487 goto cmddone;
3488 savehandler = handler;
3489 handler = &jmploc;
3490 commandname = argv[0];
3491 argptr = argv + 1;
3492 optptr = NULL; /* initialize nextopt */
3493 exitstatus = (*cmd->builtin)(argc, argv);
3494 flushall();
3495cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003496 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00003497 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003498 commandname = savecmdname;
3499 exsig = 0;
3500 handler = savehandler;
3501
3502 return i;
3503}
3504
3505static int
3506evalfun(struct funcnode *func, int argc, char **argv, int flags)
3507{
3508 volatile struct shparam saveparam;
3509 struct localvar *volatile savelocalvars;
3510 struct jmploc *volatile savehandler;
3511 struct jmploc jmploc;
3512 int e;
3513
3514 saveparam = shellparam;
3515 savelocalvars = localvars;
3516 if ((e = setjmp(jmploc.loc))) {
3517 goto funcdone;
3518 }
3519 INTOFF;
3520 savehandler = handler;
3521 handler = &jmploc;
3522 localvars = NULL;
3523 shellparam.malloc = 0;
3524 func->count++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003525 funcnest++;
Eric Andersenc470f442003-07-28 09:56:35 +00003526 INTON;
3527 shellparam.nparam = argc - 1;
3528 shellparam.p = argv + 1;
3529#ifdef CONFIG_ASH_GETOPTS
3530 shellparam.optind = 1;
3531 shellparam.optoff = -1;
3532#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003533 evaltree(&func->n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00003534funcdone:
3535 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003536 funcnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00003537 freefunc(func);
3538 poplocalvars();
3539 localvars = savelocalvars;
3540 freeparam(&shellparam);
3541 shellparam = saveparam;
3542 handler = savehandler;
3543 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003544 evalskip &= ~SKIPFUNC;
Eric Andersenc470f442003-07-28 09:56:35 +00003545 return e;
3546}
3547
3548
Rob Landley88621d72006-08-29 19:41:06 +00003549static int goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003550{
3551 return !*endofname(p);
3552}
3553
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003554/*
3555 * Search for a command. This is called before we fork so that the
3556 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003557 * the child. The check for "goodname" is an overly conservative
3558 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003559 */
3560
Eric Andersenc470f442003-07-28 09:56:35 +00003561static void
3562prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003563{
3564 struct cmdentry entry;
3565
3566 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003567 if (goodname(n->ncmd.args->narg.text))
3568 find_command(n->ncmd.args->narg.text, &entry, 0,
3569 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003570}
3571
Eric Andersencb57d552001-06-28 07:25:16 +00003572
Eric Andersenc470f442003-07-28 09:56:35 +00003573
Eric Andersencb57d552001-06-28 07:25:16 +00003574/*
3575 * Builtin commands. Builtin commands whose functions are closely
3576 * tied to evaluation are implemented here.
3577 */
3578
3579/*
Eric Andersenc470f442003-07-28 09:56:35 +00003580 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003581 */
3582
Eric Andersenc470f442003-07-28 09:56:35 +00003583static int
3584bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003585{
3586 /*
3587 * Preserve exitstatus of a previous possible redirection
3588 * as POSIX mandates
3589 */
Eric Andersenc470f442003-07-28 09:56:35 +00003590 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003591}
3592
3593
3594/*
3595 * Handle break and continue commands. Break, continue, and return are
3596 * all handled by setting the evalskip flag. The evaluation routines
3597 * above all check this flag, and if it is set they start skipping
3598 * commands rather than executing them. The variable skipcount is
3599 * the number of loops to break/continue, or the number of function
3600 * levels to return. (The latter is always 1.) It should probably
3601 * be an error to break out of more loops than exist, but it isn't
3602 * in the standard shell so we don't make it one here.
3603 */
3604
Eric Andersenc470f442003-07-28 09:56:35 +00003605static int
3606breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003607{
3608 int n = argc > 1 ? number(argv[1]) : 1;
3609
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003610 if (n <= 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003611 sh_error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003612 if (n > loopnest)
3613 n = loopnest;
3614 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003615 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003616 skipcount = n;
3617 }
3618 return 0;
3619}
3620
3621
3622/*
3623 * The return command.
3624 */
3625
Eric Andersenc470f442003-07-28 09:56:35 +00003626static int
3627returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003628{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003629 /*
3630 * If called outside a function, do what ksh does;
3631 * skip the rest of the file.
3632 */
3633 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
3634 return argv[1] ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003635}
3636
3637
Eric Andersenc470f442003-07-28 09:56:35 +00003638static int
3639falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003640{
3641 return 1;
3642}
3643
Eric Andersenc470f442003-07-28 09:56:35 +00003644
3645static int
3646truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003647{
3648 return 0;
3649}
Eric Andersen2870d962001-07-02 17:27:21 +00003650
Eric Andersencb57d552001-06-28 07:25:16 +00003651
Eric Andersenc470f442003-07-28 09:56:35 +00003652static int
3653execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003654{
3655 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003656 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003657 mflag = 0;
3658 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003659 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003660 }
3661 return 0;
3662}
3663
Eric Andersenc470f442003-07-28 09:56:35 +00003664
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003665/* exec.c */
Eric Andersenc470f442003-07-28 09:56:35 +00003666
3667/*
3668 * When commands are first encountered, they are entered in a hash table.
3669 * This ensures that a full path search will not have to be done for them
3670 * on each invocation.
3671 *
3672 * We should investigate converting to a linear search, even though that
3673 * would make the command name "hash" a misnomer.
3674 */
3675
3676#define CMDTABLESIZE 31 /* should be prime */
3677#define ARB 1 /* actual size determined at run time */
3678
3679
3680
3681struct tblentry {
3682 struct tblentry *next; /* next entry in hash chain */
3683 union param param; /* definition of builtin function */
3684 short cmdtype; /* index identifying command */
3685 char rehash; /* if set, cd done since entry created */
3686 char cmdname[ARB]; /* name of command */
3687};
3688
3689
3690static struct tblentry *cmdtable[CMDTABLESIZE];
3691static int builtinloc = -1; /* index in path of %builtin, or -1 */
3692
3693
3694static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003695static void clearcmdentry(int);
3696static struct tblentry *cmdlookup(const char *, int);
3697static void delete_cmd_entry(void);
3698
Eric Andersencb57d552001-06-28 07:25:16 +00003699
3700/*
3701 * Exec a program. Never returns. If you change this routine, you may
3702 * have to change the find_command routine as well.
3703 */
3704
Eric Andersenc470f442003-07-28 09:56:35 +00003705static void
3706shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003707{
3708 char *cmdname;
3709 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003710 char **envp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003711 int exerrno;
Eric Andersencb57d552001-06-28 07:25:16 +00003712
Eric Andersenc470f442003-07-28 09:56:35 +00003713 clearredir(1);
3714 envp = environment();
Denis Vlasenko62a69832007-01-10 00:24:50 +00003715 if (strchr(argv[0], '/') || is_safe_applet(argv[0])
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00003716#if ENABLE_FEATURE_SH_STANDALONE_SHELL
Denis Vlasenko8f27c342006-12-26 21:31:11 +00003717 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003718#endif
Denis Vlasenko8f27c342006-12-26 21:31:11 +00003719 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003720 tryexec(argv[0], argv, envp);
3721 e = errno;
3722 } else {
3723 e = ENOENT;
3724 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3725 if (--idx < 0 && pathopt == NULL) {
3726 tryexec(cmdname, argv, envp);
3727 if (errno != ENOENT && errno != ENOTDIR)
3728 e = errno;
3729 }
3730 stunalloc(cmdname);
3731 }
3732 }
3733
3734 /* Map to POSIX errors */
3735 switch (e) {
3736 case EACCES:
3737 exerrno = 126;
3738 break;
3739 case ENOENT:
3740 exerrno = 127;
3741 break;
3742 default:
3743 exerrno = 2;
3744 break;
3745 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003746 exitstatus = exerrno;
Eric Andersenc470f442003-07-28 09:56:35 +00003747 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3748 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003749 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3750 /* NOTREACHED */
3751}
3752
Eric Andersen2870d962001-07-02 17:27:21 +00003753
Eric Andersenc470f442003-07-28 09:56:35 +00003754static void
3755tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003756{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003757 int repeated = 0;
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00003758 struct BB_applet *a;
3759 int argc = 0;
3760 char **c;
Denis Vlasenkof7996f32007-01-11 17:20:00 +00003761
Denis Vlasenko8f27c342006-12-26 21:31:11 +00003762 if (strchr(cmd, '/') == NULL
3763 && (a = find_applet_by_name(cmd)) != NULL
3764 && is_safe_applet(cmd)
3765 ) {
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00003766 c = argv;
3767 while (*c != NULL) {
3768 c++; argc++;
3769 }
Denis Vlasenko8f8f2682006-10-03 21:00:43 +00003770 applet_name = cmd;
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00003771 exit(a->main(argc, argv));
3772 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00003773#if ENABLE_FEATURE_SH_STANDALONE_SHELL
Denis Vlasenko8f27c342006-12-26 21:31:11 +00003774 if (find_applet_by_name(cmd) != NULL) {
Rob Landley0fcd9432005-05-07 08:27:34 +00003775 /* re-exec ourselves with the new arguments */
Rob Landleya34b48a2006-06-14 01:27:01 +00003776 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp);
Rob Landley0fcd9432005-05-07 08:27:34 +00003777 /* If they called chroot or otherwise made the binary no longer
3778 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003779 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003780#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003781
3782repeat:
3783#ifdef SYSV
3784 do {
3785 execve(cmd, argv, envp);
3786 } while (errno == EINTR);
3787#else
Eric Andersencb57d552001-06-28 07:25:16 +00003788 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003789#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003790 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003791 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003792 } else if (errno == ENOEXEC) {
3793 char **ap;
3794 char **new;
3795
Eric Andersenc470f442003-07-28 09:56:35 +00003796 for (ap = argv; *ap; ap++)
3797 ;
3798 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003799 ap[1] = cmd;
3800 *ap = cmd = (char *)DEFAULT_SHELL;
3801 ap += 2;
3802 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003803 while ((*ap++ = *argv++))
3804 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003805 argv = new;
3806 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003807 }
Eric Andersencb57d552001-06-28 07:25:16 +00003808}
3809
Eric Andersenc470f442003-07-28 09:56:35 +00003810
Eric Andersencb57d552001-06-28 07:25:16 +00003811
3812/*
3813 * Do a path search. The variable path (passed by reference) should be
3814 * set to the start of the path before the first call; padvance will update
3815 * this value as it proceeds. Successive calls to padvance will return
3816 * the possible path expansions in sequence. If an option (indicated by
3817 * a percent sign) appears in the path entry then the global variable
3818 * pathopt will be set to point to it; otherwise pathopt will be set to
3819 * NULL.
3820 */
3821
Eric Andersenc470f442003-07-28 09:56:35 +00003822static char *
3823padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003824{
Eric Andersencb57d552001-06-28 07:25:16 +00003825 const char *p;
3826 char *q;
3827 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003828 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003829
3830 if (*path == NULL)
3831 return NULL;
3832 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003833 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3834 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003835 while (stackblocksize() < len)
3836 growstackblock();
3837 q = stackblock();
3838 if (p != start) {
3839 memcpy(q, start, p - start);
3840 q += p - start;
3841 *q++ = '/';
3842 }
3843 strcpy(q, name);
3844 pathopt = NULL;
3845 if (*p == '%') {
3846 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003847 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003848 }
3849 if (*p == ':')
3850 *path = p + 1;
3851 else
3852 *path = NULL;
3853 return stalloc(len);
3854}
3855
3856
Eric Andersencb57d552001-06-28 07:25:16 +00003857/*** Command hashing code ***/
3858
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003859static void
3860printentry(struct tblentry *cmdp)
3861{
3862 int idx;
3863 const char *path;
3864 char *name;
3865
3866 idx = cmdp->param.index;
3867 path = pathval();
3868 do {
3869 name = padvance(&path, cmdp->cmdname);
3870 stunalloc(name);
3871 } while (--idx >= 0);
3872 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3873}
3874
Eric Andersenc470f442003-07-28 09:56:35 +00003875
3876static int
3877hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003878{
3879 struct tblentry **pp;
3880 struct tblentry *cmdp;
3881 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003882 struct cmdentry entry;
3883 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003884
Eric Andersenc470f442003-07-28 09:56:35 +00003885 while ((c = nextopt("r")) != '\0') {
3886 clearcmdentry(0);
3887 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003888 }
3889 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003890 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3891 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3892 if (cmdp->cmdtype == CMDNORMAL)
3893 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003894 }
3895 }
3896 return 0;
3897 }
3898 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003899 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003900 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003901 && (cmdp->cmdtype == CMDNORMAL
3902 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003903 delete_cmd_entry();
3904 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003905 if (entry.cmdtype == CMDUNKNOWN)
3906 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003907 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003908 }
3909 return c;
3910}
3911
Eric Andersenc470f442003-07-28 09:56:35 +00003912
Eric Andersencb57d552001-06-28 07:25:16 +00003913/*
3914 * Resolve a command name. If you change this routine, you may have to
3915 * change the shellexec routine as well.
3916 */
3917
3918static void
Eric Andersenc470f442003-07-28 09:56:35 +00003919find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003920{
3921 struct tblentry *cmdp;
3922 int idx;
3923 int prev;
3924 char *fullname;
3925 struct stat statb;
3926 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003927 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003928 struct builtincmd *bcmd;
3929
Eric Andersenc470f442003-07-28 09:56:35 +00003930 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003931 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003932 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003933 if (act & DO_ABS) {
3934 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003935#ifdef SYSV
3936 if (errno == EINTR)
3937 continue;
3938#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003939 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003940 return;
3941 }
Eric Andersencb57d552001-06-28 07:25:16 +00003942 }
3943 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003944 return;
3945 }
3946
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00003947#if ENABLE_FEATURE_SH_STANDALONE_SHELL
Eric Andersenbf8bf102002-09-17 08:41:08 +00003948 if (find_applet_by_name(name)) {
3949 entry->cmdtype = CMDNORMAL;
3950 entry->u.index = -1;
3951 return;
3952 }
3953#endif
3954
Denis Vlasenkoe175ff22006-09-26 17:41:00 +00003955 if (is_safe_applet(name)) {
3956 entry->cmdtype = CMDNORMAL;
3957 entry->u.index = -1;
3958 return;
3959 }
3960
Eric Andersenc470f442003-07-28 09:56:35 +00003961 updatetbl = (path == pathval());
3962 if (!updatetbl) {
3963 act |= DO_ALTPATH;
3964 if (strstr(path, "%builtin") != NULL)
3965 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003966 }
3967
Eric Andersenc470f442003-07-28 09:56:35 +00003968 /* If name is in the table, check answer will be ok */
3969 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3970 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003971
Eric Andersenc470f442003-07-28 09:56:35 +00003972 switch (cmdp->cmdtype) {
3973 default:
3974#if DEBUG
3975 abort();
3976#endif
3977 case CMDNORMAL:
3978 bit = DO_ALTPATH;
3979 break;
3980 case CMDFUNCTION:
3981 bit = DO_NOFUNC;
3982 break;
3983 case CMDBUILTIN:
3984 bit = DO_ALTBLTIN;
3985 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003986 }
Eric Andersenc470f442003-07-28 09:56:35 +00003987 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003988 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003989 cmdp = NULL;
3990 } else if (cmdp->rehash == 0)
3991 /* if not invalidated by cd, we're done */
3992 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003993 }
3994
3995 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003996 bcmd = find_builtin(name);
3997 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3998 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3999 )))
4000 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00004001
4002 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00004003 prev = -1; /* where to start */
4004 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00004005 if (cmdp->cmdtype == CMDBUILTIN)
4006 prev = builtinloc;
4007 else
4008 prev = cmdp->param.index;
4009 }
4010
4011 e = ENOENT;
4012 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00004013loop:
Eric Andersencb57d552001-06-28 07:25:16 +00004014 while ((fullname = padvance(&path, name)) != NULL) {
4015 stunalloc(fullname);
4016 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00004017 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00004018 if (prefix(pathopt, "builtin")) {
4019 if (bcmd)
4020 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00004021 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004022 } else if (!(act & DO_NOFUNC) &&
4023 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00004024 /* handled below */
4025 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004026 /* ignore unimplemented options */
4027 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00004028 }
4029 }
4030 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00004031 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00004032 if (idx < prev)
4033 continue;
4034 TRACE(("searchexec \"%s\": no change\n", name));
4035 goto success;
4036 }
4037 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00004038#ifdef SYSV
4039 if (errno == EINTR)
4040 continue;
4041#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004042 if (errno != ENOENT && errno != ENOTDIR)
4043 e = errno;
4044 goto loop;
4045 }
Eric Andersenc470f442003-07-28 09:56:35 +00004046 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004047 if (!S_ISREG(statb.st_mode))
4048 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004049 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004050 stalloc(strlen(fullname) + 1);
4051 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004052 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4053 cmdp->cmdtype != CMDFUNCTION)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004054 sh_error("%s not defined in %s", name, fullname);
Eric Andersencb57d552001-06-28 07:25:16 +00004055 stunalloc(fullname);
4056 goto success;
4057 }
Eric Andersencb57d552001-06-28 07:25:16 +00004058 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004059 if (!updatetbl) {
4060 entry->cmdtype = CMDNORMAL;
4061 entry->u.index = idx;
4062 return;
4063 }
4064 INTOFF;
4065 cmdp = cmdlookup(name, 1);
4066 cmdp->cmdtype = CMDNORMAL;
4067 cmdp->param.index = idx;
4068 INTON;
4069 goto success;
4070 }
4071
4072 /* We failed. If there was an entry for this command, delete it */
4073 if (cmdp && updatetbl)
4074 delete_cmd_entry();
4075 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004076 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004077 entry->cmdtype = CMDUNKNOWN;
4078 return;
4079
Eric Andersenc470f442003-07-28 09:56:35 +00004080builtin_success:
4081 if (!updatetbl) {
4082 entry->cmdtype = CMDBUILTIN;
4083 entry->u.cmd = bcmd;
4084 return;
4085 }
4086 INTOFF;
4087 cmdp = cmdlookup(name, 1);
4088 cmdp->cmdtype = CMDBUILTIN;
4089 cmdp->param.cmd = bcmd;
4090 INTON;
4091success:
Eric Andersencb57d552001-06-28 07:25:16 +00004092 cmdp->rehash = 0;
4093 entry->cmdtype = cmdp->cmdtype;
4094 entry->u = cmdp->param;
4095}
4096
4097
Eric Andersenc470f442003-07-28 09:56:35 +00004098/*
4099 * Wrapper around strcmp for qsort/bsearch/...
4100 */
4101static int pstrcmp(const void *a, const void *b)
4102{
4103 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4104}
Eric Andersencb57d552001-06-28 07:25:16 +00004105
4106/*
4107 * Search the table of builtin commands.
4108 */
4109
Eric Andersenc470f442003-07-28 09:56:35 +00004110static struct builtincmd *
4111find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004112{
4113 struct builtincmd *bp;
4114
Eric Andersenc470f442003-07-28 09:56:35 +00004115 bp = bsearch(
4116 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4117 pstrcmp
4118 );
Eric Andersencb57d552001-06-28 07:25:16 +00004119 return bp;
4120}
4121
4122
Eric Andersenc470f442003-07-28 09:56:35 +00004123
Eric Andersencb57d552001-06-28 07:25:16 +00004124/*
4125 * Called when a cd is done. Marks all commands so the next time they
4126 * are executed they will be rehashed.
4127 */
4128
Eric Andersenc470f442003-07-28 09:56:35 +00004129static void
4130hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004131{
Eric Andersencb57d552001-06-28 07:25:16 +00004132 struct tblentry **pp;
4133 struct tblentry *cmdp;
4134
Eric Andersenc470f442003-07-28 09:56:35 +00004135 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4136 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4137 if (cmdp->cmdtype == CMDNORMAL || (
4138 cmdp->cmdtype == CMDBUILTIN &&
4139 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4140 builtinloc > 0
4141 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004142 cmdp->rehash = 1;
4143 }
4144 }
4145}
4146
4147
4148
4149/*
Eric Andersenc470f442003-07-28 09:56:35 +00004150 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004151 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004152 * pathval() still returns the old value at this point.
4153 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004154 */
4155
Eric Andersenc470f442003-07-28 09:56:35 +00004156static void
4157changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004158{
Eric Andersenc470f442003-07-28 09:56:35 +00004159 const char *old, *new;
4160 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004161 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004162 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004163
Eric Andersenc470f442003-07-28 09:56:35 +00004164 old = pathval();
4165 new = newval;
4166 firstchange = 9999; /* assume no change */
4167 idx = 0;
4168 idx_bltin = -1;
4169 for (;;) {
4170 if (*old != *new) {
4171 firstchange = idx;
4172 if ((*old == '\0' && *new == ':')
4173 || (*old == ':' && *new == '\0'))
4174 firstchange++;
4175 old = new; /* ignore subsequent differences */
4176 }
4177 if (*new == '\0')
4178 break;
4179 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4180 idx_bltin = idx;
4181 if (*new == ':') {
4182 idx++;
4183 }
4184 new++, old++;
4185 }
4186 if (builtinloc < 0 && idx_bltin >= 0)
4187 builtinloc = idx_bltin; /* zap builtins */
4188 if (builtinloc >= 0 && idx_bltin < 0)
4189 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004190 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004191 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004192}
4193
4194
4195/*
4196 * Clear out command entries. The argument specifies the first entry in
4197 * PATH which has changed.
4198 */
4199
Eric Andersenc470f442003-07-28 09:56:35 +00004200static void
4201clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004202{
4203 struct tblentry **tblp;
4204 struct tblentry **pp;
4205 struct tblentry *cmdp;
4206
4207 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004208 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004209 pp = tblp;
4210 while ((cmdp = *pp) != NULL) {
4211 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004212 cmdp->param.index >= firstchange)
4213 || (cmdp->cmdtype == CMDBUILTIN &&
4214 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004215 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004216 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004217 } else {
4218 pp = &cmdp->next;
4219 }
4220 }
4221 }
4222 INTON;
4223}
4224
4225
Eric Andersenc470f442003-07-28 09:56:35 +00004226
Eric Andersencb57d552001-06-28 07:25:16 +00004227/*
Eric Andersencb57d552001-06-28 07:25:16 +00004228 * Locate a command in the command hash table. If "add" is nonzero,
4229 * add the command to the table if it is not already present. The
4230 * variable "lastcmdentry" is set to point to the address of the link
4231 * pointing to the entry, so that delete_cmd_entry can delete the
4232 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004233 *
4234 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004235 */
4236
Eric Andersen2870d962001-07-02 17:27:21 +00004237static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004238
Eric Andersenc470f442003-07-28 09:56:35 +00004239
4240static struct tblentry *
4241cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004242{
Eric Andersenc470f442003-07-28 09:56:35 +00004243 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004244 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004245 struct tblentry *cmdp;
4246 struct tblentry **pp;
4247
4248 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004249 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004250 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004251 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004252 hashval &= 0x7FFF;
4253 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004254 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004255 if (equal(cmdp->cmdname, name))
4256 break;
4257 pp = &cmdp->next;
4258 }
4259 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004260 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4261 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004262 cmdp->next = NULL;
4263 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004264 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004265 }
4266 lastcmdentry = pp;
4267 return cmdp;
4268}
4269
4270/*
4271 * Delete the command entry returned on the last lookup.
4272 */
4273
Eric Andersenc470f442003-07-28 09:56:35 +00004274static void
4275delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004276{
Eric Andersencb57d552001-06-28 07:25:16 +00004277 struct tblentry *cmdp;
4278
4279 INTOFF;
4280 cmdp = *lastcmdentry;
4281 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004282 if (cmdp->cmdtype == CMDFUNCTION)
4283 freefunc(cmdp->param.func);
4284 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004285 INTON;
4286}
4287
4288
Eric Andersenc470f442003-07-28 09:56:35 +00004289/*
4290 * Add a new command entry, replacing any existing command entry for
4291 * the same name - except special builtins.
4292 */
Eric Andersencb57d552001-06-28 07:25:16 +00004293
Rob Landley88621d72006-08-29 19:41:06 +00004294static void addcmdentry(char *name, struct cmdentry *entry)
Eric Andersenc470f442003-07-28 09:56:35 +00004295{
4296 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004297
Eric Andersenc470f442003-07-28 09:56:35 +00004298 cmdp = cmdlookup(name, 1);
4299 if (cmdp->cmdtype == CMDFUNCTION) {
4300 freefunc(cmdp->param.func);
4301 }
4302 cmdp->cmdtype = entry->cmdtype;
4303 cmdp->param = entry->u;
4304 cmdp->rehash = 0;
4305}
Eric Andersencb57d552001-06-28 07:25:16 +00004306
Eric Andersenc470f442003-07-28 09:56:35 +00004307/*
4308 * Make a copy of a parse tree.
4309 */
Eric Andersencb57d552001-06-28 07:25:16 +00004310
Rob Landley88621d72006-08-29 19:41:06 +00004311static struct funcnode * copyfunc(union node *n)
Eric Andersenc470f442003-07-28 09:56:35 +00004312{
4313 struct funcnode *f;
4314 size_t blocksize;
4315
4316 funcblocksize = offsetof(struct funcnode, n);
4317 funcstringsize = 0;
4318 calcsize(n);
4319 blocksize = funcblocksize;
4320 f = ckmalloc(blocksize + funcstringsize);
4321 funcblock = (char *) f + offsetof(struct funcnode, n);
4322 funcstring = (char *) f + blocksize;
4323 copynode(n);
4324 f->count = 0;
4325 return f;
4326}
4327
4328/*
4329 * Define a shell function.
4330 */
4331
4332static void
4333defun(char *name, union node *func)
4334{
4335 struct cmdentry entry;
4336
4337 INTOFF;
4338 entry.cmdtype = CMDFUNCTION;
4339 entry.u.func = copyfunc(func);
4340 addcmdentry(name, &entry);
4341 INTON;
4342}
Eric Andersencb57d552001-06-28 07:25:16 +00004343
4344
4345/*
4346 * Delete a function if it exists.
4347 */
4348
Eric Andersenc470f442003-07-28 09:56:35 +00004349static void
4350unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004351{
Eric Andersencb57d552001-06-28 07:25:16 +00004352 struct tblentry *cmdp;
4353
Eric Andersenc470f442003-07-28 09:56:35 +00004354 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4355 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004356 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004357}
4358
Eric Andersen2870d962001-07-02 17:27:21 +00004359/*
Eric Andersencb57d552001-06-28 07:25:16 +00004360 * Locate and print what a word is...
4361 */
4362
Eric Andersenc470f442003-07-28 09:56:35 +00004363
4364#ifdef CONFIG_ASH_CMDCMD
4365static int
4366describe_command(char *command, int describe_command_verbose)
4367#else
4368#define describe_command_verbose 1
4369static int
4370describe_command(char *command)
4371#endif
4372{
4373 struct cmdentry entry;
4374 struct tblentry *cmdp;
4375#ifdef CONFIG_ASH_ALIAS
4376 const struct alias *ap;
4377#endif
4378 const char *path = pathval();
4379
4380 if (describe_command_verbose) {
4381 out1str(command);
4382 }
4383
4384 /* First look at the keywords */
4385 if (findkwd(command)) {
4386 out1str(describe_command_verbose ? " is a shell keyword" : command);
4387 goto out;
4388 }
4389
4390#ifdef CONFIG_ASH_ALIAS
4391 /* Then look at the aliases */
4392 if ((ap = lookupalias(command, 0)) != NULL) {
4393 if (describe_command_verbose) {
4394 out1fmt(" is an alias for %s", ap->val);
4395 } else {
4396 out1str("alias ");
4397 printalias(ap);
4398 return 0;
4399 }
4400 goto out;
4401 }
4402#endif
4403 /* Then check if it is a tracked alias */
4404 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4405 entry.cmdtype = cmdp->cmdtype;
4406 entry.u = cmdp->param;
4407 } else {
4408 /* Finally use brute force */
4409 find_command(command, &entry, DO_ABS, path);
4410 }
4411
4412 switch (entry.cmdtype) {
4413 case CMDNORMAL: {
4414 int j = entry.u.index;
4415 char *p;
4416 if (j == -1) {
4417 p = command;
4418 } else {
4419 do {
4420 p = padvance(&path, command);
4421 stunalloc(p);
4422 } while (--j >= 0);
4423 }
4424 if (describe_command_verbose) {
4425 out1fmt(" is%s %s",
4426 (cmdp ? " a tracked alias for" : nullstr), p
4427 );
4428 } else {
4429 out1str(p);
4430 }
4431 break;
4432 }
4433
4434 case CMDFUNCTION:
4435 if (describe_command_verbose) {
4436 out1str(" is a shell function");
4437 } else {
4438 out1str(command);
4439 }
4440 break;
4441
4442 case CMDBUILTIN:
4443 if (describe_command_verbose) {
4444 out1fmt(" is a %sshell builtin",
4445 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4446 "special " : nullstr
4447 );
4448 } else {
4449 out1str(command);
4450 }
4451 break;
4452
4453 default:
4454 if (describe_command_verbose) {
4455 out1str(": not found\n");
4456 }
4457 return 127;
4458 }
4459
4460out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004461 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004462 return 0;
4463}
4464
4465static int
4466typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004467{
4468 int i;
4469 int err = 0;
4470
4471 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004472#ifdef CONFIG_ASH_CMDCMD
4473 err |= describe_command(argv[i], 1);
4474#else
4475 err |= describe_command(argv[i]);
4476#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004477 }
4478 return err;
4479}
4480
Eric Andersend35c5df2002-01-09 15:37:36 +00004481#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004482static int
4483commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004484{
4485 int c;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004486 enum {
4487 VERIFY_BRIEF = 1,
4488 VERIFY_VERBOSE = 2,
4489 } verify = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004490
4491 while ((c = nextopt("pvV")) != '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004492 if (c == 'V')
4493 verify |= VERIFY_VERBOSE;
4494 else if (c == 'v')
4495 verify |= VERIFY_BRIEF;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00004496#if DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004497 else if (c != 'p')
4498 abort();
Eric Andersenc470f442003-07-28 09:56:35 +00004499#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004500 if (verify)
4501 return describe_command(*argptr, verify - VERIFY_BRIEF);
Eric Andersencb57d552001-06-28 07:25:16 +00004502
4503 return 0;
4504}
Eric Andersen2870d962001-07-02 17:27:21 +00004505#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004506
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004507/* expand.c */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004508
Eric Andersencb57d552001-06-28 07:25:16 +00004509/*
4510 * Routines to expand arguments to commands. We have to deal with
4511 * backquotes, shell variables, and file metacharacters.
4512 */
Eric Andersenc470f442003-07-28 09:56:35 +00004513
Eric Andersencb57d552001-06-28 07:25:16 +00004514/*
4515 * _rmescape() flags
4516 */
Eric Andersenc470f442003-07-28 09:56:35 +00004517#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4518#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4519#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4520#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4521#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004522
4523/*
4524 * Structure specifying which parts of the string should be searched
4525 * for IFS characters.
4526 */
4527
4528struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004529 struct ifsregion *next; /* next region in list */
4530 int begoff; /* offset of start of region */
4531 int endoff; /* offset of end of region */
4532 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004533};
4534
Eric Andersenc470f442003-07-28 09:56:35 +00004535/* output of current string */
4536static char *expdest;
4537/* list of back quote expressions */
4538static struct nodelist *argbackq;
4539/* first struct in list of ifs regions */
4540static struct ifsregion ifsfirst;
4541/* last struct in list */
4542static struct ifsregion *ifslastp;
4543/* holds expanded arg list */
4544static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004545
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004546static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004547static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004548static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004549static const char *subevalvar(char *, char *, int, int, int, int, int);
4550static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004551static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004552static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004553static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004554static void recordregion(int, int, int);
4555static void removerecordregions(int);
4556static void ifsbreakup(char *, struct arglist *);
4557static void ifsfree(void);
4558static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004559static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004560
Eric Andersened9ecf72004-06-22 08:29:45 +00004561static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004562static size_t esclen(const char *, const char *);
4563static char *scanleft(char *, char *, char *, char *, int, int);
4564static char *scanright(char *, char *, char *, char *, int, int);
4565static void varunset(const char *, const char *, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00004566 ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004567
Eric Andersenc470f442003-07-28 09:56:35 +00004568
4569#define pmatch(a, b) !fnmatch((a), (b), 0)
4570/*
Eric Andersen90898442003-08-06 11:20:52 +00004571 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004572 *
4573 * Returns an stalloced string.
4574 */
4575
Rob Landley88621d72006-08-29 19:41:06 +00004576static char * preglob(const char *pattern, int quoted, int flag) {
Eric Andersenc470f442003-07-28 09:56:35 +00004577 flag |= RMESCAPE_GLOB;
4578 if (quoted) {
4579 flag |= RMESCAPE_QUOTED;
4580 }
4581 return _rmescapes((char *)pattern, flag);
4582}
4583
4584
4585static size_t
4586esclen(const char *start, const char *p) {
4587 size_t esc = 0;
4588
4589 while (p > start && *--p == CTLESC) {
4590 esc++;
4591 }
4592 return esc;
4593}
4594
Eric Andersencb57d552001-06-28 07:25:16 +00004595
4596/*
4597 * Expand shell variables and backquotes inside a here document.
4598 */
4599
Rob Landley88621d72006-08-29 19:41:06 +00004600static void expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004601{
Eric Andersencb57d552001-06-28 07:25:16 +00004602 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004603 expandarg(arg, (struct arglist *)NULL, 0);
Rob Landley53437472006-07-16 08:14:35 +00004604 full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004605}
4606
4607
4608/*
4609 * Perform variable substitution and command substitution on an argument,
4610 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4611 * perform splitting and file name expansion. When arglist is NULL, perform
4612 * here document expansion.
4613 */
4614
Eric Andersenc470f442003-07-28 09:56:35 +00004615void
4616expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004617{
4618 struct strlist *sp;
4619 char *p;
4620
4621 argbackq = arg->narg.backquote;
4622 STARTSTACKSTR(expdest);
4623 ifsfirst.next = NULL;
4624 ifslastp = NULL;
4625 argstr(arg->narg.text, flag);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004626 p = _STPUTC('\0', expdest);
4627 expdest = p - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004628 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004629 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004630 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004631 p = grabstackstr(p);
Eric Andersencb57d552001-06-28 07:25:16 +00004632 exparg.lastp = &exparg.list;
4633 /*
4634 * TODO - EXP_REDIR
4635 */
4636 if (flag & EXP_FULL) {
4637 ifsbreakup(p, &exparg);
4638 *exparg.lastp = NULL;
4639 exparg.lastp = &exparg.list;
4640 expandmeta(exparg.list, flag);
4641 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004642 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004643 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004644 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004645 sp->text = p;
4646 *exparg.lastp = sp;
4647 exparg.lastp = &sp->next;
4648 }
Eric Andersenc470f442003-07-28 09:56:35 +00004649 if (ifsfirst.next)
4650 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004651 *exparg.lastp = NULL;
4652 if (exparg.list) {
4653 *arglist->lastp = exparg.list;
4654 arglist->lastp = exparg.lastp;
4655 }
4656}
4657
4658
Eric Andersenc470f442003-07-28 09:56:35 +00004659/*
4660 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4661 * characters to allow for further processing. Otherwise treat
4662 * $@ like $* since no splitting will be performed.
4663 */
4664
4665static void
4666argstr(char *p, int flag)
4667{
4668 static const char spclchars[] = {
4669 '=',
4670 ':',
4671 CTLQUOTEMARK,
4672 CTLENDVAR,
4673 CTLESC,
4674 CTLVAR,
4675 CTLBACKQ,
4676 CTLBACKQ | CTLQUOTE,
4677#ifdef CONFIG_ASH_MATH_SUPPORT
4678 CTLENDARI,
4679#endif
4680 0
4681 };
4682 const char *reject = spclchars;
4683 int c;
4684 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4685 int breakall = flag & EXP_WORD;
4686 int inquotes;
4687 size_t length;
4688 int startloc;
4689
4690 if (!(flag & EXP_VARTILDE)) {
4691 reject += 2;
4692 } else if (flag & EXP_VARTILDE2) {
4693 reject++;
4694 }
4695 inquotes = 0;
4696 length = 0;
4697 if (flag & EXP_TILDE) {
4698 char *q;
4699
4700 flag &= ~EXP_TILDE;
4701tilde:
4702 q = p;
4703 if (*q == CTLESC && (flag & EXP_QWORD))
4704 q++;
4705 if (*q == '~')
4706 p = exptilde(p, q, flag);
4707 }
4708start:
4709 startloc = expdest - (char *)stackblock();
4710 for (;;) {
4711 length += strcspn(p + length, reject);
4712 c = p[length];
4713 if (c && (!(c & 0x80)
4714#ifdef CONFIG_ASH_MATH_SUPPORT
4715 || c == CTLENDARI
4716#endif
4717 )) {
4718 /* c == '=' || c == ':' || c == CTLENDARI */
4719 length++;
4720 }
4721 if (length > 0) {
4722 int newloc;
4723 expdest = stnputs(p, length, expdest);
4724 newloc = expdest - (char *)stackblock();
4725 if (breakall && !inquotes && newloc > startloc) {
4726 recordregion(startloc, newloc, 0);
4727 }
4728 startloc = newloc;
4729 }
4730 p += length + 1;
4731 length = 0;
4732
4733 switch (c) {
4734 case '\0':
4735 goto breakloop;
4736 case '=':
4737 if (flag & EXP_VARTILDE2) {
4738 p--;
4739 continue;
4740 }
4741 flag |= EXP_VARTILDE2;
4742 reject++;
4743 /* fall through */
4744 case ':':
4745 /*
4746 * sort of a hack - expand tildes in variable
4747 * assignments (after the first '=' and after ':'s).
4748 */
4749 if (*--p == '~') {
4750 goto tilde;
4751 }
4752 continue;
4753 }
4754
4755 switch (c) {
4756 case CTLENDVAR: /* ??? */
4757 goto breakloop;
4758 case CTLQUOTEMARK:
4759 /* "$@" syntax adherence hack */
4760 if (
4761 !inquotes &&
4762 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4763 (p[4] == CTLQUOTEMARK || (
4764 p[4] == CTLENDVAR &&
4765 p[5] == CTLQUOTEMARK
4766 ))
4767 ) {
4768 p = evalvar(p + 1, flag) + 1;
4769 goto start;
4770 }
4771 inquotes = !inquotes;
4772addquote:
4773 if (quotes) {
4774 p--;
4775 length++;
4776 startloc++;
4777 }
4778 break;
4779 case CTLESC:
4780 startloc++;
4781 length++;
4782 goto addquote;
4783 case CTLVAR:
4784 p = evalvar(p, flag);
4785 goto start;
4786 case CTLBACKQ:
4787 c = 0;
4788 case CTLBACKQ|CTLQUOTE:
4789 expbackq(argbackq->n, c, quotes);
4790 argbackq = argbackq->next;
4791 goto start;
4792#ifdef CONFIG_ASH_MATH_SUPPORT
4793 case CTLENDARI:
4794 p--;
4795 expari(quotes);
4796 goto start;
4797#endif
4798 }
4799 }
4800breakloop:
4801 ;
4802}
4803
4804static char *
4805exptilde(char *startp, char *p, int flag)
4806{
4807 char c;
4808 char *name;
4809 struct passwd *pw;
4810 const char *home;
4811 int quotes = flag & (EXP_FULL | EXP_CASE);
4812 int startloc;
4813
4814 name = p + 1;
4815
4816 while ((c = *++p) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +00004817 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004818 case CTLESC:
Denis Vlasenko097c3242006-11-27 16:59:15 +00004819 return startp;
Eric Andersenc470f442003-07-28 09:56:35 +00004820 case CTLQUOTEMARK:
Denis Vlasenko097c3242006-11-27 16:59:15 +00004821 return startp;
Eric Andersenc470f442003-07-28 09:56:35 +00004822 case ':':
4823 if (flag & EXP_VARTILDE)
4824 goto done;
4825 break;
4826 case '/':
4827 case CTLENDVAR:
4828 goto done;
4829 }
4830 }
4831done:
4832 *p = '\0';
4833 if (*name == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004834 home = lookupvar(homestr);
Eric Andersenc470f442003-07-28 09:56:35 +00004835 } else {
4836 if ((pw = getpwnam(name)) == NULL)
4837 goto lose;
4838 home = pw->pw_dir;
4839 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004840 if (!home || !*home)
Eric Andersenc470f442003-07-28 09:56:35 +00004841 goto lose;
4842 *p = c;
4843 startloc = expdest - (char *)stackblock();
4844 strtodest(home, SQSYNTAX, quotes);
4845 recordregion(startloc, expdest - (char *)stackblock(), 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004846 return p;
Eric Andersenc470f442003-07-28 09:56:35 +00004847lose:
4848 *p = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004849 return startp;
Eric Andersenc470f442003-07-28 09:56:35 +00004850}
4851
4852
4853static void
4854removerecordregions(int endoff)
4855{
4856 if (ifslastp == NULL)
4857 return;
4858
4859 if (ifsfirst.endoff > endoff) {
4860 while (ifsfirst.next != NULL) {
4861 struct ifsregion *ifsp;
4862 INTOFF;
4863 ifsp = ifsfirst.next->next;
4864 ckfree(ifsfirst.next);
4865 ifsfirst.next = ifsp;
4866 INTON;
4867 }
4868 if (ifsfirst.begoff > endoff)
4869 ifslastp = NULL;
4870 else {
4871 ifslastp = &ifsfirst;
4872 ifsfirst.endoff = endoff;
4873 }
4874 return;
4875 }
4876
4877 ifslastp = &ifsfirst;
4878 while (ifslastp->next && ifslastp->next->begoff < endoff)
4879 ifslastp=ifslastp->next;
4880 while (ifslastp->next != NULL) {
4881 struct ifsregion *ifsp;
4882 INTOFF;
4883 ifsp = ifslastp->next->next;
4884 ckfree(ifslastp->next);
4885 ifslastp->next = ifsp;
4886 INTON;
4887 }
4888 if (ifslastp->endoff > endoff)
4889 ifslastp->endoff = endoff;
4890}
4891
4892
4893#ifdef CONFIG_ASH_MATH_SUPPORT
4894/*
4895 * Expand arithmetic expression. Backup to start of expression,
4896 * evaluate, place result in (backed up) result, adjust string position.
4897 */
4898void
4899expari(int quotes)
4900{
4901 char *p, *start;
4902 int begoff;
4903 int flag;
4904 int len;
4905
4906 /* ifsfree(); */
4907
4908 /*
4909 * This routine is slightly over-complicated for
4910 * efficiency. Next we scan backwards looking for the
4911 * start of arithmetic.
4912 */
4913 start = stackblock();
4914 p = expdest - 1;
4915 *p = '\0';
4916 p--;
4917 do {
4918 int esc;
4919
4920 while (*p != CTLARI) {
4921 p--;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00004922#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00004923 if (p < start) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004924 sh_error("missing CTLARI (shouldn't happen)");
Eric Andersenc470f442003-07-28 09:56:35 +00004925 }
4926#endif
4927 }
4928
4929 esc = esclen(start, p);
4930 if (!(esc % 2)) {
4931 break;
4932 }
4933
4934 p -= esc + 1;
4935 } while (1);
4936
4937 begoff = p - start;
4938
4939 removerecordregions(begoff);
4940
4941 flag = p[1];
4942
4943 expdest = p;
4944
4945 if (quotes)
4946 rmescapes(p + 2);
4947
4948 len = cvtnum(dash_arith(p + 2));
4949
4950 if (flag != '"')
4951 recordregion(begoff, begoff + len, 0);
4952}
4953#endif
4954
4955/*
4956 * Expand stuff in backwards quotes.
4957 */
4958
4959static void
4960expbackq(union node *cmd, int quoted, int quotes)
4961{
4962 struct backcmd in;
4963 int i;
4964 char buf[128];
4965 char *p;
4966 char *dest;
4967 int startloc;
4968 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4969 struct stackmark smark;
4970
4971 INTOFF;
4972 setstackmark(&smark);
4973 dest = expdest;
4974 startloc = dest - (char *)stackblock();
4975 grabstackstr(dest);
4976 evalbackcmd(cmd, (struct backcmd *) &in);
4977 popstackmark(&smark);
4978
4979 p = in.buf;
4980 i = in.nleft;
4981 if (i == 0)
4982 goto read;
4983 for (;;) {
4984 memtodest(p, i, syntax, quotes);
4985read:
4986 if (in.fd < 0)
4987 break;
4988 i = safe_read(in.fd, buf, sizeof buf);
4989 TRACE(("expbackq: read returns %d\n", i));
4990 if (i <= 0)
4991 break;
4992 p = buf;
4993 }
4994
4995 if (in.buf)
4996 ckfree(in.buf);
4997 if (in.fd >= 0) {
4998 close(in.fd);
4999 back_exitstatus = waitforjob(in.jp);
5000 }
5001 INTON;
5002
5003 /* Eat all trailing newlines */
5004 dest = expdest;
5005 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5006 STUNPUTC(dest);
5007 expdest = dest;
5008
5009 if (quoted == 0)
5010 recordregion(startloc, dest - (char *)stackblock(), 0);
5011 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5012 (dest - (char *)stackblock()) - startloc,
5013 (dest - (char *)stackblock()) - startloc,
5014 stackblock() + startloc));
5015}
5016
5017
5018static char *
Eric Andersen90898442003-08-06 11:20:52 +00005019scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5020 int zero)
5021{
Eric Andersenc470f442003-07-28 09:56:35 +00005022 char *loc;
5023 char *loc2;
5024 char c;
5025
5026 loc = startp;
5027 loc2 = rmesc;
5028 do {
5029 int match;
5030 const char *s = loc2;
5031 c = *loc2;
5032 if (zero) {
5033 *loc2 = '\0';
5034 s = rmesc;
5035 }
5036 match = pmatch(str, s);
5037 *loc2 = c;
5038 if (match)
5039 return loc;
5040 if (quotes && *loc == CTLESC)
5041 loc++;
5042 loc++;
5043 loc2++;
5044 } while (c);
5045 return 0;
5046}
5047
5048
5049static char *
Eric Andersen90898442003-08-06 11:20:52 +00005050scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5051 int zero)
5052{
Eric Andersenc470f442003-07-28 09:56:35 +00005053 int esc = 0;
5054 char *loc;
5055 char *loc2;
5056
5057 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5058 int match;
5059 char c = *loc2;
5060 const char *s = loc2;
5061 if (zero) {
5062 *loc2 = '\0';
5063 s = rmesc;
5064 }
5065 match = pmatch(str, s);
5066 *loc2 = c;
5067 if (match)
5068 return loc;
5069 loc--;
5070 if (quotes) {
5071 if (--esc < 0) {
5072 esc = esclen(startp, loc);
5073 }
5074 if (esc % 2) {
5075 esc--;
5076 loc--;
5077 }
5078 }
5079 }
5080 return 0;
5081}
5082
5083static const char *
5084subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5085{
5086 char *startp;
5087 char *loc;
5088 int saveherefd = herefd;
5089 struct nodelist *saveargbackq = argbackq;
5090 int amount;
5091 char *rmesc, *rmescend;
5092 int zero;
5093 char *(*scan)(char *, char *, char *, char *, int , int);
5094
5095 herefd = -1;
5096 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5097 STPUTC('\0', expdest);
5098 herefd = saveherefd;
5099 argbackq = saveargbackq;
5100 startp = stackblock() + startloc;
5101
5102 switch (subtype) {
5103 case VSASSIGN:
5104 setvar(str, startp, 0);
5105 amount = startp - expdest;
5106 STADJUST(amount, expdest);
5107 return startp;
5108
5109 case VSQUESTION:
5110 varunset(p, str, startp, varflags);
5111 /* NOTREACHED */
5112 }
5113
5114 subtype -= VSTRIMRIGHT;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00005115#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00005116 if (subtype < 0 || subtype > 3)
5117 abort();
5118#endif
5119
5120 rmesc = startp;
5121 rmescend = stackblock() + strloc;
5122 if (quotes) {
5123 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5124 if (rmesc != startp) {
5125 rmescend = expdest;
5126 startp = stackblock() + startloc;
5127 }
5128 }
5129 rmescend--;
5130 str = stackblock() + strloc;
5131 preglob(str, varflags & VSQUOTE, 0);
5132
5133 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5134 zero = subtype >> 1;
5135 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5136 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5137
5138 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5139 if (loc) {
5140 if (zero) {
5141 memmove(startp, loc, str - loc);
5142 loc = startp + (str - loc) - 1;
5143 }
5144 *loc = '\0';
5145 amount = loc - expdest;
5146 STADJUST(amount, expdest);
5147 }
5148 return loc;
5149}
5150
5151
Eric Andersen62483552001-07-10 06:09:16 +00005152/*
5153 * Expand a variable, and return a pointer to the next character in the
5154 * input string.
5155 */
Eric Andersenc470f442003-07-28 09:56:35 +00005156static char *
5157evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005158{
5159 int subtype;
5160 int varflags;
5161 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005162 int patloc;
5163 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005164 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005165 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005166 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005167 int quotes;
5168 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005169
Eric Andersenc470f442003-07-28 09:56:35 +00005170 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005171 varflags = *p++;
5172 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005173 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005174 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005175 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005176 startloc = expdest - (char *)stackblock();
5177 p = strchr(p, '=') + 1;
5178
Eric Andersenc470f442003-07-28 09:56:35 +00005179again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005180 varlen = varvalue(var, varflags, flag);
5181 if (varflags & VSNUL)
5182 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005183
Glenn L McGrath76620622004-01-13 10:19:37 +00005184 if (subtype == VSPLUS) {
5185 varlen = -1 - varlen;
5186 goto vsplus;
5187 }
Eric Andersen62483552001-07-10 06:09:16 +00005188
Eric Andersenc470f442003-07-28 09:56:35 +00005189 if (subtype == VSMINUS) {
5190vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005191 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005192 argstr(
5193 p, flag | EXP_TILDE |
5194 (quoted ? EXP_QWORD : EXP_WORD)
5195 );
5196 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005197 }
5198 if (easy)
5199 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005200 goto end;
5201 }
Eric Andersen62483552001-07-10 06:09:16 +00005202
Eric Andersenc470f442003-07-28 09:56:35 +00005203 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005204 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005205 if (subevalvar(p, var, 0, subtype, startloc,
5206 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005207 varflags &= ~VSNUL;
5208 /*
5209 * Remove any recorded regions beyond
5210 * start of variable
5211 */
5212 removerecordregions(startloc);
5213 goto again;
5214 }
Eric Andersenc470f442003-07-28 09:56:35 +00005215 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005216 }
5217 if (easy)
5218 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005219 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005220 }
5221
Glenn L McGrath76620622004-01-13 10:19:37 +00005222 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005223 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005224
Eric Andersenc470f442003-07-28 09:56:35 +00005225 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005226 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005227 goto record;
5228 }
5229
5230 if (subtype == VSNORMAL) {
5231 if (!easy)
5232 goto end;
5233record:
5234 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5235 goto end;
5236 }
5237
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00005238#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00005239 switch (subtype) {
5240 case VSTRIMLEFT:
5241 case VSTRIMLEFTMAX:
5242 case VSTRIMRIGHT:
5243 case VSTRIMRIGHTMAX:
5244 break;
5245 default:
5246 abort();
5247 }
5248#endif
5249
Glenn L McGrath76620622004-01-13 10:19:37 +00005250 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005251 /*
5252 * Terminate the string and start recording the pattern
5253 * right after it
5254 */
5255 STPUTC('\0', expdest);
5256 patloc = expdest - (char *)stackblock();
5257 if (subevalvar(p, NULL, patloc, subtype,
5258 startloc, varflags, quotes) == 0) {
5259 int amount = expdest - (
5260 (char *)stackblock() + patloc - 1
5261 );
5262 STADJUST(-amount, expdest);
5263 }
5264 /* Remove any recorded regions beyond start of variable */
5265 removerecordregions(startloc);
5266 goto record;
5267 }
5268
5269end:
5270 if (subtype != VSNORMAL) { /* skip to end of alternative */
5271 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005272 for (;;) {
5273 if ((c = *p++) == CTLESC)
5274 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005275 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005276 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005277 argbackq = argbackq->next;
5278 } else if (c == CTLVAR) {
5279 if ((*p++ & VSTYPE) != VSNORMAL)
5280 nesting++;
5281 } else if (c == CTLENDVAR) {
5282 if (--nesting == 0)
5283 break;
5284 }
5285 }
5286 }
5287 return p;
5288}
5289
Eric Andersencb57d552001-06-28 07:25:16 +00005290
Eric Andersencb57d552001-06-28 07:25:16 +00005291/*
5292 * Put a string on the stack.
5293 */
5294
Eric Andersenc470f442003-07-28 09:56:35 +00005295static void
5296memtodest(const char *p, size_t len, int syntax, int quotes) {
5297 char *q = expdest;
5298
5299 q = makestrspace(len * 2, q);
5300
5301 while (len--) {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005302 int c = SC2INT(*p++);
Eric Andersenc470f442003-07-28 09:56:35 +00005303 if (!c)
5304 continue;
5305 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5306 USTPUTC(CTLESC, q);
5307 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005308 }
Eric Andersenc470f442003-07-28 09:56:35 +00005309
5310 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005311}
5312
Eric Andersenc470f442003-07-28 09:56:35 +00005313
5314static void
5315strtodest(const char *p, int syntax, int quotes)
5316{
5317 memtodest(p, strlen(p), syntax, quotes);
5318}
5319
5320
Eric Andersencb57d552001-06-28 07:25:16 +00005321/*
5322 * Add the value of a specialized variable to the stack string.
5323 */
5324
Glenn L McGrath76620622004-01-13 10:19:37 +00005325static ssize_t
5326varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005327{
5328 int num;
5329 char *p;
5330 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005331 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005332 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005333 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005334 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005335 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005336 int quoted = varflags & VSQUOTE;
5337 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005338 int quotes = flags & (EXP_FULL | EXP_CASE);
5339
Glenn L McGrath76620622004-01-13 10:19:37 +00005340 if (quoted && (flags & EXP_FULL))
5341 sep = 1 << CHAR_BIT;
5342
Eric Andersencb57d552001-06-28 07:25:16 +00005343 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5344 switch (*name) {
5345 case '$':
5346 num = rootpid;
5347 goto numvar;
5348 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005349 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005350 goto numvar;
5351 case '#':
5352 num = shellparam.nparam;
5353 goto numvar;
5354 case '!':
5355 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005356 if (num == 0)
5357 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005358numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005359 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005360 break;
5361 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005362 p = makestrspace(NOPTS, expdest);
5363 for (i = NOPTS - 1; i >= 0; i--) {
5364 if (optlist[i]) {
5365 USTPUTC(optletters(i), p);
5366 len++;
5367 }
Eric Andersencb57d552001-06-28 07:25:16 +00005368 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005369 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005370 break;
5371 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005372 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005373 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005374 /* fall through */
5375 case '*':
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005376 sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005377 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5378 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005379param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005380 if (!(ap = shellparam.p))
5381 return -1;
5382 while ((p = *ap++)) {
5383 size_t partlen;
5384
5385 partlen = strlen(p);
Glenn L McGrath76620622004-01-13 10:19:37 +00005386 len += partlen;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00005387
5388 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5389 memtodest(p, partlen, syntax, quotes);
5390
5391 if (*ap && sep) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005392 char *q;
5393
5394 len++;
5395 if (subtype == VSPLUS || subtype == VSLENGTH) {
5396 continue;
5397 }
5398 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005399 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005400 STPUTC(CTLESC, q);
5401 STPUTC(sep, q);
5402 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005403 }
5404 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005405 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005406 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005407 case '1':
5408 case '2':
5409 case '3':
5410 case '4':
5411 case '5':
5412 case '6':
5413 case '7':
5414 case '8':
5415 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005416 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005417 if (num < 0 || num > shellparam.nparam)
5418 return -1;
5419 p = num ? shellparam.p[num - 1] : arg0;
5420 goto value;
5421 default:
5422 p = lookupvar(name);
5423value:
5424 if (!p)
5425 return -1;
5426
5427 len = strlen(p);
5428 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5429 memtodest(p, len, syntax, quotes);
5430 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005431 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005432
5433 if (subtype == VSPLUS || subtype == VSLENGTH)
5434 STADJUST(-len, expdest);
5435 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005436}
5437
5438
Eric Andersencb57d552001-06-28 07:25:16 +00005439/*
5440 * Record the fact that we have to scan this region of the
5441 * string for IFS characters.
5442 */
5443
Eric Andersenc470f442003-07-28 09:56:35 +00005444static void
5445recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005446{
5447 struct ifsregion *ifsp;
5448
5449 if (ifslastp == NULL) {
5450 ifsp = &ifsfirst;
5451 } else {
5452 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005453 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005454 ifsp->next = NULL;
5455 ifslastp->next = ifsp;
5456 INTON;
5457 }
5458 ifslastp = ifsp;
5459 ifslastp->begoff = start;
5460 ifslastp->endoff = end;
5461 ifslastp->nulonly = nulonly;
5462}
5463
5464
Eric Andersencb57d552001-06-28 07:25:16 +00005465/*
5466 * Break the argument string into pieces based upon IFS and add the
5467 * strings to the argument list. The regions of the string to be
5468 * searched for IFS characters have been stored by recordregion.
5469 */
Eric Andersenc470f442003-07-28 09:56:35 +00005470static void
5471ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005472{
Eric Andersencb57d552001-06-28 07:25:16 +00005473 struct ifsregion *ifsp;
5474 struct strlist *sp;
5475 char *start;
5476 char *p;
5477 char *q;
5478 const char *ifs, *realifs;
5479 int ifsspc;
5480 int nulonly;
5481
5482
5483 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005484 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005485 ifsspc = 0;
5486 nulonly = 0;
5487 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005488 ifsp = &ifsfirst;
5489 do {
5490 p = string + ifsp->begoff;
5491 nulonly = ifsp->nulonly;
5492 ifs = nulonly ? nullstr : realifs;
5493 ifsspc = 0;
5494 while (p < string + ifsp->endoff) {
5495 q = p;
5496 if (*p == CTLESC)
5497 p++;
5498 if (strchr(ifs, *p)) {
5499 if (!nulonly)
5500 ifsspc = (strchr(defifs, *p) != NULL);
5501 /* Ignore IFS whitespace at start */
5502 if (q == start && ifsspc) {
5503 p++;
5504 start = p;
5505 continue;
5506 }
5507 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005508 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005509 sp->text = start;
5510 *arglist->lastp = sp;
5511 arglist->lastp = &sp->next;
5512 p++;
5513 if (!nulonly) {
5514 for (;;) {
5515 if (p >= string + ifsp->endoff) {
5516 break;
5517 }
5518 q = p;
5519 if (*p == CTLESC)
5520 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005521 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005522 p = q;
5523 break;
5524 } else if (strchr(defifs, *p) == NULL) {
5525 if (ifsspc) {
5526 p++;
5527 ifsspc = 0;
5528 } else {
5529 p = q;
5530 break;
5531 }
5532 } else
5533 p++;
5534 }
5535 }
5536 start = p;
5537 } else
5538 p++;
5539 }
5540 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005541 if (nulonly)
5542 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005543 }
5544
Eric Andersenc470f442003-07-28 09:56:35 +00005545 if (!*start)
5546 return;
5547
5548add:
5549 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005550 sp->text = start;
5551 *arglist->lastp = sp;
5552 arglist->lastp = &sp->next;
5553}
5554
Eric Andersenc470f442003-07-28 09:56:35 +00005555static void
5556ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005557{
Eric Andersenc470f442003-07-28 09:56:35 +00005558 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005559
Eric Andersenc470f442003-07-28 09:56:35 +00005560 INTOFF;
5561 p = ifsfirst.next;
5562 do {
5563 struct ifsregion *ifsp;
5564 ifsp = p->next;
5565 ckfree(p);
5566 p = ifsp;
5567 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005568 ifslastp = NULL;
5569 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005570 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005571}
5572
Eric Andersen90898442003-08-06 11:20:52 +00005573static void expmeta(char *, char *);
5574static struct strlist *expsort(struct strlist *);
5575static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005576
Eric Andersen90898442003-08-06 11:20:52 +00005577static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005578
Eric Andersencb57d552001-06-28 07:25:16 +00005579
Eric Andersenc470f442003-07-28 09:56:35 +00005580static void
Eric Andersen90898442003-08-06 11:20:52 +00005581expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005582{
Eric Andersen90898442003-08-06 11:20:52 +00005583 static const char metachars[] = {
5584 '*', '?', '[', 0
5585 };
Eric Andersencb57d552001-06-28 07:25:16 +00005586 /* TODO - EXP_REDIR */
5587
5588 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005589 struct strlist **savelastp;
5590 struct strlist *sp;
5591 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005592
Eric Andersencb57d552001-06-28 07:25:16 +00005593 if (fflag)
5594 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005595 if (!strpbrk(str->text, metachars))
5596 goto nometa;
5597 savelastp = exparg.lastp;
5598
Eric Andersencb57d552001-06-28 07:25:16 +00005599 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005600 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005601 {
5602 int i = strlen(str->text);
5603 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5604 }
5605
5606 expmeta(expdir, p);
5607 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005608 if (p != str->text)
5609 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005610 INTON;
5611 if (exparg.lastp == savelastp) {
5612 /*
5613 * no matches
5614 */
Eric Andersenc470f442003-07-28 09:56:35 +00005615nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005616 *exparg.lastp = str;
5617 rmescapes(str->text);
5618 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005619 } else {
5620 *exparg.lastp = NULL;
5621 *savelastp = sp = expsort(*savelastp);
5622 while (sp->next != NULL)
5623 sp = sp->next;
5624 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005625 }
5626 str = str->next;
5627 }
5628}
5629
Eric Andersencb57d552001-06-28 07:25:16 +00005630/*
Eric Andersenc470f442003-07-28 09:56:35 +00005631 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005632 */
5633
Eric Andersenc470f442003-07-28 09:56:35 +00005634static void
Eric Andersen90898442003-08-06 11:20:52 +00005635addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005636{
Eric Andersencb57d552001-06-28 07:25:16 +00005637 struct strlist *sp;
5638
Eric Andersenc470f442003-07-28 09:56:35 +00005639 sp = (struct strlist *)stalloc(sizeof *sp);
5640 sp->text = sstrdup(name);
5641 *exparg.lastp = sp;
5642 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005643}
5644
5645
Eric Andersencb57d552001-06-28 07:25:16 +00005646/*
Eric Andersen90898442003-08-06 11:20:52 +00005647 * Do metacharacter (i.e. *, ?, [...]) expansion.
5648 */
5649
5650static void
5651expmeta(char *enddir, char *name)
5652{
5653 char *p;
5654 const char *cp;
5655 char *start;
5656 char *endname;
5657 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005658 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005659 DIR *dirp;
5660 struct dirent *dp;
5661 int atend;
5662 int matchdot;
5663
5664 metaflag = 0;
5665 start = name;
5666 for (p = name; *p; p++) {
5667 if (*p == '*' || *p == '?')
5668 metaflag = 1;
5669 else if (*p == '[') {
5670 char *q = p + 1;
5671 if (*q == '!')
5672 q++;
5673 for (;;) {
5674 if (*q == '\\')
5675 q++;
5676 if (*q == '/' || *q == '\0')
5677 break;
5678 if (*++q == ']') {
5679 metaflag = 1;
5680 break;
5681 }
5682 }
5683 } else if (*p == '\\')
5684 p++;
5685 else if (*p == '/') {
5686 if (metaflag)
5687 goto out;
5688 start = p + 1;
5689 }
5690 }
5691out:
5692 if (metaflag == 0) { /* we've reached the end of the file name */
5693 if (enddir != expdir)
5694 metaflag++;
5695 p = name;
5696 do {
5697 if (*p == '\\')
5698 p++;
5699 *enddir++ = *p;
5700 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005701 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005702 addfname(expdir);
5703 return;
5704 }
5705 endname = p;
5706 if (name < start) {
5707 p = name;
5708 do {
5709 if (*p == '\\')
5710 p++;
5711 *enddir++ = *p++;
5712 } while (p < start);
5713 }
5714 if (enddir == expdir) {
5715 cp = ".";
5716 } else if (enddir == expdir + 1 && *expdir == '/') {
5717 cp = "/";
5718 } else {
5719 cp = expdir;
5720 enddir[-1] = '\0';
5721 }
5722 if ((dirp = opendir(cp)) == NULL)
5723 return;
5724 if (enddir != expdir)
5725 enddir[-1] = '/';
5726 if (*endname == 0) {
5727 atend = 1;
5728 } else {
5729 atend = 0;
5730 *endname++ = '\0';
5731 }
5732 matchdot = 0;
5733 p = start;
5734 if (*p == '\\')
5735 p++;
5736 if (*p == '.')
5737 matchdot++;
5738 while (! intpending && (dp = readdir(dirp)) != NULL) {
5739 if (dp->d_name[0] == '.' && ! matchdot)
5740 continue;
5741 if (pmatch(start, dp->d_name)) {
5742 if (atend) {
5743 scopy(dp->d_name, enddir);
5744 addfname(expdir);
5745 } else {
5746 for (p = enddir, cp = dp->d_name;
5747 (*p++ = *cp++) != '\0';)
5748 continue;
5749 p[-1] = '/';
5750 expmeta(p, endname);
5751 }
5752 }
5753 }
5754 closedir(dirp);
5755 if (! atend)
5756 endname[-1] = '/';
5757}
5758
5759/*
5760 * Sort the results of file name expansion. It calculates the number of
5761 * strings to sort and then calls msort (short for merge sort) to do the
5762 * work.
5763 */
5764
5765static struct strlist *
5766expsort(struct strlist *str)
5767{
5768 int len;
5769 struct strlist *sp;
5770
5771 len = 0;
5772 for (sp = str ; sp ; sp = sp->next)
5773 len++;
5774 return msort(str, len);
5775}
5776
5777
5778static struct strlist *
5779msort(struct strlist *list, int len)
5780{
5781 struct strlist *p, *q = NULL;
5782 struct strlist **lpp;
5783 int half;
5784 int n;
5785
5786 if (len <= 1)
5787 return list;
5788 half = len >> 1;
5789 p = list;
5790 for (n = half ; --n >= 0 ; ) {
5791 q = p;
5792 p = p->next;
5793 }
5794 q->next = NULL; /* terminate first half of list */
5795 q = msort(list, half); /* sort first half of list */
5796 p = msort(p, len - half); /* sort second half */
5797 lpp = &list;
5798 for (;;) {
5799#ifdef CONFIG_LOCALE_SUPPORT
5800 if (strcoll(p->text, q->text) < 0)
5801#else
5802 if (strcmp(p->text, q->text) < 0)
5803#endif
5804 {
5805 *lpp = p;
5806 lpp = &p->next;
5807 if ((p = *lpp) == NULL) {
5808 *lpp = q;
5809 break;
5810 }
5811 } else {
5812 *lpp = q;
5813 lpp = &q->next;
5814 if ((q = *lpp) == NULL) {
5815 *lpp = p;
5816 break;
5817 }
5818 }
5819 }
5820 return list;
5821}
5822
5823
5824/*
Eric Andersencb57d552001-06-28 07:25:16 +00005825 * Returns true if the pattern matches the string.
5826 */
5827
Rob Landley88621d72006-08-29 19:41:06 +00005828static int patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005829{
Eric Andersenc470f442003-07-28 09:56:35 +00005830 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005831}
5832
5833
Eric Andersencb57d552001-06-28 07:25:16 +00005834/*
5835 * Remove any CTLESC characters from a string.
5836 */
5837
Eric Andersenc470f442003-07-28 09:56:35 +00005838static char *
5839_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005840{
5841 char *p, *q, *r;
5842 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005843 unsigned inquotes;
5844 int notescaped;
5845 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005846
5847 p = strpbrk(str, qchars);
5848 if (!p) {
5849 return str;
5850 }
5851 q = p;
5852 r = str;
5853 if (flag & RMESCAPE_ALLOC) {
5854 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005855 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005856
Eric Andersenc470f442003-07-28 09:56:35 +00005857 if (flag & RMESCAPE_GROW) {
5858 r = makestrspace(fulllen, expdest);
5859 } else if (flag & RMESCAPE_HEAP) {
5860 r = ckmalloc(fulllen);
5861 } else {
5862 r = stalloc(fulllen);
5863 }
5864 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005865 if (len > 0) {
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00005866 q = memcpy(q, str, len) + len;
Eric Andersencb57d552001-06-28 07:25:16 +00005867 }
5868 }
Eric Andersenc470f442003-07-28 09:56:35 +00005869 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5870 globbing = flag & RMESCAPE_GLOB;
5871 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005872 while (*p) {
5873 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005874 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005875 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005876 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005877 continue;
5878 }
Eric Andersenc470f442003-07-28 09:56:35 +00005879 if (*p == '\\') {
5880 /* naked back slash */
5881 notescaped = 0;
5882 goto copy;
5883 }
Eric Andersencb57d552001-06-28 07:25:16 +00005884 if (*p == CTLESC) {
5885 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005886 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005887 *q++ = '\\';
5888 }
5889 }
Eric Andersenc470f442003-07-28 09:56:35 +00005890 notescaped = globbing;
5891copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005892 *q++ = *p++;
5893 }
5894 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005895 if (flag & RMESCAPE_GROW) {
5896 expdest = r;
5897 STADJUST(q - r + 1, expdest);
5898 }
Eric Andersencb57d552001-06-28 07:25:16 +00005899 return r;
5900}
Eric Andersencb57d552001-06-28 07:25:16 +00005901
5902
Eric Andersencb57d552001-06-28 07:25:16 +00005903/*
5904 * See if a pattern matches in a case statement.
5905 */
5906
Eric Andersenc470f442003-07-28 09:56:35 +00005907int
5908casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005909{
Eric Andersencb57d552001-06-28 07:25:16 +00005910 struct stackmark smark;
5911 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005912
5913 setstackmark(&smark);
5914 argbackq = pattern->narg.backquote;
5915 STARTSTACKSTR(expdest);
5916 ifslastp = NULL;
5917 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005918 STACKSTRNUL(expdest);
5919 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005920 popstackmark(&smark);
5921 return result;
5922}
5923
5924/*
5925 * Our own itoa().
5926 */
5927
Eric Andersenc470f442003-07-28 09:56:35 +00005928static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005929cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005930{
Eric Andersencb57d552001-06-28 07:25:16 +00005931 int len;
5932
Eric Andersenc470f442003-07-28 09:56:35 +00005933 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005934#ifdef CONFIG_ASH_MATH_SUPPORT_64
5935 len = fmtstr(expdest, 32, "%lld", (long long) num);
5936#else
Eric Andersenc470f442003-07-28 09:56:35 +00005937 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005938#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005939 STADJUST(len, expdest);
5940 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005941}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005942
Eric Andersenc470f442003-07-28 09:56:35 +00005943static void
5944varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005945{
Eric Andersenc470f442003-07-28 09:56:35 +00005946 const char *msg;
5947 const char *tail;
5948
5949 tail = nullstr;
5950 msg = "parameter not set";
5951 if (umsg) {
5952 if (*end == CTLENDVAR) {
5953 if (varflags & VSNUL)
5954 tail = " or null";
5955 } else
5956 msg = umsg;
5957 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005958 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005959}
Eric Andersen90898442003-08-06 11:20:52 +00005960
5961
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005962/* input.c */
Eric Andersencb57d552001-06-28 07:25:16 +00005963
Eric Andersencb57d552001-06-28 07:25:16 +00005964/*
Eric Andersen90898442003-08-06 11:20:52 +00005965 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005966 */
5967
Eric Andersenc470f442003-07-28 09:56:35 +00005968#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005969
Eric Andersenc470f442003-07-28 09:56:35 +00005970static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005971
Eric Andersencb57d552001-06-28 07:25:16 +00005972/*
Eric Andersenc470f442003-07-28 09:56:35 +00005973 * Read a character from the script, returning PEOF on end of file.
5974 * Nul characters in the input are silently discarded.
5975 */
5976
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005977
5978#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
Eric Andersenc470f442003-07-28 09:56:35 +00005979
5980#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5981#define pgetc_macro() pgetc()
5982static int
5983pgetc(void)
5984{
5985 return pgetc_as_macro();
5986}
5987#else
5988#define pgetc_macro() pgetc_as_macro()
5989static int
5990pgetc(void)
5991{
5992 return pgetc_macro();
5993}
5994#endif
5995
5996
5997/*
5998 * Same as pgetc(), but ignores PEOA.
5999 */
6000#ifdef CONFIG_ASH_ALIAS
6001static int pgetc2(void)
6002{
6003 int c;
6004
6005 do {
6006 c = pgetc_macro();
6007 } while (c == PEOA);
6008 return c;
6009}
6010#else
Rob Landley88621d72006-08-29 19:41:06 +00006011static int pgetc2(void)
Eric Andersenc470f442003-07-28 09:56:35 +00006012{
6013 return pgetc_macro();
6014}
6015#endif
6016
Glenn L McGrath28939ad2004-07-21 10:20:19 +00006017/*
6018 * Read a line from the script.
6019 */
6020
Rob Landley88621d72006-08-29 19:41:06 +00006021static char * pfgets(char *line, int len)
Glenn L McGrath28939ad2004-07-21 10:20:19 +00006022{
6023 char *p = line;
6024 int nleft = len;
6025 int c;
6026
6027 while (--nleft > 0) {
6028 c = pgetc2();
6029 if (c == PEOF) {
6030 if (p == line)
6031 return NULL;
6032 break;
6033 }
6034 *p++ = c;
6035 if (c == '\n')
6036 break;
6037 }
6038 *p = '\0';
6039 return line;
6040}
6041
6042
Denis Vlasenko38f63192007-01-22 09:03:07 +00006043#if ENABLE_FEATURE_EDITING
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00006044static line_input_t *line_input_state;
6045//static SKIP_ASH_EXPAND_PRMT(const) char *cmdedit_prompt;
Eric Andersenc470f442003-07-28 09:56:35 +00006046static const char *cmdedit_prompt;
Rob Landley88621d72006-08-29 19:41:06 +00006047static void putprompt(const char *s)
Eric Andersenc470f442003-07-28 09:56:35 +00006048{
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00006049 if (ENABLE_ASH_EXPAND_PRMT) {
6050 free((char*)cmdedit_prompt);
6051 cmdedit_prompt = xstrdup(s);
6052 return;
6053 }
Eric Andersenc470f442003-07-28 09:56:35 +00006054 cmdedit_prompt = s;
6055}
6056#else
Rob Landley88621d72006-08-29 19:41:06 +00006057static void putprompt(const char *s)
Eric Andersenc470f442003-07-28 09:56:35 +00006058{
6059 out2str(s);
6060}
6061#endif
6062
Denis Vlasenko38f63192007-01-22 09:03:07 +00006063#if ENABLE_FEATURE_EDITING_VI
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00006064#define setvimode(on) do { \
6065 if (on) line_input_state->flags |= VI_MODE; \
6066 else line_input_state->flags &= ~VI_MODE; \
6067} while (0)
6068#else
6069#define setvimode(on) viflag = 0 /* forcibly keep the option off */
6070#endif
6071
6072
Rob Landley88621d72006-08-29 19:41:06 +00006073static int preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006074{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006075 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006076 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006077 parsenextc = buf;
6078
Eric Andersenc470f442003-07-28 09:56:35 +00006079retry:
Denis Vlasenko38f63192007-01-22 09:03:07 +00006080#if ENABLE_FEATURE_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006081 if (!iflag || parsefile->fd)
6082 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6083 else {
Denis Vlasenko38f63192007-01-22 09:03:07 +00006084#if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00006085 line_input_state->path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006086#endif
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00006087 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state);
6088 if (nr == 0) {
6089 /* Ctrl+C pressed */
6090 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006091 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00006092 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006093 raise(SIGINT);
6094 return 1;
6095 }
Eric Andersenc470f442003-07-28 09:56:35 +00006096 goto retry;
6097 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00006098 if (nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006099 /* Ctrl+D presend */
6100 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006101 }
Eric Andersencb57d552001-06-28 07:25:16 +00006102 }
6103#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006104 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006105#endif
6106
6107 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006108 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6109 int flags = fcntl(0, F_GETFL, 0);
6110 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006111 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006112 if (fcntl(0, F_SETFL, flags) >= 0) {
6113 out2str("sh: turning off NDELAY mode\n");
6114 goto retry;
6115 }
6116 }
6117 }
6118 }
6119 return nr;
6120}
6121
6122/*
6123 * Refill the input buffer and return the next input character:
6124 *
6125 * 1) If a string was pushed back on the input, pop it;
6126 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6127 * from a string so we can't refill the buffer, return EOF.
6128 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6129 * 4) Process input up to the next newline, deleting nul characters.
6130 */
6131
Eric Andersenc470f442003-07-28 09:56:35 +00006132int
6133preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006134{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006135 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00006136 int more;
6137 char savec;
6138
6139 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006140#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006141 if (parsenleft == -1 && parsefile->strpush->ap &&
6142 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006143 return PEOA;
6144 }
Eric Andersen2870d962001-07-02 17:27:21 +00006145#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006146 popstring();
6147 if (--parsenleft >= 0)
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006148 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006149 }
6150 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6151 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006152 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006153
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006154 more = parselleft;
6155 if (more <= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006156again:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006157 if ((more = preadfd()) <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006158 parselleft = parsenleft = EOF_NLEFT;
6159 return PEOF;
6160 }
6161 }
6162
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006163 q = parsenextc;
Eric Andersencb57d552001-06-28 07:25:16 +00006164
6165 /* delete nul characters */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006166 for (;;) {
6167 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00006168
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006169 more--;
6170 c = *q;
Eric Andersenc470f442003-07-28 09:56:35 +00006171
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006172 if (!c)
6173 memmove(q, q + 1, more);
6174 else {
6175 q++;
6176 if (c == '\n') {
6177 parsenleft = q - parsenextc - 1;
6178 break;
6179 }
Eric Andersencb57d552001-06-28 07:25:16 +00006180 }
6181
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006182 if (more <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006183 parsenleft = q - parsenextc - 1;
6184 if (parsenleft < 0)
6185 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006186 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006187 }
6188 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006189 parselleft = more;
Eric Andersencb57d552001-06-28 07:25:16 +00006190
6191 savec = *q;
6192 *q = '\0';
6193
6194 if (vflag) {
6195 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006196 }
6197
6198 *q = savec;
6199
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006200 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006201}
6202
Eric Andersenc470f442003-07-28 09:56:35 +00006203/*
6204 * Undo the last call to pgetc. Only one character may be pushed back.
6205 * PEOF may be pushed back.
6206 */
6207
6208void
6209pungetc(void)
6210{
6211 parsenleft++;
6212 parsenextc--;
6213}
Eric Andersencb57d552001-06-28 07:25:16 +00006214
6215/*
6216 * Push a string back onto the input at this current parsefile level.
6217 * We handle aliases this way.
6218 */
Eric Andersenc470f442003-07-28 09:56:35 +00006219void
6220pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006221{
Eric Andersencb57d552001-06-28 07:25:16 +00006222 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006223 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006224
Eric Andersenc470f442003-07-28 09:56:35 +00006225 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006226 INTOFF;
6227/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6228 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006229 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006230 sp->prev = parsefile->strpush;
6231 parsefile->strpush = sp;
6232 } else
6233 sp = parsefile->strpush = &(parsefile->basestrpush);
6234 sp->prevstring = parsenextc;
6235 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006236#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006237 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006238 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006239 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006240 sp->string = s;
6241 }
Eric Andersen2870d962001-07-02 17:27:21 +00006242#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006243 parsenextc = s;
6244 parsenleft = len;
6245 INTON;
6246}
6247
Eric Andersenc470f442003-07-28 09:56:35 +00006248void
6249popstring(void)
6250{
6251 struct strpush *sp = parsefile->strpush;
6252
6253 INTOFF;
6254#ifdef CONFIG_ASH_ALIAS
6255 if (sp->ap) {
6256 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6257 checkkwd |= CHKALIAS;
6258 }
6259 if (sp->string != sp->ap->val) {
6260 ckfree(sp->string);
6261 }
6262 sp->ap->flag &= ~ALIASINUSE;
6263 if (sp->ap->flag & ALIASDEAD) {
6264 unalias(sp->ap->name);
6265 }
6266 }
6267#endif
6268 parsenextc = sp->prevstring;
6269 parsenleft = sp->prevnleft;
6270/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6271 parsefile->strpush = sp->prev;
6272 if (sp != &(parsefile->basestrpush))
6273 ckfree(sp);
6274 INTON;
6275}
6276
6277/*
6278 * Set the input to take input from a file. If push is set, push the
6279 * old input onto the stack first.
6280 */
6281
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006282static int
6283setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00006284{
6285 int fd;
6286 int fd2;
6287
6288 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006289 if ((fd = open(fname, O_RDONLY)) < 0) {
6290 if (flags & INPUT_NOFILE_OK)
6291 goto out;
6292 sh_error("Can't open %s", fname);
6293 }
Eric Andersenc470f442003-07-28 09:56:35 +00006294 if (fd < 10) {
6295 fd2 = copyfd(fd, 10);
6296 close(fd);
6297 if (fd2 < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006298 sh_error("Out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +00006299 fd = fd2;
6300 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006301 setinputfd(fd, flags & INPUT_PUSH_FILE);
6302out:
Eric Andersenc470f442003-07-28 09:56:35 +00006303 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006304 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +00006305}
6306
6307
6308/*
6309 * Like setinputfile, but takes an open file descriptor. Call this with
6310 * interrupts off.
6311 */
6312
6313static void
6314setinputfd(int fd, int push)
6315{
6316 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6317 if (push) {
6318 pushfile();
6319 parsefile->buf = 0;
6320 }
6321 parsefile->fd = fd;
6322 if (parsefile->buf == NULL)
6323 parsefile->buf = ckmalloc(IBUFSIZ);
6324 parselleft = parsenleft = 0;
6325 plinno = 1;
6326}
6327
Eric Andersencb57d552001-06-28 07:25:16 +00006328
Eric Andersencb57d552001-06-28 07:25:16 +00006329/*
6330 * Like setinputfile, but takes input from a string.
6331 */
6332
Eric Andersenc470f442003-07-28 09:56:35 +00006333static void
6334setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006335{
Eric Andersencb57d552001-06-28 07:25:16 +00006336 INTOFF;
6337 pushfile();
6338 parsenextc = string;
6339 parsenleft = strlen(string);
6340 parsefile->buf = NULL;
6341 plinno = 1;
6342 INTON;
6343}
6344
6345
Eric Andersencb57d552001-06-28 07:25:16 +00006346/*
6347 * To handle the "." command, a stack of input files is used. Pushfile
6348 * adds a new entry to the stack and popfile restores the previous level.
6349 */
6350
Eric Andersenc470f442003-07-28 09:56:35 +00006351static void
6352pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006353{
Eric Andersencb57d552001-06-28 07:25:16 +00006354 struct parsefile *pf;
6355
6356 parsefile->nleft = parsenleft;
6357 parsefile->lleft = parselleft;
6358 parsefile->nextc = parsenextc;
6359 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006360 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006361 pf->prev = parsefile;
6362 pf->fd = -1;
6363 pf->strpush = NULL;
6364 pf->basestrpush.prev = NULL;
6365 parsefile = pf;
6366}
6367
Eric Andersenc470f442003-07-28 09:56:35 +00006368
6369static void
6370popfile(void)
6371{
6372 struct parsefile *pf = parsefile;
6373
6374 INTOFF;
6375 if (pf->fd >= 0)
6376 close(pf->fd);
6377 if (pf->buf)
6378 ckfree(pf->buf);
6379 while (pf->strpush)
6380 popstring();
6381 parsefile = pf->prev;
6382 ckfree(pf);
6383 parsenleft = parsefile->nleft;
6384 parselleft = parsefile->lleft;
6385 parsenextc = parsefile->nextc;
6386 plinno = parsefile->linno;
6387 INTON;
6388}
Eric Andersencb57d552001-06-28 07:25:16 +00006389
6390
Eric Andersen2870d962001-07-02 17:27:21 +00006391/*
Eric Andersenc470f442003-07-28 09:56:35 +00006392 * Return to top level.
6393 */
Eric Andersen2870d962001-07-02 17:27:21 +00006394
Eric Andersenc470f442003-07-28 09:56:35 +00006395static void
6396popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006397{
Eric Andersenc470f442003-07-28 09:56:35 +00006398 while (parsefile != &basepf)
6399 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006400}
6401
Eric Andersen2870d962001-07-02 17:27:21 +00006402
Eric Andersenc470f442003-07-28 09:56:35 +00006403/*
6404 * Close the file(s) that the shell is reading commands from. Called
6405 * after a fork is done.
6406 */
6407
6408static void
6409closescript(void)
6410{
6411 popallfiles();
6412 if (parsefile->fd > 0) {
6413 close(parsefile->fd);
6414 parsefile->fd = 0;
6415 }
6416}
Eric Andersenc470f442003-07-28 09:56:35 +00006417
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006418/* jobs.c */
Eric Andersenc470f442003-07-28 09:56:35 +00006419
6420/* mode flags for set_curjob */
6421#define CUR_DELETE 2
6422#define CUR_RUNNING 1
6423#define CUR_STOPPED 0
6424
6425/* mode flags for dowait */
6426#define DOWAIT_NORMAL 0
6427#define DOWAIT_BLOCK 1
6428
6429/* array of jobs */
6430static struct job *jobtab;
6431/* size of array */
6432static unsigned njobs;
6433#if JOBS
6434/* pgrp of shell on invocation */
6435static int initialpgrp;
6436static int ttyfd = -1;
6437#endif
6438/* current job */
6439static struct job *curjob;
6440/* number of presumed living untracked jobs */
6441static int jobless;
6442
6443static void set_curjob(struct job *, unsigned);
6444#if JOBS
6445static int restartjob(struct job *, int);
6446static void xtcsetpgrp(int, pid_t);
6447static char *commandtext(union node *);
6448static void cmdlist(union node *, int);
6449static void cmdtxt(union node *);
6450static void cmdputs(const char *);
6451static void showpipe(struct job *, FILE *);
6452#endif
6453static int sprint_status(char *, int, int);
6454static void freejob(struct job *);
6455static struct job *getjob(const char *, int);
6456static struct job *growjobtab(void);
6457static void forkchild(struct job *, union node *, int);
6458static void forkparent(struct job *, union node *, int, pid_t);
6459static int dowait(int, struct job *);
6460static int getstatus(struct job *);
6461
6462static void
6463set_curjob(struct job *jp, unsigned mode)
6464{
6465 struct job *jp1;
6466 struct job **jpp, **curp;
6467
6468 /* first remove from list */
6469 jpp = curp = &curjob;
6470 do {
6471 jp1 = *jpp;
6472 if (jp1 == jp)
6473 break;
6474 jpp = &jp1->prev_job;
6475 } while (1);
6476 *jpp = jp1->prev_job;
6477
6478 /* Then re-insert in correct position */
6479 jpp = curp;
6480 switch (mode) {
6481 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00006482#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00006483 abort();
6484#endif
6485 case CUR_DELETE:
6486 /* job being deleted */
6487 break;
6488 case CUR_RUNNING:
6489 /* newly created job or backgrounded job,
6490 put after all stopped jobs. */
6491 do {
6492 jp1 = *jpp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006493#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006494 if (!jp1 || jp1->state != JOBSTOPPED)
6495#endif
6496 break;
6497 jpp = &jp1->prev_job;
6498 } while (1);
6499 /* FALLTHROUGH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006500#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006501 case CUR_STOPPED:
6502#endif
6503 /* newly stopped job - becomes curjob */
6504 jp->prev_job = *jpp;
6505 *jpp = jp;
6506 break;
6507 }
6508}
6509
6510#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006511/*
6512 * Turn job control on and off.
6513 *
6514 * Note: This code assumes that the third arg to ioctl is a character
6515 * pointer, which is true on Berkeley systems but not System V. Since
6516 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006517 *
6518 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006519 */
6520
Eric Andersenc470f442003-07-28 09:56:35 +00006521void
6522setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006523{
Eric Andersenc470f442003-07-28 09:56:35 +00006524 int fd;
6525 int pgrp;
6526
6527 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006528 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006529 if (on) {
6530 int ofd;
6531 ofd = fd = open(_PATH_TTY, O_RDWR);
6532 if (fd < 0) {
Denis Vlasenko2f0c0d02007-01-21 00:41:04 +00006533 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
6534 * That sometimes helps to acquire controlling tty.
6535 * Obviously, a workaround for bugs when someone
6536 * failed to provide a controlling tty to bash! :) */
Eric Andersenc470f442003-07-28 09:56:35 +00006537 fd += 3;
6538 while (!isatty(fd) && --fd >= 0)
6539 ;
6540 }
6541 fd = fcntl(fd, F_DUPFD, 10);
6542 close(ofd);
6543 if (fd < 0)
6544 goto out;
6545 fcntl(fd, F_SETFD, FD_CLOEXEC);
6546 do { /* while we are in the background */
6547 if ((pgrp = tcgetpgrp(fd)) < 0) {
6548out:
6549 sh_warnx("can't access tty; job control turned off");
6550 mflag = on = 0;
6551 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006552 }
Eric Andersenc470f442003-07-28 09:56:35 +00006553 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006554 break;
6555 killpg(0, SIGTTIN);
6556 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006557 initialpgrp = pgrp;
6558
Eric Andersencb57d552001-06-28 07:25:16 +00006559 setsignal(SIGTSTP);
6560 setsignal(SIGTTOU);
6561 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006562 pgrp = rootpid;
6563 setpgid(0, pgrp);
6564 xtcsetpgrp(fd, pgrp);
6565 } else {
6566 /* turning job control off */
6567 fd = ttyfd;
6568 pgrp = initialpgrp;
6569 xtcsetpgrp(fd, pgrp);
6570 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006571 setsignal(SIGTSTP);
6572 setsignal(SIGTTOU);
6573 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006574close:
6575 close(fd);
6576 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006577 }
Eric Andersenc470f442003-07-28 09:56:35 +00006578 ttyfd = fd;
6579 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006580}
Eric Andersencb57d552001-06-28 07:25:16 +00006581
Eric Andersenc470f442003-07-28 09:56:35 +00006582static int
Eric Andersen90898442003-08-06 11:20:52 +00006583killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006584{
6585 int signo = -1;
6586 int list = 0;
6587 int i;
6588 pid_t pid;
6589 struct job *jp;
6590
6591 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006592usage:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006593 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006594"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6595"kill -l [exitstatus]"
6596 );
Eric Andersencb57d552001-06-28 07:25:16 +00006597 }
6598
Eric Andersenc470f442003-07-28 09:56:35 +00006599 if (**++argv == '-') {
Rob Landleyc9c1a412006-07-12 19:17:55 +00006600 signo = get_signum(*argv + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006601 if (signo < 0) {
6602 int c;
6603
6604 while ((c = nextopt("ls:")) != '\0')
6605 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006606 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00006607#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00006608 abort();
6609#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006610 case 'l':
6611 list = 1;
6612 break;
6613 case 's':
Rob Landleyc9c1a412006-07-12 19:17:55 +00006614 signo = get_signum(optionarg);
Eric Andersencb57d552001-06-28 07:25:16 +00006615 if (signo < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006616 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006617 "invalid signal number or name: %s",
6618 optionarg
6619 );
Eric Andersencb57d552001-06-28 07:25:16 +00006620 }
Eric Andersen2870d962001-07-02 17:27:21 +00006621 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006622 }
Eric Andersenc470f442003-07-28 09:56:35 +00006623 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006624 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006625 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006626 }
6627
6628 if (!list && signo < 0)
6629 signo = SIGTERM;
6630
Eric Andersenc470f442003-07-28 09:56:35 +00006631 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006632 goto usage;
6633 }
6634
6635 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006636 const char *name;
6637
Eric Andersenc470f442003-07-28 09:56:35 +00006638 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006639 for (i = 1; i < NSIG; i++) {
Rob Landleyc9c1a412006-07-12 19:17:55 +00006640 name = get_signame(i);
6641 if (isdigit(*name))
Eric Andersenc470f442003-07-28 09:56:35 +00006642 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006643 }
6644 return 0;
6645 }
Rob Landleyc9c1a412006-07-12 19:17:55 +00006646 name = get_signame(signo);
6647 if (isdigit(*name))
Eric Andersenc470f442003-07-28 09:56:35 +00006648 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006649 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006650 sh_error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006651 return 0;
6652 }
6653
Eric Andersenc470f442003-07-28 09:56:35 +00006654 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006655 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006656 if (**argv == '%') {
6657 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006658 pid = -jp->ps[0].pid;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006659 } else {
6660 pid = **argv == '-' ?
6661 -number(*argv + 1) : number(*argv);
6662 }
Eric Andersenc470f442003-07-28 09:56:35 +00006663 if (kill(pid, signo) != 0) {
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006664 sh_warnx("(%d) - %m", pid);
Eric Andersenc470f442003-07-28 09:56:35 +00006665 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006666 }
Eric Andersenc470f442003-07-28 09:56:35 +00006667 } while (*++argv);
6668
6669 return i;
6670}
6671#endif /* JOBS */
6672
Denis Vlasenko666da5e2006-12-26 18:17:42 +00006673#if JOBS || DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00006674static int
6675jobno(const struct job *jp)
6676{
6677 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006678}
6679#endif
6680
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006681#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006682static int
6683fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006684{
Eric Andersenc470f442003-07-28 09:56:35 +00006685 struct job *jp;
6686 FILE *out;
6687 int mode;
6688 int retval;
6689
6690 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6691 nextopt(nullstr);
6692 argv = argptr;
6693 out = stdout;
6694 do {
6695 jp = getjob(*argv, 1);
6696 if (mode == FORK_BG) {
6697 set_curjob(jp, CUR_RUNNING);
6698 fprintf(out, "[%d] ", jobno(jp));
6699 }
6700 outstr(jp->ps->cmd, out);
6701 showpipe(jp, out);
6702 retval = restartjob(jp, mode);
6703 } while (*argv && *++argv);
6704 return retval;
6705}
6706
6707static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6708
6709
6710static int
6711restartjob(struct job *jp, int mode)
6712{
6713 struct procstat *ps;
6714 int i;
6715 int status;
6716 pid_t pgid;
6717
6718 INTOFF;
6719 if (jp->state == JOBDONE)
6720 goto out;
6721 jp->state = JOBRUNNING;
6722 pgid = jp->ps->pid;
6723 if (mode == FORK_FG)
6724 xtcsetpgrp(ttyfd, pgid);
6725 killpg(pgid, SIGCONT);
6726 ps = jp->ps;
6727 i = jp->nprocs;
6728 do {
6729 if (WIFSTOPPED(ps->status)) {
6730 ps->status = -1;
6731 }
6732 } while (ps++, --i);
6733out:
6734 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6735 INTON;
6736 return status;
6737}
6738#endif
6739
6740static int
6741sprint_status(char *s, int status, int sigonly)
6742{
6743 int col;
6744 int st;
6745
6746 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006747 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006748#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006749 if (WIFSTOPPED(status))
6750 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006751 else
Eric Andersenc470f442003-07-28 09:56:35 +00006752#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006753 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006754 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006755 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006756 goto out;
6757#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006758 if (WIFSTOPPED(status))
6759 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006760#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006761 }
6762 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006763 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006764 if (WCOREDUMP(status)) {
6765 col += fmtstr(s + col, 16, " (core dumped)");
6766 }
6767 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006768 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006769 if (st)
6770 col = fmtstr(s, 16, "Done(%d)", st);
6771 else
6772 col = fmtstr(s, 16, "Done");
6773 }
6774
6775out:
6776 return col;
6777}
6778
6779#if JOBS
6780static void
6781showjob(FILE *out, struct job *jp, int mode)
6782{
6783 struct procstat *ps;
6784 struct procstat *psend;
6785 int col;
6786 int indent;
6787 char s[80];
6788
6789 ps = jp->ps;
6790
6791 if (mode & SHOW_PGID) {
6792 /* just output process (group) id of pipeline */
6793 fprintf(out, "%d\n", ps->pid);
6794 return;
6795 }
6796
6797 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6798 indent = col;
6799
6800 if (jp == curjob)
6801 s[col - 2] = '+';
6802 else if (curjob && jp == curjob->prev_job)
6803 s[col - 2] = '-';
6804
6805 if (mode & SHOW_PID)
6806 col += fmtstr(s + col, 16, "%d ", ps->pid);
6807
6808 psend = ps + jp->nprocs;
6809
6810 if (jp->state == JOBRUNNING) {
6811 scopy("Running", s + col);
6812 col += strlen("Running");
6813 } else {
6814 int status = psend[-1].status;
6815#if JOBS
6816 if (jp->state == JOBSTOPPED)
6817 status = jp->stopstatus;
6818#endif
6819 col += sprint_status(s + col, status, 0);
6820 }
6821
6822 goto start;
6823
6824 do {
6825 /* for each process */
6826 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6827
6828start:
Eric Andersen90898442003-08-06 11:20:52 +00006829 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006830 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6831 );
6832 if (!(mode & SHOW_PID)) {
6833 showpipe(jp, out);
6834 break;
6835 }
6836 if (++ps == psend) {
6837 outcslow('\n', out);
6838 break;
6839 }
6840 } while (1);
6841
6842 jp->changed = 0;
6843
6844 if (jp->state == JOBDONE) {
6845 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6846 freejob(jp);
6847 }
6848}
6849
6850
6851static int
6852jobscmd(int argc, char **argv)
6853{
6854 int mode, m;
6855 FILE *out;
6856
6857 mode = 0;
6858 while ((m = nextopt("lp")))
6859 if (m == 'l')
6860 mode = SHOW_PID;
6861 else
6862 mode = SHOW_PGID;
6863
6864 out = stdout;
6865 argv = argptr;
6866 if (*argv)
6867 do
6868 showjob(out, getjob(*argv,0), mode);
6869 while (*++argv);
6870 else
6871 showjobs(out, mode);
6872
Eric Andersencb57d552001-06-28 07:25:16 +00006873 return 0;
6874}
6875
6876
6877/*
6878 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6879 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006880 */
6881
Eric Andersenc470f442003-07-28 09:56:35 +00006882static void
6883showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006884{
Eric Andersencb57d552001-06-28 07:25:16 +00006885 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006886
Eric Andersenc470f442003-07-28 09:56:35 +00006887 TRACE(("showjobs(%x) called\n", mode));
6888
6889 /* If not even one one job changed, there is nothing to do */
6890 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6891 continue;
6892
6893 for (jp = curjob; jp; jp = jp->prev_job) {
6894 if (!(mode & SHOW_CHANGED) || jp->changed)
6895 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006896 }
6897}
Eric Andersenc470f442003-07-28 09:56:35 +00006898#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006899
6900/*
6901 * Mark a job structure as unused.
6902 */
6903
Eric Andersenc470f442003-07-28 09:56:35 +00006904static void
6905freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006906{
Eric Andersenc470f442003-07-28 09:56:35 +00006907 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006908 int i;
6909
6910 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006911 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006912 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006913 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006914 }
6915 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006916 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006917 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006918 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006919 INTON;
6920}
6921
6922
Eric Andersenc470f442003-07-28 09:56:35 +00006923static int
6924waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006925{
6926 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006927 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006928 struct job *jp;
6929
Eric Andersenc470f442003-07-28 09:56:35 +00006930 EXSIGON();
6931
6932 nextopt(nullstr);
6933 retval = 0;
6934
6935 argv = argptr;
6936 if (!*argv) {
6937 /* wait for all jobs */
6938 for (;;) {
6939 jp = curjob;
6940 while (1) {
6941 if (!jp) {
6942 /* no running procs */
6943 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006944 }
Eric Andersenc470f442003-07-28 09:56:35 +00006945 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006946 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006947 jp->waited = 1;
6948 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006949 }
Eric Andersenc470f442003-07-28 09:56:35 +00006950 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006951 }
6952 }
Eric Andersenc470f442003-07-28 09:56:35 +00006953
6954 retval = 127;
6955 do {
6956 if (**argv != '%') {
6957 pid_t pid = number(*argv);
6958 job = curjob;
6959 goto start;
6960 do {
6961 if (job->ps[job->nprocs - 1].pid == pid)
6962 break;
6963 job = job->prev_job;
6964start:
6965 if (!job)
6966 goto repeat;
6967 } while (1);
6968 } else
6969 job = getjob(*argv, 0);
6970 /* loop until process terminated or stopped */
6971 while (job->state == JOBRUNNING)
6972 dowait(DOWAIT_BLOCK, 0);
6973 job->waited = 1;
6974 retval = getstatus(job);
6975repeat:
6976 ;
6977 } while (*++argv);
6978
6979out:
6980 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006981}
6982
6983
Eric Andersencb57d552001-06-28 07:25:16 +00006984/*
6985 * Convert a job name to a job structure.
6986 */
6987
Eric Andersenc470f442003-07-28 09:56:35 +00006988static struct job *
6989getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006990{
Eric Andersencb57d552001-06-28 07:25:16 +00006991 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006992 struct job *found;
6993 const char *err_msg = "No such job: %s";
6994 unsigned num;
6995 int c;
6996 const char *p;
6997 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006998
Eric Andersenc470f442003-07-28 09:56:35 +00006999 jp = curjob;
7000 p = name;
7001 if (!p)
7002 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007003
Eric Andersenc470f442003-07-28 09:56:35 +00007004 if (*p != '%')
7005 goto err;
7006
7007 c = *++p;
7008 if (!c)
7009 goto currentjob;
7010
7011 if (!p[1]) {
7012 if (c == '+' || c == '%') {
7013currentjob:
7014 err_msg = "No current job";
7015 goto check;
7016 } else if (c == '-') {
7017 if (jp)
7018 jp = jp->prev_job;
7019 err_msg = "No previous job";
7020check:
7021 if (!jp)
7022 goto err;
7023 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00007024 }
7025 }
Eric Andersenc470f442003-07-28 09:56:35 +00007026
7027 if (is_number(p)) {
7028 num = atoi(p);
7029 if (num < njobs) {
7030 jp = jobtab + num - 1;
7031 if (jp->used)
7032 goto gotit;
7033 goto err;
7034 }
7035 }
7036
7037 match = prefix;
7038 if (*p == '?') {
7039 match = strstr;
7040 p++;
7041 }
7042
7043 found = 0;
7044 while (1) {
7045 if (!jp)
7046 goto err;
7047 if (match(jp->ps[0].cmd, p)) {
7048 if (found)
7049 goto err;
7050 found = jp;
7051 err_msg = "%s: ambiguous";
7052 }
7053 jp = jp->prev_job;
7054 }
7055
7056gotit:
7057#if JOBS
7058 err_msg = "job %s not created under job control";
7059 if (getctl && jp->jobctl == 0)
7060 goto err;
7061#endif
7062 return jp;
7063err:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007064 sh_error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007065}
7066
7067
Eric Andersencb57d552001-06-28 07:25:16 +00007068/*
Eric Andersenc470f442003-07-28 09:56:35 +00007069 * Return a new job structure.
7070 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007071 */
7072
Eric Andersenc470f442003-07-28 09:56:35 +00007073static struct job *
7074makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007075{
7076 int i;
7077 struct job *jp;
7078
Eric Andersenc470f442003-07-28 09:56:35 +00007079 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007080 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007081 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007082 break;
7083 }
7084 if (jp->used == 0)
7085 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007086 if (jp->state != JOBDONE || !jp->waited)
7087 continue;
7088#if JOBS
7089 if (jobctl)
7090 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007091#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007092 freejob(jp);
7093 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007094 }
Eric Andersenc470f442003-07-28 09:56:35 +00007095 memset(jp, 0, sizeof(*jp));
7096#if JOBS
7097 if (jobctl)
7098 jp->jobctl = 1;
7099#endif
7100 jp->prev_job = curjob;
7101 curjob = jp;
7102 jp->used = 1;
7103 jp->ps = &jp->ps0;
7104 if (nprocs > 1) {
7105 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7106 }
7107 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7108 jobno(jp)));
7109 return jp;
7110}
7111
7112static struct job *
7113growjobtab(void)
7114{
7115 size_t len;
7116 ptrdiff_t offset;
7117 struct job *jp, *jq;
7118
7119 len = njobs * sizeof(*jp);
7120 jq = jobtab;
7121 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7122
7123 offset = (char *)jp - (char *)jq;
7124 if (offset) {
7125 /* Relocate pointers */
7126 size_t l = len;
7127
7128 jq = (struct job *)((char *)jq + l);
7129 while (l) {
7130 l -= sizeof(*jp);
7131 jq--;
7132#define joff(p) ((struct job *)((char *)(p) + l))
7133#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007134 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007135 jmove(joff(jp)->ps);
7136 if (joff(jp)->prev_job)
7137 jmove(joff(jp)->prev_job);
7138 }
7139 if (curjob)
7140 jmove(curjob);
7141#undef joff
7142#undef jmove
7143 }
7144
7145 njobs += 4;
7146 jobtab = jp;
7147 jp = (struct job *)((char *)jp + len);
7148 jq = jp + 3;
7149 do {
7150 jq->used = 0;
7151 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007152 return jp;
7153}
7154
7155
7156/*
Eric Andersenc470f442003-07-28 09:56:35 +00007157 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007158 * own process group. Jp is a job structure that the job is to be added to.
7159 * N is the command that will be evaluated by the child. Both jp and n may
7160 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007161 * FORK_FG - Fork off a foreground process.
7162 * FORK_BG - Fork off a background process.
7163 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7164 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007165 *
7166 * When job control is turned off, background processes have their standard
7167 * input redirected to /dev/null (except for the second and later processes
7168 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007169 *
7170 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007171 */
7172
Rob Landley88621d72006-08-29 19:41:06 +00007173static void forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007174{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007175 int oldlvl;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007176
Eric Andersenc470f442003-07-28 09:56:35 +00007177 TRACE(("Child shell %d\n", getpid()));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007178 oldlvl = shlvl;
7179 shlvl++;
Eric Andersenc470f442003-07-28 09:56:35 +00007180
7181 closescript();
7182 clear_traps();
7183#if JOBS
7184 /* do job control only in root shell */
7185 jobctl = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007186 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007187 pid_t pgrp;
7188
7189 if (jp->nprocs == 0)
7190 pgrp = getpid();
7191 else
7192 pgrp = jp->ps[0].pid;
7193 /* This can fail because we are doing it in the parent also */
7194 (void)setpgid(0, pgrp);
7195 if (mode == FORK_FG)
7196 xtcsetpgrp(ttyfd, pgrp);
7197 setsignal(SIGTSTP);
7198 setsignal(SIGTTOU);
7199 } else
Eric Andersen62483552001-07-10 06:09:16 +00007200#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007201 if (mode == FORK_BG) {
7202 ignoresig(SIGINT);
7203 ignoresig(SIGQUIT);
7204 if (jp->nprocs == 0) {
7205 close(0);
Bernhard Reutner-Fischer0a8812b2006-05-19 13:12:21 +00007206 if (open(bb_dev_null, O_RDONLY) != 0)
7207 sh_error("Can't open %s", bb_dev_null);
Eric Andersencb57d552001-06-28 07:25:16 +00007208 }
Eric Andersencb57d552001-06-28 07:25:16 +00007209 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007210 if (!oldlvl && iflag) {
Eric Andersenc470f442003-07-28 09:56:35 +00007211 setsignal(SIGINT);
7212 setsignal(SIGQUIT);
7213 setsignal(SIGTERM);
7214 }
7215 for (jp = curjob; jp; jp = jp->prev_job)
7216 freejob(jp);
7217 jobless = 0;
7218}
7219
Rob Landley88621d72006-08-29 19:41:06 +00007220static void forkparent(struct job *jp, union node *n, int mode, pid_t pid)
Eric Andersenc470f442003-07-28 09:56:35 +00007221{
7222 TRACE(("In parent shell: child = %d\n", pid));
7223 if (!jp) {
7224 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7225 jobless++;
7226 return;
7227 }
7228#if JOBS
7229 if (mode != FORK_NOJOB && jp->jobctl) {
7230 int pgrp;
7231
7232 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007233 pgrp = pid;
7234 else
7235 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007236 /* This can fail because we are doing it in the child also */
7237 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007238 }
Eric Andersen62483552001-07-10 06:09:16 +00007239#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007240 if (mode == FORK_BG) {
7241 backgndpid = pid; /* set $! */
7242 set_curjob(jp, CUR_RUNNING);
7243 }
Eric Andersencb57d552001-06-28 07:25:16 +00007244 if (jp) {
7245 struct procstat *ps = &jp->ps[jp->nprocs++];
7246 ps->pid = pid;
7247 ps->status = -1;
7248 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007249#if JOBS
7250 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007251 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007252#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007253 }
Eric Andersencb57d552001-06-28 07:25:16 +00007254}
7255
Eric Andersenc470f442003-07-28 09:56:35 +00007256static int
7257forkshell(struct job *jp, union node *n, int mode)
7258{
7259 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007260
Eric Andersenc470f442003-07-28 09:56:35 +00007261 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7262 pid = fork();
7263 if (pid < 0) {
7264 TRACE(("Fork failed, errno=%d", errno));
7265 if (jp)
7266 freejob(jp);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007267 sh_error("Cannot fork");
Eric Andersenc470f442003-07-28 09:56:35 +00007268 }
7269 if (pid == 0)
7270 forkchild(jp, n, mode);
7271 else
7272 forkparent(jp, n, mode, pid);
7273 return pid;
7274}
Eric Andersencb57d552001-06-28 07:25:16 +00007275
7276/*
7277 * Wait for job to finish.
7278 *
7279 * Under job control we have the problem that while a child process is
7280 * running interrupts generated by the user are sent to the child but not
7281 * to the shell. This means that an infinite loop started by an inter-
7282 * active user may be hard to kill. With job control turned off, an
7283 * interactive user may place an interactive program inside a loop. If
7284 * the interactive program catches interrupts, the user doesn't want
7285 * these interrupts to also abort the loop. The approach we take here
7286 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007287 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007288 * signal if the child process was terminated by an interrupt signal.
7289 * Unfortunately, some programs want to do a bit of cleanup and then
7290 * exit on interrupt; unless these processes terminate themselves by
7291 * sending a signal to themselves (instead of calling exit) they will
7292 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007293 *
7294 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007295 */
7296
Eric Andersenc470f442003-07-28 09:56:35 +00007297int
7298waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007299{
Eric Andersencb57d552001-06-28 07:25:16 +00007300 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007301
Eric Andersenc470f442003-07-28 09:56:35 +00007302 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7303 while (jp->state == JOBRUNNING) {
7304 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007305 }
Eric Andersenc470f442003-07-28 09:56:35 +00007306 st = getstatus(jp);
7307#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007308 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007309 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007310 /*
7311 * This is truly gross.
7312 * If we're doing job control, then we did a TIOCSPGRP which
7313 * caused us (the shell) to no longer be in the controlling
7314 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7315 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007316 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007317 */
Eric Andersenc470f442003-07-28 09:56:35 +00007318 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007319 raise(SIGINT);
7320 }
Eric Andersen2870d962001-07-02 17:27:21 +00007321 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007322#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007323 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007324 return st;
7325}
7326
7327
Eric Andersen62483552001-07-10 06:09:16 +00007328/*
7329 * Do a wait system call. If job control is compiled in, we accept
7330 * stopped processes. If block is zero, we return a value of zero
7331 * rather than blocking.
7332 *
7333 * System V doesn't have a non-blocking wait system call. It does
7334 * have a SIGCLD signal that is sent to a process when one of it's
7335 * children dies. The obvious way to use SIGCLD would be to install
7336 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7337 * was received, and have waitproc bump another counter when it got
7338 * the status of a process. Waitproc would then know that a wait
7339 * system call would not block if the two counters were different.
7340 * This approach doesn't work because if a process has children that
7341 * have not been waited for, System V will send it a SIGCLD when it
7342 * installs a signal handler for SIGCLD. What this means is that when
7343 * a child exits, the shell will be sent SIGCLD signals continuously
7344 * until is runs out of stack space, unless it does a wait call before
7345 * restoring the signal handler. The code below takes advantage of
7346 * this (mis)feature by installing a signal handler for SIGCLD and
7347 * then checking to see whether it was called. If there are any
7348 * children to be waited for, it will be.
7349 *
Eric Andersenc470f442003-07-28 09:56:35 +00007350 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7351 * waits at all. In this case, the user will not be informed when
7352 * a background process until the next time she runs a real program
7353 * (as opposed to running a builtin command or just typing return),
7354 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007355 */
7356
Rob Landley88621d72006-08-29 19:41:06 +00007357static int waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007358{
Eric Andersenc470f442003-07-28 09:56:35 +00007359 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007360
Eric Andersenc470f442003-07-28 09:56:35 +00007361#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007362 if (jobctl)
7363 flags |= WUNTRACED;
7364#endif
7365 if (block == 0)
7366 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007367 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007368}
7369
Eric Andersenc470f442003-07-28 09:56:35 +00007370/*
7371 * Wait for a process to terminate.
7372 */
7373
7374static int
7375dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007376{
7377 int pid;
7378 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007379 struct job *jp;
7380 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007381 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007382
7383 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007384 pid = waitproc(block, &status);
7385 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007386 if (pid <= 0)
7387 return pid;
7388 INTOFF;
7389 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007390 for (jp = curjob; jp; jp = jp->prev_job) {
7391 struct procstat *sp;
7392 struct procstat *spend;
7393 if (jp->state == JOBDONE)
7394 continue;
7395 state = JOBDONE;
7396 spend = jp->ps + jp->nprocs;
7397 sp = jp->ps;
7398 do {
7399 if (sp->pid == pid) {
7400 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7401 sp->status = status;
7402 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007403 }
Eric Andersenc470f442003-07-28 09:56:35 +00007404 if (sp->status == -1)
7405 state = JOBRUNNING;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007406#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007407 if (state == JOBRUNNING)
7408 continue;
7409 if (WIFSTOPPED(sp->status)) {
7410 jp->stopstatus = sp->status;
7411 state = JOBSTOPPED;
7412 }
Eric Andersencb57d552001-06-28 07:25:16 +00007413#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007414 } while (++sp < spend);
7415 if (thisjob)
7416 goto gotjob;
7417 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007418#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007419 if (!WIFSTOPPED(status))
7420#endif
7421
7422 jobless--;
7423 goto out;
7424
7425gotjob:
7426 if (state != JOBRUNNING) {
7427 thisjob->changed = 1;
7428
7429 if (thisjob->state != state) {
7430 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7431 thisjob->state = state;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007432#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007433 if (state == JOBSTOPPED) {
7434 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007435 }
Eric Andersenc470f442003-07-28 09:56:35 +00007436#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007437 }
7438 }
Eric Andersencb57d552001-06-28 07:25:16 +00007439
Eric Andersenc470f442003-07-28 09:56:35 +00007440out:
7441 INTON;
7442
7443 if (thisjob && thisjob == job) {
7444 char s[48 + 1];
7445 int len;
7446
7447 len = sprint_status(s, status, 1);
7448 if (len) {
7449 s[len] = '\n';
7450 s[len + 1] = 0;
7451 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007452 }
Eric Andersencb57d552001-06-28 07:25:16 +00007453 }
7454 return pid;
7455}
7456
7457
Eric Andersencb57d552001-06-28 07:25:16 +00007458/*
7459 * return 1 if there are stopped jobs, otherwise 0
7460 */
Eric Andersen90898442003-08-06 11:20:52 +00007461
Eric Andersenc470f442003-07-28 09:56:35 +00007462int
7463stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007464{
Eric Andersencb57d552001-06-28 07:25:16 +00007465 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007466 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007467
Eric Andersenc470f442003-07-28 09:56:35 +00007468 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007469 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007470 goto out;
7471 jp = curjob;
7472 if (jp && jp->state == JOBSTOPPED) {
7473 out2str("You have stopped jobs.\n");
7474 job_warning = 2;
7475 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007476 }
7477
Eric Andersenc470f442003-07-28 09:56:35 +00007478out:
7479 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007480}
7481
7482/*
7483 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007484 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007485 */
7486
Eric Andersenc470f442003-07-28 09:56:35 +00007487#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007488static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007489
Eric Andersenc470f442003-07-28 09:56:35 +00007490static char *
7491commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007492{
Eric Andersenc470f442003-07-28 09:56:35 +00007493 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007494
Eric Andersenc470f442003-07-28 09:56:35 +00007495 STARTSTACKSTR(cmdnextc);
7496 cmdtxt(n);
7497 name = stackblock();
7498 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7499 name, cmdnextc, cmdnextc));
7500 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007501}
7502
Eric Andersenc470f442003-07-28 09:56:35 +00007503static void
7504cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007505{
Eric Andersencb57d552001-06-28 07:25:16 +00007506 union node *np;
7507 struct nodelist *lp;
7508 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007509 char s[2];
7510
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007511 if (!n)
7512 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007513 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007514 default:
7515#if DEBUG
7516 abort();
7517#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007518 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007519 lp = n->npipe.cmdlist;
7520 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007521 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007522 lp = lp->next;
7523 if (!lp)
7524 break;
7525 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007526 }
7527 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007528 case NSEMI:
7529 p = "; ";
7530 goto binop;
7531 case NAND:
7532 p = " && ";
7533 goto binop;
7534 case NOR:
7535 p = " || ";
7536binop:
7537 cmdtxt(n->nbinary.ch1);
7538 cmdputs(p);
7539 n = n->nbinary.ch2;
7540 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007541 case NREDIR:
7542 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007543 n = n->nredir.n;
7544 goto donode;
7545 case NNOT:
7546 cmdputs("!");
7547 n = n->nnot.com;
7548donode:
7549 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007550 break;
7551 case NIF:
7552 cmdputs("if ");
7553 cmdtxt(n->nif.test);
7554 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007555 n = n->nif.ifpart;
7556 if (n->nif.elsepart) {
7557 cmdtxt(n);
7558 cmdputs("; else ");
7559 n = n->nif.elsepart;
7560 }
7561 p = "; fi";
7562 goto dotail;
7563 case NSUBSHELL:
7564 cmdputs("(");
7565 n = n->nredir.n;
7566 p = ")";
7567 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007568 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007569 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007570 goto until;
7571 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007572 p = "until ";
7573until:
7574 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007575 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007576 n = n->nbinary.ch2;
7577 p = "; done";
7578dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007579 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007580dotail:
7581 cmdtxt(n);
7582 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007583 case NFOR:
7584 cmdputs("for ");
7585 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007586 cmdputs(" in ");
7587 cmdlist(n->nfor.args, 1);
7588 n = n->nfor.body;
7589 p = "; done";
7590 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007591 case NDEFUN:
7592 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007593 p = "() { ... }";
7594 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007595 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007596 cmdlist(n->ncmd.args, 1);
7597 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007598 break;
7599 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007600 p = n->narg.text;
7601dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007602 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007603 break;
7604 case NHERE:
7605 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007606 p = "<<...";
7607 goto dotail2;
7608 case NCASE:
7609 cmdputs("case ");
7610 cmdputs(n->ncase.expr->narg.text);
7611 cmdputs(" in ");
7612 for (np = n->ncase.cases; np; np = np->nclist.next) {
7613 cmdtxt(np->nclist.pattern);
7614 cmdputs(") ");
7615 cmdtxt(np->nclist.body);
7616 cmdputs(";; ");
7617 }
7618 p = "esac";
7619 goto dotail2;
7620 case NTO:
7621 p = ">";
7622 goto redir;
7623 case NCLOBBER:
7624 p = ">|";
7625 goto redir;
7626 case NAPPEND:
7627 p = ">>";
7628 goto redir;
7629 case NTOFD:
7630 p = ">&";
7631 goto redir;
7632 case NFROM:
7633 p = "<";
7634 goto redir;
7635 case NFROMFD:
7636 p = "<&";
7637 goto redir;
7638 case NFROMTO:
7639 p = "<>";
7640redir:
7641 s[0] = n->nfile.fd + '0';
7642 s[1] = '\0';
7643 cmdputs(s);
7644 cmdputs(p);
7645 if (n->type == NTOFD || n->type == NFROMFD) {
7646 s[0] = n->ndup.dupfd + '0';
7647 p = s;
7648 goto dotail2;
7649 } else {
7650 n = n->nfile.fname;
7651 goto donode;
7652 }
Eric Andersencb57d552001-06-28 07:25:16 +00007653 }
7654}
Eric Andersencb57d552001-06-28 07:25:16 +00007655
Eric Andersenc470f442003-07-28 09:56:35 +00007656static void
7657cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007658{
Eric Andersenc470f442003-07-28 09:56:35 +00007659 for (; np; np = np->narg.next) {
7660 if (!sep)
7661 cmdputs(spcstr);
7662 cmdtxt(np);
7663 if (sep && np->narg.next)
7664 cmdputs(spcstr);
7665 }
Eric Andersencb57d552001-06-28 07:25:16 +00007666}
7667
Eric Andersenc470f442003-07-28 09:56:35 +00007668static void
7669cmdputs(const char *s)
7670{
7671 const char *p, *str;
7672 char c, cc[2] = " ";
7673 char *nextc;
7674 int subtype = 0;
7675 int quoted = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007676 static const char vstype[VSTYPE + 1][4] = {
7677 "", "}", "-", "+", "?", "=",
7678 "%", "%%", "#", "##"
Eric Andersenc470f442003-07-28 09:56:35 +00007679 };
Eric Andersenc470f442003-07-28 09:56:35 +00007680 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7681 p = s;
7682 while ((c = *p++) != 0) {
7683 str = 0;
7684 switch (c) {
7685 case CTLESC:
7686 c = *p++;
7687 break;
7688 case CTLVAR:
7689 subtype = *p++;
7690 if ((subtype & VSTYPE) == VSLENGTH)
7691 str = "${#";
7692 else
7693 str = "${";
7694 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7695 quoted ^= 1;
7696 c = '"';
7697 } else
7698 goto dostr;
7699 break;
7700 case CTLENDVAR:
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007701 str = "\"}" + !(quoted & 1);
Eric Andersenc470f442003-07-28 09:56:35 +00007702 quoted >>= 1;
7703 subtype = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007704 goto dostr;
Eric Andersenc470f442003-07-28 09:56:35 +00007705 case CTLBACKQ:
7706 str = "$(...)";
7707 goto dostr;
7708 case CTLBACKQ+CTLQUOTE:
7709 str = "\"$(...)\"";
7710 goto dostr;
7711#ifdef CONFIG_ASH_MATH_SUPPORT
7712 case CTLARI:
7713 str = "$((";
7714 goto dostr;
7715 case CTLENDARI:
7716 str = "))";
7717 goto dostr;
7718#endif
7719 case CTLQUOTEMARK:
7720 quoted ^= 1;
7721 c = '"';
7722 break;
7723 case '=':
7724 if (subtype == 0)
7725 break;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007726 if ((subtype & VSTYPE) != VSNORMAL)
7727 quoted <<= 1;
Eric Andersenc470f442003-07-28 09:56:35 +00007728 str = vstype[subtype & VSTYPE];
7729 if (subtype & VSNUL)
7730 c = ':';
7731 else
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007732 goto checkstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007733 break;
7734 case '\'':
7735 case '\\':
7736 case '"':
7737 case '$':
7738 /* These can only happen inside quotes */
7739 cc[0] = c;
7740 str = cc;
7741 c = '\\';
7742 break;
7743 default:
7744 break;
7745 }
7746 USTPUTC(c, nextc);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007747checkstr:
Eric Andersenc470f442003-07-28 09:56:35 +00007748 if (!str)
7749 continue;
7750dostr:
7751 while ((c = *str++)) {
7752 USTPUTC(c, nextc);
7753 }
7754 }
7755 if (quoted & 1) {
7756 USTPUTC('"', nextc);
7757 }
7758 *nextc = 0;
7759 cmdnextc = nextc;
7760}
7761
7762
7763static void
7764showpipe(struct job *jp, FILE *out)
7765{
7766 struct procstat *sp;
7767 struct procstat *spend;
7768
7769 spend = jp->ps + jp->nprocs;
7770 for (sp = jp->ps + 1; sp < spend; sp++)
7771 fprintf(out, " | %s", sp->cmd);
7772 outcslow('\n', out);
7773 flushall();
7774}
7775
7776static void
7777xtcsetpgrp(int fd, pid_t pgrp)
7778{
7779 if (tcsetpgrp(fd, pgrp))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007780 sh_error("Cannot set tty process group (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +00007781}
7782#endif /* JOBS */
7783
7784static int
7785getstatus(struct job *job) {
7786 int status;
7787 int retval;
7788
7789 status = job->ps[job->nprocs - 1].status;
7790 retval = WEXITSTATUS(status);
7791 if (!WIFEXITED(status)) {
7792#if JOBS
7793 retval = WSTOPSIG(status);
7794 if (!WIFSTOPPED(status))
7795#endif
7796 {
7797 /* XXX: limits number of signals */
7798 retval = WTERMSIG(status);
7799#if JOBS
7800 if (retval == SIGINT)
7801 job->sigint = 1;
7802#endif
7803 }
7804 retval += 128;
7805 }
7806 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7807 jobno(job), job->nprocs, status, retval));
7808 return retval;
7809}
7810
Eric Andersend35c5df2002-01-09 15:37:36 +00007811#ifdef CONFIG_ASH_MAIL
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007812/* mail.c */
Eric Andersenec074692001-10-31 11:05:49 +00007813
Eric Andersencb57d552001-06-28 07:25:16 +00007814/*
Eric Andersenc470f442003-07-28 09:56:35 +00007815 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007816 */
7817
Eric Andersencb57d552001-06-28 07:25:16 +00007818#define MAXMBOXES 10
7819
Eric Andersenc470f442003-07-28 09:56:35 +00007820/* times of mailboxes */
7821static time_t mailtime[MAXMBOXES];
7822/* Set if MAIL or MAILPATH is changed. */
7823static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007824
7825
7826
7827/*
Eric Andersenc470f442003-07-28 09:56:35 +00007828 * Print appropriate message(s) if mail has arrived.
7829 * If mail_var_path_changed is set,
7830 * then the value of MAIL has mail_var_path_changed,
7831 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007832 */
7833
Eric Andersenc470f442003-07-28 09:56:35 +00007834static void
7835chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007836{
Eric Andersencb57d552001-06-28 07:25:16 +00007837 const char *mpath;
7838 char *p;
7839 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007840 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007841 struct stackmark smark;
7842 struct stat statb;
7843
Eric Andersencb57d552001-06-28 07:25:16 +00007844 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007845 mpath = mpathset() ? mpathval() : mailval();
7846 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007847 p = padvance(&mpath, nullstr);
7848 if (p == NULL)
7849 break;
7850 if (*p == '\0')
7851 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007852 for (q = p ; *q ; q++);
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00007853#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00007854 if (q[-1] != '/')
7855 abort();
7856#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007857 q[-1] = '\0'; /* delete trailing '/' */
7858 if (stat(p, &statb) < 0) {
7859 *mtp = 0;
7860 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007861 }
Eric Andersenc470f442003-07-28 09:56:35 +00007862 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7863 fprintf(
7864 stderr, snlfmt,
7865 pathopt ? pathopt : "you have mail"
7866 );
7867 }
7868 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007869 }
Eric Andersenc470f442003-07-28 09:56:35 +00007870 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007871 popstackmark(&smark);
7872}
Eric Andersencb57d552001-06-28 07:25:16 +00007873
Eric Andersenec074692001-10-31 11:05:49 +00007874
Eric Andersenc470f442003-07-28 09:56:35 +00007875static void
7876changemail(const char *val)
7877{
7878 mail_var_path_changed++;
7879}
7880
7881#endif /* CONFIG_ASH_MAIL */
7882
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007883/* main.c */
Eric Andersenc470f442003-07-28 09:56:35 +00007884
Eric Andersencb57d552001-06-28 07:25:16 +00007885
Eric Andersencb57d552001-06-28 07:25:16 +00007886#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007887static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007888extern int etext();
7889#endif
7890
Eric Andersenc470f442003-07-28 09:56:35 +00007891static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007892
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007893static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007894
Eric Andersencb57d552001-06-28 07:25:16 +00007895/*
7896 * Main routine. We initialize things, parse the arguments, execute
7897 * profiles if we're a login shell, and then call cmdloop to execute
7898 * commands. The setjmp call sets up the location to jump to when an
7899 * exception occurs. When an exception occurs the variable "state"
7900 * is used to figure out how far we had gotten.
7901 */
7902
Eric Andersenc470f442003-07-28 09:56:35 +00007903int
7904ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007905{
Eric Andersenc470f442003-07-28 09:56:35 +00007906 char *shinit;
7907 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007908 struct jmploc jmploc;
7909 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007910
Eric Andersenc470f442003-07-28 09:56:35 +00007911#ifdef __GLIBC__
7912 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007913#endif
7914
Eric Andersencb57d552001-06-28 07:25:16 +00007915#if PROFILE
7916 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7917#endif
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00007918
Denis Vlasenko38f63192007-01-22 09:03:07 +00007919#if ENABLE_FEATURE_EDITING
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00007920 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
7921#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007922 state = 0;
7923 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007924 int e;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007925 int s;
Eric Andersenc470f442003-07-28 09:56:35 +00007926
Eric Andersencb57d552001-06-28 07:25:16 +00007927 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007928
7929 e = exception;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007930 if (e == EXERROR)
7931 exitstatus = 2;
7932 s = state;
7933 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00007934 exitshell();
7935
Eric Andersen90898442003-08-06 11:20:52 +00007936 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007937 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007938 }
7939 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007940 FORCEINTON; /* enable interrupts */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007941 if (s == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00007942 goto state1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007943 else if (s == 2)
Eric Andersencb57d552001-06-28 07:25:16 +00007944 goto state2;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007945 else if (s == 3)
Eric Andersencb57d552001-06-28 07:25:16 +00007946 goto state3;
7947 else
7948 goto state4;
7949 }
7950 handler = &jmploc;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00007951#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00007952 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007953 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007954#endif
7955 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007956
7957#ifdef CONFIG_ASH_RANDOM_SUPPORT
7958 rseed = rootpid + ((time_t)time((time_t *)0));
7959#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007960 init();
7961 setstackmark(&smark);
7962 procargs(argc, argv);
Denis Vlasenko38f63192007-01-22 09:03:07 +00007963#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00007964 if (iflag) {
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007965 const char *hp = lookupvar("HISTFILE");
7966
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00007967 if (hp == NULL) {
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007968 hp = lookupvar("HOME");
7969 if(hp != NULL) {
7970 char *defhp = concat_path_file(hp, ".ash_history");
7971 setvar("HISTFILE", defhp, 0);
7972 free(defhp);
7973 }
7974 }
7975 }
7976#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007977 if (argv[0] && argv[0][0] == '-')
7978 isloginsh = 1;
7979 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007980 state = 1;
7981 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007982state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007983 state = 2;
7984 read_profile(".profile");
7985 }
Eric Andersenc470f442003-07-28 09:56:35 +00007986state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007987 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007988 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007989#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007990 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007991#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007992 iflag
7993 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007994 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007995 read_profile(shinit);
7996 }
Eric Andersencb57d552001-06-28 07:25:16 +00007997 }
Eric Andersenc470f442003-07-28 09:56:35 +00007998state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007999 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00008000 if (minusc)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008001 evalstring(minusc, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00008002
8003 if (sflag || minusc == NULL) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00008004#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00008005 if ( iflag ) {
8006 const char *hp = lookupvar("HISTFILE");
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00008007
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00008008 if (hp != NULL)
8009 line_input_state->hist_file = hp;
8010 }
Robert Griebl350d26b2002-12-03 22:45:46 +00008011#endif
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00008012 state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00008013 cmdloop(1);
8014 }
8015#if PROFILE
8016 monitor(0);
8017#endif
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008018#ifdef GPROF
Eric Andersenc470f442003-07-28 09:56:35 +00008019 {
8020 extern void _mcleanup(void);
8021 _mcleanup();
8022 }
8023#endif
8024 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00008025 /* NOTREACHED */
8026}
8027
8028
8029/*
8030 * Read and execute commands. "Top" is nonzero for the top level command
8031 * loop; it turns on prompting if the shell is interactive.
8032 */
8033
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008034static int
Eric Andersenc470f442003-07-28 09:56:35 +00008035cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008036{
8037 union node *n;
8038 struct stackmark smark;
8039 int inter;
8040 int numeof = 0;
8041
8042 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008043 for (;;) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008044 int skip;
8045
Glenn L McGrath76620622004-01-13 10:19:37 +00008046 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00008047#if JOBS
8048 if (jobctl)
8049 showjobs(stderr, SHOW_CHANGED);
8050#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008051 inter = 0;
8052 if (iflag && top) {
8053 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008054#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008055 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008056#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008057 }
8058 n = parsecmd(inter);
8059 /* showtree(n); DEBUG */
8060 if (n == NEOF) {
8061 if (!top || numeof >= 50)
8062 break;
8063 if (!stoppedjobs()) {
8064 if (!Iflag)
8065 break;
8066 out2str("\nUse \"exit\" to leave shell.\n");
8067 }
8068 numeof++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008069 } else if (nflag == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008070 job_warning = (job_warning == 2) ? 1 : 0;
8071 numeof = 0;
8072 evaltree(n, 0);
8073 }
8074 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008075 skip = evalskip;
8076
8077 if (skip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008078 evalskip = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008079 return skip & SKIPEVAL;
Eric Andersencb57d552001-06-28 07:25:16 +00008080 }
8081 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008082
8083 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008084}
8085
8086
Eric Andersencb57d552001-06-28 07:25:16 +00008087/*
8088 * Read /etc/profile or .profile. Return on error.
8089 */
8090
Eric Andersenc470f442003-07-28 09:56:35 +00008091static void
8092read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008093{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008094 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008095
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008096 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008097 return;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008098
8099 skip = cmdloop(0);
Eric Andersencb57d552001-06-28 07:25:16 +00008100 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008101
8102 if (skip)
8103 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00008104}
8105
8106
Eric Andersencb57d552001-06-28 07:25:16 +00008107/*
8108 * Read a file containing shell functions.
8109 */
8110
Eric Andersenc470f442003-07-28 09:56:35 +00008111static void
8112readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008113{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008114 setinputfile(name, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008115 cmdloop(0);
8116 popfile();
8117}
8118
8119
Eric Andersencb57d552001-06-28 07:25:16 +00008120/*
Eric Andersenc470f442003-07-28 09:56:35 +00008121 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008122 * search for the file, which is necessary to find sub-commands.
8123 */
8124
Rob Landley88621d72006-08-29 19:41:06 +00008125static char * find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008126{
8127 char *fullname;
8128 const char *path = pathval();
8129 struct stat statb;
8130
8131 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008132 if (strchr(name, '/'))
8133 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008134
Eric Andersenc470f442003-07-28 09:56:35 +00008135 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008136 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8137 /*
8138 * Don't bother freeing here, since it will
8139 * be freed by the caller.
8140 */
8141 return fullname;
8142 }
8143 stunalloc(fullname);
8144 }
8145
8146 /* not found in the PATH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008147 sh_error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008148 /* NOTREACHED */
8149}
8150
Eric Andersen1e6aba92004-04-12 19:12:13 +00008151static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008152{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008153 struct strlist *sp;
8154 volatile struct shparam saveparam;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008155 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008156
Eric Andersen1e6aba92004-04-12 19:12:13 +00008157 for (sp = cmdenviron; sp; sp = sp->next)
Rob Landleyd921b2e2006-08-03 15:41:12 +00008158 setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008159
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00008160 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008161 char *fullname;
Eric Andersencb57d552001-06-28 07:25:16 +00008162
Eric Andersencb57d552001-06-28 07:25:16 +00008163 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008164
8165 if (argc > 2) {
8166 saveparam = shellparam;
8167 shellparam.malloc = 0;
8168 shellparam.nparam = argc - 2;
8169 shellparam.p = argv + 2;
8170 };
8171
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008172 setinputfile(fullname, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008173 commandname = fullname;
8174 cmdloop(0);
8175 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008176
8177 if (argc > 2) {
8178 freeparam(&shellparam);
8179 shellparam = saveparam;
8180 };
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008181 status = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00008182 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008183 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008184}
8185
8186
Eric Andersenc470f442003-07-28 09:56:35 +00008187static int
8188exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008189{
8190 if (stoppedjobs())
8191 return 0;
8192 if (argc > 1)
8193 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008194 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008195 /* NOTREACHED */
8196}
Eric Andersen62483552001-07-10 06:09:16 +00008197
Paul Fox0b621582005-08-09 19:38:05 +00008198#ifdef CONFIG_ASH_BUILTIN_ECHO
8199static int
8200echocmd(int argc, char **argv)
8201{
Denis Vlasenkobf66fbc2006-12-21 13:23:14 +00008202 return bb_echo(argv);
Paul Fox0b621582005-08-09 19:38:05 +00008203}
8204#endif
Paul Fox6ab03782006-06-08 21:37:26 +00008205
8206#ifdef CONFIG_ASH_BUILTIN_TEST
8207static int
8208testcmd(int argc, char **argv)
8209{
8210 return bb_test(argc, argv);
8211}
8212#endif
8213
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008214/* memalloc.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008215
8216/*
Eric Andersen90898442003-08-06 11:20:52 +00008217 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008218 */
8219
8220static pointer
8221ckrealloc(pointer p, size_t nbytes)
8222{
8223 p = realloc(p, nbytes);
8224 if (p == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008225 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008226 return p;
8227}
8228
Eric Andersen90898442003-08-06 11:20:52 +00008229static pointer
8230ckmalloc(size_t nbytes)
8231{
8232 return ckrealloc(NULL, nbytes);
8233}
Eric Andersenc470f442003-07-28 09:56:35 +00008234
8235/*
8236 * Make a copy of a string in safe storage.
8237 */
8238
8239static char *
8240savestr(const char *s)
8241{
8242 char *p = strdup(s);
8243 if (!p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008244 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008245 return p;
8246}
8247
8248
8249/*
8250 * Parse trees for commands are allocated in lifo order, so we use a stack
8251 * to make this more efficient, and also to avoid all sorts of exception
8252 * handling code to handle interrupts in the middle of a parse.
8253 *
8254 * The size 504 was chosen because the Ultrix malloc handles that size
8255 * well.
8256 */
8257
8258
8259static pointer
8260stalloc(size_t nbytes)
8261{
8262 char *p;
8263 size_t aligned;
8264
8265 aligned = SHELL_ALIGN(nbytes);
8266 if (aligned > stacknleft) {
8267 size_t len;
8268 size_t blocksize;
8269 struct stack_block *sp;
8270
8271 blocksize = aligned;
8272 if (blocksize < MINSIZE)
8273 blocksize = MINSIZE;
8274 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8275 if (len < blocksize)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008276 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008277 INTOFF;
8278 sp = ckmalloc(len);
8279 sp->prev = stackp;
8280 stacknxt = sp->space;
8281 stacknleft = blocksize;
8282 sstrend = stacknxt + blocksize;
8283 stackp = sp;
8284 INTON;
8285 }
8286 p = stacknxt;
8287 stacknxt += aligned;
8288 stacknleft -= aligned;
8289 return p;
8290}
8291
8292
8293void
8294stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008295{
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008296#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008297 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008298 write(2, "stunalloc\n", 10);
8299 abort();
8300 }
8301#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008302 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008303 stacknxt = p;
8304}
8305
8306
Eric Andersenc470f442003-07-28 09:56:35 +00008307void
8308setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008309{
Eric Andersencb57d552001-06-28 07:25:16 +00008310 mark->stackp = stackp;
8311 mark->stacknxt = stacknxt;
8312 mark->stacknleft = stacknleft;
8313 mark->marknext = markp;
8314 markp = mark;
8315}
8316
8317
Eric Andersenc470f442003-07-28 09:56:35 +00008318void
8319popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008320{
Eric Andersencb57d552001-06-28 07:25:16 +00008321 struct stack_block *sp;
8322
8323 INTOFF;
8324 markp = mark->marknext;
8325 while (stackp != mark->stackp) {
8326 sp = stackp;
8327 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008328 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008329 }
8330 stacknxt = mark->stacknxt;
8331 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008332 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008333 INTON;
8334}
8335
8336
8337/*
8338 * When the parser reads in a string, it wants to stick the string on the
8339 * stack and only adjust the stack pointer when it knows how big the
8340 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8341 * of space on top of the stack and stackblocklen returns the length of
8342 * this block. Growstackblock will grow this space by at least one byte,
8343 * possibly moving it (like realloc). Grabstackblock actually allocates the
8344 * part of the block that has been used.
8345 */
8346
Eric Andersenc470f442003-07-28 09:56:35 +00008347void
8348growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008349{
Eric Andersenc470f442003-07-28 09:56:35 +00008350 size_t newlen;
8351
8352 newlen = stacknleft * 2;
8353 if (newlen < stacknleft)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008354 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008355 if (newlen < 128)
8356 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008357
8358 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008359 struct stack_block *oldstackp;
8360 struct stackmark *xmark;
8361 struct stack_block *sp;
8362 struct stack_block *prevstackp;
8363 size_t grosslen;
8364
Eric Andersencb57d552001-06-28 07:25:16 +00008365 INTOFF;
8366 oldstackp = stackp;
8367 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008368 prevstackp = sp->prev;
8369 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8370 sp = ckrealloc((pointer)sp, grosslen);
8371 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008372 stackp = sp;
8373 stacknxt = sp->space;
8374 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008375 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008376
Eric Andersenc470f442003-07-28 09:56:35 +00008377 /*
8378 * Stack marks pointing to the start of the old block
8379 * must be relocated to point to the new block
8380 */
8381 xmark = markp;
8382 while (xmark != NULL && xmark->stackp == oldstackp) {
8383 xmark->stackp = stackp;
8384 xmark->stacknxt = stacknxt;
8385 xmark->stacknleft = stacknleft;
8386 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008387 }
8388 INTON;
8389 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008390 char *oldspace = stacknxt;
8391 int oldlen = stacknleft;
8392 char *p = stalloc(newlen);
8393
8394 /* free the space we just allocated */
8395 stacknxt = memcpy(p, oldspace, oldlen);
8396 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008397 }
8398}
8399
Rob Landley88621d72006-08-29 19:41:06 +00008400static void grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008401{
Eric Andersenc470f442003-07-28 09:56:35 +00008402 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008403 stacknxt += len;
8404 stacknleft -= len;
8405}
8406
Eric Andersencb57d552001-06-28 07:25:16 +00008407/*
Eric Andersenc470f442003-07-28 09:56:35 +00008408 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008409 * The user declares a variable of type STACKSTR, which may be declared
8410 * to be a register. The macro STARTSTACKSTR initializes things. Then
8411 * the user uses the macro STPUTC to add characters to the string. In
8412 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8413 * grown as necessary. When the user is done, she can just leave the
8414 * string there and refer to it using stackblock(). Or she can allocate
8415 * the space for it using grabstackstr(). If it is necessary to allow
8416 * someone else to use the stack temporarily and then continue to grow
8417 * the string, the user should use grabstack to allocate the space, and
8418 * then call ungrabstr(p) to return to the previous mode of operation.
8419 *
8420 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8421 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8422 * is space for at least one character.
8423 */
8424
Eric Andersenc470f442003-07-28 09:56:35 +00008425void *
8426growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008427{
Eric Andersenc470f442003-07-28 09:56:35 +00008428 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008429 if (herefd >= 0 && len >= 1024) {
Rob Landley53437472006-07-16 08:14:35 +00008430 full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008431 return stackblock();
8432 }
8433 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008434 return stackblock() + len;
8435}
8436
Eric Andersencb57d552001-06-28 07:25:16 +00008437/*
8438 * Called from CHECKSTRSPACE.
8439 */
8440
Eric Andersenc470f442003-07-28 09:56:35 +00008441char *
8442makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008443{
Eric Andersenc470f442003-07-28 09:56:35 +00008444 size_t len = p - stacknxt;
8445 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008446
Eric Andersenc470f442003-07-28 09:56:35 +00008447 for (;;) {
8448 size_t nleft;
8449
8450 size = stackblocksize();
8451 nleft = size - len;
8452 if (nleft >= newlen)
8453 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008454 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008455 }
Eric Andersencb57d552001-06-28 07:25:16 +00008456 return stackblock() + len;
8457}
8458
Eric Andersenc470f442003-07-28 09:56:35 +00008459char *
8460stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008461{
Eric Andersenc470f442003-07-28 09:56:35 +00008462 p = makestrspace(n, p);
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008463 p = memcpy(p, s, n) + n;
Eric Andersenc470f442003-07-28 09:56:35 +00008464 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008465}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008466
Eric Andersenc470f442003-07-28 09:56:35 +00008467char *
8468stputs(const char *s, char *p)
8469{
8470 return stnputs(s, strlen(s), p);
8471}
8472
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008473/* mystring.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008474
Eric Andersencb57d552001-06-28 07:25:16 +00008475/*
Eric Andersenc470f442003-07-28 09:56:35 +00008476 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008477 *
Eric Andersenc470f442003-07-28 09:56:35 +00008478 * number(s) Convert a string of digits to an integer.
8479 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008480 */
8481
Eric Andersencb57d552001-06-28 07:25:16 +00008482/*
8483 * prefix -- see if pfx is a prefix of string.
8484 */
8485
Eric Andersenc470f442003-07-28 09:56:35 +00008486char *
8487prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008488{
Eric Andersencb57d552001-06-28 07:25:16 +00008489 while (*pfx) {
8490 if (*pfx++ != *string++)
8491 return 0;
8492 }
Eric Andersenc470f442003-07-28 09:56:35 +00008493 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008494}
8495
8496
8497/*
8498 * Convert a string of digits to an integer, printing an error message on
8499 * failure.
8500 */
8501
Eric Andersenc470f442003-07-28 09:56:35 +00008502int
8503number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008504{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008505
Eric Andersenc470f442003-07-28 09:56:35 +00008506 if (! is_number(s))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008507 sh_error(illnum, s);
Eric Andersenc470f442003-07-28 09:56:35 +00008508 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008509}
8510
Eric Andersenc470f442003-07-28 09:56:35 +00008511
Eric Andersenc470f442003-07-28 09:56:35 +00008512/*
8513 * Check for a valid number. This should be elsewhere.
8514 */
8515
8516int
8517is_number(const char *p)
8518{
8519 do {
8520 if (! is_digit(*p))
8521 return 0;
8522 } while (*++p != '\0');
8523 return 1;
8524}
8525
8526
Eric Andersencb57d552001-06-28 07:25:16 +00008527/*
8528 * Produce a possibly single quoted string suitable as input to the shell.
8529 * The return string is allocated on the stack.
8530 */
8531
Eric Andersenc470f442003-07-28 09:56:35 +00008532char *
8533single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008534 char *p;
8535
8536 STARTSTACKSTR(p);
8537
8538 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008539 char *q;
8540 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008541
Eric Andersenc470f442003-07-28 09:56:35 +00008542 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008543
Eric Andersenc470f442003-07-28 09:56:35 +00008544 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008545
Eric Andersenc470f442003-07-28 09:56:35 +00008546 *q++ = '\'';
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008547 q = memcpy(q, s, len) + len;
Eric Andersenc470f442003-07-28 09:56:35 +00008548 *q++ = '\'';
8549 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008550
Eric Andersenc470f442003-07-28 09:56:35 +00008551 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008552
Eric Andersenc470f442003-07-28 09:56:35 +00008553 len = strspn(s, "'");
8554 if (!len)
8555 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008556
Eric Andersenc470f442003-07-28 09:56:35 +00008557 q = p = makestrspace(len + 3, p);
8558
8559 *q++ = '"';
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008560 q = memcpy(q, s, len) + len;
Eric Andersenc470f442003-07-28 09:56:35 +00008561 *q++ = '"';
8562 s += len;
8563
8564 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008565 } while (*s);
8566
8567 USTPUTC(0, p);
8568
Eric Andersenc470f442003-07-28 09:56:35 +00008569 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008570}
8571
8572/*
Eric Andersenc470f442003-07-28 09:56:35 +00008573 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008574 */
8575
Eric Andersenc470f442003-07-28 09:56:35 +00008576char *
8577sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008578{
Eric Andersenc470f442003-07-28 09:56:35 +00008579 size_t len = strlen(p) + 1;
8580 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008581}
Eric Andersenc470f442003-07-28 09:56:35 +00008582
8583
8584static void
8585calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008586{
Eric Andersenc470f442003-07-28 09:56:35 +00008587 if (n == NULL)
8588 return;
8589 funcblocksize += nodesize[n->type];
8590 switch (n->type) {
8591 case NCMD:
8592 calcsize(n->ncmd.redirect);
8593 calcsize(n->ncmd.args);
8594 calcsize(n->ncmd.assign);
8595 break;
8596 case NPIPE:
8597 sizenodelist(n->npipe.cmdlist);
8598 break;
8599 case NREDIR:
8600 case NBACKGND:
8601 case NSUBSHELL:
8602 calcsize(n->nredir.redirect);
8603 calcsize(n->nredir.n);
8604 break;
8605 case NAND:
8606 case NOR:
8607 case NSEMI:
8608 case NWHILE:
8609 case NUNTIL:
8610 calcsize(n->nbinary.ch2);
8611 calcsize(n->nbinary.ch1);
8612 break;
8613 case NIF:
8614 calcsize(n->nif.elsepart);
8615 calcsize(n->nif.ifpart);
8616 calcsize(n->nif.test);
8617 break;
8618 case NFOR:
8619 funcstringsize += strlen(n->nfor.var) + 1;
8620 calcsize(n->nfor.body);
8621 calcsize(n->nfor.args);
8622 break;
8623 case NCASE:
8624 calcsize(n->ncase.cases);
8625 calcsize(n->ncase.expr);
8626 break;
8627 case NCLIST:
8628 calcsize(n->nclist.body);
8629 calcsize(n->nclist.pattern);
8630 calcsize(n->nclist.next);
8631 break;
8632 case NDEFUN:
8633 case NARG:
8634 sizenodelist(n->narg.backquote);
8635 funcstringsize += strlen(n->narg.text) + 1;
8636 calcsize(n->narg.next);
8637 break;
8638 case NTO:
8639 case NCLOBBER:
8640 case NFROM:
8641 case NFROMTO:
8642 case NAPPEND:
8643 calcsize(n->nfile.fname);
8644 calcsize(n->nfile.next);
8645 break;
8646 case NTOFD:
8647 case NFROMFD:
8648 calcsize(n->ndup.vname);
8649 calcsize(n->ndup.next);
8650 break;
8651 case NHERE:
8652 case NXHERE:
8653 calcsize(n->nhere.doc);
8654 calcsize(n->nhere.next);
8655 break;
8656 case NNOT:
8657 calcsize(n->nnot.com);
8658 break;
8659 };
Eric Andersencb57d552001-06-28 07:25:16 +00008660}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008661
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008662
Eric Andersenc470f442003-07-28 09:56:35 +00008663static void
8664sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008665{
8666 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008667 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008668 calcsize(lp->n);
8669 lp = lp->next;
8670 }
8671}
Eric Andersencb57d552001-06-28 07:25:16 +00008672
8673
Eric Andersenc470f442003-07-28 09:56:35 +00008674static union node *
8675copynode(union node *n)
8676{
8677 union node *new;
8678
8679 if (n == NULL)
8680 return NULL;
8681 new = funcblock;
8682 funcblock = (char *) funcblock + nodesize[n->type];
8683 switch (n->type) {
8684 case NCMD:
8685 new->ncmd.redirect = copynode(n->ncmd.redirect);
8686 new->ncmd.args = copynode(n->ncmd.args);
8687 new->ncmd.assign = copynode(n->ncmd.assign);
8688 break;
8689 case NPIPE:
8690 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8691 new->npipe.backgnd = n->npipe.backgnd;
8692 break;
8693 case NREDIR:
8694 case NBACKGND:
8695 case NSUBSHELL:
8696 new->nredir.redirect = copynode(n->nredir.redirect);
8697 new->nredir.n = copynode(n->nredir.n);
8698 break;
8699 case NAND:
8700 case NOR:
8701 case NSEMI:
8702 case NWHILE:
8703 case NUNTIL:
8704 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8705 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8706 break;
8707 case NIF:
8708 new->nif.elsepart = copynode(n->nif.elsepart);
8709 new->nif.ifpart = copynode(n->nif.ifpart);
8710 new->nif.test = copynode(n->nif.test);
8711 break;
8712 case NFOR:
8713 new->nfor.var = nodesavestr(n->nfor.var);
8714 new->nfor.body = copynode(n->nfor.body);
8715 new->nfor.args = copynode(n->nfor.args);
8716 break;
8717 case NCASE:
8718 new->ncase.cases = copynode(n->ncase.cases);
8719 new->ncase.expr = copynode(n->ncase.expr);
8720 break;
8721 case NCLIST:
8722 new->nclist.body = copynode(n->nclist.body);
8723 new->nclist.pattern = copynode(n->nclist.pattern);
8724 new->nclist.next = copynode(n->nclist.next);
8725 break;
8726 case NDEFUN:
8727 case NARG:
8728 new->narg.backquote = copynodelist(n->narg.backquote);
8729 new->narg.text = nodesavestr(n->narg.text);
8730 new->narg.next = copynode(n->narg.next);
8731 break;
8732 case NTO:
8733 case NCLOBBER:
8734 case NFROM:
8735 case NFROMTO:
8736 case NAPPEND:
8737 new->nfile.fname = copynode(n->nfile.fname);
8738 new->nfile.fd = n->nfile.fd;
8739 new->nfile.next = copynode(n->nfile.next);
8740 break;
8741 case NTOFD:
8742 case NFROMFD:
8743 new->ndup.vname = copynode(n->ndup.vname);
8744 new->ndup.dupfd = n->ndup.dupfd;
8745 new->ndup.fd = n->ndup.fd;
8746 new->ndup.next = copynode(n->ndup.next);
8747 break;
8748 case NHERE:
8749 case NXHERE:
8750 new->nhere.doc = copynode(n->nhere.doc);
8751 new->nhere.fd = n->nhere.fd;
8752 new->nhere.next = copynode(n->nhere.next);
8753 break;
8754 case NNOT:
8755 new->nnot.com = copynode(n->nnot.com);
8756 break;
8757 };
8758 new->type = n->type;
8759 return new;
8760}
8761
8762
8763static struct nodelist *
8764copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008765{
8766 struct nodelist *start;
8767 struct nodelist **lpp;
8768
8769 lpp = &start;
8770 while (lp) {
8771 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008772 funcblock = (char *) funcblock +
8773 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008774 (*lpp)->n = copynode(lp->n);
8775 lp = lp->next;
8776 lpp = &(*lpp)->next;
8777 }
8778 *lpp = NULL;
8779 return start;
8780}
8781
8782
Eric Andersenc470f442003-07-28 09:56:35 +00008783static char *
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008784nodesavestr(char *s)
Eric Andersenc470f442003-07-28 09:56:35 +00008785{
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008786 char *rtn = funcstring;
Eric Andersenc470f442003-07-28 09:56:35 +00008787
Denis Vlasenko7cfecc42006-12-18 22:32:45 +00008788 strcpy(funcstring, s);
8789 funcstring += strlen(s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008790 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008791}
8792
Eric Andersenc470f442003-07-28 09:56:35 +00008793
Eric Andersenc470f442003-07-28 09:56:35 +00008794/*
8795 * Free a parse tree.
8796 */
8797
8798static void
8799freefunc(struct funcnode *f)
8800{
8801 if (f && --f->count < 0)
8802 ckfree(f);
8803}
8804
8805
8806static void options(int);
8807static void setoption(int, int);
8808
Eric Andersencb57d552001-06-28 07:25:16 +00008809
Eric Andersencb57d552001-06-28 07:25:16 +00008810/*
8811 * Process the shell command line arguments.
8812 */
8813
Eric Andersenc470f442003-07-28 09:56:35 +00008814void
8815procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008816{
8817 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008818 const char *xminusc;
8819 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008820
Eric Andersenc470f442003-07-28 09:56:35 +00008821 xargv = argv;
8822 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008823 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008824 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008825 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008826 optlist[i] = 2;
8827 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008828 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008829 xargv = argptr;
8830 xminusc = minusc;
8831 if (*xargv == NULL) {
8832 if (xminusc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +00008833 sh_error(bb_msg_requires_arg, "-c");
Eric Andersencb57d552001-06-28 07:25:16 +00008834 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008835 }
Eric Andersencb57d552001-06-28 07:25:16 +00008836 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8837 iflag = 1;
8838 if (mflag == 2)
8839 mflag = iflag;
8840 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008841 if (optlist[i] == 2)
8842 optlist[i] = 0;
8843#if DEBUG == 2
8844 debug = 1;
8845#endif
8846 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8847 if (xminusc) {
8848 minusc = *xargv++;
8849 if (*xargv)
8850 goto setarg0;
8851 } else if (!sflag) {
8852 setinputfile(*xargv, 0);
8853setarg0:
8854 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008855 commandname = arg0;
8856 }
Eric Andersencb57d552001-06-28 07:25:16 +00008857
Eric Andersenc470f442003-07-28 09:56:35 +00008858 shellparam.p = xargv;
8859#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008860 shellparam.optind = 1;
8861 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008862#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008863 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008864 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008865 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008866 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008867 }
8868 optschanged();
8869}
8870
8871
Eric Andersenc470f442003-07-28 09:56:35 +00008872void
8873optschanged(void)
8874{
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008875#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008876 opentrace();
8877#endif
8878 setinteractive(iflag);
8879 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008880 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008881}
Eric Andersencb57d552001-06-28 07:25:16 +00008882
Rob Landley88621d72006-08-29 19:41:06 +00008883static void minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008884{
8885 int i;
8886
8887 if (name == NULL) {
8888 out1str("Current option settings\n");
8889 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008890 out1fmt("%-16s%s\n", optnames(i),
8891 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008892 } else {
8893 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008894 if (equal(name, optnames(i))) {
8895 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008896 return;
8897 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008898 sh_error("Illegal option -o %s", name);
Eric Andersen62483552001-07-10 06:09:16 +00008899 }
8900}
8901
Eric Andersenc470f442003-07-28 09:56:35 +00008902/*
8903 * Process shell options. The global variable argptr contains a pointer
8904 * to the argument list; we advance it past the options.
8905 */
Eric Andersen62483552001-07-10 06:09:16 +00008906
Eric Andersenc470f442003-07-28 09:56:35 +00008907static void
8908options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008909{
8910 char *p;
8911 int val;
8912 int c;
8913
8914 if (cmdline)
8915 minusc = NULL;
8916 while ((p = *argptr) != NULL) {
8917 argptr++;
8918 if ((c = *p++) == '-') {
8919 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +00008920 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +00008921 if (!cmdline) {
8922 /* "-" means turn off -x and -v */
8923 if (p[0] == '\0')
8924 xflag = vflag = 0;
8925 /* "--" means reset params */
8926 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008927 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008928 }
Eric Andersenc470f442003-07-28 09:56:35 +00008929 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008930 }
8931 } else if (c == '+') {
8932 val = 0;
8933 } else {
8934 argptr--;
8935 break;
8936 }
8937 while ((c = *p++) != '\0') {
8938 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008939 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008940 } else if (c == 'o') {
8941 minus_o(*argptr, val);
8942 if (*argptr)
8943 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008944 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008945 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008946 isloginsh = 1;
8947 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008948 } else {
8949 setoption(c, val);
8950 }
8951 }
8952 }
8953}
8954
Eric Andersencb57d552001-06-28 07:25:16 +00008955
Eric Andersenc470f442003-07-28 09:56:35 +00008956static void
8957setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008958{
Eric Andersencb57d552001-06-28 07:25:16 +00008959 int i;
8960
8961 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008962 if (optletters(i) == flag) {
8963 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008964 return;
8965 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008966 sh_error("Illegal option -%c", flag);
Eric Andersencb57d552001-06-28 07:25:16 +00008967 /* NOTREACHED */
8968}
8969
8970
8971
Eric Andersencb57d552001-06-28 07:25:16 +00008972/*
8973 * Set the shell parameters.
8974 */
8975
Eric Andersenc470f442003-07-28 09:56:35 +00008976void
8977setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008978{
Eric Andersencb57d552001-06-28 07:25:16 +00008979 char **newparam;
8980 char **ap;
8981 int nparam;
8982
Eric Andersenc470f442003-07-28 09:56:35 +00008983 for (nparam = 0 ; argv[nparam] ; nparam++);
8984 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008985 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008986 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008987 }
8988 *ap = NULL;
8989 freeparam(&shellparam);
8990 shellparam.malloc = 1;
8991 shellparam.nparam = nparam;
8992 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008993#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008994 shellparam.optind = 1;
8995 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008996#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008997}
8998
8999
9000/*
9001 * Free the list of positional parameters.
9002 */
9003
Eric Andersenc470f442003-07-28 09:56:35 +00009004void
9005freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00009006{
Eric Andersencb57d552001-06-28 07:25:16 +00009007 char **ap;
9008
9009 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009010 for (ap = param->p ; *ap ; ap++)
9011 ckfree(*ap);
9012 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00009013 }
9014}
9015
9016
9017
9018/*
9019 * The shift builtin command.
9020 */
9021
Eric Andersenc470f442003-07-28 09:56:35 +00009022int
9023shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009024{
9025 int n;
9026 char **ap1, **ap2;
9027
9028 n = 1;
9029 if (argc > 1)
9030 n = number(argv[1]);
9031 if (n > shellparam.nparam)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009032 sh_error("can't shift that many");
Eric Andersencb57d552001-06-28 07:25:16 +00009033 INTOFF;
9034 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009035 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009036 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009037 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009038 }
9039 ap2 = shellparam.p;
9040 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009041#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009042 shellparam.optind = 1;
9043 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009044#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009045 INTON;
9046 return 0;
9047}
9048
9049
9050
9051/*
9052 * The set command builtin.
9053 */
9054
Eric Andersenc470f442003-07-28 09:56:35 +00009055int
9056setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009057{
9058 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009059 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009060 INTOFF;
9061 options(0);
9062 optschanged();
9063 if (*argptr != NULL) {
9064 setparam(argptr);
9065 }
9066 INTON;
9067 return 0;
9068}
9069
9070
Eric Andersenc470f442003-07-28 09:56:35 +00009071#ifdef CONFIG_ASH_GETOPTS
9072static void
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00009073getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009074{
9075 shellparam.optind = number(value);
9076 shellparam.optoff = -1;
9077}
Eric Andersenc470f442003-07-28 09:56:35 +00009078#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009079
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009080#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009081static void change_lc_all(const char *value)
9082{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009083 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009084 setlocale(LC_ALL, value);
9085}
9086
9087static void change_lc_ctype(const char *value)
9088{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009089 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009090 setlocale(LC_CTYPE, value);
9091}
9092
9093#endif
9094
Eric Andersen16767e22004-03-16 05:14:10 +00009095#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009096/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009097static void change_random(const char *value)
9098{
Eric Andersen16767e22004-03-16 05:14:10 +00009099 if(value == NULL) {
9100 /* "get", generate */
9101 char buf[16];
9102
9103 rseed = rseed * 1103515245 + 12345;
9104 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9105 /* set without recursion */
9106 setvar(vrandom.text, buf, VNOFUNC);
9107 vrandom.flags &= ~VNOFUNC;
9108 } else {
9109 /* set/reset */
9110 rseed = strtoul(value, (char **)NULL, 10);
9111 }
Eric Andersenef02f822004-03-11 13:34:24 +00009112}
Eric Andersen16767e22004-03-16 05:14:10 +00009113#endif
9114
Eric Andersenef02f822004-03-11 13:34:24 +00009115
Eric Andersend35c5df2002-01-09 15:37:36 +00009116#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009117static int
Eric Andersenc470f442003-07-28 09:56:35 +00009118getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009119{
9120 char *p, *q;
9121 char c = '?';
9122 int done = 0;
9123 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009124 char s[12];
9125 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009126
Eric Andersena48b0a32003-10-22 10:56:47 +00009127 if(*param_optind < 1)
9128 return 1;
9129 optnext = optfirst + *param_optind - 1;
9130
9131 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009132 p = NULL;
9133 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009134 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009135 if (p == NULL || *p == '\0') {
9136 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009137 p = *optnext;
9138 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009139atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009140 p = NULL;
9141 done = 1;
9142 goto out;
9143 }
9144 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +00009145 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009146 goto atend;
9147 }
9148
9149 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009150 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009151 if (*q == '\0') {
9152 if (optstr[0] == ':') {
9153 s[0] = c;
9154 s[1] = '\0';
9155 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009156 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009157 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009158 (void) unsetvar("OPTARG");
9159 }
9160 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009161 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009162 }
9163 if (*++q == ':')
9164 q++;
9165 }
9166
9167 if (*++q == ':') {
9168 if (*p == '\0' && (p = *optnext) == NULL) {
9169 if (optstr[0] == ':') {
9170 s[0] = c;
9171 s[1] = '\0';
9172 err |= setvarsafe("OPTARG", s, 0);
9173 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009174 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009175 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009176 (void) unsetvar("OPTARG");
9177 c = '?';
9178 }
Eric Andersenc470f442003-07-28 09:56:35 +00009179 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009180 }
9181
9182 if (p == *optnext)
9183 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009184 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009185 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009186 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009187 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009188
Eric Andersenc470f442003-07-28 09:56:35 +00009189out:
Eric Andersencb57d552001-06-28 07:25:16 +00009190 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009191 *param_optind = optnext - optfirst + 1;
9192 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009193 err |= setvarsafe("OPTIND", s, VNOFUNC);
9194 s[0] = c;
9195 s[1] = '\0';
9196 err |= setvarsafe(optvar, s, 0);
9197 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009198 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009199 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009200 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009201 exraise(EXERROR);
9202 }
9203 return done;
9204}
Eric Andersenc470f442003-07-28 09:56:35 +00009205
9206/*
9207 * The getopts builtin. Shellparam.optnext points to the next argument
9208 * to be processed. Shellparam.optptr points to the next character to
9209 * be processed in the current argument. If shellparam.optnext is NULL,
9210 * then it's the first time getopts has been called.
9211 */
9212
9213int
9214getoptscmd(int argc, char **argv)
9215{
9216 char **optbase;
9217
9218 if (argc < 3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009219 sh_error("Usage: getopts optstring var [arg]");
Eric Andersenc470f442003-07-28 09:56:35 +00009220 else if (argc == 3) {
9221 optbase = shellparam.p;
9222 if (shellparam.optind > shellparam.nparam + 1) {
9223 shellparam.optind = 1;
9224 shellparam.optoff = -1;
9225 }
9226 }
9227 else {
9228 optbase = &argv[3];
9229 if (shellparam.optind > argc - 2) {
9230 shellparam.optind = 1;
9231 shellparam.optoff = -1;
9232 }
9233 }
9234
9235 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9236 &shellparam.optoff);
9237}
9238#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009239
9240/*
9241 * XXX - should get rid of. have all builtins use getopt(3). the
9242 * library getopt must have the BSD extension static variable "optreset"
9243 * otherwise it can't be used within the shell safely.
9244 *
9245 * Standard option processing (a la getopt) for builtin routines. The
9246 * only argument that is passed to nextopt is the option string; the
9247 * other arguments are unnecessary. It return the character, or '\0' on
9248 * end of input.
9249 */
9250
Eric Andersenc470f442003-07-28 09:56:35 +00009251static int
9252nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009253{
Eric Andersencb57d552001-06-28 07:25:16 +00009254 char *p;
9255 const char *q;
9256 char c;
9257
9258 if ((p = optptr) == NULL || *p == '\0') {
9259 p = *argptr;
9260 if (p == NULL || *p != '-' || *++p == '\0')
9261 return '\0';
9262 argptr++;
Denis Vlasenko9f739442006-12-16 23:49:13 +00009263 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009264 return '\0';
9265 }
9266 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009267 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009268 if (*q == '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009269 sh_error("Illegal option -%c", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009270 if (*++q == ':')
9271 q++;
9272 }
9273 if (*++q == ':') {
9274 if (*p == '\0' && (p = *argptr++) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009275 sh_error("No arg for -%c option", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009276 optionarg = p;
9277 p = NULL;
9278 }
9279 optptr = p;
9280 return c;
9281}
9282
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009283
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009284/* output.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009285
Eric Andersenc470f442003-07-28 09:56:35 +00009286void
9287outstr(const char *p, FILE *file)
9288{
9289 INTOFF;
9290 fputs(p, file);
9291 INTON;
9292}
9293
9294void
9295flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009296{
Eric Andersencb57d552001-06-28 07:25:16 +00009297 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009298 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009299 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009300 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009301}
9302
Eric Andersenc470f442003-07-28 09:56:35 +00009303void
Eric Andersen16767e22004-03-16 05:14:10 +00009304flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009305{
9306 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009307 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009308 INTON;
9309}
9310
9311static void
9312outcslow(int c, FILE *dest)
9313{
9314 INTOFF;
9315 putc(c, dest);
9316 fflush(dest);
9317 INTON;
9318}
9319
9320
9321static int
9322out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009323{
9324 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009325 int r;
9326
9327 INTOFF;
9328 va_start(ap, fmt);
9329 r = vprintf(fmt, ap);
9330 va_end(ap);
9331 INTON;
9332 return r;
9333}
9334
9335
9336int
9337fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9338{
9339 va_list ap;
9340 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009341
Eric Andersencb57d552001-06-28 07:25:16 +00009342 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009343 INTOFF;
9344 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009345 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009346 INTON;
9347 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009348}
9349
Eric Andersenc470f442003-07-28 09:56:35 +00009350
Eric Andersencb57d552001-06-28 07:25:16 +00009351
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009352/* parser.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009353
9354
Eric Andersencb57d552001-06-28 07:25:16 +00009355/*
9356 * Shell command parser.
9357 */
9358
9359#define EOFMARKLEN 79
9360
9361
Eric Andersencb57d552001-06-28 07:25:16 +00009362struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009363 struct heredoc *next; /* next here document in list */
9364 union node *here; /* redirection node */
9365 char *eofmark; /* string indicating end of input */
9366 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009367};
9368
9369
9370
Eric Andersenc470f442003-07-28 09:56:35 +00009371static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009372
9373
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009374static union node *list(int);
9375static union node *andor(void);
9376static union node *pipeline(void);
9377static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009378static union node *simplecmd(void);
9379static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009380static void parsefname(void);
9381static void parseheredoc(void);
9382static char peektoken(void);
9383static int readtoken(void);
9384static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009385static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009386static int noexpand(char *);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00009387static void synexpect(int) ATTRIBUTE_NORETURN;
9388static void synerror(const char *) ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009389static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009390
9391
Eric Andersenc470f442003-07-28 09:56:35 +00009392
Eric Andersenc470f442003-07-28 09:56:35 +00009393
Eric Andersencb57d552001-06-28 07:25:16 +00009394/*
9395 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9396 * valid parse tree indicating a blank line.)
9397 */
9398
Eric Andersenc470f442003-07-28 09:56:35 +00009399union node *
9400parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009401{
9402 int t;
9403
9404 tokpushback = 0;
9405 doprompt = interact;
9406 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009407 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009408 needprompt = 0;
9409 t = readtoken();
9410 if (t == TEOF)
9411 return NEOF;
9412 if (t == TNL)
9413 return NULL;
9414 tokpushback++;
9415 return list(1);
9416}
9417
9418
Eric Andersenc470f442003-07-28 09:56:35 +00009419static union node *
9420list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009421{
9422 union node *n1, *n2, *n3;
9423 int tok;
9424
Eric Andersenc470f442003-07-28 09:56:35 +00009425 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9426 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009427 return NULL;
9428 n1 = NULL;
9429 for (;;) {
9430 n2 = andor();
9431 tok = readtoken();
9432 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009433 if (n2->type == NPIPE) {
9434 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009435 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009436 if (n2->type != NREDIR) {
9437 n3 = stalloc(sizeof(struct nredir));
9438 n3->nredir.n = n2;
9439 n3->nredir.redirect = NULL;
9440 n2 = n3;
9441 }
9442 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009443 }
9444 }
9445 if (n1 == NULL) {
9446 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009447 }
9448 else {
9449 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009450 n3->type = NSEMI;
9451 n3->nbinary.ch1 = n1;
9452 n3->nbinary.ch2 = n2;
9453 n1 = n3;
9454 }
9455 switch (tok) {
9456 case TBACKGND:
9457 case TSEMI:
9458 tok = readtoken();
9459 /* fall through */
9460 case TNL:
9461 if (tok == TNL) {
9462 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009463 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009464 return n1;
9465 } else {
9466 tokpushback++;
9467 }
Eric Andersenc470f442003-07-28 09:56:35 +00009468 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009469 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009470 return n1;
9471 break;
9472 case TEOF:
9473 if (heredoclist)
9474 parseheredoc();
9475 else
Eric Andersenc470f442003-07-28 09:56:35 +00009476 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009477 return n1;
9478 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009479 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009480 synexpect(-1);
9481 tokpushback++;
9482 return n1;
9483 }
9484 }
9485}
9486
9487
9488
Eric Andersenc470f442003-07-28 09:56:35 +00009489static union node *
9490andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009491{
Eric Andersencb57d552001-06-28 07:25:16 +00009492 union node *n1, *n2, *n3;
9493 int t;
9494
Eric Andersencb57d552001-06-28 07:25:16 +00009495 n1 = pipeline();
9496 for (;;) {
9497 if ((t = readtoken()) == TAND) {
9498 t = NAND;
9499 } else if (t == TOR) {
9500 t = NOR;
9501 } else {
9502 tokpushback++;
9503 return n1;
9504 }
Eric Andersenc470f442003-07-28 09:56:35 +00009505 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009506 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009507 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009508 n3->type = t;
9509 n3->nbinary.ch1 = n1;
9510 n3->nbinary.ch2 = n2;
9511 n1 = n3;
9512 }
9513}
9514
9515
9516
Eric Andersenc470f442003-07-28 09:56:35 +00009517static union node *
9518pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009519{
Eric Andersencb57d552001-06-28 07:25:16 +00009520 union node *n1, *n2, *pipenode;
9521 struct nodelist *lp, *prev;
9522 int negate;
9523
9524 negate = 0;
9525 TRACE(("pipeline: entered\n"));
9526 if (readtoken() == TNOT) {
9527 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009528 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009529 } else
9530 tokpushback++;
9531 n1 = command();
9532 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009533 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009534 pipenode->type = NPIPE;
9535 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009536 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009537 pipenode->npipe.cmdlist = lp;
9538 lp->n = n1;
9539 do {
9540 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009541 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9542 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009543 lp->n = command();
9544 prev->next = lp;
9545 } while (readtoken() == TPIPE);
9546 lp->next = NULL;
9547 n1 = pipenode;
9548 }
9549 tokpushback++;
9550 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009551 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009552 n2->type = NNOT;
9553 n2->nnot.com = n1;
9554 return n2;
9555 } else
9556 return n1;
9557}
9558
9559
9560
Eric Andersenc470f442003-07-28 09:56:35 +00009561static union node *
9562command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009563{
Eric Andersencb57d552001-06-28 07:25:16 +00009564 union node *n1, *n2;
9565 union node *ap, **app;
9566 union node *cp, **cpp;
9567 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009568 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009569 int t;
9570
9571 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009572 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009573
Eric Andersencb57d552001-06-28 07:25:16 +00009574 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009575 default:
9576 synexpect(-1);
9577 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009578 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009579 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009580 n1->type = NIF;
9581 n1->nif.test = list(0);
9582 if (readtoken() != TTHEN)
9583 synexpect(TTHEN);
9584 n1->nif.ifpart = list(0);
9585 n2 = n1;
9586 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009587 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009588 n2 = n2->nif.elsepart;
9589 n2->type = NIF;
9590 n2->nif.test = list(0);
9591 if (readtoken() != TTHEN)
9592 synexpect(TTHEN);
9593 n2->nif.ifpart = list(0);
9594 }
9595 if (lasttoken == TELSE)
9596 n2->nif.elsepart = list(0);
9597 else {
9598 n2->nif.elsepart = NULL;
9599 tokpushback++;
9600 }
Eric Andersenc470f442003-07-28 09:56:35 +00009601 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009602 break;
9603 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009604 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009605 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009606 n1 = (union node *)stalloc(sizeof (struct nbinary));
9607 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009608 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009609 if ((got=readtoken()) != TDO) {
9610TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009611 synexpect(TDO);
9612 }
9613 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009614 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009615 break;
9616 }
9617 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009618 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009619 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009620 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009621 n1->type = NFOR;
9622 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009623 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009624 if (readtoken() == TIN) {
9625 app = &ap;
9626 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009627 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009628 n2->type = NARG;
9629 n2->narg.text = wordtext;
9630 n2->narg.backquote = backquotelist;
9631 *app = n2;
9632 app = &n2->narg.next;
9633 }
9634 *app = NULL;
9635 n1->nfor.args = ap;
9636 if (lasttoken != TNL && lasttoken != TSEMI)
9637 synexpect(-1);
9638 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009639 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009640 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009641 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009642 n2->narg.backquote = NULL;
9643 n2->narg.next = NULL;
9644 n1->nfor.args = n2;
9645 /*
9646 * Newline or semicolon here is optional (but note
9647 * that the original Bourne shell only allowed NL).
9648 */
9649 if (lasttoken != TNL && lasttoken != TSEMI)
9650 tokpushback++;
9651 }
Eric Andersenc470f442003-07-28 09:56:35 +00009652 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009653 if (readtoken() != TDO)
9654 synexpect(TDO);
9655 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009656 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009657 break;
9658 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009659 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009660 n1->type = NCASE;
9661 if (readtoken() != TWORD)
9662 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009663 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009664 n2->type = NARG;
9665 n2->narg.text = wordtext;
9666 n2->narg.backquote = backquotelist;
9667 n2->narg.next = NULL;
9668 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009669 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009670 } while (readtoken() == TNL);
9671 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009672 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009673 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009674next_case:
9675 checkkwd = CHKNL | CHKKWD;
9676 t = readtoken();
9677 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009678 if (lasttoken == TLP)
9679 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009680 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009681 cp->type = NCLIST;
9682 app = &cp->nclist.pattern;
9683 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009684 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009685 ap->type = NARG;
9686 ap->narg.text = wordtext;
9687 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009688 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009689 break;
9690 app = &ap->narg.next;
9691 readtoken();
9692 }
9693 ap->narg.next = NULL;
9694 if (lasttoken != TRP)
9695 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009696 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009697
Eric Andersenc470f442003-07-28 09:56:35 +00009698 cpp = &cp->nclist.next;
9699
9700 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009701 if ((t = readtoken()) != TESAC) {
9702 if (t != TENDCASE)
9703 synexpect(TENDCASE);
9704 else
Eric Andersenc470f442003-07-28 09:56:35 +00009705 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009706 }
Eric Andersenc470f442003-07-28 09:56:35 +00009707 }
Eric Andersencb57d552001-06-28 07:25:16 +00009708 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009709 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009710 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009711 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009712 n1->type = NSUBSHELL;
9713 n1->nredir.n = list(0);
9714 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009715 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009716 break;
9717 case TBEGIN:
9718 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009719 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009720 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009721 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009722 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009723 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009724 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009725 }
9726
Eric Andersenc470f442003-07-28 09:56:35 +00009727 if (readtoken() != t)
9728 synexpect(t);
9729
9730redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009731 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009732 checkkwd = CHKKWD | CHKALIAS;
9733 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009734 while (readtoken() == TREDIR) {
9735 *rpp = n2 = redirnode;
9736 rpp = &n2->nfile.next;
9737 parsefname();
9738 }
9739 tokpushback++;
9740 *rpp = NULL;
9741 if (redir) {
9742 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009743 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009744 n2->type = NREDIR;
9745 n2->nredir.n = n1;
9746 n1 = n2;
9747 }
9748 n1->nredir.redirect = redir;
9749 }
9750
9751 return n1;
9752}
9753
9754
Eric Andersenc470f442003-07-28 09:56:35 +00009755static union node *
9756simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009757 union node *args, **app;
9758 union node *n = NULL;
9759 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009760 union node **rpp, *redir;
9761 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009762
9763 args = NULL;
9764 app = &args;
9765 vars = NULL;
9766 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009767 redir = NULL;
9768 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009769
Eric Andersenc470f442003-07-28 09:56:35 +00009770 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009771 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009772 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009773 switch (readtoken()) {
9774 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009775 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009776 n->type = NARG;
9777 n->narg.text = wordtext;
9778 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009779 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009780 *vpp = n;
9781 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009782 } else {
9783 *app = n;
9784 app = &n->narg.next;
9785 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009786 }
9787 break;
9788 case TREDIR:
9789 *rpp = n = redirnode;
9790 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009791 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009792 break;
9793 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009794 if (
9795 args && app == &args->narg.next &&
9796 !vars && !redir
9797 ) {
9798 struct builtincmd *bcmd;
9799 const char *name;
9800
Eric Andersencb57d552001-06-28 07:25:16 +00009801 /* We have a function */
9802 if (readtoken() != TRP)
9803 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009804 name = n->narg.text;
9805 if (
9806 !goodname(name) || (
9807 (bcmd = find_builtin(name)) &&
9808 IS_BUILTIN_SPECIAL(bcmd)
9809 )
9810 )
9811 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009812 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009813 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009814 n->narg.next = command();
9815 return n;
9816 }
9817 /* fall through */
9818 default:
9819 tokpushback++;
9820 goto out;
9821 }
9822 }
Eric Andersenc470f442003-07-28 09:56:35 +00009823out:
Eric Andersencb57d552001-06-28 07:25:16 +00009824 *app = NULL;
9825 *vpp = NULL;
9826 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009827 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009828 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009829 n->ncmd.args = args;
9830 n->ncmd.assign = vars;
9831 n->ncmd.redirect = redir;
9832 return n;
9833}
9834
Eric Andersenc470f442003-07-28 09:56:35 +00009835static union node *
9836makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009837{
Eric Andersencb57d552001-06-28 07:25:16 +00009838 union node *n;
9839
Eric Andersenc470f442003-07-28 09:56:35 +00009840 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009841 n->type = NARG;
9842 n->narg.next = NULL;
9843 n->narg.text = wordtext;
9844 n->narg.backquote = backquotelist;
9845 return n;
9846}
9847
Eric Andersenc470f442003-07-28 09:56:35 +00009848void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009849{
Eric Andersencb57d552001-06-28 07:25:16 +00009850 TRACE(("Fix redir %s %d\n", text, err));
9851 if (!err)
9852 n->ndup.vname = NULL;
9853
9854 if (is_digit(text[0]) && text[1] == '\0')
9855 n->ndup.dupfd = digit_val(text[0]);
Denis Vlasenko9f739442006-12-16 23:49:13 +00009856 else if (LONE_DASH(text))
Eric Andersencb57d552001-06-28 07:25:16 +00009857 n->ndup.dupfd = -1;
9858 else {
9859
9860 if (err)
9861 synerror("Bad fd number");
9862 else
9863 n->ndup.vname = makename();
9864 }
9865}
9866
9867
Eric Andersenc470f442003-07-28 09:56:35 +00009868static void
9869parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009870{
Eric Andersencb57d552001-06-28 07:25:16 +00009871 union node *n = redirnode;
9872
9873 if (readtoken() != TWORD)
9874 synexpect(-1);
9875 if (n->type == NHERE) {
9876 struct heredoc *here = heredoc;
9877 struct heredoc *p;
9878 int i;
9879
9880 if (quoteflag == 0)
9881 n->type = NXHERE;
9882 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009883 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009884 synerror("Illegal eof marker for << redirection");
9885 rmescapes(wordtext);
9886 here->eofmark = wordtext;
9887 here->next = NULL;
9888 if (heredoclist == NULL)
9889 heredoclist = here;
9890 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009891 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009892 p->next = here;
9893 }
9894 } else if (n->type == NTOFD || n->type == NFROMFD) {
9895 fixredir(n, wordtext, 0);
9896 } else {
9897 n->nfile.fname = makename();
9898 }
9899}
9900
9901
9902/*
9903 * Input any here documents.
9904 */
9905
Eric Andersenc470f442003-07-28 09:56:35 +00009906static void
9907parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009908{
Eric Andersencb57d552001-06-28 07:25:16 +00009909 struct heredoc *here;
9910 union node *n;
9911
Eric Andersenc470f442003-07-28 09:56:35 +00009912 here = heredoclist;
9913 heredoclist = 0;
9914
9915 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009916 if (needprompt) {
9917 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009918 }
Eric Andersenc470f442003-07-28 09:56:35 +00009919 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9920 here->eofmark, here->striptabs);
9921 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009922 n->narg.type = NARG;
9923 n->narg.next = NULL;
9924 n->narg.text = wordtext;
9925 n->narg.backquote = backquotelist;
9926 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009927 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009928 }
9929}
9930
Eric Andersenc470f442003-07-28 09:56:35 +00009931static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009932{
Eric Andersencb57d552001-06-28 07:25:16 +00009933 int t;
9934
9935 t = readtoken();
9936 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009937 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009938}
9939
Eric Andersenc470f442003-07-28 09:56:35 +00009940static int
9941readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009942{
Eric Andersencb57d552001-06-28 07:25:16 +00009943 int t;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009944#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00009945 int alreadyseen = tokpushback;
9946#endif
9947
Eric Andersend35c5df2002-01-09 15:37:36 +00009948#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009949top:
Eric Andersen2870d962001-07-02 17:27:21 +00009950#endif
9951
Eric Andersencb57d552001-06-28 07:25:16 +00009952 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009953
Eric Andersenc470f442003-07-28 09:56:35 +00009954 /*
9955 * eat newlines
9956 */
9957 if (checkkwd & CHKNL) {
9958 while (t == TNL) {
9959 parseheredoc();
9960 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009961 }
9962 }
9963
Eric Andersenc470f442003-07-28 09:56:35 +00009964 if (t != TWORD || quoteflag) {
9965 goto out;
9966 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009967
Eric Andersenc470f442003-07-28 09:56:35 +00009968 /*
9969 * check for keywords
9970 */
9971 if (checkkwd & CHKKWD) {
9972 const char *const *pp;
9973
9974 if ((pp = findkwd(wordtext))) {
9975 lasttoken = t = pp - tokname_array;
9976 TRACE(("keyword %s recognized\n", tokname(t)));
9977 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009978 }
Eric Andersenc470f442003-07-28 09:56:35 +00009979 }
9980
9981 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009982#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009983 struct alias *ap;
9984 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009985 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009986 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009987 }
Eric Andersencb57d552001-06-28 07:25:16 +00009988 goto top;
9989 }
Eric Andersen2870d962001-07-02 17:27:21 +00009990#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009991 }
Eric Andersenc470f442003-07-28 09:56:35 +00009992out:
9993 checkkwd = 0;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00009994#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00009995 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009996 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009997 else
Eric Andersenc470f442003-07-28 09:56:35 +00009998 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009999#endif
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000010000 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000010001}
10002
10003
10004/*
10005 * Read the next input token.
10006 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010007 * backquotes. We set quoteflag to true if any part of the word was
10008 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010009 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010010 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010011 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010012 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010013 *
10014 * [Change comment: here documents and internal procedures]
10015 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10016 * word parsing code into a separate routine. In this case, readtoken
10017 * doesn't need to have any internal procedures, but parseword does.
10018 * We could also make parseoperator in essence the main routine, and
10019 * have parseword (readtoken1?) handle both words and redirection.]
10020 */
10021
Eric Andersen81fe1232003-07-29 06:38:40 +000010022#define NEW_xxreadtoken
10023#ifdef NEW_xxreadtoken
10024
10025/* singles must be first! */
10026static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10027
10028static const char xxreadtoken_tokens[] = {
10029 TNL, TLP, TRP, /* only single occurrence allowed */
10030 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10031 TEOF, /* corresponds to trailing nul */
10032 TAND, TOR, TENDCASE, /* if double occurrence */
10033};
10034
10035#define xxreadtoken_doubles \
10036 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10037#define xxreadtoken_singles \
10038 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10039
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +000010040static int xxreadtoken(void)
Eric Andersen81fe1232003-07-29 06:38:40 +000010041{
10042 int c;
10043
10044 if (tokpushback) {
10045 tokpushback = 0;
10046 return lasttoken;
10047 }
10048 if (needprompt) {
10049 setprompt(2);
Eric Andersen81fe1232003-07-29 06:38:40 +000010050 }
10051 startlinno = plinno;
10052 for (;;) { /* until token or start of word found */
10053 c = pgetc_macro();
10054
10055 if ((c != ' ') && (c != '\t')
10056#ifdef CONFIG_ASH_ALIAS
10057 && (c != PEOA)
10058#endif
10059 ) {
10060 if (c == '#') {
10061 while ((c = pgetc()) != '\n' && c != PEOF);
10062 pungetc();
10063 } else if (c == '\\') {
10064 if (pgetc() != '\n') {
10065 pungetc();
10066 goto READTOKEN1;
10067 }
10068 startlinno = ++plinno;
10069 if (doprompt)
10070 setprompt(2);
10071 } else {
10072 const char *p
10073 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10074
10075 if (c != PEOF) {
10076 if (c == '\n') {
10077 plinno++;
10078 needprompt = doprompt;
10079 }
10080
10081 p = strchr(xxreadtoken_chars, c);
10082 if (p == NULL) {
10083 READTOKEN1:
10084 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10085 }
10086
10087 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10088 if (pgetc() == *p) { /* double occurrence? */
10089 p += xxreadtoken_doubles + 1;
10090 } else {
10091 pungetc();
10092 }
10093 }
10094 }
10095
10096 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10097 }
10098 }
10099 }
10100}
10101
10102
10103#else
Eric Andersen2870d962001-07-02 17:27:21 +000010104#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010105
Eric Andersenc470f442003-07-28 09:56:35 +000010106static int
10107xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010108{
Eric Andersencb57d552001-06-28 07:25:16 +000010109 int c;
10110
10111 if (tokpushback) {
10112 tokpushback = 0;
10113 return lasttoken;
10114 }
10115 if (needprompt) {
10116 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010117 }
10118 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010119 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010120 c = pgetc_macro();
10121 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010122 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010123#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010124 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010125#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010126 continue;
10127 case '#':
10128 while ((c = pgetc()) != '\n' && c != PEOF);
10129 pungetc();
10130 continue;
10131 case '\\':
10132 if (pgetc() == '\n') {
10133 startlinno = ++plinno;
10134 if (doprompt)
10135 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010136 continue;
10137 }
10138 pungetc();
10139 goto breakloop;
10140 case '\n':
10141 plinno++;
10142 needprompt = doprompt;
10143 RETURN(TNL);
10144 case PEOF:
10145 RETURN(TEOF);
10146 case '&':
10147 if (pgetc() == '&')
10148 RETURN(TAND);
10149 pungetc();
10150 RETURN(TBACKGND);
10151 case '|':
10152 if (pgetc() == '|')
10153 RETURN(TOR);
10154 pungetc();
10155 RETURN(TPIPE);
10156 case ';':
10157 if (pgetc() == ';')
10158 RETURN(TENDCASE);
10159 pungetc();
10160 RETURN(TSEMI);
10161 case '(':
10162 RETURN(TLP);
10163 case ')':
10164 RETURN(TRP);
10165 default:
10166 goto breakloop;
10167 }
10168 }
Eric Andersenc470f442003-07-28 09:56:35 +000010169breakloop:
10170 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010171#undef RETURN
10172}
Eric Andersen81fe1232003-07-29 06:38:40 +000010173#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010174
Eric Andersencb57d552001-06-28 07:25:16 +000010175
Eric Andersencb57d552001-06-28 07:25:16 +000010176/*
10177 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10178 * is not NULL, read a here document. In the latter case, eofmark is the
10179 * word which marks the end of the document and striptabs is true if
10180 * leading tabs should be stripped from the document. The argument firstc
10181 * is the first character of the input token or document.
10182 *
10183 * Because C does not have internal subroutines, I have simulated them
10184 * using goto's to implement the subroutine linkage. The following macros
10185 * will run code that appears at the end of readtoken1.
10186 */
10187
Eric Andersen2870d962001-07-02 17:27:21 +000010188#define CHECKEND() {goto checkend; checkend_return:;}
10189#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10190#define PARSESUB() {goto parsesub; parsesub_return:;}
10191#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10192#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10193#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010194
10195static int
Eric Andersenc470f442003-07-28 09:56:35 +000010196readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010197{
Eric Andersencb57d552001-06-28 07:25:16 +000010198 int c = firstc;
10199 char *out;
10200 int len;
10201 char line[EOFMARKLEN + 1];
Eric Andersena68ea1c2006-01-30 22:48:39 +000010202 struct nodelist *bqlist = 0;
10203 int quotef = 0;
10204 int dblquote = 0;
10205 int varnest = 0; /* levels of variables expansion */
10206 int arinest = 0; /* levels of arithmetic expansion */
10207 int parenlevel = 0; /* levels of parens in arithmetic */
10208 int dqvarnest = 0; /* levels of variables expansion within double quotes */
10209 int oldstyle = 0;
10210 int prevsyntax = 0; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010211#if __GNUC__
10212 /* Avoid longjmp clobbering */
10213 (void) &out;
10214 (void) &quotef;
10215 (void) &dblquote;
10216 (void) &varnest;
10217 (void) &arinest;
10218 (void) &parenlevel;
10219 (void) &dqvarnest;
10220 (void) &oldstyle;
10221 (void) &prevsyntax;
10222 (void) &syntax;
10223#endif
10224
10225 startlinno = plinno;
10226 dblquote = 0;
10227 if (syntax == DQSYNTAX)
10228 dblquote = 1;
10229 quotef = 0;
10230 bqlist = NULL;
10231 varnest = 0;
10232 arinest = 0;
10233 parenlevel = 0;
10234 dqvarnest = 0;
10235
10236 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010237 loop: { /* for each line, until end of word */
10238 CHECKEND(); /* set c to PEOF if at end of here document */
10239 for (;;) { /* until end of line or end of word */
10240 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000010241 switch (SIT(c, syntax)) {
Eric Andersenc470f442003-07-28 09:56:35 +000010242 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010243 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010244 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010245 USTPUTC(c, out);
10246 plinno++;
10247 if (doprompt)
10248 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010249 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010250 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010251 case CWORD:
10252 USTPUTC(c, out);
10253 break;
10254 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010255 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010256 USTPUTC(CTLESC, out);
10257 USTPUTC(c, out);
10258 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010259 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010260 c = pgetc2();
10261 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010262 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010263 USTPUTC('\\', out);
10264 pungetc();
10265 } else if (c == '\n') {
10266 if (doprompt)
10267 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010268 } else {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010269 if (dblquote &&
Eric Andersenc470f442003-07-28 09:56:35 +000010270 c != '\\' && c != '`' &&
10271 c != '$' && (
10272 c != '"' ||
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010273 eofmark != NULL)
Eric Andersenc470f442003-07-28 09:56:35 +000010274 ) {
10275 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010276 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010277 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010278 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010279 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010280 USTPUTC(c, out);
10281 quotef++;
10282 }
10283 break;
10284 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010285 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010286quotemark:
10287 if (eofmark == NULL) {
10288 USTPUTC(CTLQUOTEMARK, out);
10289 }
Eric Andersencb57d552001-06-28 07:25:16 +000010290 break;
10291 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010292 syntax = DQSYNTAX;
10293 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010294 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010295 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010296 if (eofmark != NULL && arinest == 0 &&
10297 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010298 USTPUTC(c, out);
10299 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010300 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010301 syntax = BASESYNTAX;
10302 dblquote = 0;
10303 }
10304 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010305 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010306 }
10307 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010308 case CVAR: /* '$' */
10309 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010310 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010311 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010312 if (varnest > 0) {
10313 varnest--;
10314 if (dqvarnest > 0) {
10315 dqvarnest--;
10316 }
10317 USTPUTC(CTLENDVAR, out);
10318 } else {
10319 USTPUTC(c, out);
10320 }
10321 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010322#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010323 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010324 parenlevel++;
10325 USTPUTC(c, out);
10326 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010327 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010328 if (parenlevel > 0) {
10329 USTPUTC(c, out);
10330 --parenlevel;
10331 } else {
10332 if (pgetc() == ')') {
10333 if (--arinest == 0) {
10334 USTPUTC(CTLENDARI, out);
10335 syntax = prevsyntax;
10336 if (syntax == DQSYNTAX)
10337 dblquote = 1;
10338 else
10339 dblquote = 0;
10340 } else
10341 USTPUTC(')', out);
10342 } else {
10343 /*
10344 * unbalanced parens
10345 * (don't 2nd guess - no error)
10346 */
10347 pungetc();
10348 USTPUTC(')', out);
10349 }
10350 }
10351 break;
10352#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010353 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010354 PARSEBACKQOLD();
10355 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010356 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010357 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010358 case CIGN:
10359 break;
10360 default:
10361 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010362 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010363#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010364 if (c != PEOA)
10365#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010366 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010367
Eric Andersencb57d552001-06-28 07:25:16 +000010368 }
10369 c = pgetc_macro();
10370 }
10371 }
Eric Andersenc470f442003-07-28 09:56:35 +000010372endword:
10373#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010374 if (syntax == ARISYNTAX)
10375 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010376#endif
10377 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010378 synerror("Unterminated quoted string");
10379 if (varnest != 0) {
10380 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010381 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010382 synerror("Missing '}'");
10383 }
10384 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010385 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010386 out = stackblock();
10387 if (eofmark == NULL) {
10388 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010389 && quotef == 0
10390 && len <= 2
10391 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010392 PARSEREDIR();
10393 return lasttoken = TREDIR;
10394 } else {
10395 pungetc();
10396 }
10397 }
10398 quoteflag = quotef;
10399 backquotelist = bqlist;
10400 grabstackblock(len);
10401 wordtext = out;
10402 return lasttoken = TWORD;
10403/* end of readtoken routine */
10404
10405
10406
10407/*
10408 * Check to see whether we are at the end of the here document. When this
10409 * is called, c is set to the first character of the next input line. If
10410 * we are at the end of the here document, this routine sets the c to PEOF.
10411 */
10412
Eric Andersenc470f442003-07-28 09:56:35 +000010413checkend: {
10414 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010415#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010416 if (c == PEOA) {
10417 c = pgetc2();
10418 }
10419#endif
10420 if (striptabs) {
10421 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010422 c = pgetc2();
10423 }
Eric Andersenc470f442003-07-28 09:56:35 +000010424 }
10425 if (c == *eofmark) {
10426 if (pfgets(line, sizeof line) != NULL) {
10427 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010428
Eric Andersenc470f442003-07-28 09:56:35 +000010429 p = line;
10430 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10431 if (*p == '\n' && *q == '\0') {
10432 c = PEOF;
10433 plinno++;
10434 needprompt = doprompt;
10435 } else {
10436 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010437 }
10438 }
10439 }
10440 }
Eric Andersenc470f442003-07-28 09:56:35 +000010441 goto checkend_return;
10442}
Eric Andersencb57d552001-06-28 07:25:16 +000010443
10444
10445/*
10446 * Parse a redirection operator. The variable "out" points to a string
10447 * specifying the fd to be redirected. The variable "c" contains the
10448 * first character of the redirection operator.
10449 */
10450
Eric Andersenc470f442003-07-28 09:56:35 +000010451parseredir: {
10452 char fd = *out;
10453 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010454
Eric Andersenc470f442003-07-28 09:56:35 +000010455 np = (union node *)stalloc(sizeof (struct nfile));
10456 if (c == '>') {
10457 np->nfile.fd = 1;
10458 c = pgetc();
10459 if (c == '>')
10460 np->type = NAPPEND;
10461 else if (c == '|')
10462 np->type = NCLOBBER;
10463 else if (c == '&')
10464 np->type = NTOFD;
10465 else {
10466 np->type = NTO;
10467 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010468 }
Eric Andersenc470f442003-07-28 09:56:35 +000010469 } else { /* c == '<' */
10470 np->nfile.fd = 0;
10471 switch (c = pgetc()) {
10472 case '<':
10473 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10474 np = (union node *)stalloc(sizeof (struct nhere));
10475 np->nfile.fd = 0;
10476 }
10477 np->type = NHERE;
10478 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10479 heredoc->here = np;
10480 if ((c = pgetc()) == '-') {
10481 heredoc->striptabs = 1;
10482 } else {
10483 heredoc->striptabs = 0;
10484 pungetc();
10485 }
10486 break;
10487
10488 case '&':
10489 np->type = NFROMFD;
10490 break;
10491
10492 case '>':
10493 np->type = NFROMTO;
10494 break;
10495
10496 default:
10497 np->type = NFROM;
10498 pungetc();
10499 break;
10500 }
Eric Andersencb57d552001-06-28 07:25:16 +000010501 }
Eric Andersenc470f442003-07-28 09:56:35 +000010502 if (fd != '\0')
10503 np->nfile.fd = digit_val(fd);
10504 redirnode = np;
10505 goto parseredir_return;
10506}
Eric Andersencb57d552001-06-28 07:25:16 +000010507
10508
10509/*
10510 * Parse a substitution. At this point, we have read the dollar sign
10511 * and nothing else.
10512 */
10513
Eric Andersenc470f442003-07-28 09:56:35 +000010514parsesub: {
10515 int subtype;
10516 int typeloc;
10517 int flags;
10518 char *p;
10519 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010520
Eric Andersenc470f442003-07-28 09:56:35 +000010521 c = pgetc();
10522 if (
10523 c <= PEOA_OR_PEOF ||
10524 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10525 ) {
10526 USTPUTC('$', out);
10527 pungetc();
10528 } else if (c == '(') { /* $(command) or $((arith)) */
10529 if (pgetc() == '(') {
10530#ifdef CONFIG_ASH_MATH_SUPPORT
10531 PARSEARITH();
10532#else
10533 synerror("We unsupport $((arith))");
10534#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010535 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010536 pungetc();
10537 PARSEBACKQNEW();
10538 }
10539 } else {
10540 USTPUTC(CTLVAR, out);
10541 typeloc = out - (char *)stackblock();
10542 USTPUTC(VSNORMAL, out);
10543 subtype = VSNORMAL;
10544 if (c == '{') {
10545 c = pgetc();
10546 if (c == '#') {
10547 if ((c = pgetc()) == '}')
10548 c = '#';
10549 else
10550 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010551 }
Eric Andersenc470f442003-07-28 09:56:35 +000010552 else
10553 subtype = 0;
10554 }
10555 if (c > PEOA_OR_PEOF && is_name(c)) {
10556 do {
10557 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010558 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010559 } while (c > PEOA_OR_PEOF && is_in_name(c));
10560 } else if (is_digit(c)) {
10561 do {
10562 STPUTC(c, out);
10563 c = pgetc();
10564 } while (is_digit(c));
10565 }
10566 else if (is_special(c)) {
10567 USTPUTC(c, out);
10568 c = pgetc();
10569 }
10570 else
10571badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010572
Eric Andersenc470f442003-07-28 09:56:35 +000010573 STPUTC('=', out);
10574 flags = 0;
10575 if (subtype == 0) {
10576 switch (c) {
10577 case ':':
10578 flags = VSNUL;
10579 c = pgetc();
10580 /*FALLTHROUGH*/
10581 default:
10582 p = strchr(types, c);
10583 if (p == NULL)
10584 goto badsub;
10585 subtype = p - types + VSNORMAL;
10586 break;
10587 case '%':
10588 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010589 {
10590 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010591 subtype = c == '#' ? VSTRIMLEFT :
10592 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010593 c = pgetc();
10594 if (c == cc)
10595 subtype++;
10596 else
10597 pungetc();
10598 break;
10599 }
10600 }
Eric Andersenc470f442003-07-28 09:56:35 +000010601 } else {
10602 pungetc();
10603 }
10604 if (dblquote || arinest)
10605 flags |= VSQUOTE;
10606 *((char *)stackblock() + typeloc) = subtype | flags;
10607 if (subtype != VSNORMAL) {
10608 varnest++;
10609 if (dblquote || arinest) {
10610 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010611 }
10612 }
10613 }
Eric Andersenc470f442003-07-28 09:56:35 +000010614 goto parsesub_return;
10615}
Eric Andersencb57d552001-06-28 07:25:16 +000010616
10617
10618/*
10619 * Called to parse command substitutions. Newstyle is set if the command
10620 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10621 * list of commands (passed by reference), and savelen is the number of
10622 * characters on the top of the stack which must be preserved.
10623 */
10624
Eric Andersenc470f442003-07-28 09:56:35 +000010625parsebackq: {
10626 struct nodelist **nlpp;
10627 int savepbq;
10628 union node *n;
10629 char *volatile str;
10630 struct jmploc jmploc;
10631 struct jmploc *volatile savehandler;
10632 size_t savelen;
Eric Andersena68ea1c2006-01-30 22:48:39 +000010633 int saveprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010634#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010635 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010636#endif
10637
Eric Andersenc470f442003-07-28 09:56:35 +000010638 savepbq = parsebackquote;
10639 if (setjmp(jmploc.loc)) {
10640 if (str)
10641 ckfree(str);
10642 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010643 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010644 longjmp(handler->loc, 1);
10645 }
10646 INTOFF;
10647 str = NULL;
10648 savelen = out - (char *)stackblock();
10649 if (savelen > 0) {
10650 str = ckmalloc(savelen);
10651 memcpy(str, stackblock(), savelen);
10652 }
10653 savehandler = handler;
10654 handler = &jmploc;
10655 INTON;
10656 if (oldstyle) {
10657 /* We must read until the closing backquote, giving special
10658 treatment to some slashes, and then push the string and
10659 reread it as input, interpreting it normally. */
10660 char *pout;
10661 int pc;
10662 size_t psavelen;
10663 char *pstr;
10664
10665
10666 STARTSTACKSTR(pout);
10667 for (;;) {
10668 if (needprompt) {
10669 setprompt(2);
Eric Andersenc470f442003-07-28 09:56:35 +000010670 }
10671 switch (pc = pgetc()) {
10672 case '`':
10673 goto done;
10674
10675 case '\\':
10676 if ((pc = pgetc()) == '\n') {
10677 plinno++;
10678 if (doprompt)
10679 setprompt(2);
10680 /*
10681 * If eating a newline, avoid putting
10682 * the newline into the new character
10683 * stream (via the STPUTC after the
10684 * switch).
10685 */
10686 continue;
10687 }
10688 if (pc != '\\' && pc != '`' && pc != '$'
10689 && (!dblquote || pc != '"'))
10690 STPUTC('\\', pout);
10691 if (pc > PEOA_OR_PEOF) {
10692 break;
10693 }
10694 /* fall through */
10695
10696 case PEOF:
10697#ifdef CONFIG_ASH_ALIAS
10698 case PEOA:
10699#endif
10700 startlinno = plinno;
10701 synerror("EOF in backquote substitution");
10702
10703 case '\n':
10704 plinno++;
10705 needprompt = doprompt;
10706 break;
10707
10708 default:
10709 break;
10710 }
10711 STPUTC(pc, pout);
10712 }
10713done:
10714 STPUTC('\0', pout);
10715 psavelen = pout - (char *)stackblock();
10716 if (psavelen > 0) {
10717 pstr = grabstackstr(pout);
10718 setinputstring(pstr);
10719 }
10720 }
10721 nlpp = &bqlist;
10722 while (*nlpp)
10723 nlpp = &(*nlpp)->next;
10724 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10725 (*nlpp)->next = NULL;
10726 parsebackquote = oldstyle;
10727
10728 if (oldstyle) {
10729 saveprompt = doprompt;
10730 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010731 }
10732
Eric Andersenc470f442003-07-28 09:56:35 +000010733 n = list(2);
10734
10735 if (oldstyle)
10736 doprompt = saveprompt;
10737 else {
10738 if (readtoken() != TRP)
10739 synexpect(TRP);
10740 }
10741
10742 (*nlpp)->n = n;
10743 if (oldstyle) {
10744 /*
10745 * Start reading from old file again, ignoring any pushed back
10746 * tokens left from the backquote parsing
10747 */
10748 popfile();
10749 tokpushback = 0;
10750 }
10751 while (stackblocksize() <= savelen)
10752 growstackblock();
10753 STARTSTACKSTR(out);
10754 if (str) {
10755 memcpy(out, str, savelen);
10756 STADJUST(savelen, out);
10757 INTOFF;
10758 ckfree(str);
10759 str = NULL;
10760 INTON;
10761 }
10762 parsebackquote = savepbq;
10763 handler = savehandler;
10764 if (arinest || dblquote)
10765 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10766 else
10767 USTPUTC(CTLBACKQ, out);
10768 if (oldstyle)
10769 goto parsebackq_oldreturn;
10770 else
10771 goto parsebackq_newreturn;
10772}
10773
10774#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010775/*
10776 * Parse an arithmetic expansion (indicate start of one and set state)
10777 */
Eric Andersenc470f442003-07-28 09:56:35 +000010778parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010779
Eric Andersenc470f442003-07-28 09:56:35 +000010780 if (++arinest == 1) {
10781 prevsyntax = syntax;
10782 syntax = ARISYNTAX;
10783 USTPUTC(CTLARI, out);
10784 if (dblquote)
10785 USTPUTC('"',out);
10786 else
10787 USTPUTC(' ',out);
10788 } else {
10789 /*
10790 * we collapse embedded arithmetic expansion to
10791 * parenthesis, which should be equivalent
10792 */
10793 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010794 }
Eric Andersenc470f442003-07-28 09:56:35 +000010795 goto parsearith_return;
10796}
10797#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010798
Eric Andersenc470f442003-07-28 09:56:35 +000010799} /* end of readtoken */
10800
Eric Andersencb57d552001-06-28 07:25:16 +000010801
10802
Eric Andersencb57d552001-06-28 07:25:16 +000010803/*
10804 * Returns true if the text contains nothing to expand (no dollar signs
10805 * or backquotes).
10806 */
10807
Eric Andersenc470f442003-07-28 09:56:35 +000010808static int
10809noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010810{
Eric Andersencb57d552001-06-28 07:25:16 +000010811 char *p;
10812 char c;
10813
10814 p = text;
10815 while ((c = *p++) != '\0') {
10816 if (c == CTLQUOTEMARK)
10817 continue;
10818 if (c == CTLESC)
10819 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010820 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010821 return 0;
10822 }
10823 return 1;
10824}
10825
10826
10827/*
Eric Andersenc470f442003-07-28 09:56:35 +000010828 * Return of a legal variable name (a letter or underscore followed by zero or
10829 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010830 */
10831
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010832static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010833endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010834{
Eric Andersenc470f442003-07-28 09:56:35 +000010835 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010836
Eric Andersenc470f442003-07-28 09:56:35 +000010837 p = (char *) name;
10838 if (! is_name(*p))
10839 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010840 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010841 if (! is_in_name(*p))
10842 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010843 }
Eric Andersenc470f442003-07-28 09:56:35 +000010844 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010845}
10846
10847
10848/*
10849 * Called when an unexpected token is read during the parse. The argument
10850 * is the token that is expected, or -1 if more than one type of token can
10851 * occur at this point.
10852 */
10853
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010854static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010855{
10856 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010857 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010858
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010859 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10860 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010861 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010862 synerror(msg);
10863 /* NOTREACHED */
10864}
10865
Eric Andersenc470f442003-07-28 09:56:35 +000010866static void
10867synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010868{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010869 sh_error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010870 /* NOTREACHED */
10871}
10872
Eric Andersencb57d552001-06-28 07:25:16 +000010873
10874/*
10875 * called by editline -- any expansions to the prompt
10876 * should be added here.
10877 */
Eric Andersenc470f442003-07-28 09:56:35 +000010878
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010879#ifdef CONFIG_ASH_EXPAND_PRMT
10880static const char *
10881expandstr(const char *ps)
10882{
10883 union node n;
10884
10885 /* XXX Fix (char *) cast. */
10886 setinputstring((char *)ps);
10887 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10888 popfile();
10889
10890 n.narg.type = NARG;
10891 n.narg.next = NULL;
10892 n.narg.text = wordtext;
10893 n.narg.backquote = backquotelist;
10894
10895 expandarg(&n, NULL, 0);
10896 return stackblock();
10897}
10898#endif
10899
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010900static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010901{
Eric Andersenc470f442003-07-28 09:56:35 +000010902 const char *prompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010903#ifdef CONFIG_ASH_EXPAND_PRMT
10904 struct stackmark smark;
10905#endif
10906
10907 needprompt = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010908
10909 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010910 case 1:
10911 prompt = ps1val();
10912 break;
10913 case 2:
10914 prompt = ps2val();
10915 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010916 default: /* 0 */
10917 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010918 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010919#ifdef CONFIG_ASH_EXPAND_PRMT
10920 setstackmark(&smark);
10921 stalloc(stackblocksize());
10922#endif
10923 putprompt(expandstr(prompt));
10924#ifdef CONFIG_ASH_EXPAND_PRMT
10925 popstackmark(&smark);
10926#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010927}
10928
Eric Andersencb57d552001-06-28 07:25:16 +000010929
Eric Andersenc470f442003-07-28 09:56:35 +000010930static const char *const *findkwd(const char *s)
10931{
10932 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010933 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010934 sizeof(const char *), pstrcmp);
10935}
10936
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010937/* redir.c */
Eric Andersenc470f442003-07-28 09:56:35 +000010938
Eric Andersencb57d552001-06-28 07:25:16 +000010939/*
10940 * Code for dealing with input/output redirection.
10941 */
10942
Eric Andersenc470f442003-07-28 09:56:35 +000010943#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010944#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010945# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010946#else
10947# define PIPESIZE PIPE_BUF
10948#endif
10949
Eric Andersen62483552001-07-10 06:09:16 +000010950/*
10951 * Open a file in noclobber mode.
10952 * The code was copied from bash.
10953 */
Rob Landley88621d72006-08-29 19:41:06 +000010954static int noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010955{
10956 int r, fd;
10957 struct stat finfo, finfo2;
10958
10959 /*
10960 * If the file exists and is a regular file, return an error
10961 * immediately.
10962 */
10963 r = stat(fname, &finfo);
10964 if (r == 0 && S_ISREG(finfo.st_mode)) {
10965 errno = EEXIST;
10966 return -1;
10967 }
10968
10969 /*
10970 * If the file was not present (r != 0), make sure we open it
10971 * exclusively so that if it is created before we open it, our open
10972 * will fail. Make sure that we do not truncate an existing file.
10973 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10974 * file was not a regular file, we leave O_EXCL off.
10975 */
10976 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010977 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10978 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010979
10980 /* If the open failed, return the file descriptor right away. */
10981 if (fd < 0)
10982 return fd;
10983
10984 /*
10985 * OK, the open succeeded, but the file may have been changed from a
10986 * non-regular file to a regular file between the stat and the open.
10987 * We are assuming that the O_EXCL open handles the case where FILENAME
10988 * did not exist and is symlinked to an existing file between the stat
10989 * and open.
10990 */
10991
10992 /*
10993 * If we can open it and fstat the file descriptor, and neither check
10994 * revealed that it was a regular file, and the file has not been
10995 * replaced, return the file descriptor.
10996 */
Eric Andersenc470f442003-07-28 09:56:35 +000010997 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10998 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010999 return fd;
11000
11001 /* The file has been replaced. badness. */
11002 close(fd);
11003 errno = EEXIST;
11004 return -1;
11005}
Eric Andersencb57d552001-06-28 07:25:16 +000011006
11007/*
Eric Andersen62483552001-07-10 06:09:16 +000011008 * Handle here documents. Normally we fork off a process to write the
11009 * data to a pipe. If the document is short, we can stuff the data in
11010 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000011011 */
11012
Rob Landley88621d72006-08-29 19:41:06 +000011013static int openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011014{
11015 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000011016 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011017
Eric Andersen62483552001-07-10 06:09:16 +000011018 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011019 sh_error("Pipe call failed");
Eric Andersen62483552001-07-10 06:09:16 +000011020 if (redir->type == NHERE) {
11021 len = strlen(redir->nhere.doc->narg.text);
11022 if (len <= PIPESIZE) {
Rob Landley53437472006-07-16 08:14:35 +000011023 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000011024 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011025 }
Eric Andersencb57d552001-06-28 07:25:16 +000011026 }
Eric Andersenc470f442003-07-28 09:56:35 +000011027 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000011028 close(pip[0]);
11029 signal(SIGINT, SIG_IGN);
11030 signal(SIGQUIT, SIG_IGN);
11031 signal(SIGHUP, SIG_IGN);
11032#ifdef SIGTSTP
11033 signal(SIGTSTP, SIG_IGN);
11034#endif
11035 signal(SIGPIPE, SIG_DFL);
11036 if (redir->type == NHERE)
Rob Landley53437472006-07-16 08:14:35 +000011037 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000011038 else
11039 expandhere(redir->nhere.doc, pip[1]);
11040 _exit(0);
11041 }
Eric Andersenc470f442003-07-28 09:56:35 +000011042out:
Eric Andersen62483552001-07-10 06:09:16 +000011043 close(pip[1]);
11044 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011045}
11046
Eric Andersenc470f442003-07-28 09:56:35 +000011047static int
11048openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011049{
Eric Andersencb57d552001-06-28 07:25:16 +000011050 char *fname;
11051 int f;
11052
11053 switch (redir->nfile.type) {
11054 case NFROM:
11055 fname = redir->nfile.expfname;
11056 if ((f = open(fname, O_RDONLY)) < 0)
11057 goto eopen;
11058 break;
11059 case NFROMTO:
11060 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011061 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011062 goto ecreate;
11063 break;
11064 case NTO:
11065 /* Take care of noclobber mode. */
11066 if (Cflag) {
11067 fname = redir->nfile.expfname;
11068 if ((f = noclobberopen(fname)) < 0)
11069 goto ecreate;
11070 break;
11071 }
Eric Andersenc470f442003-07-28 09:56:35 +000011072 /* FALLTHROUGH */
11073 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011074 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011075 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011076 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011077 break;
11078 case NAPPEND:
11079 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011080 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011081 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011082 break;
11083 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011084#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011085 abort();
11086#endif
11087 /* Fall through to eliminate warning. */
11088 case NTOFD:
11089 case NFROMFD:
11090 f = -1;
11091 break;
11092 case NHERE:
11093 case NXHERE:
11094 f = openhere(redir);
11095 break;
11096 }
11097
11098 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011099ecreate:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011100 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011101eopen:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011102 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
Eric Andersencb57d552001-06-28 07:25:16 +000011103}
11104
Rob Landley88621d72006-08-29 19:41:06 +000011105static void dupredirect(union node *redir, int f)
Eric Andersenc470f442003-07-28 09:56:35 +000011106{
11107 int fd = redir->nfile.fd;
11108
11109 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11110 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11111 copyfd(redir->ndup.dupfd, fd);
11112 }
11113 return;
11114 }
11115
11116 if (f != fd) {
11117 copyfd(f, fd);
11118 close(f);
11119 }
11120 return;
11121}
Eric Andersencb57d552001-06-28 07:25:16 +000011122
Eric Andersen62483552001-07-10 06:09:16 +000011123/*
11124 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11125 * old file descriptors are stashed away so that the redirection can be
11126 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11127 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011128 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011129 */
11130
Eric Andersenc470f442003-07-28 09:56:35 +000011131static void
11132redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011133{
11134 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011135 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011136 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011137 int fd;
11138 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011139 int *p;
11140 nullredirs++;
11141 if (!redir) {
11142 return;
Eric Andersen62483552001-07-10 06:09:16 +000011143 }
Eric Andersenc470f442003-07-28 09:56:35 +000011144 sv = NULL;
11145 INTOFF;
11146 if (flags & REDIR_PUSH) {
11147 struct redirtab *q;
11148 q = ckmalloc(sizeof (struct redirtab));
11149 q->next = redirlist;
11150 redirlist = q;
11151 q->nullredirs = nullredirs - 1;
11152 for (i = 0 ; i < 10 ; i++)
11153 q->renamed[i] = EMPTY;
11154 nullredirs = 0;
11155 sv = q;
11156 }
11157 n = redir;
11158 do {
Eric Andersen62483552001-07-10 06:09:16 +000011159 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011160 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011161 n->ndup.dupfd == fd)
11162 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011163
Eric Andersen62483552001-07-10 06:09:16 +000011164 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011165 if (fd == newfd)
11166 continue;
11167 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11168 i = fcntl(fd, F_DUPFD, 10);
11169
11170 if (i == -1) {
11171 i = errno;
11172 if (i != EBADF) {
11173 close(newfd);
11174 errno = i;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011175 sh_error("%d: %m", fd);
Eric Andersen62483552001-07-10 06:09:16 +000011176 /* NOTREACHED */
11177 }
Eric Andersenc470f442003-07-28 09:56:35 +000011178 } else {
11179 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011180 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011181 }
Eric Andersenc470f442003-07-28 09:56:35 +000011182 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011183 close(fd);
11184 }
Eric Andersenc470f442003-07-28 09:56:35 +000011185 dupredirect(n, newfd);
11186 } while ((n = n->nfile.next));
11187 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011188 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11189 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011190}
11191
11192
Eric Andersencb57d552001-06-28 07:25:16 +000011193/*
11194 * Undo the effects of the last redirection.
11195 */
11196
Eric Andersenc470f442003-07-28 09:56:35 +000011197void
11198popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011199{
Eric Andersenc470f442003-07-28 09:56:35 +000011200 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011201 int i;
11202
Eric Andersenc470f442003-07-28 09:56:35 +000011203 if (--nullredirs >= 0)
11204 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011205 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011206 rp = redirlist;
11207 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011208 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011209 if (!drop) {
11210 close(i);
11211 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011212 }
Eric Andersenc470f442003-07-28 09:56:35 +000011213 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011214 }
11215 }
11216 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011217 nullredirs = rp->nullredirs;
11218 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011219 INTON;
11220}
11221
11222/*
Eric Andersenc470f442003-07-28 09:56:35 +000011223 * Undo all redirections. Called on error or interrupt.
11224 */
11225
11226/*
Eric Andersencb57d552001-06-28 07:25:16 +000011227 * Discard all saved file descriptors.
11228 */
11229
Eric Andersenc470f442003-07-28 09:56:35 +000011230void
11231clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011232{
Eric Andersenc470f442003-07-28 09:56:35 +000011233 for (;;) {
11234 nullredirs = 0;
11235 if (!redirlist)
11236 break;
11237 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011238 }
Eric Andersencb57d552001-06-28 07:25:16 +000011239}
11240
11241
Eric Andersencb57d552001-06-28 07:25:16 +000011242/*
11243 * Copy a file descriptor to be >= to. Returns -1
11244 * if the source file descriptor is closed, EMPTY if there are no unused
11245 * file descriptors left.
11246 */
11247
Eric Andersenc470f442003-07-28 09:56:35 +000011248int
11249copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011250{
11251 int newfd;
11252
11253 newfd = fcntl(from, F_DUPFD, to);
11254 if (newfd < 0) {
11255 if (errno == EMFILE)
11256 return EMPTY;
11257 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011258 sh_error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011259 }
11260 return newfd;
11261}
11262
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011263
Eric Andersenc470f442003-07-28 09:56:35 +000011264int
11265redirectsafe(union node *redir, int flags)
11266{
11267 int err;
11268 volatile int saveint;
11269 struct jmploc *volatile savehandler = handler;
11270 struct jmploc jmploc;
11271
11272 SAVEINT(saveint);
11273 if (!(err = setjmp(jmploc.loc) * 2)) {
11274 handler = &jmploc;
11275 redirect(redir, flags);
11276 }
11277 handler = savehandler;
11278 if (err && exception != EXERROR)
11279 longjmp(handler->loc, 1);
11280 RESTOREINT(saveint);
11281 return err;
11282}
11283
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011284/* show.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011285
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011286#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +000011287static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011288static void shcmd(union node *, FILE *);
11289static void sharg(union node *, FILE *);
11290static void indent(int, char *, FILE *);
11291static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011292
11293
Eric Andersenc470f442003-07-28 09:56:35 +000011294void
11295showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011296{
11297 trputs("showtree called\n");
11298 shtree(n, 1, NULL, stdout);
11299}
Eric Andersencb57d552001-06-28 07:25:16 +000011300
Eric Andersenc470f442003-07-28 09:56:35 +000011301
11302static void
11303shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011304{
11305 struct nodelist *lp;
11306 const char *s;
11307
11308 if (n == NULL)
11309 return;
11310
11311 indent(ind, pfx, fp);
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000011312 switch (n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011313 case NSEMI:
11314 s = "; ";
11315 goto binop;
11316 case NAND:
11317 s = " && ";
11318 goto binop;
11319 case NOR:
11320 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011321binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011322 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011323 /* if (ind < 0) */
11324 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011325 shtree(n->nbinary.ch2, ind, NULL, fp);
11326 break;
11327 case NCMD:
11328 shcmd(n, fp);
11329 if (ind >= 0)
11330 putc('\n', fp);
11331 break;
11332 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011333 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011334 shcmd(lp->n, fp);
11335 if (lp->next)
11336 fputs(" | ", fp);
11337 }
11338 if (n->npipe.backgnd)
11339 fputs(" &", fp);
11340 if (ind >= 0)
11341 putc('\n', fp);
11342 break;
11343 default:
11344 fprintf(fp, "<node type %d>", n->type);
11345 if (ind >= 0)
11346 putc('\n', fp);
11347 break;
11348 }
11349}
11350
11351
Eric Andersenc470f442003-07-28 09:56:35 +000011352static void
11353shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011354{
11355 union node *np;
11356 int first;
11357 const char *s;
11358 int dftfd;
11359
11360 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011361 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11362 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011363 putchar(' ');
11364 sharg(np, fp);
11365 first = 0;
11366 }
Eric Andersenc470f442003-07-28 09:56:35 +000011367 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11368 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011369 putchar(' ');
11370 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011371 case NTO: s = ">"; dftfd = 1; break;
11372 case NCLOBBER: s = ">|"; dftfd = 1; break;
11373 case NAPPEND: s = ">>"; dftfd = 1; break;
11374 case NTOFD: s = ">&"; dftfd = 1; break;
11375 case NFROM: s = "<"; dftfd = 0; break;
11376 case NFROMFD: s = "<&"; dftfd = 0; break;
11377 case NFROMTO: s = "<>"; dftfd = 0; break;
11378 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011379 }
11380 if (np->nfile.fd != dftfd)
11381 fprintf(fp, "%d", np->nfile.fd);
11382 fputs(s, fp);
11383 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11384 fprintf(fp, "%d", np->ndup.dupfd);
11385 } else {
11386 sharg(np->nfile.fname, fp);
11387 }
11388 first = 0;
11389 }
11390}
11391
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011392
Eric Andersenc470f442003-07-28 09:56:35 +000011393
11394static void
11395sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011396{
Eric Andersencb57d552001-06-28 07:25:16 +000011397 char *p;
11398 struct nodelist *bqlist;
11399 int subtype;
11400
11401 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011402 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011403 abort();
11404 }
11405 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011406 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011407 switch (*p) {
11408 case CTLESC:
11409 putc(*++p, fp);
11410 break;
11411 case CTLVAR:
11412 putc('$', fp);
11413 putc('{', fp);
11414 subtype = *++p;
11415 if (subtype == VSLENGTH)
11416 putc('#', fp);
11417
11418 while (*p != '=')
11419 putc(*p++, fp);
11420
11421 if (subtype & VSNUL)
11422 putc(':', fp);
11423
11424 switch (subtype & VSTYPE) {
11425 case VSNORMAL:
11426 putc('}', fp);
11427 break;
11428 case VSMINUS:
11429 putc('-', fp);
11430 break;
11431 case VSPLUS:
11432 putc('+', fp);
11433 break;
11434 case VSQUESTION:
11435 putc('?', fp);
11436 break;
11437 case VSASSIGN:
11438 putc('=', fp);
11439 break;
11440 case VSTRIMLEFT:
11441 putc('#', fp);
11442 break;
11443 case VSTRIMLEFTMAX:
11444 putc('#', fp);
11445 putc('#', fp);
11446 break;
11447 case VSTRIMRIGHT:
11448 putc('%', fp);
11449 break;
11450 case VSTRIMRIGHTMAX:
11451 putc('%', fp);
11452 putc('%', fp);
11453 break;
11454 case VSLENGTH:
11455 break;
11456 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011457 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011458 }
11459 break;
11460 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011461 putc('}', fp);
11462 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011463 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011464 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011465 putc('$', fp);
11466 putc('(', fp);
11467 shtree(bqlist->n, -1, NULL, fp);
11468 putc(')', fp);
11469 break;
11470 default:
11471 putc(*p, fp);
11472 break;
11473 }
11474 }
11475}
11476
11477
Eric Andersenc470f442003-07-28 09:56:35 +000011478static void
11479indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011480{
11481 int i;
11482
Eric Andersenc470f442003-07-28 09:56:35 +000011483 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011484 if (pfx && i == amount - 1)
11485 fputs(pfx, fp);
11486 putc('\t', fp);
11487 }
11488}
Eric Andersencb57d552001-06-28 07:25:16 +000011489
Eric Andersenc470f442003-07-28 09:56:35 +000011490
11491
11492/*
11493 * Debugging stuff.
11494 */
11495
11496
Eric Andersencb57d552001-06-28 07:25:16 +000011497FILE *tracefile;
11498
Eric Andersencb57d552001-06-28 07:25:16 +000011499
Eric Andersenc470f442003-07-28 09:56:35 +000011500void
11501trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011502{
Eric Andersenc470f442003-07-28 09:56:35 +000011503 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011504 return;
11505 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011506}
11507
Eric Andersenc470f442003-07-28 09:56:35 +000011508void
11509trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011510{
11511 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011512
Eric Andersenc470f442003-07-28 09:56:35 +000011513 if (debug != 1)
11514 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011515 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011516 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011517 va_end(va);
11518}
11519
Eric Andersenc470f442003-07-28 09:56:35 +000011520void
11521tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011522{
Eric Andersenc470f442003-07-28 09:56:35 +000011523 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011524 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011525 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011526}
11527
11528
Eric Andersenc470f442003-07-28 09:56:35 +000011529void
11530trputs(const char *s)
11531{
11532 if (debug != 1)
11533 return;
11534 fputs(s, tracefile);
11535}
11536
11537
11538static void
11539trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011540{
11541 char *p;
11542 char c;
11543
Eric Andersenc470f442003-07-28 09:56:35 +000011544 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011545 return;
11546 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011547 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011548 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011549 case '\n': c = 'n'; goto backslash;
11550 case '\t': c = 't'; goto backslash;
11551 case '\r': c = 'r'; goto backslash;
11552 case '"': c = '"'; goto backslash;
11553 case '\\': c = '\\'; goto backslash;
11554 case CTLESC: c = 'e'; goto backslash;
11555 case CTLVAR: c = 'v'; goto backslash;
11556 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11557 case CTLBACKQ: c = 'q'; goto backslash;
11558 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11559backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011560 putc(c, tracefile);
11561 break;
11562 default:
11563 if (*p >= ' ' && *p <= '~')
11564 putc(*p, tracefile);
11565 else {
11566 putc('\\', tracefile);
11567 putc(*p >> 6 & 03, tracefile);
11568 putc(*p >> 3 & 07, tracefile);
11569 putc(*p & 07, tracefile);
11570 }
11571 break;
11572 }
11573 }
11574 putc('"', tracefile);
11575}
11576
11577
Eric Andersenc470f442003-07-28 09:56:35 +000011578void
11579trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011580{
Eric Andersenc470f442003-07-28 09:56:35 +000011581 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011582 return;
11583 while (*ap) {
11584 trstring(*ap++);
11585 if (*ap)
11586 putc(' ', tracefile);
11587 else
11588 putc('\n', tracefile);
11589 }
Eric Andersencb57d552001-06-28 07:25:16 +000011590}
11591
11592
Eric Andersenc470f442003-07-28 09:56:35 +000011593void
11594opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011595{
Eric Andersencb57d552001-06-28 07:25:16 +000011596 char s[100];
11597#ifdef O_APPEND
11598 int flags;
11599#endif
11600
Eric Andersenc470f442003-07-28 09:56:35 +000011601 if (debug != 1) {
11602 if (tracefile)
11603 fflush(tracefile);
11604 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011605 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011606 }
Eric Andersenc470f442003-07-28 09:56:35 +000011607 scopy("./trace", s);
11608 if (tracefile) {
11609 if (!freopen(s, "a", tracefile)) {
11610 fprintf(stderr, "Can't re-open %s\n", s);
11611 debug = 0;
11612 return;
11613 }
11614 } else {
11615 if ((tracefile = fopen(s, "a")) == NULL) {
11616 fprintf(stderr, "Can't open %s\n", s);
11617 debug = 0;
11618 return;
11619 }
11620 }
Eric Andersencb57d552001-06-28 07:25:16 +000011621#ifdef O_APPEND
11622 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11623 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11624#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011625 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011626 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011627}
Eric Andersenc470f442003-07-28 09:56:35 +000011628#endif /* DEBUG */
11629
11630
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011631/* trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011632
11633/*
11634 * Sigmode records the current value of the signal handlers for the various
11635 * modes. A value of zero means that the current handler is not known.
11636 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11637 */
11638
11639#define S_DFL 1 /* default signal handling (SIG_DFL) */
11640#define S_CATCH 2 /* signal is caught */
11641#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11642#define S_HARD_IGN 4 /* signal is ignored permenantly */
11643#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11644
Eric Andersencb57d552001-06-28 07:25:16 +000011645
11646
11647/*
Eric Andersencb57d552001-06-28 07:25:16 +000011648 * The trap builtin.
11649 */
11650
Eric Andersenc470f442003-07-28 09:56:35 +000011651int
11652trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011653{
11654 char *action;
11655 char **ap;
11656 int signo;
11657
Eric Andersenc470f442003-07-28 09:56:35 +000011658 nextopt(nullstr);
11659 ap = argptr;
11660 if (!*ap) {
11661 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011662 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011663 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011664
Rob Landleyc9c1a412006-07-12 19:17:55 +000011665 sn = get_signame(signo);
Eric Andersenc470f442003-07-28 09:56:35 +000011666 out1fmt("trap -- %s %s\n",
11667 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011668 }
11669 }
11670 return 0;
11671 }
Eric Andersenc470f442003-07-28 09:56:35 +000011672 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011673 action = NULL;
11674 else
11675 action = *ap++;
11676 while (*ap) {
Rob Landleyc9c1a412006-07-12 19:17:55 +000011677 if ((signo = get_signum(*ap)) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011678 sh_error("%s: bad trap", *ap);
Eric Andersencb57d552001-06-28 07:25:16 +000011679 INTOFF;
11680 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000011681 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000011682 action = NULL;
11683 else
Eric Andersenc470f442003-07-28 09:56:35 +000011684 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011685 }
Eric Andersenc470f442003-07-28 09:56:35 +000011686 if (trap[signo])
11687 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011688 trap[signo] = action;
11689 if (signo != 0)
11690 setsignal(signo);
11691 INTON;
11692 ap++;
11693 }
11694 return 0;
11695}
11696
11697
Eric Andersenc470f442003-07-28 09:56:35 +000011698/*
11699 * Clear traps on a fork.
11700 */
11701
11702void
11703clear_traps(void)
11704{
11705 char **tp;
11706
11707 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11708 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11709 INTOFF;
11710 ckfree(*tp);
11711 *tp = NULL;
11712 if (tp != &trap[0])
11713 setsignal(tp - trap);
11714 INTON;
11715 }
11716 }
11717}
11718
11719
Eric Andersencb57d552001-06-28 07:25:16 +000011720/*
11721 * Set the signal handler for the specified signal. The routine figures
11722 * out what it should be set to.
11723 */
11724
Eric Andersenc470f442003-07-28 09:56:35 +000011725void
11726setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011727{
11728 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011729 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011730 struct sigaction act;
11731
11732 if ((t = trap[signo]) == NULL)
11733 action = S_DFL;
11734 else if (*t != '\0')
11735 action = S_CATCH;
11736 else
11737 action = S_IGN;
11738 if (rootshell && action == S_DFL) {
11739 switch (signo) {
11740 case SIGINT:
11741 if (iflag || minusc || sflag == 0)
11742 action = S_CATCH;
11743 break;
11744 case SIGQUIT:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000011745#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011746 if (debug)
11747 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011748#endif
11749 /* FALLTHROUGH */
11750 case SIGTERM:
11751 if (iflag)
11752 action = S_IGN;
11753 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011754#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011755 case SIGTSTP:
11756 case SIGTTOU:
11757 if (mflag)
11758 action = S_IGN;
11759 break;
11760#endif
11761 }
11762 }
11763
11764 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011765 tsig = *t;
11766 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011767 /*
11768 * current setting unknown
11769 */
11770 if (sigaction(signo, 0, &act) == -1) {
11771 /*
11772 * Pretend it worked; maybe we should give a warning
11773 * here, but other shells don't. We don't alter
11774 * sigmode, so that we retry every time.
11775 */
11776 return;
11777 }
11778 if (act.sa_handler == SIG_IGN) {
11779 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011780 signo == SIGTTIN || signo == SIGTTOU)) {
11781 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011782 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011783 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011784 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011785 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011786 }
11787 }
Eric Andersenc470f442003-07-28 09:56:35 +000011788 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011789 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011790 switch (action) {
11791 case S_CATCH:
11792 act.sa_handler = onsig;
11793 break;
11794 case S_IGN:
11795 act.sa_handler = SIG_IGN;
11796 break;
11797 default:
11798 act.sa_handler = SIG_DFL;
11799 }
Eric Andersencb57d552001-06-28 07:25:16 +000011800 *t = action;
11801 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011802 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011803 sigaction(signo, &act, 0);
11804}
11805
11806/*
11807 * Ignore a signal.
11808 */
11809
Eric Andersenc470f442003-07-28 09:56:35 +000011810void
11811ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011812{
11813 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11814 signal(signo, SIG_IGN);
11815 }
11816 sigmode[signo - 1] = S_HARD_IGN;
11817}
11818
11819
Eric Andersencb57d552001-06-28 07:25:16 +000011820/*
11821 * Signal handler.
11822 */
11823
Eric Andersenc470f442003-07-28 09:56:35 +000011824void
11825onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011826{
Eric Andersencb57d552001-06-28 07:25:16 +000011827 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011828 pendingsigs = signo;
11829
11830 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11831 if (!suppressint)
11832 onint();
11833 intpending = 1;
11834 }
Eric Andersencb57d552001-06-28 07:25:16 +000011835}
11836
11837
Eric Andersencb57d552001-06-28 07:25:16 +000011838/*
11839 * Called to execute a trap. Perhaps we should avoid entering new trap
11840 * handlers while we are executing a trap handler.
11841 */
11842
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011843int
Eric Andersenc470f442003-07-28 09:56:35 +000011844dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011845{
Eric Andersenc470f442003-07-28 09:56:35 +000011846 char *p;
11847 char *q;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011848 int i;
Eric Andersencb57d552001-06-28 07:25:16 +000011849 int savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011850 int skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011851
Eric Andersenc470f442003-07-28 09:56:35 +000011852 savestatus = exitstatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011853 pendingsigs = 0;
11854 xbarrier();
11855
11856 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11857 if (!*q)
11858 continue;
11859 *q = 0;
11860
11861 p = trap[i + 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011862 if (!p)
11863 continue;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011864 skip = evalstring(p, SKIPEVAL);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011865 exitstatus = savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011866 if (skip)
11867 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011868 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011869
11870 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +000011871}
11872
Eric Andersenc470f442003-07-28 09:56:35 +000011873
Eric Andersenc470f442003-07-28 09:56:35 +000011874/*
11875 * Controls whether the shell is interactive or not.
11876 */
11877
Eric Andersenc470f442003-07-28 09:56:35 +000011878void
11879setinteractive(int on)
11880{
11881 static int is_interactive;
11882
11883 if (++on == is_interactive)
11884 return;
11885 is_interactive = on;
11886 setsignal(SIGINT);
11887 setsignal(SIGQUIT);
11888 setsignal(SIGTERM);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000011889#if !ENABLE_FEATURE_SH_EXTRA_QUIET
Eric Andersenc470f442003-07-28 09:56:35 +000011890 if(is_interactive > 1) {
11891 /* Looks like they want an interactive shell */
11892 static int do_banner;
11893
11894 if(!do_banner) {
11895 out1fmt(
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +000011896 "\n\n%s Built-in shell (ash)\n"
11897 "Enter 'help' for a list of built-in commands.\n\n",
11898 BB_BANNER);
Eric Andersenc470f442003-07-28 09:56:35 +000011899 do_banner++;
11900 }
11901 }
11902#endif
11903}
11904
11905
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000011906#if !ENABLE_FEATURE_SH_EXTRA_QUIET
Eric Andersenc470f442003-07-28 09:56:35 +000011907/*** List the available builtins ***/
11908
11909static int helpcmd(int argc, char **argv)
11910{
11911 int col, i;
11912
11913 out1fmt("\nBuilt-in commands:\n-------------------\n");
11914 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11915 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11916 builtincmd[i].name + 1);
11917 if (col > 60) {
11918 out1fmt("\n");
11919 col = 0;
11920 }
11921 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000011922#if ENABLE_FEATURE_SH_STANDALONE_SHELL
Denis Vlasenko0ee39992006-12-24 15:23:28 +000011923 for (i = 0; i < NUM_APPLETS; i++) {
11924 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11925 if (col > 60) {
11926 out1fmt("\n");
11927 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011928 }
11929 }
11930#endif
11931 out1fmt("\n\n");
11932 return EXIT_SUCCESS;
11933}
11934#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11935
Eric Andersencb57d552001-06-28 07:25:16 +000011936/*
11937 * Called to exit the shell.
11938 */
11939
Eric Andersenc470f442003-07-28 09:56:35 +000011940void
11941exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011942{
Eric Andersenc470f442003-07-28 09:56:35 +000011943 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011944 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011945 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011946
Eric Andersenc470f442003-07-28 09:56:35 +000011947 status = exitstatus;
11948 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011949 if (setjmp(loc.loc)) {
11950 if (exception == EXEXIT)
Denis Vlasenko7f0d7ae2007-01-18 01:12:57 +000011951/* dash bug: it just does _exit(exitstatus) here
11952 * but we have to do setjobctl(0) first!
11953 * (bug is still not fixed in dash-0.5.3 - if you run dash
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000011954 * under Midnight Commander, on exit from dash MC is backgrounded) */
Denis Vlasenko7f0d7ae2007-01-18 01:12:57 +000011955 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +000011956 goto out;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011957 }
Eric Andersenc470f442003-07-28 09:56:35 +000011958 handler = &loc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011959 if ((p = trap[0])) {
Eric Andersencb57d552001-06-28 07:25:16 +000011960 trap[0] = NULL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011961 evalstring(p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011962 }
Eric Andersencb57d552001-06-28 07:25:16 +000011963 flushall();
Eric Andersenc470f442003-07-28 09:56:35 +000011964out:
Denis Vlasenko7f0d7ae2007-01-18 01:12:57 +000011965 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011966 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011967 /* NOTREACHED */
11968}
11969
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011970/* var.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011971
11972static struct var *vartab[VTABSIZE];
11973
11974static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011975static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011976
11977/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011978 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011979 */
11980
Eric Andersenc470f442003-07-28 09:56:35 +000011981
11982#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011983/*
Eric Andersenc470f442003-07-28 09:56:35 +000011984 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011985 */
11986
Eric Andersenc470f442003-07-28 09:56:35 +000011987int
11988setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011989{
Eric Andersenc470f442003-07-28 09:56:35 +000011990 int err;
11991 volatile int saveint;
11992 struct jmploc *volatile savehandler = handler;
11993 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011994
Eric Andersenc470f442003-07-28 09:56:35 +000011995 SAVEINT(saveint);
11996 if (setjmp(jmploc.loc))
11997 err = 1;
11998 else {
11999 handler = &jmploc;
12000 setvar(name, val, flags);
12001 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012002 }
Eric Andersenc470f442003-07-28 09:56:35 +000012003 handler = savehandler;
12004 RESTOREINT(saveint);
12005 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000012006}
Eric Andersenc470f442003-07-28 09:56:35 +000012007#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012008
12009/*
12010 * Set the value of a variable. The flags argument is ored with the
12011 * flags of the variable. If val is NULL, the variable is unset.
12012 */
12013
Eric Andersenc470f442003-07-28 09:56:35 +000012014static void
12015setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012016{
Eric Andersenc470f442003-07-28 09:56:35 +000012017 char *p, *q;
12018 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000012019 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000012020 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000012021
Eric Andersenc470f442003-07-28 09:56:35 +000012022 q = endofname(name);
12023 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012024 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000012025 if (!namelen || p != q)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012026 sh_error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012027 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012028 if (val == NULL) {
12029 flags |= VUNSET;
12030 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012031 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000012032 }
12033 INTOFF;
Denis Vlasenko15b213e2006-12-19 00:20:20 +000012034 nameeq = ckmalloc(namelen + vallen + 2);
Denis Vlasenko7cfecc42006-12-18 22:32:45 +000012035 p = memcpy(nameeq, name, namelen) + namelen;
Paul Fox8de331d2005-07-21 12:03:05 +000012036 if (val) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012037 *p++ = '=';
Denis Vlasenko7cfecc42006-12-18 22:32:45 +000012038 p = memcpy(p, val, vallen) + vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000012039 }
Eric Andersenc470f442003-07-28 09:56:35 +000012040 *p = '\0';
12041 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012042 INTON;
12043}
12044
12045
Eric Andersencb57d552001-06-28 07:25:16 +000012046/*
12047 * Same as setvar except that the variable and value are passed in
12048 * the first argument as name=value. Since the first argument will
12049 * be actually stored in the table, it should not be a string that
12050 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012051 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012052 */
12053
Eric Andersenc470f442003-07-28 09:56:35 +000012054void
12055setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012056{
12057 struct var *vp, **vpp;
12058
12059 vpp = hashvar(s);
12060 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012061 vp = *findvar(vpp, s);
12062 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012063 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12064 const char *n;
12065
Eric Andersenc470f442003-07-28 09:56:35 +000012066 if (flags & VNOSAVE)
12067 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012068 n = vp->text;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012069 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012070 }
Eric Andersenc470f442003-07-28 09:56:35 +000012071
12072 if (flags & VNOSET)
12073 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012074
12075 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012076 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012077
Eric Andersenc470f442003-07-28 09:56:35 +000012078 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12079 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012080
Eric Andersenc470f442003-07-28 09:56:35 +000012081 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12082 } else {
12083 if (flags & VNOSET)
12084 return;
12085 /* not found */
12086 vp = ckmalloc(sizeof (*vp));
12087 vp->next = *vpp;
12088 vp->func = NULL;
12089 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012090 }
Eric Andersenc470f442003-07-28 09:56:35 +000012091 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12092 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012093 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012094 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012095}
12096
12097
Eric Andersencb57d552001-06-28 07:25:16 +000012098/*
12099 * Process a linked list of variable assignments.
12100 */
12101
Eric Andersenc470f442003-07-28 09:56:35 +000012102static void
12103listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012104{
Eric Andersenc470f442003-07-28 09:56:35 +000012105 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012106
Eric Andersenc470f442003-07-28 09:56:35 +000012107 if (!lp)
12108 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012109 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012110 do {
12111 setvareq(lp->text, flags);
12112 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012113 INTON;
12114}
12115
12116
Eric Andersencb57d552001-06-28 07:25:16 +000012117/*
12118 * Find the value of a variable. Returns NULL if not set.
12119 */
12120
Eric Andersenc470f442003-07-28 09:56:35 +000012121static char *
12122lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012123{
Eric Andersencb57d552001-06-28 07:25:16 +000012124 struct var *v;
12125
Eric Andersen16767e22004-03-16 05:14:10 +000012126 if ((v = *findvar(hashvar(name), name))) {
12127#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012128 /*
12129 * Dynamic variables are implemented roughly the same way they are
12130 * in bash. Namely, they're "special" so long as they aren't unset.
12131 * As soon as they're unset, they're no longer dynamic, and dynamic
12132 * lookup will no longer happen at that point. -- PFM.
12133 */
Eric Andersen16767e22004-03-16 05:14:10 +000012134 if((v->flags & VDYNAMIC))
12135 (*v->func)(NULL);
12136#endif
12137 if(!(v->flags & VUNSET))
12138 return strchrnul(v->text, '=') + 1;
12139 }
Eric Andersenef02f822004-03-11 13:34:24 +000012140
Eric Andersencb57d552001-06-28 07:25:16 +000012141 return NULL;
12142}
12143
12144
Eric Andersencb57d552001-06-28 07:25:16 +000012145/*
12146 * Search the environment of a builtin command.
12147 */
12148
Eric Andersenc470f442003-07-28 09:56:35 +000012149static char *
12150bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012151{
Eric Andersenc470f442003-07-28 09:56:35 +000012152 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012153
Eric Andersenc470f442003-07-28 09:56:35 +000012154 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012155 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012156 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012157 }
12158 return lookupvar(name);
12159}
12160
12161
Eric Andersencb57d552001-06-28 07:25:16 +000012162/*
Eric Andersenc470f442003-07-28 09:56:35 +000012163 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012164 */
12165
Eric Andersenc470f442003-07-28 09:56:35 +000012166static char **
12167listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012168{
Eric Andersencb57d552001-06-28 07:25:16 +000012169 struct var **vpp;
12170 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012171 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012172 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012173
Eric Andersenc470f442003-07-28 09:56:35 +000012174 STARTSTACKSTR(ep);
12175 vpp = vartab;
12176 mask = on | off;
12177 do {
12178 for (vp = *vpp ; vp ; vp = vp->next)
12179 if ((vp->flags & mask) == on) {
12180 if (ep == stackstrend())
12181 ep = growstackstr();
12182 *ep++ = (char *) vp->text;
12183 }
12184 } while (++vpp < vartab + VTABSIZE);
12185 if (ep == stackstrend())
12186 ep = growstackstr();
12187 if (end)
12188 *end = ep;
12189 *ep++ = NULL;
12190 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012191}
12192
12193
12194/*
Eric Andersenc470f442003-07-28 09:56:35 +000012195 * POSIX requires that 'set' (but not export or readonly) output the
12196 * variables in lexicographic order - by the locale's collating order (sigh).
12197 * Maybe we could keep them in an ordered balanced binary tree
12198 * instead of hashed lists.
12199 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012200 */
12201
Eric Andersenc470f442003-07-28 09:56:35 +000012202static int
12203showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012204{
Eric Andersenc470f442003-07-28 09:56:35 +000012205 const char *sep;
12206 char **ep, **epend;
12207
12208 ep = listvars(on, off, &epend);
12209 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12210
12211 sep = *sep_prefix ? spcstr : sep_prefix;
12212
12213 for (; ep < epend; ep++) {
12214 const char *p;
12215 const char *q;
12216
12217 p = strchrnul(*ep, '=');
12218 q = nullstr;
12219 if (*p)
12220 q = single_quote(++p);
12221
12222 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12223 }
12224
Eric Andersencb57d552001-06-28 07:25:16 +000012225 return 0;
12226}
12227
12228
12229
12230/*
12231 * The export and readonly commands.
12232 */
12233
Eric Andersenc470f442003-07-28 09:56:35 +000012234static int
12235exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012236{
12237 struct var *vp;
12238 char *name;
12239 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012240 char **aptr;
12241 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12242 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012243
Eric Andersenc470f442003-07-28 09:56:35 +000012244 notp = nextopt("p") - 'p';
12245 if (notp && ((name = *(aptr = argptr)))) {
12246 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012247 if ((p = strchr(name, '=')) != NULL) {
12248 p++;
12249 } else {
12250 if ((vp = *findvar(hashvar(name), name))) {
12251 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012252 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012253 }
12254 }
12255 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012256 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012257 } else {
12258 showvars(argv[0], flag, 0);
12259 }
12260 return 0;
12261}
12262
Eric Andersen34506362001-08-02 05:02:46 +000012263
Eric Andersencb57d552001-06-28 07:25:16 +000012264/*
Eric Andersencb57d552001-06-28 07:25:16 +000012265 * Make a variable a local variable. When a variable is made local, it's
12266 * value and flags are saved in a localvar structure. The saved values
12267 * will be restored when the shell function returns. We handle the name
12268 * "-" as a special case.
12269 */
12270
Rob Landley88621d72006-08-29 19:41:06 +000012271static void mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012272{
Eric Andersencb57d552001-06-28 07:25:16 +000012273 struct localvar *lvp;
12274 struct var **vpp;
12275 struct var *vp;
12276
12277 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012278 lvp = ckmalloc(sizeof (struct localvar));
Denis Vlasenko9f739442006-12-16 23:49:13 +000012279 if (LONE_DASH(name)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012280 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012281 p = ckmalloc(sizeof(optlist));
12282 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012283 vp = NULL;
12284 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012285 char *eq;
12286
Eric Andersencb57d552001-06-28 07:25:16 +000012287 vpp = hashvar(name);
12288 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012289 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012290 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012291 if (eq)
12292 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012293 else
12294 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012295 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012296 lvp->flags = VUNSET;
12297 } else {
12298 lvp->text = vp->text;
12299 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012300 vp->flags |= VSTRFIXED|VTEXTFIXED;
12301 if (eq)
12302 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012303 }
12304 }
12305 lvp->vp = vp;
12306 lvp->next = localvars;
12307 localvars = lvp;
12308 INTON;
12309}
12310
Eric Andersenc470f442003-07-28 09:56:35 +000012311/*
12312 * The "local" command.
12313 */
12314
12315static int
12316localcmd(int argc, char **argv)
12317{
12318 char *name;
12319
12320 argv = argptr;
12321 while ((name = *argv++) != NULL) {
12322 mklocal(name);
12323 }
12324 return 0;
12325}
12326
12327
Eric Andersencb57d552001-06-28 07:25:16 +000012328/*
12329 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012330 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012331 */
12332
Eric Andersenc470f442003-07-28 09:56:35 +000012333static void
12334poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012335{
Eric Andersencb57d552001-06-28 07:25:16 +000012336 struct localvar *lvp;
12337 struct var *vp;
12338
12339 while ((lvp = localvars) != NULL) {
12340 localvars = lvp->next;
12341 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012342 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12343 if (vp == NULL) { /* $- saved */
12344 memcpy(optlist, lvp->text, sizeof(optlist));
12345 ckfree(lvp->text);
12346 optschanged();
12347 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12348 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012349 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012350 if (vp->func)
12351 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12352 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12353 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012354 vp->flags = lvp->flags;
12355 vp->text = lvp->text;
12356 }
Eric Andersenc470f442003-07-28 09:56:35 +000012357 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012358 }
12359}
12360
12361
Eric Andersencb57d552001-06-28 07:25:16 +000012362/*
12363 * The unset builtin command. We unset the function before we unset the
12364 * variable to allow a function to be unset when there is a readonly variable
12365 * with the same name.
12366 */
12367
Eric Andersenc470f442003-07-28 09:56:35 +000012368int
12369unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012370{
12371 char **ap;
12372 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012373 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012374 int ret = 0;
12375
12376 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012377 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012378 }
Eric Andersencb57d552001-06-28 07:25:16 +000012379
Eric Andersenc470f442003-07-28 09:56:35 +000012380 for (ap = argptr; *ap ; ap++) {
12381 if (flag != 'f') {
12382 i = unsetvar(*ap);
12383 ret |= i;
12384 if (!(i & 2))
12385 continue;
12386 }
12387 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012388 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012389 }
Eric Andersenc470f442003-07-28 09:56:35 +000012390 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012391}
12392
12393
12394/*
12395 * Unset the specified variable.
12396 */
12397
Eric Andersenc470f442003-07-28 09:56:35 +000012398int
12399unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012400{
Eric Andersencb57d552001-06-28 07:25:16 +000012401 struct var **vpp;
12402 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012403 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012404
12405 vpp = findvar(hashvar(s), s);
12406 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012407 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012408 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012409 int flags = vp->flags;
12410
12411 retval = 1;
12412 if (flags & VREADONLY)
12413 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012414#ifdef DYNAMIC_VAR
12415 vp->flags &= ~VDYNAMIC;
12416#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012417 if (flags & VUNSET)
12418 goto ok;
12419 if ((flags & VSTRFIXED) == 0) {
12420 INTOFF;
12421 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12422 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012423 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012424 ckfree(vp);
12425 INTON;
12426 } else {
12427 setvar(s, 0, 0);
12428 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012429 }
Eric Andersenc470f442003-07-28 09:56:35 +000012430ok:
12431 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012432 }
12433
Eric Andersenc470f442003-07-28 09:56:35 +000012434out:
12435 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012436}
12437
12438
12439
12440/*
12441 * Find the appropriate entry in the hash table from the name.
12442 */
12443
Eric Andersenc470f442003-07-28 09:56:35 +000012444static struct var **
12445hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012446{
Eric Andersencb57d552001-06-28 07:25:16 +000012447 unsigned int hashval;
12448
12449 hashval = ((unsigned char) *p) << 4;
12450 while (*p && *p != '=')
12451 hashval += (unsigned char) *p++;
12452 return &vartab[hashval % VTABSIZE];
12453}
12454
12455
12456
12457/*
Eric Andersenc470f442003-07-28 09:56:35 +000012458 * Compares two strings up to the first = or '\0'. The first
12459 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012460 * either '=' or '\0'.
12461 */
12462
Eric Andersenc470f442003-07-28 09:56:35 +000012463int
12464varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012465{
Eric Andersenc470f442003-07-28 09:56:35 +000012466 int c, d;
12467
12468 while ((c = *p) == (d = *q)) {
12469 if (!c || c == '=')
12470 goto out;
12471 p++;
12472 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012473 }
Eric Andersenc470f442003-07-28 09:56:35 +000012474 if (c == '=')
12475 c = 0;
12476 if (d == '=')
12477 d = 0;
12478out:
12479 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012480}
12481
Eric Andersenc470f442003-07-28 09:56:35 +000012482static int
12483vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012484{
Eric Andersenc470f442003-07-28 09:56:35 +000012485 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012486}
12487
Eric Andersenc470f442003-07-28 09:56:35 +000012488static struct var **
12489findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012490{
12491 for (; *vpp; vpp = &(*vpp)->next) {
12492 if (varequal((*vpp)->text, name)) {
12493 break;
12494 }
12495 }
12496 return vpp;
12497}
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012498/* setmode.c */
Eric Andersencb57d552001-06-28 07:25:16 +000012499
Eric Andersenc470f442003-07-28 09:56:35 +000012500#include <sys/times.h>
12501
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012502static const unsigned char timescmd_str[] = {
12503 ' ', offsetof(struct tms, tms_utime),
12504 '\n', offsetof(struct tms, tms_stime),
12505 ' ', offsetof(struct tms, tms_cutime),
12506 '\n', offsetof(struct tms, tms_cstime),
12507 0
12508};
Eric Andersencb57d552001-06-28 07:25:16 +000012509
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012510static int timescmd(int ac, char **av)
12511{
12512 long int clk_tck, s, t;
12513 const unsigned char *p;
12514 struct tms buf;
12515
12516 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012517 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012518
12519 p = timescmd_str;
12520 do {
12521 t = *(clock_t *)(((char *) &buf) + p[1]);
12522 s = t / clk_tck;
12523 out1fmt("%ldm%ld.%.3lds%c",
12524 s/60, s%60,
12525 ((t - s * clk_tck) * 1000) / clk_tck,
12526 p[0]);
12527 } while (*(p += 2));
12528
Eric Andersencb57d552001-06-28 07:25:16 +000012529 return 0;
12530}
12531
Eric Andersend35c5df2002-01-09 15:37:36 +000012532#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012533static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012534dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012535{
Eric Andersened9ecf72004-06-22 08:29:45 +000012536 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012537 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012538
Eric Andersenc470f442003-07-28 09:56:35 +000012539 INTOFF;
12540 result = arith(s, &errcode);
12541 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012542 if (errcode == -3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012543 sh_error("exponent less than 0");
Eric Andersen90898442003-08-06 11:20:52 +000012544 else if (errcode == -2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012545 sh_error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012546 else if (errcode == -5)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012547 sh_error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012548 else
12549 synerror(s);
12550 }
12551 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012552
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012553 return result;
Eric Andersen74bcd162001-07-30 21:41:37 +000012554}
Eric Andersenc470f442003-07-28 09:56:35 +000012555
12556
12557/*
Eric Andersen90898442003-08-06 11:20:52 +000012558 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12559 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12560 *
12561 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012562 */
Eric Andersen90898442003-08-06 11:20:52 +000012563
Eric Andersenc470f442003-07-28 09:56:35 +000012564static int
Eric Andersen90898442003-08-06 11:20:52 +000012565letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012566{
Eric Andersenc470f442003-07-28 09:56:35 +000012567 char **ap;
Denis Vlasenkocba9ef52006-10-10 21:00:47 +000012568 arith_t i = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000012569
Eric Andersen90898442003-08-06 11:20:52 +000012570 ap = argv + 1;
12571 if(!*ap)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012572 sh_error("expression expected");
Eric Andersen90898442003-08-06 11:20:52 +000012573 for (ap = argv + 1; *ap; ap++) {
12574 i = dash_arith(*ap);
12575 }
Eric Andersenc470f442003-07-28 09:56:35 +000012576
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012577 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012578}
12579#endif /* CONFIG_ASH_MATH_SUPPORT */
12580
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012581/* miscbltin.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012582
12583/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012584 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012585 */
12586
12587#undef rflag
12588
Denis Vlasenko83e5d6f2006-12-18 21:49:06 +000012589#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012590typedef enum __rlimit_resource rlim_t;
12591#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012592
12593
Eric Andersenc470f442003-07-28 09:56:35 +000012594/*
12595 * The read builtin. The -e option causes backslashes to escape the
12596 * following character.
12597 *
12598 * This uses unbuffered input, which may be avoidable in some cases.
12599 */
12600
12601static int
12602readcmd(int argc, char **argv)
12603{
12604 char **ap;
12605 int backslash;
12606 char c;
12607 int rflag;
12608 char *prompt;
12609 const char *ifs;
12610 char *p;
12611 int startword;
12612 int status;
12613 int i;
Paul Fox02eb9342005-09-07 16:56:02 +000012614#if defined(CONFIG_ASH_READ_NCHARS)
12615 int nch_flag = 0;
12616 int nchars = 0;
12617 int silent = 0;
12618 struct termios tty, old_tty;
12619#endif
12620#if defined(CONFIG_ASH_READ_TIMEOUT)
12621 fd_set set;
12622 struct timeval ts;
12623
12624 ts.tv_sec = ts.tv_usec = 0;
12625#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012626
12627 rflag = 0;
12628 prompt = NULL;
Paul Fox02eb9342005-09-07 16:56:02 +000012629#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12630 while ((i = nextopt("p:rt:n:s")) != '\0')
12631#elif defined(CONFIG_ASH_READ_NCHARS)
12632 while ((i = nextopt("p:rn:s")) != '\0')
12633#elif defined(CONFIG_ASH_READ_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012634 while ((i = nextopt("p:rt:")) != '\0')
12635#else
12636 while ((i = nextopt("p:r")) != '\0')
12637#endif
12638 {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012639 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012640 case 'p':
Eric Andersenc470f442003-07-28 09:56:35 +000012641 prompt = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012642 break;
12643#if defined(CONFIG_ASH_READ_NCHARS)
12644 case 'n':
12645 nchars = strtol(optionarg, &p, 10);
12646 if (*p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012647 sh_error("invalid count");
Paul Fox02eb9342005-09-07 16:56:02 +000012648 nch_flag = (nchars > 0);
12649 break;
12650 case 's':
12651 silent = 1;
12652 break;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012653#endif
Paul Fox02eb9342005-09-07 16:56:02 +000012654#if defined(CONFIG_ASH_READ_TIMEOUT)
12655 case 't':
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012656 ts.tv_sec = strtol(optionarg, &p, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012657 ts.tv_usec = 0;
12658 if (*p == '.') {
12659 char *p2;
12660 if (*++p) {
12661 int scale;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012662 ts.tv_usec = strtol(p, &p2, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012663 if (*p2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012664 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012665 scale = p2 - p;
12666 /* normalize to usec */
12667 if (scale > 6)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012668 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012669 while (scale++ < 6)
12670 ts.tv_usec *= 10;
12671 }
12672 } else if (*p) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012673 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012674 }
12675 if ( ! ts.tv_sec && ! ts.tv_usec)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012676 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012677 break;
12678#endif
12679 case 'r':
12680 rflag = 1;
12681 break;
12682 default:
12683 break;
12684 }
Eric Andersenc470f442003-07-28 09:56:35 +000012685 }
12686 if (prompt && isatty(0)) {
12687 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012688 }
12689 if (*(ap = argptr) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012690 sh_error("arg count");
Eric Andersenc470f442003-07-28 09:56:35 +000012691 if ((ifs = bltinlookup("IFS")) == NULL)
12692 ifs = defifs;
Paul Fox02eb9342005-09-07 16:56:02 +000012693#if defined(CONFIG_ASH_READ_NCHARS)
12694 if (nch_flag || silent) {
12695 tcgetattr(0, &tty);
12696 old_tty = tty;
12697 if (nch_flag) {
12698 tty.c_lflag &= ~ICANON;
12699 tty.c_cc[VMIN] = nchars;
12700 }
12701 if (silent) {
12702 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12703
12704 }
12705 tcsetattr(0, TCSANOW, &tty);
12706 }
12707#endif
12708#if defined(CONFIG_ASH_READ_TIMEOUT)
12709 if (ts.tv_sec || ts.tv_usec) {
12710 FD_ZERO (&set);
12711 FD_SET (0, &set);
12712
Denis Vlasenkof4dff772006-12-24 07:14:17 +000012713 i = select(FD_SETSIZE, &set, NULL, NULL, &ts);
Paul Fox02eb9342005-09-07 16:56:02 +000012714 if (!i) {
12715#if defined(CONFIG_ASH_READ_NCHARS)
12716 if (nch_flag)
12717 tcsetattr(0, TCSANOW, &old_tty);
12718#endif
12719 return 1;
12720 }
12721 }
Ned Ludd2123b7c2005-02-09 21:07:23 +000012722#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012723 status = 0;
12724 startword = 1;
12725 backslash = 0;
12726 STARTSTACKSTR(p);
Paul Fox02eb9342005-09-07 16:56:02 +000012727#if defined(CONFIG_ASH_READ_NCHARS)
12728 while (!nch_flag || nchars--)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012729#else
12730 for (;;)
12731#endif
12732 {
Eric Andersenc470f442003-07-28 09:56:35 +000012733 if (read(0, &c, 1) != 1) {
12734 status = 1;
12735 break;
12736 }
12737 if (c == '\0')
12738 continue;
12739 if (backslash) {
12740 backslash = 0;
12741 if (c != '\n')
12742 goto put;
12743 continue;
12744 }
12745 if (!rflag && c == '\\') {
12746 backslash++;
12747 continue;
12748 }
12749 if (c == '\n')
12750 break;
12751 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12752 continue;
12753 }
12754 startword = 0;
12755 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12756 STACKSTRNUL(p);
12757 setvar(*ap, stackblock(), 0);
12758 ap++;
12759 startword = 1;
12760 STARTSTACKSTR(p);
12761 } else {
12762put:
12763 STPUTC(c, p);
12764 }
12765 }
Paul Fox02eb9342005-09-07 16:56:02 +000012766#if defined(CONFIG_ASH_READ_NCHARS)
12767 if (nch_flag || silent)
12768 tcsetattr(0, TCSANOW, &old_tty);
12769#endif
12770
Eric Andersenc470f442003-07-28 09:56:35 +000012771 STACKSTRNUL(p);
12772 /* Remove trailing blanks */
12773 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12774 *p = '\0';
12775 setvar(*ap, stackblock(), 0);
12776 while (*++ap != NULL)
12777 setvar(*ap, nullstr, 0);
12778 return status;
12779}
12780
12781
12782static int umaskcmd(int argc, char **argv)
12783{
12784 static const char permuser[3] = "ugo";
12785 static const char permmode[3] = "rwx";
12786 static const short int permmask[] = {
12787 S_IRUSR, S_IWUSR, S_IXUSR,
12788 S_IRGRP, S_IWGRP, S_IXGRP,
12789 S_IROTH, S_IWOTH, S_IXOTH
12790 };
12791
12792 char *ap;
12793 mode_t mask;
12794 int i;
12795 int symbolic_mode = 0;
12796
12797 while (nextopt("S") != '\0') {
12798 symbolic_mode = 1;
12799 }
12800
12801 INTOFF;
12802 mask = umask(0);
12803 umask(mask);
12804 INTON;
12805
12806 if ((ap = *argptr) == NULL) {
12807 if (symbolic_mode) {
12808 char buf[18];
12809 char *p = buf;
12810
12811 for (i = 0; i < 3; i++) {
12812 int j;
12813
12814 *p++ = permuser[i];
12815 *p++ = '=';
12816 for (j = 0; j < 3; j++) {
12817 if ((mask & permmask[3 * i + j]) == 0) {
12818 *p++ = permmode[j];
12819 }
12820 }
12821 *p++ = ',';
12822 }
12823 *--p = 0;
12824 puts(buf);
12825 } else {
12826 out1fmt("%.4o\n", mask);
12827 }
12828 } else {
12829 if (is_digit((unsigned char) *ap)) {
12830 mask = 0;
12831 do {
12832 if (*ap >= '8' || *ap < '0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012833 sh_error(illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012834 mask = (mask << 3) + (*ap - '0');
12835 } while (*++ap != '\0');
12836 umask(mask);
12837 } else {
12838 mask = ~mask & 0777;
12839 if (!bb_parse_mode(ap, &mask)) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012840 sh_error("Illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012841 }
12842 umask(~mask & 0777);
12843 }
12844 }
12845 return 0;
12846}
12847
12848/*
12849 * ulimit builtin
12850 *
12851 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12852 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12853 * ash by J.T. Conklin.
12854 *
12855 * Public domain.
12856 */
12857
12858struct limits {
12859 const char *name;
12860 int cmd;
12861 int factor; /* multiply by to get rlim_{cur,max} values */
12862 char option;
12863};
12864
12865static const struct limits limits[] = {
12866#ifdef RLIMIT_CPU
12867 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12868#endif
12869#ifdef RLIMIT_FSIZE
12870 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12871#endif
12872#ifdef RLIMIT_DATA
12873 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12874#endif
12875#ifdef RLIMIT_STACK
12876 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12877#endif
12878#ifdef RLIMIT_CORE
12879 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12880#endif
12881#ifdef RLIMIT_RSS
12882 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12883#endif
12884#ifdef RLIMIT_MEMLOCK
12885 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12886#endif
12887#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012888 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012889#endif
12890#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012891 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012892#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012893#ifdef RLIMIT_AS
12894 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012895#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012896#ifdef RLIMIT_LOCKS
12897 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012898#endif
12899 { (char *) 0, 0, 0, '\0' }
12900};
12901
Glenn L McGrath76620622004-01-13 10:19:37 +000012902enum limtype { SOFT = 0x1, HARD = 0x2 };
12903
12904static void printlim(enum limtype how, const struct rlimit *limit,
12905 const struct limits *l)
12906{
12907 rlim_t val;
12908
12909 val = limit->rlim_max;
12910 if (how & SOFT)
12911 val = limit->rlim_cur;
12912
12913 if (val == RLIM_INFINITY)
12914 out1fmt("unlimited\n");
12915 else {
12916 val /= l->factor;
12917 out1fmt("%lld\n", (long long) val);
12918 }
12919}
12920
Eric Andersenc470f442003-07-28 09:56:35 +000012921int
12922ulimitcmd(int argc, char **argv)
12923{
12924 int c;
12925 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012926 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012927 const struct limits *l;
12928 int set, all = 0;
12929 int optc, what;
12930 struct rlimit limit;
12931
12932 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012933 while ((optc = nextopt("HSa"
12934#ifdef RLIMIT_CPU
12935 "t"
12936#endif
12937#ifdef RLIMIT_FSIZE
12938 "f"
12939#endif
12940#ifdef RLIMIT_DATA
12941 "d"
12942#endif
12943#ifdef RLIMIT_STACK
12944 "s"
12945#endif
12946#ifdef RLIMIT_CORE
12947 "c"
12948#endif
12949#ifdef RLIMIT_RSS
12950 "m"
12951#endif
12952#ifdef RLIMIT_MEMLOCK
12953 "l"
12954#endif
12955#ifdef RLIMIT_NPROC
12956 "p"
12957#endif
12958#ifdef RLIMIT_NOFILE
12959 "n"
12960#endif
12961#ifdef RLIMIT_AS
12962 "v"
12963#endif
12964#ifdef RLIMIT_LOCKS
12965 "w"
12966#endif
12967 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012968 switch (optc) {
12969 case 'H':
12970 how = HARD;
12971 break;
12972 case 'S':
12973 how = SOFT;
12974 break;
12975 case 'a':
12976 all = 1;
12977 break;
12978 default:
12979 what = optc;
12980 }
12981
Glenn L McGrath76620622004-01-13 10:19:37 +000012982 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012983 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012984
12985 set = *argptr ? 1 : 0;
12986 if (set) {
12987 char *p = *argptr;
12988
12989 if (all || argptr[1])
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012990 sh_error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012991 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012992 val = RLIM_INFINITY;
12993 else {
12994 val = (rlim_t) 0;
12995
12996 while ((c = *p++) >= '0' && c <= '9')
12997 {
12998 val = (val * 10) + (long)(c - '0');
12999 if (val < (rlim_t) 0)
13000 break;
13001 }
13002 if (c)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000013003 sh_error("bad number");
Eric Andersenc470f442003-07-28 09:56:35 +000013004 val *= l->factor;
13005 }
13006 }
13007 if (all) {
13008 for (l = limits; l->name; l++) {
13009 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000013010 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000013011 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000013012 }
13013 return 0;
13014 }
13015
13016 getrlimit(l->cmd, &limit);
13017 if (set) {
13018 if (how & HARD)
13019 limit.rlim_max = val;
13020 if (how & SOFT)
13021 limit.rlim_cur = val;
13022 if (setrlimit(l->cmd, &limit) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000013023 sh_error("error setting limit (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +000013024 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000013025 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000013026 }
13027 return 0;
13028}
13029
Eric Andersen90898442003-08-06 11:20:52 +000013030
13031#ifdef CONFIG_ASH_MATH_SUPPORT
13032
13033/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
13034
13035 Permission is hereby granted, free of charge, to any person obtaining
13036 a copy of this software and associated documentation files (the
13037 "Software"), to deal in the Software without restriction, including
13038 without limitation the rights to use, copy, modify, merge, publish,
13039 distribute, sublicense, and/or sell copies of the Software, and to
13040 permit persons to whom the Software is furnished to do so, subject to
13041 the following conditions:
13042
13043 The above copyright notice and this permission notice shall be
13044 included in all copies or substantial portions of the Software.
13045
13046 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13047 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13048 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13049 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13050 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13051 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13052 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13053*/
13054
13055/* This is my infix parser/evaluator. It is optimized for size, intended
13056 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000013057 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000013058 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000013059 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000013060 * be that which POSIX specifies for shells. */
13061
13062/* The code uses a simple two-stack algorithm. See
13063 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000013064 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000013065 * this is based (this code differs in that it applies operators immediately
13066 * to the stack instead of adding them to a queue to end up with an
13067 * expression). */
13068
13069/* To use the routine, call it with an expression string and error return
13070 * pointer */
13071
13072/*
13073 * Aug 24, 2001 Manuel Novoa III
13074 *
13075 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13076 *
13077 * 1) In arith_apply():
13078 * a) Cached values of *numptr and &(numptr[-1]).
13079 * b) Removed redundant test for zero denominator.
13080 *
13081 * 2) In arith():
13082 * a) Eliminated redundant code for processing operator tokens by moving
13083 * to a table-based implementation. Also folded handling of parens
13084 * into the table.
13085 * b) Combined all 3 loops which called arith_apply to reduce generated
13086 * code size at the cost of speed.
13087 *
13088 * 3) The following expressions were treated as valid by the original code:
13089 * 1() , 0! , 1 ( *3 ) .
13090 * These bugs have been fixed by internally enclosing the expression in
13091 * parens and then checking that all binary ops and right parens are
13092 * preceded by a valid expression (NUM_TOKEN).
13093 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013094 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013095 * ctype's isspace() if it is used by another busybox applet or if additional
13096 * whitespace chars should be considered. Look below the "#include"s for a
13097 * precompiler test.
13098 */
13099
13100/*
13101 * Aug 26, 2001 Manuel Novoa III
13102 *
13103 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13104 *
13105 * Merge in Aaron's comments previously posted to the busybox list,
13106 * modified slightly to take account of my changes to the code.
13107 *
13108 */
13109
13110/*
13111 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13112 *
13113 * - allow access to variable,
13114 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13115 * - realize assign syntax (VAR=expr, +=, *= etc)
13116 * - realize exponentiation (** operator)
13117 * - realize comma separated - expr, expr
13118 * - realise ++expr --expr expr++ expr--
13119 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013120 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013121 * - was restored loses XOR operator
13122 * - remove one goto label, added three ;-)
13123 * - protect $((num num)) as true zero expr (Manuel`s error)
13124 * - always use special isspace(), see comment from bash ;-)
13125 */
13126
13127
13128#define arith_isspace(arithval) \
13129 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13130
13131
13132typedef unsigned char operator;
13133
13134/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013135 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013136 * precedence. The ID portion is so that multiple operators can have the
13137 * same precedence, ensuring that the leftmost one is evaluated first.
13138 * Consider * and /. */
13139
13140#define tok_decl(prec,id) (((id)<<5)|(prec))
13141#define PREC(op) ((op) & 0x1F)
13142
13143#define TOK_LPAREN tok_decl(0,0)
13144
13145#define TOK_COMMA tok_decl(1,0)
13146
13147#define TOK_ASSIGN tok_decl(2,0)
13148#define TOK_AND_ASSIGN tok_decl(2,1)
13149#define TOK_OR_ASSIGN tok_decl(2,2)
13150#define TOK_XOR_ASSIGN tok_decl(2,3)
13151#define TOK_PLUS_ASSIGN tok_decl(2,4)
13152#define TOK_MINUS_ASSIGN tok_decl(2,5)
13153#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13154#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13155
13156#define TOK_MUL_ASSIGN tok_decl(3,0)
13157#define TOK_DIV_ASSIGN tok_decl(3,1)
13158#define TOK_REM_ASSIGN tok_decl(3,2)
13159
13160/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13161#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13162
13163/* conditional is right associativity too */
13164#define TOK_CONDITIONAL tok_decl(4,0)
13165#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13166
13167#define TOK_OR tok_decl(5,0)
13168
13169#define TOK_AND tok_decl(6,0)
13170
13171#define TOK_BOR tok_decl(7,0)
13172
13173#define TOK_BXOR tok_decl(8,0)
13174
13175#define TOK_BAND tok_decl(9,0)
13176
13177#define TOK_EQ tok_decl(10,0)
13178#define TOK_NE tok_decl(10,1)
13179
13180#define TOK_LT tok_decl(11,0)
13181#define TOK_GT tok_decl(11,1)
13182#define TOK_GE tok_decl(11,2)
13183#define TOK_LE tok_decl(11,3)
13184
13185#define TOK_LSHIFT tok_decl(12,0)
13186#define TOK_RSHIFT tok_decl(12,1)
13187
13188#define TOK_ADD tok_decl(13,0)
13189#define TOK_SUB tok_decl(13,1)
13190
13191#define TOK_MUL tok_decl(14,0)
13192#define TOK_DIV tok_decl(14,1)
13193#define TOK_REM tok_decl(14,2)
13194
13195/* exponent is right associativity */
13196#define TOK_EXPONENT tok_decl(15,1)
13197
13198/* For now unary operators. */
13199#define UNARYPREC 16
13200#define TOK_BNOT tok_decl(UNARYPREC,0)
13201#define TOK_NOT tok_decl(UNARYPREC,1)
13202
13203#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13204#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13205
13206#define PREC_PRE (UNARYPREC+2)
13207
13208#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13209#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13210
13211#define PREC_POST (UNARYPREC+3)
13212
13213#define TOK_POST_INC tok_decl(PREC_POST, 0)
13214#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13215
13216#define SPEC_PREC (UNARYPREC+4)
13217
13218#define TOK_NUM tok_decl(SPEC_PREC, 0)
13219#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13220
13221#define NUMPTR (*numstackptr)
13222
Rob Landley88621d72006-08-29 19:41:06 +000013223static int tok_have_assign(operator op)
Eric Andersen90898442003-08-06 11:20:52 +000013224{
13225 operator prec = PREC(op);
13226
13227 convert_prec_is_assing(prec);
13228 return (prec == PREC(TOK_ASSIGN) ||
13229 prec == PREC_PRE || prec == PREC_POST);
13230}
13231
Rob Landley88621d72006-08-29 19:41:06 +000013232static int is_right_associativity(operator prec)
Eric Andersen90898442003-08-06 11:20:52 +000013233{
13234 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13235 prec == PREC(TOK_CONDITIONAL));
13236}
13237
13238
13239typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013240 arith_t val;
13241 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013242 char contidional_second_val_initialized;
13243 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013244 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013245} v_n_t;
13246
13247
13248typedef struct CHK_VAR_RECURSIVE_LOOPED {
13249 const char *var;
13250 struct CHK_VAR_RECURSIVE_LOOPED *next;
13251} chk_var_recursive_looped_t;
13252
13253static chk_var_recursive_looped_t *prev_chk_var_recursive;
13254
13255
13256static int arith_lookup_val(v_n_t *t)
13257{
13258 if(t->var) {
13259 const char * p = lookupvar(t->var);
13260
13261 if(p) {
13262 int errcode;
13263
13264 /* recursive try as expression */
13265 chk_var_recursive_looped_t *cur;
13266 chk_var_recursive_looped_t cur_save;
13267
13268 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13269 if(strcmp(cur->var, t->var) == 0) {
13270 /* expression recursion loop detected */
13271 return -5;
13272 }
13273 }
13274 /* save current lookuped var name */
13275 cur = prev_chk_var_recursive;
13276 cur_save.var = t->var;
13277 cur_save.next = cur;
13278 prev_chk_var_recursive = &cur_save;
13279
13280 t->val = arith (p, &errcode);
13281 /* restore previous ptr after recursiving */
13282 prev_chk_var_recursive = cur;
13283 return errcode;
13284 } else {
13285 /* allow undefined var as 0 */
13286 t->val = 0;
13287 }
13288 }
13289 return 0;
13290}
13291
13292/* "applying" a token means performing it on the top elements on the integer
13293 * stack. For a unary operator it will only change the top element, but a
13294 * binary operator will pop two arguments and push a result */
Rob Landley88621d72006-08-29 19:41:06 +000013295static int arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
Eric Andersen90898442003-08-06 11:20:52 +000013296{
Eric Andersen90898442003-08-06 11:20:52 +000013297 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013298 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013299 int ret_arith_lookup_val;
13300
13301 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13302 without arguments */
13303 numptr_m1 = NUMPTR - 1;
13304
13305 /* check operand is var with noninteger value */
13306 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13307 if(ret_arith_lookup_val)
13308 return ret_arith_lookup_val;
13309
13310 rez = numptr_m1->val;
13311 if (op == TOK_UMINUS)
13312 rez *= -1;
13313 else if (op == TOK_NOT)
13314 rez = !rez;
13315 else if (op == TOK_BNOT)
13316 rez = ~rez;
13317 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13318 rez++;
13319 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13320 rez--;
13321 else if (op != TOK_UPLUS) {
13322 /* Binary operators */
13323
13324 /* check and binary operators need two arguments */
13325 if (numptr_m1 == numstack) goto err;
13326
13327 /* ... and they pop one */
13328 --NUMPTR;
13329 numptr_val = rez;
13330 if (op == TOK_CONDITIONAL) {
13331 if(! numptr_m1->contidional_second_val_initialized) {
13332 /* protect $((expr1 ? expr2)) without ": expr" */
13333 goto err;
13334 }
13335 rez = numptr_m1->contidional_second_val;
13336 } else if(numptr_m1->contidional_second_val_initialized) {
13337 /* protect $((expr1 : expr2)) without "expr ? " */
13338 goto err;
13339 }
13340 numptr_m1 = NUMPTR - 1;
13341 if(op != TOK_ASSIGN) {
13342 /* check operand is var with noninteger value for not '=' */
13343 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13344 if(ret_arith_lookup_val)
13345 return ret_arith_lookup_val;
13346 }
13347 if (op == TOK_CONDITIONAL) {
13348 numptr_m1->contidional_second_val = rez;
13349 }
13350 rez = numptr_m1->val;
13351 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13352 rez |= numptr_val;
13353 else if (op == TOK_OR)
13354 rez = numptr_val || rez;
13355 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13356 rez &= numptr_val;
13357 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13358 rez ^= numptr_val;
13359 else if (op == TOK_AND)
13360 rez = rez && numptr_val;
13361 else if (op == TOK_EQ)
13362 rez = (rez == numptr_val);
13363 else if (op == TOK_NE)
13364 rez = (rez != numptr_val);
13365 else if (op == TOK_GE)
13366 rez = (rez >= numptr_val);
13367 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13368 rez >>= numptr_val;
13369 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13370 rez <<= numptr_val;
13371 else if (op == TOK_GT)
13372 rez = (rez > numptr_val);
13373 else if (op == TOK_LT)
13374 rez = (rez < numptr_val);
13375 else if (op == TOK_LE)
13376 rez = (rez <= numptr_val);
13377 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13378 rez *= numptr_val;
13379 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13380 rez += numptr_val;
13381 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13382 rez -= numptr_val;
13383 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13384 rez = numptr_val;
13385 else if (op == TOK_CONDITIONAL_SEP) {
13386 if (numptr_m1 == numstack) {
13387 /* protect $((expr : expr)) without "expr ? " */
13388 goto err;
13389 }
13390 numptr_m1->contidional_second_val_initialized = op;
13391 numptr_m1->contidional_second_val = numptr_val;
13392 }
13393 else if (op == TOK_CONDITIONAL) {
13394 rez = rez ?
13395 numptr_val : numptr_m1->contidional_second_val;
13396 }
13397 else if(op == TOK_EXPONENT) {
13398 if(numptr_val < 0)
13399 return -3; /* exponent less than 0 */
13400 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013401 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013402
13403 if(numptr_val)
13404 while(numptr_val--)
13405 c *= rez;
13406 rez = c;
13407 }
13408 }
13409 else if(numptr_val==0) /* zero divisor check */
13410 return -2;
13411 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13412 rez /= numptr_val;
13413 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13414 rez %= numptr_val;
13415 }
13416 if(tok_have_assign(op)) {
13417 char buf[32];
13418
13419 if(numptr_m1->var == NULL) {
13420 /* Hmm, 1=2 ? */
13421 goto err;
13422 }
13423 /* save to shell variable */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013424#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersena68ea1c2006-01-30 22:48:39 +000013425 snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013426#else
Eric Andersena68ea1c2006-01-30 22:48:39 +000013427 snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013428#endif
Eric Andersen90898442003-08-06 11:20:52 +000013429 setvar(numptr_m1->var, buf, 0);
13430 /* after saving, make previous value for v++ or v-- */
13431 if(op == TOK_POST_INC)
13432 rez--;
13433 else if(op == TOK_POST_DEC)
13434 rez++;
13435 }
13436 numptr_m1->val = rez;
13437 /* protect geting var value, is number now */
13438 numptr_m1->var = NULL;
13439 return 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +000013440 err:
13441 return -1;
Eric Andersen90898442003-08-06 11:20:52 +000013442}
13443
13444/* longest must first */
13445static const char op_tokens[] = {
13446 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13447 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13448 '<','<', 0, TOK_LSHIFT,
13449 '>','>', 0, TOK_RSHIFT,
13450 '|','|', 0, TOK_OR,
13451 '&','&', 0, TOK_AND,
13452 '!','=', 0, TOK_NE,
13453 '<','=', 0, TOK_LE,
13454 '>','=', 0, TOK_GE,
13455 '=','=', 0, TOK_EQ,
13456 '|','=', 0, TOK_OR_ASSIGN,
13457 '&','=', 0, TOK_AND_ASSIGN,
13458 '*','=', 0, TOK_MUL_ASSIGN,
13459 '/','=', 0, TOK_DIV_ASSIGN,
13460 '%','=', 0, TOK_REM_ASSIGN,
13461 '+','=', 0, TOK_PLUS_ASSIGN,
13462 '-','=', 0, TOK_MINUS_ASSIGN,
13463 '-','-', 0, TOK_POST_DEC,
13464 '^','=', 0, TOK_XOR_ASSIGN,
13465 '+','+', 0, TOK_POST_INC,
13466 '*','*', 0, TOK_EXPONENT,
13467 '!', 0, TOK_NOT,
13468 '<', 0, TOK_LT,
13469 '>', 0, TOK_GT,
13470 '=', 0, TOK_ASSIGN,
13471 '|', 0, TOK_BOR,
13472 '&', 0, TOK_BAND,
13473 '*', 0, TOK_MUL,
13474 '/', 0, TOK_DIV,
13475 '%', 0, TOK_REM,
13476 '+', 0, TOK_ADD,
13477 '-', 0, TOK_SUB,
13478 '^', 0, TOK_BXOR,
13479 /* uniq */
13480 '~', 0, TOK_BNOT,
13481 ',', 0, TOK_COMMA,
13482 '?', 0, TOK_CONDITIONAL,
13483 ':', 0, TOK_CONDITIONAL_SEP,
13484 ')', 0, TOK_RPAREN,
13485 '(', 0, TOK_LPAREN,
13486 0
13487};
13488/* ptr to ")" */
13489#define endexpression &op_tokens[sizeof(op_tokens)-7]
13490
13491
Denis Vlasenko8e1c7152007-01-22 07:21:38 +000013492static arith_t arith(const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013493{
"Robert P. J. Day"68229832006-07-01 13:08:46 +000013494 char arithval; /* Current character under analysis */
Eric Andersen90898442003-08-06 11:20:52 +000013495 operator lasttok, op;
13496 operator prec;
13497
13498 const char *p = endexpression;
13499 int errcode;
13500
13501 size_t datasizes = strlen(expr) + 2;
13502
13503 /* Stack of integers */
13504 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013505 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013506 * the reader. */
13507 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13508 *numstackptr = numstack;
13509 /* Stack of operator tokens */
13510 operator *stack = alloca((datasizes) * sizeof(operator)),
13511 *stackptr = stack;
13512
13513 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13514 *perrcode = errcode = 0;
13515
13516 while(1) {
13517 if ((arithval = *expr) == 0) {
13518 if (p == endexpression) {
13519 /* Null expression. */
13520 return 0;
13521 }
13522
13523 /* This is only reached after all tokens have been extracted from the
13524 * input stream. If there are still tokens on the operator stack, they
13525 * are to be applied in order. At the end, there should be a final
13526 * result on the integer stack */
13527
13528 if (expr != endexpression + 1) {
13529 /* If we haven't done so already, */
13530 /* append a closing right paren */
13531 expr = endexpression;
13532 /* and let the loop process it. */
13533 continue;
13534 }
13535 /* At this point, we're done with the expression. */
13536 if (numstackptr != numstack+1) {
13537 /* ... but if there isn't, it's bad */
13538 err:
13539 return (*perrcode = -1);
13540 }
13541 if(numstack->var) {
13542 /* expression is $((var)) only, lookup now */
13543 errcode = arith_lookup_val(numstack);
13544 }
13545 ret:
13546 *perrcode = errcode;
13547 return numstack->val;
13548 } else {
13549 /* Continue processing the expression. */
13550 if (arith_isspace(arithval)) {
13551 /* Skip whitespace */
13552 goto prologue;
13553 }
13554 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013555 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013556
13557 numstackptr->var = alloca(var_name_size);
13558 safe_strncpy(numstackptr->var, expr, var_name_size);
13559 expr = p;
13560 num:
13561 numstackptr->contidional_second_val_initialized = 0;
13562 numstackptr++;
13563 lasttok = TOK_NUM;
13564 continue;
13565 } else if (is_digit(arithval)) {
13566 numstackptr->var = NULL;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013567#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersenad63cb22004-10-08 09:43:34 +000013568 numstackptr->val = strtoll(expr, (char **) &expr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013569#else
13570 numstackptr->val = strtol(expr, (char **) &expr, 0);
13571#endif
Eric Andersen90898442003-08-06 11:20:52 +000013572 goto num;
13573 }
13574 for(p = op_tokens; ; p++) {
13575 const char *o;
13576
13577 if(*p == 0) {
13578 /* strange operator not found */
13579 goto err;
13580 }
13581 for(o = expr; *p && *o == *p; p++)
13582 o++;
13583 if(! *p) {
13584 /* found */
13585 expr = o - 1;
13586 break;
13587 }
13588 /* skip tail uncompared token */
13589 while(*p)
13590 p++;
13591 /* skip zero delim */
13592 p++;
13593 }
13594 op = p[1];
13595
13596 /* post grammar: a++ reduce to num */
13597 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13598 lasttok = TOK_NUM;
13599
13600 /* Plus and minus are binary (not unary) _only_ if the last
13601 * token was as number, or a right paren (which pretends to be
13602 * a number, since it evaluates to one). Think about it.
13603 * It makes sense. */
13604 if (lasttok != TOK_NUM) {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013605 switch (op) {
Eric Andersen90898442003-08-06 11:20:52 +000013606 case TOK_ADD:
13607 op = TOK_UPLUS;
13608 break;
13609 case TOK_SUB:
13610 op = TOK_UMINUS;
13611 break;
13612 case TOK_POST_INC:
13613 op = TOK_PRE_INC;
13614 break;
13615 case TOK_POST_DEC:
13616 op = TOK_PRE_DEC;
13617 break;
13618 }
13619 }
13620 /* We don't want a unary operator to cause recursive descent on the
13621 * stack, because there can be many in a row and it could cause an
13622 * operator to be evaluated before its argument is pushed onto the
13623 * integer stack. */
13624 /* But for binary operators, "apply" everything on the operator
13625 * stack until we find an operator with a lesser priority than the
13626 * one we have just extracted. */
13627 /* Left paren is given the lowest priority so it will never be
13628 * "applied" in this way.
13629 * if associativity is right and priority eq, applied also skip
13630 */
13631 prec = PREC(op);
13632 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13633 /* not left paren or unary */
13634 if (lasttok != TOK_NUM) {
13635 /* binary op must be preceded by a num */
13636 goto err;
13637 }
13638 while (stackptr != stack) {
13639 if (op == TOK_RPAREN) {
13640 /* The algorithm employed here is simple: while we don't
13641 * hit an open paren nor the bottom of the stack, pop
13642 * tokens and apply them */
13643 if (stackptr[-1] == TOK_LPAREN) {
13644 --stackptr;
13645 /* Any operator directly after a */
13646 lasttok = TOK_NUM;
13647 /* close paren should consider itself binary */
13648 goto prologue;
13649 }
13650 } else {
13651 operator prev_prec = PREC(stackptr[-1]);
13652
13653 convert_prec_is_assing(prec);
13654 convert_prec_is_assing(prev_prec);
13655 if (prev_prec < prec)
13656 break;
13657 /* check right assoc */
13658 if(prev_prec == prec && is_right_associativity(prec))
13659 break;
13660 }
13661 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13662 if(errcode) goto ret;
13663 }
13664 if (op == TOK_RPAREN) {
13665 goto err;
13666 }
13667 }
13668
13669 /* Push this operator to the stack and remember it. */
13670 *stackptr++ = lasttok = op;
13671
13672 prologue:
13673 ++expr;
13674 }
13675 }
13676}
13677#endif /* CONFIG_ASH_MATH_SUPPORT */
13678
13679
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000013680#if DEBUG
Denis Vlasenko8f8f2682006-10-03 21:00:43 +000013681const char *applet_name = "debug stuff usage";
Eric Andersenc470f442003-07-28 09:56:35 +000013682int main(int argc, char **argv)
13683{
13684 return ash_main(argc, argv);
13685}
13686#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013687
Eric Andersendf82f612001-06-28 07:46:40 +000013688/*-
13689 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013690 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013691 *
13692 * This code is derived from software contributed to Berkeley by
13693 * Kenneth Almquist.
13694 *
13695 * Redistribution and use in source and binary forms, with or without
13696 * modification, are permitted provided that the following conditions
13697 * are met:
13698 * 1. Redistributions of source code must retain the above copyright
13699 * notice, this list of conditions and the following disclaimer.
13700 * 2. Redistributions in binary form must reproduce the above copyright
13701 * notice, this list of conditions and the following disclaimer in the
13702 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013703 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013704 * may be used to endorse or promote products derived from this software
13705 * without specific prior written permission.
13706 *
13707 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13708 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13709 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13710 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13711 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13712 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13713 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13714 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13715 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13716 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13717 * SUCH DAMAGE.
13718 */