blob: c1b2b0ed658a4cdced95719c535bfb29d28eaf45 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +00008 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
Eric Andersen81fe1232003-07-29 06:38:40 +00009 * was re-ported from NetBSD and debianized.
10 *
11 *
Eric Andersencb57d552001-06-28 07:25:16 +000012 * This code is derived from software contributed to Berkeley by
13 * Kenneth Almquist.
14 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +000015 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersendf82f612001-06-28 07:46:40 +000016 *
Eric Andersen81fe1232003-07-29 06:38:40 +000017 * Original BSD copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000018 */
19
Eric Andersenc470f442003-07-28 09:56:35 +000020/*
Eric Andersen90898442003-08-06 11:20:52 +000021 * rewrite arith.y to micro stack based cryptic algorithm by
22 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
23 *
Eric Andersenef02f822004-03-11 13:34:24 +000024 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
25 * dynamic variables.
Eric Andersen16767e22004-03-16 05:14:10 +000026 *
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000027 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be
Eric Andersen16767e22004-03-16 05:14:10 +000028 * used in busybox and size optimizations,
29 * rewrote arith (see notes to this), added locale support,
30 * rewrote dynamic variables.
31 *
Eric Andersen90898442003-08-06 11:20:52 +000032 */
33
34
35/*
Eric Andersenc470f442003-07-28 09:56:35 +000036 * The follow should be set to reflect the type of system you have:
37 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
38 * define SYSV if you are running under System V.
39 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
40 * define DEBUG=2 to compile in and turn on debugging.
41 *
42 * When debugging is on, debugging info will be written to ./trace and
43 * a quit signal will generate a core dump.
44 */
Eric Andersen2870d962001-07-02 17:27:21 +000045
Eric Andersen2870d962001-07-02 17:27:21 +000046
Eric Andersen5bb16772001-09-06 18:00:41 +000047#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000048
Eric Andersenc470f442003-07-28 09:56:35 +000049#define PROFILE 0
50
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000051#include "busybox.h"
52
Eric Andersenc470f442003-07-28 09:56:35 +000053#ifdef DEBUG
54#define _GNU_SOURCE
55#endif
56
57#include <sys/types.h>
Eric Andersenc470f442003-07-28 09:56:35 +000058#include <sys/ioctl.h>
59#include <sys/param.h>
60#include <sys/resource.h>
61#include <sys/stat.h>
Eric Andersenc470f442003-07-28 09:56:35 +000062#include <sys/wait.h>
63
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67#include <unistd.h>
68
69#include <stdarg.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000070#include <stddef.h>
Eric Andersenc470f442003-07-28 09:56:35 +000071#include <assert.h>
Eric Andersencb57d552001-06-28 07:25:16 +000072#include <ctype.h>
73#include <dirent.h>
74#include <errno.h>
75#include <fcntl.h>
76#include <limits.h>
77#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000078#include <setjmp.h>
79#include <signal.h>
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000080/*#include <stdint.h>*/
Eric Andersenef02f822004-03-11 13:34:24 +000081#include <time.h>
Eric Andersenc470f442003-07-28 09:56:35 +000082#include <fnmatch.h>
Eric Andersenc470f442003-07-28 09:56:35 +000083
Eric Andersen887ca792002-07-03 23:19:26 +000084#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +000085
Eric Andersend35c5df2002-01-09 15:37:36 +000086#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000087#define JOBS 1
88#else
Eric Andersenca162042003-07-29 07:15:17 +000089#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +000090#endif
91
Paul Fox02eb9342005-09-07 16:56:02 +000092#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
Eric Andersencb57d552001-06-28 07:25:16 +000093#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +000094#endif
95
Eric Andersen2870d962001-07-02 17:27:21 +000096#include "cmdedit.h"
97
Eric Andersenc470f442003-07-28 09:56:35 +000098#ifdef __GLIBC__
99/* glibc sucks */
100static int *dash_errno;
101#undef errno
102#define errno (*dash_errno)
103#endif
104
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000105#if defined(__uClinux__)
106#error "Do not even bother, ash will not run on uClinux"
107#endif
108
Eric Andersenc470f442003-07-28 09:56:35 +0000109#ifdef DEBUG
110#define _DIAGASSERT(assert_expr) assert(assert_expr)
111#else
112#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000113#endif
114
Eric Andersen2870d962001-07-02 17:27:21 +0000115
Eric Andersenc470f442003-07-28 09:56:35 +0000116#ifdef CONFIG_ASH_ALIAS
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000117/* alias.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000118
119#define ALIASINUSE 1
120#define ALIASDEAD 2
121
122struct alias {
123 struct alias *next;
124 char *name;
125 char *val;
126 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000127};
128
Eric Andersenc470f442003-07-28 09:56:35 +0000129static struct alias *lookupalias(const char *, int);
130static int aliascmd(int, char **);
131static int unaliascmd(int, char **);
132static void rmaliases(void);
133static int unalias(const char *);
134static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000135#endif
136
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000137/* cd.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000138
139
140static void setpwd(const char *, int);
141
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000142/* error.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000143
144
145/*
146 * Types of operations (passed to the errmsg routine).
147 */
148
149
150static const char not_found_msg[] = "%s: not found";
151
152
153#define E_OPEN "No such file" /* opening a file */
154#define E_CREAT "Directory nonexistent" /* creating a file */
155#define E_EXEC not_found_msg+4 /* executing a program */
156
157/*
158 * We enclose jmp_buf in a structure so that we can declare pointers to
159 * jump locations. The global variable handler contains the location to
160 * jump to when an exception occurs, and the global variable exception
Eric Andersenaff114c2004-04-14 17:51:38 +0000161 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000162 * exception handlers, the user should save the value of handler on entry
163 * to an inner scope, set handler to point to a jmploc structure for the
164 * inner scope, and restore handler on exit from the scope.
165 */
166
167struct jmploc {
168 jmp_buf loc;
169};
170
171static struct jmploc *handler;
172static int exception;
173static volatile int suppressint;
174static volatile sig_atomic_t intpending;
175
Eric Andersenc470f442003-07-28 09:56:35 +0000176/* exceptions */
177#define EXINT 0 /* SIGINT received */
178#define EXERROR 1 /* a generic error */
179#define EXSHELLPROC 2 /* execute a shell procedure */
180#define EXEXEC 3 /* command execution failed */
181#define EXEXIT 4 /* exit the shell */
182#define EXSIG 5 /* trapped signal in wait(1) */
183
184
185/* do we generate EXSIG events */
186static int exsig;
187/* last pending signal */
188static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000189
190/*
191 * These macros allow the user to suspend the handling of interrupt signals
192 * over a period of time. This is similar to SIGHOLD to or sigblock, but
193 * much more efficient and portable. (But hacking the kernel is so much
194 * more fun than worrying about efficiency and portability. :-))
195 */
196
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000197#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
Eric Andersenc470f442003-07-28 09:56:35 +0000198#define INTOFF \
199 ({ \
200 suppressint++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000201 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000202 0; \
203 })
204#define SAVEINT(v) ((v) = suppressint)
205#define RESTOREINT(v) \
206 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000207 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000208 if ((suppressint = (v)) == 0 && intpending) onint(); \
209 0; \
210 })
211#define EXSIGON() \
212 ({ \
213 exsig++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000214 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000215 if (pendingsigs) \
216 exraise(EXSIG); \
217 0; \
218 })
219/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000220
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000221
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000222static void exraise(int) ATTRIBUTE_NORETURN;
223static void onint(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000224
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000225static void sh_error(const char *, ...) ATTRIBUTE_NORETURN;
226static void exerror(int, const char *, ...) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000227
228static void sh_warnx(const char *, ...);
229
230#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
231static void
232inton(void) {
233 if (--suppressint == 0 && intpending) {
234 onint();
235 }
236}
237#define INTON inton()
238static void forceinton(void)
239{
240 suppressint = 0;
241 if (intpending)
242 onint();
243}
Eric Andersen3102ac42001-07-06 04:26:23 +0000244#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000245#else
Eric Andersenc470f442003-07-28 09:56:35 +0000246#define INTON \
247 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000248 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000249 if (--suppressint == 0 && intpending) onint(); \
250 0; \
251 })
252#define FORCEINTON \
253 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000254 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000255 suppressint = 0; \
256 if (intpending) onint(); \
257 0; \
258 })
259#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000260
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000261/* expand.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000262
263struct strlist {
264 struct strlist *next;
265 char *text;
266};
267
268
269struct arglist {
270 struct strlist *list;
271 struct strlist **lastp;
272};
273
Eric Andersenc470f442003-07-28 09:56:35 +0000274/*
275 * expandarg() flags
276 */
277#define EXP_FULL 0x1 /* perform word splitting & file globbing */
278#define EXP_TILDE 0x2 /* do normal tilde expansion */
279#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
280#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
281#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
282#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
283#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
284#define EXP_WORD 0x80 /* expand word in parameter expansion */
285#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
286
287
288union node;
289static void expandarg(union node *, struct arglist *, int);
290#define rmescapes(p) _rmescapes((p), 0)
291static char *_rmescapes(char *, int);
292static int casematch(union node *, char *);
293
294#ifdef CONFIG_ASH_MATH_SUPPORT
295static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000296#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000297
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000298/* eval.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000299
Eric Andersenc470f442003-07-28 09:56:35 +0000300static char *commandname; /* currently executing command */
301static struct strlist *cmdenviron; /* environment for builtin command */
302static int exitstatus; /* exit status of last command */
303static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000304
Eric Andersenc470f442003-07-28 09:56:35 +0000305
306struct backcmd { /* result of evalbackcmd */
307 int fd; /* file descriptor to read from */
308 char *buf; /* buffer */
309 int nleft; /* number of chars in buffer */
310 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000311};
312
Eric Andersen62483552001-07-10 06:09:16 +0000313/*
Eric Andersenc470f442003-07-28 09:56:35 +0000314 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000315 */
Eric Andersenc470f442003-07-28 09:56:35 +0000316
317#define NCMD 0
318#define NPIPE 1
319#define NREDIR 2
320#define NBACKGND 3
321#define NSUBSHELL 4
322#define NAND 5
323#define NOR 6
324#define NSEMI 7
325#define NIF 8
326#define NWHILE 9
327#define NUNTIL 10
328#define NFOR 11
329#define NCASE 12
330#define NCLIST 13
331#define NDEFUN 14
332#define NARG 15
333#define NTO 16
334#define NCLOBBER 17
335#define NFROM 18
336#define NFROMTO 19
337#define NAPPEND 20
338#define NTOFD 21
339#define NFROMFD 22
340#define NHERE 23
341#define NXHERE 24
342#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000343
344
345
Eric Andersenc470f442003-07-28 09:56:35 +0000346struct ncmd {
347 int type;
348 union node *assign;
349 union node *args;
350 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000351};
352
353
Eric Andersenc470f442003-07-28 09:56:35 +0000354struct npipe {
355 int type;
356 int backgnd;
357 struct nodelist *cmdlist;
358};
Eric Andersen62483552001-07-10 06:09:16 +0000359
360
Eric Andersenc470f442003-07-28 09:56:35 +0000361struct nredir {
362 int type;
363 union node *n;
364 union node *redirect;
365};
Eric Andersen62483552001-07-10 06:09:16 +0000366
367
Eric Andersenc470f442003-07-28 09:56:35 +0000368struct nbinary {
369 int type;
370 union node *ch1;
371 union node *ch2;
372};
Eric Andersen2870d962001-07-02 17:27:21 +0000373
Eric Andersen2870d962001-07-02 17:27:21 +0000374
Eric Andersenc470f442003-07-28 09:56:35 +0000375struct nif {
376 int type;
377 union node *test;
378 union node *ifpart;
379 union node *elsepart;
380};
381
382
383struct nfor {
384 int type;
385 union node *args;
386 union node *body;
387 char *var;
388};
389
390
391struct ncase {
392 int type;
393 union node *expr;
394 union node *cases;
395};
396
397
398struct nclist {
399 int type;
400 union node *next;
401 union node *pattern;
402 union node *body;
403};
404
405
406struct narg {
407 int type;
408 union node *next;
409 char *text;
410 struct nodelist *backquote;
411};
412
413
414struct nfile {
415 int type;
416 union node *next;
417 int fd;
418 union node *fname;
419 char *expfname;
420};
421
422
423struct ndup {
424 int type;
425 union node *next;
426 int fd;
427 int dupfd;
428 union node *vname;
429};
430
431
432struct nhere {
433 int type;
434 union node *next;
435 int fd;
436 union node *doc;
437};
438
439
440struct nnot {
441 int type;
442 union node *com;
443};
444
445
446union node {
447 int type;
448 struct ncmd ncmd;
449 struct npipe npipe;
450 struct nredir nredir;
451 struct nbinary nbinary;
452 struct nif nif;
453 struct nfor nfor;
454 struct ncase ncase;
455 struct nclist nclist;
456 struct narg narg;
457 struct nfile nfile;
458 struct ndup ndup;
459 struct nhere nhere;
460 struct nnot nnot;
461};
462
463
464struct nodelist {
465 struct nodelist *next;
466 union node *n;
467};
468
469
470struct funcnode {
471 int count;
472 union node n;
473};
474
475
476static void freefunc(struct funcnode *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000477/* parser.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000478
479/* control characters in argument strings */
480#define CTL_FIRST '\201' /* first 'special' character */
481#define CTLESC '\201' /* escape next character */
482#define CTLVAR '\202' /* variable defn */
483#define CTLENDVAR '\203'
484#define CTLBACKQ '\204'
485#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
486/* CTLBACKQ | CTLQUOTE == '\205' */
487#define CTLARI '\206' /* arithmetic expression */
488#define CTLENDARI '\207'
489#define CTLQUOTEMARK '\210'
490#define CTL_LAST '\210' /* last 'special' character */
491
492/* variable substitution byte (follows CTLVAR) */
493#define VSTYPE 0x0f /* type of variable substitution */
494#define VSNUL 0x10 /* colon--treat the empty string as unset */
495#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
496
497/* values of VSTYPE field */
498#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
499#define VSMINUS 0x2 /* ${var-text} */
500#define VSPLUS 0x3 /* ${var+text} */
501#define VSQUESTION 0x4 /* ${var?message} */
502#define VSASSIGN 0x5 /* ${var=text} */
503#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
504#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
505#define VSTRIMLEFT 0x8 /* ${var#pattern} */
506#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
507#define VSLENGTH 0xa /* ${#var} */
508
509/* values of checkkwd variable */
510#define CHKALIAS 0x1
511#define CHKKWD 0x2
512#define CHKNL 0x4
513
514#define IBUFSIZ (BUFSIZ + 1)
515
516/*
517 * NEOF is returned by parsecmd when it encounters an end of file. It
518 * must be distinct from NULL, so we use the address of a variable that
519 * happens to be handy.
520 */
521static int plinno = 1; /* input line number */
522
523/* number of characters left in input buffer */
524static int parsenleft; /* copy of parsefile->nleft */
525static int parselleft; /* copy of parsefile->lleft */
526
527/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000528static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000529
530struct strpush {
531 struct strpush *prev; /* preceding string on stack */
532 char *prevstring;
533 int prevnleft;
534#ifdef CONFIG_ASH_ALIAS
535 struct alias *ap; /* if push was associated with an alias */
536#endif
537 char *string; /* remember the string since it may change */
538};
539
540struct parsefile {
541 struct parsefile *prev; /* preceding file on stack */
542 int linno; /* current line */
543 int fd; /* file descriptor (or -1 if string) */
544 int nleft; /* number of chars left in this line */
545 int lleft; /* number of chars left in this buffer */
546 char *nextc; /* next char in buffer */
547 char *buf; /* input buffer */
548 struct strpush *strpush; /* for pushing strings at this level */
549 struct strpush basestrpush; /* so pushing one is fast */
550};
551
Eric Andersenc470f442003-07-28 09:56:35 +0000552static struct parsefile basepf; /* top level input file */
"Vladimir N. Oleynik"6f347ef2005-10-15 10:23:55 +0000553#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
Eric Andersenc470f442003-07-28 09:56:35 +0000554static struct parsefile *parsefile = &basepf; /* current input file */
555
556
557static int tokpushback; /* last token pushed back */
558#define NEOF ((union node *)&tokpushback)
559static int parsebackquote; /* nonzero if we are inside backquotes */
560static int doprompt; /* if set, prompt the user */
561static int needprompt; /* true if interactive and at start of line */
562static int lasttoken; /* last token read */
563static char *wordtext; /* text of last word returned by readtoken */
564static int checkkwd;
565static struct nodelist *backquotelist;
566static union node *redirnode;
567static struct heredoc *heredoc;
568static int quoteflag; /* set if (part of) last token was quoted */
569static int startlinno; /* line # where last token started */
570
571static union node *parsecmd(int);
572static void fixredir(union node *, const char *, int);
573static const char *const *findkwd(const char *);
574static char *endofname(const char *);
575
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000576/* shell.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000577
578typedef void *pointer;
579
580static char nullstr[1]; /* zero length string */
581static const char spcstr[] = " ";
582static const char snlfmt[] = "%s\n";
583static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
584static const char illnum[] = "Illegal number: %s";
585static const char homestr[] = "HOME";
586
587#ifdef DEBUG
588#define TRACE(param) trace param
589#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000590#else
Eric Andersenc470f442003-07-28 09:56:35 +0000591#define TRACE(param)
592#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000593#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000594
Eric Andersenc470f442003-07-28 09:56:35 +0000595#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
596#define __builtin_expect(x, expected_value) (x)
597#endif
598
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000599#define xlikely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000600
Eric Andersenc470f442003-07-28 09:56:35 +0000601
602#define TEOF 0
603#define TNL 1
604#define TREDIR 2
605#define TWORD 3
606#define TSEMI 4
607#define TBACKGND 5
608#define TAND 6
609#define TOR 7
610#define TPIPE 8
611#define TLP 9
612#define TRP 10
613#define TENDCASE 11
614#define TENDBQUOTE 12
615#define TNOT 13
616#define TCASE 14
617#define TDO 15
618#define TDONE 16
619#define TELIF 17
620#define TELSE 18
621#define TESAC 19
622#define TFI 20
623#define TFOR 21
624#define TIF 22
625#define TIN 23
626#define TTHEN 24
627#define TUNTIL 25
628#define TWHILE 26
629#define TBEGIN 27
630#define TEND 28
631
632/* first char is indicating which tokens mark the end of a list */
633static const char *const tokname_array[] = {
634 "\1end of file",
635 "\0newline",
636 "\0redirection",
637 "\0word",
638 "\0;",
639 "\0&",
640 "\0&&",
641 "\0||",
642 "\0|",
643 "\0(",
644 "\1)",
645 "\1;;",
646 "\1`",
647#define KWDOFFSET 13
648 /* the following are keywords */
649 "\0!",
650 "\0case",
651 "\1do",
652 "\1done",
653 "\1elif",
654 "\1else",
655 "\1esac",
656 "\1fi",
657 "\0for",
658 "\0if",
659 "\0in",
660 "\1then",
661 "\0until",
662 "\0while",
663 "\0{",
664 "\1}",
665};
666
667static const char *tokname(int tok)
668{
669 static char buf[16];
670
671 if (tok >= TSEMI)
672 buf[0] = '"';
673 sprintf(buf + (tok >= TSEMI), "%s%c",
674 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
675 return buf;
676}
677
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000678/* machdep.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000679
680/*
681 * Most machines require the value returned from malloc to be aligned
682 * in some way. The following macro will get this right on many machines.
683 */
684
685#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
686/*
687 * It appears that grabstackstr() will barf with such alignments
688 * because stalloc() will return a string allocated in a new stackblock.
689 */
690#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
691
692/*
693 * This file was generated by the mksyntax program.
694 */
695
696
697/* Syntax classes */
698#define CWORD 0 /* character is nothing special */
699#define CNL 1 /* newline character */
700#define CBACK 2 /* a backslash character */
701#define CSQUOTE 3 /* single quote */
702#define CDQUOTE 4 /* double quote */
703#define CENDQUOTE 5 /* a terminating quote */
704#define CBQUOTE 6 /* backwards single quote */
705#define CVAR 7 /* a dollar sign */
706#define CENDVAR 8 /* a '}' character */
707#define CLP 9 /* a left paren in arithmetic */
708#define CRP 10 /* a right paren in arithmetic */
709#define CENDFILE 11 /* end of file */
710#define CCTL 12 /* like CWORD, except it must be escaped */
711#define CSPCL 13 /* these terminate a word */
712#define CIGN 14 /* character should be ignored */
713
714#ifdef CONFIG_ASH_ALIAS
715#define SYNBASE 130
716#define PEOF -130
717#define PEOA -129
718#define PEOA_OR_PEOF PEOA
719#else
720#define SYNBASE 129
721#define PEOF -129
722#define PEOA_OR_PEOF PEOF
723#endif
724
725#define is_digit(c) ((unsigned)((c) - '0') <= 9)
726#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
727#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
728
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000729/* C99 say: "char" declaration may be signed or unsigned default */
730#define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int)
731
Eric Andersenc470f442003-07-28 09:56:35 +0000732/*
733 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
734 * (assuming ascii char codes, as the original implementation did)
735 */
736#define is_special(c) \
737 ( (((unsigned int)c) - 33 < 32) \
738 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
739
740#define digit_val(c) ((c) - '0')
741
742/*
743 * This file was generated by the mksyntax program.
744 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000745
Eric Andersend35c5df2002-01-09 15:37:36 +0000746#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000747#define USE_SIT_FUNCTION
748#endif
749
750/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000751#define BASESYNTAX 0 /* not in quotes */
752#define DQSYNTAX 1 /* in double quotes */
753#define SQSYNTAX 2 /* in single quotes */
754#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000755
Eric Andersenc470f442003-07-28 09:56:35 +0000756#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000757static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000758#ifdef CONFIG_ASH_ALIAS
759 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
760#endif
761 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
762 {CNL, CNL, CNL, CNL}, /* 2, \n */
763 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
764 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
765 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
766 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
767 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
768 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
769 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
770 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
771 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000772#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000773 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
774 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
775 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000776#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000777};
Eric Andersenc470f442003-07-28 09:56:35 +0000778#else
779static const char S_I_T[][3] = {
780#ifdef CONFIG_ASH_ALIAS
781 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
782#endif
783 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
784 {CNL, CNL, CNL}, /* 2, \n */
785 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
786 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
787 {CVAR, CVAR, CWORD}, /* 5, $ */
788 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
789 {CSPCL, CWORD, CWORD}, /* 7, ( */
790 {CSPCL, CWORD, CWORD}, /* 8, ) */
791 {CBACK, CBACK, CCTL}, /* 9, \ */
792 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
793 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
794#ifndef USE_SIT_FUNCTION
795 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
796 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
797 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
798#endif
799};
800#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000801
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000802#ifdef USE_SIT_FUNCTION
803
804#define U_C(c) ((unsigned char)(c))
805
806static int SIT(int c, int syntax)
807{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000808 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000809#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000810 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000811 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
812 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
813 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
814 11, 3 /* "}~" */
815 };
816#else
817 static const char syntax_index_table[] = {
818 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
819 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
820 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
821 10, 2 /* "}~" */
822 };
823#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000824 const char *s;
825 int indx;
826
Eric Andersenc470f442003-07-28 09:56:35 +0000827 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000828 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000829#ifdef CONFIG_ASH_ALIAS
830 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000831 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000832 else
833#endif
834 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
835 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000836 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000837 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000838 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000839 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000840 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000841 }
842 return S_I_T[indx][syntax];
843}
844
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000845#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000846
847#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
848
Eric Andersenc470f442003-07-28 09:56:35 +0000849#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000850#define CSPCL_CIGN_CIGN_CIGN 0
851#define CSPCL_CWORD_CWORD_CWORD 1
852#define CNL_CNL_CNL_CNL 2
853#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000854#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000855#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000856#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000857#define CSPCL_CWORD_CWORD_CLP 7
858#define CSPCL_CWORD_CWORD_CRP 8
859#define CBACK_CBACK_CCTL_CBACK 9
860#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
861#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
862#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
863#define CWORD_CWORD_CWORD_CWORD 13
864#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000865#else
866#define CSPCL_CWORD_CWORD_CWORD 0
867#define CNL_CNL_CNL_CNL 1
868#define CWORD_CCTL_CCTL_CWORD 2
869#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
870#define CVAR_CVAR_CWORD_CVAR 4
871#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
872#define CSPCL_CWORD_CWORD_CLP 6
873#define CSPCL_CWORD_CWORD_CRP 7
874#define CBACK_CBACK_CCTL_CBACK 8
875#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
876#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
877#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
878#define CWORD_CWORD_CWORD_CWORD 12
879#define CCTL_CCTL_CCTL_CCTL 13
880#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000881
882static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000883 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000884 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
885#ifdef CONFIG_ASH_ALIAS
886 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
887#endif
888 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
889 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
890 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
891 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
892 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
893 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
894 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
895 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
896 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000897 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
898 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
899 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
900 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
901 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
902 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
903 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
904 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
905 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
906 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
907 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
908 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
909 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
910 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
911 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
912 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
913 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
914 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
915 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
916 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
917 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
918 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
919 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
920 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
921 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
922 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
923 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
924 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
925 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
926 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
927 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
928 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
929 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
930 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
931 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
932 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
933 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
934 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
935 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
936 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
937 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
938 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
939 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
940 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
941 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
942 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
943 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
944 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
945 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
946 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
947 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
948 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
949 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
950 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
951 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
952 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
953 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
954 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
955 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
956 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
957 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
958 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
959 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
960 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
961 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
962 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
963 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
964 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
965 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
966 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
967 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
968 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
969 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
970 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
971 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
972 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
973 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
974 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
975 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
976 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
977 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
978 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
979 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
980 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
981 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
982 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
983 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
984 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
985 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
986 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
987 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
988 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
989 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
990 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
991 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
992 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
993 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
994 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
995 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
996 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
997 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
998 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
999 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1026 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1027 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1049 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001050 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001051 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1052 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1053 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1054 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001055 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001056 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1057 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1058 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1059 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1060 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1061 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1062 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1063 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1064 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1072 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1073 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1074 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1075 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1076 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1077 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1078 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1079 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1080 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1108 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1109 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1110 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1113 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1141 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1142 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1143 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001144};
1145
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001146#endif /* USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00001147
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001148/* alias.c */
Eric Andersen2870d962001-07-02 17:27:21 +00001149
Eric Andersen2870d962001-07-02 17:27:21 +00001150
Eric Andersenc470f442003-07-28 09:56:35 +00001151#define ATABSIZE 39
1152
1153static int funcblocksize; /* size of structures in function */
1154static int funcstringsize; /* size of strings in node */
1155static pointer funcblock; /* block to allocate function from */
1156static char *funcstring; /* block to allocate strings from */
1157
1158static const short nodesize[26] = {
1159 SHELL_ALIGN(sizeof (struct ncmd)),
1160 SHELL_ALIGN(sizeof (struct npipe)),
1161 SHELL_ALIGN(sizeof (struct nredir)),
1162 SHELL_ALIGN(sizeof (struct nredir)),
1163 SHELL_ALIGN(sizeof (struct nredir)),
1164 SHELL_ALIGN(sizeof (struct nbinary)),
1165 SHELL_ALIGN(sizeof (struct nbinary)),
1166 SHELL_ALIGN(sizeof (struct nbinary)),
1167 SHELL_ALIGN(sizeof (struct nif)),
1168 SHELL_ALIGN(sizeof (struct nbinary)),
1169 SHELL_ALIGN(sizeof (struct nbinary)),
1170 SHELL_ALIGN(sizeof (struct nfor)),
1171 SHELL_ALIGN(sizeof (struct ncase)),
1172 SHELL_ALIGN(sizeof (struct nclist)),
1173 SHELL_ALIGN(sizeof (struct narg)),
1174 SHELL_ALIGN(sizeof (struct narg)),
1175 SHELL_ALIGN(sizeof (struct nfile)),
1176 SHELL_ALIGN(sizeof (struct nfile)),
1177 SHELL_ALIGN(sizeof (struct nfile)),
1178 SHELL_ALIGN(sizeof (struct nfile)),
1179 SHELL_ALIGN(sizeof (struct nfile)),
1180 SHELL_ALIGN(sizeof (struct ndup)),
1181 SHELL_ALIGN(sizeof (struct ndup)),
1182 SHELL_ALIGN(sizeof (struct nhere)),
1183 SHELL_ALIGN(sizeof (struct nhere)),
1184 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001185};
1186
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001187
Eric Andersenc470f442003-07-28 09:56:35 +00001188static void calcsize(union node *);
1189static void sizenodelist(struct nodelist *);
1190static union node *copynode(union node *);
1191static struct nodelist *copynodelist(struct nodelist *);
1192static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001193
1194
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001195static int evalstring(char *, int mask);
Eric Andersenc470f442003-07-28 09:56:35 +00001196union node; /* BLETCH for ansi C */
1197static void evaltree(union node *, int);
1198static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001199
Eric Andersenc470f442003-07-28 09:56:35 +00001200static int evalskip; /* set if we are skipping commands */
1201static int skipcount; /* number of levels to skip */
1202static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001203
1204/* reasons for skipping commands (see comment on breakcmd routine) */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001205#define SKIPBREAK (1 << 0)
1206#define SKIPCONT (1 << 1)
1207#define SKIPFUNC (1 << 2)
1208#define SKIPFILE (1 << 3)
1209#define SKIPEVAL (1 << 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001210
Eric Andersenc470f442003-07-28 09:56:35 +00001211/*
1212 * This file was generated by the mkbuiltins program.
1213 */
Eric Andersen2870d962001-07-02 17:27:21 +00001214
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001215#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001216static int bgcmd(int, char **);
1217#endif
1218static int breakcmd(int, char **);
1219static int cdcmd(int, char **);
1220#ifdef CONFIG_ASH_CMDCMD
1221static int commandcmd(int, char **);
1222#endif
1223static int dotcmd(int, char **);
1224static int evalcmd(int, char **);
Paul Fox0b621582005-08-09 19:38:05 +00001225#ifdef CONFIG_ASH_BUILTIN_ECHO
1226static int echocmd(int, char **);
1227#endif
Paul Fox6ab03782006-06-08 21:37:26 +00001228#ifdef CONFIG_ASH_BUILTIN_TEST
1229static int testcmd(int, char **);
1230#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001231static int execcmd(int, char **);
1232static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001233static int exportcmd(int, char **);
1234static int falsecmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001235#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001236static int fgcmd(int, char **);
1237#endif
1238#ifdef CONFIG_ASH_GETOPTS
1239static int getoptscmd(int, char **);
1240#endif
1241static int hashcmd(int, char **);
1242#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1243static int helpcmd(int argc, char **argv);
1244#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001245#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001246static int jobscmd(int, char **);
1247#endif
Eric Andersen90898442003-08-06 11:20:52 +00001248#ifdef CONFIG_ASH_MATH_SUPPORT
1249static int letcmd(int, char **);
1250#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001251static int localcmd(int, char **);
1252static int pwdcmd(int, char **);
1253static int readcmd(int, char **);
1254static int returncmd(int, char **);
1255static int setcmd(int, char **);
1256static int shiftcmd(int, char **);
1257static int timescmd(int, char **);
1258static int trapcmd(int, char **);
1259static int truecmd(int, char **);
1260static int typecmd(int, char **);
1261static int umaskcmd(int, char **);
1262static int unsetcmd(int, char **);
1263static int waitcmd(int, char **);
1264static int ulimitcmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001265#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001266static int killcmd(int, char **);
1267#endif
1268
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001269/* mail.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001270
1271#ifdef CONFIG_ASH_MAIL
1272static void chkmail(void);
1273static void changemail(const char *);
1274#endif
1275
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001276/* exec.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001277
1278/* values of cmdtype */
1279#define CMDUNKNOWN -1 /* no entry in table for command */
1280#define CMDNORMAL 0 /* command is an executable program */
1281#define CMDFUNCTION 1 /* command is a shell function */
1282#define CMDBUILTIN 2 /* command is a shell builtin */
1283
1284struct builtincmd {
1285 const char *name;
1286 int (*builtin)(int, char **);
1287 /* unsigned flags; */
1288};
1289
Paul Fox0b621582005-08-09 19:38:05 +00001290
1291#define COMMANDCMD (builtincmd + 5 + \
Paul Fox6ab03782006-06-08 21:37:26 +00001292 2 * ENABLE_ASH_BUILTIN_TEST + \
1293 ENABLE_ASH_ALIAS + \
1294 ENABLE_ASH_JOB_CONTROL)
Paul Fox0b621582005-08-09 19:38:05 +00001295#define EXECCMD (builtincmd + 7 + \
Paul Fox6ab03782006-06-08 21:37:26 +00001296 2 * ENABLE_ASH_BUILTIN_TEST + \
1297 ENABLE_ASH_ALIAS + \
1298 ENABLE_ASH_JOB_CONTROL + \
1299 ENABLE_ASH_CMDCMD + \
1300 ENABLE_ASH_BUILTIN_ECHO)
Eric Andersenc470f442003-07-28 09:56:35 +00001301
1302#define BUILTIN_NOSPEC "0"
1303#define BUILTIN_SPECIAL "1"
1304#define BUILTIN_REGULAR "2"
1305#define BUILTIN_SPEC_REG "3"
1306#define BUILTIN_ASSIGN "4"
1307#define BUILTIN_SPEC_ASSG "5"
1308#define BUILTIN_REG_ASSG "6"
1309#define BUILTIN_SPEC_REG_ASSG "7"
1310
1311#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1312#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
Paul Foxc3850c82005-07-20 18:23:39 +00001313#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001314
Bernhard Reutner-Fischer35492132006-06-21 18:19:53 +00001315/* make sure to keep these in proper order since it is searched via bsearch() */
Eric Andersenc470f442003-07-28 09:56:35 +00001316static const struct builtincmd builtincmd[] = {
1317 { BUILTIN_SPEC_REG ".", dotcmd },
1318 { BUILTIN_SPEC_REG ":", truecmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001319#ifdef CONFIG_ASH_BUILTIN_TEST
1320 { BUILTIN_REGULAR "[", testcmd },
1321 { BUILTIN_REGULAR "[[", testcmd },
1322#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001323#ifdef CONFIG_ASH_ALIAS
1324 { BUILTIN_REG_ASSG "alias", aliascmd },
1325#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001326#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001327 { BUILTIN_REGULAR "bg", bgcmd },
1328#endif
1329 { BUILTIN_SPEC_REG "break", breakcmd },
1330 { BUILTIN_REGULAR "cd", cdcmd },
1331 { BUILTIN_NOSPEC "chdir", cdcmd },
1332#ifdef CONFIG_ASH_CMDCMD
1333 { BUILTIN_REGULAR "command", commandcmd },
1334#endif
1335 { BUILTIN_SPEC_REG "continue", breakcmd },
Paul Fox0b621582005-08-09 19:38:05 +00001336#ifdef CONFIG_ASH_BUILTIN_ECHO
1337 { BUILTIN_REGULAR "echo", echocmd },
1338#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001339 { BUILTIN_SPEC_REG "eval", evalcmd },
1340 { BUILTIN_SPEC_REG "exec", execcmd },
1341 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001342 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1343 { BUILTIN_REGULAR "false", falsecmd },
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001344#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001345 { BUILTIN_REGULAR "fg", fgcmd },
1346#endif
1347#ifdef CONFIG_ASH_GETOPTS
1348 { BUILTIN_REGULAR "getopts", getoptscmd },
1349#endif
1350 { BUILTIN_NOSPEC "hash", hashcmd },
1351#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1352 { BUILTIN_NOSPEC "help", helpcmd },
1353#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001354#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001355 { BUILTIN_REGULAR "jobs", jobscmd },
1356 { BUILTIN_REGULAR "kill", killcmd },
1357#endif
1358#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001359 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001360#endif
1361 { BUILTIN_ASSIGN "local", localcmd },
1362 { BUILTIN_NOSPEC "pwd", pwdcmd },
1363 { BUILTIN_REGULAR "read", readcmd },
1364 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1365 { BUILTIN_SPEC_REG "return", returncmd },
1366 { BUILTIN_SPEC_REG "set", setcmd },
1367 { BUILTIN_SPEC_REG "shift", shiftcmd },
Mike Frysingerc2ad4f52006-06-21 18:04:49 +00001368 { BUILTIN_SPEC_REG "source", dotcmd },
Paul Fox6ab03782006-06-08 21:37:26 +00001369#ifdef CONFIG_ASH_BUILTIN_TEST
1370 { BUILTIN_REGULAR "test", testcmd },
1371#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001372 { BUILTIN_SPEC_REG "times", timescmd },
1373 { BUILTIN_SPEC_REG "trap", trapcmd },
1374 { BUILTIN_REGULAR "true", truecmd },
1375 { BUILTIN_NOSPEC "type", typecmd },
1376 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1377 { BUILTIN_REGULAR "umask", umaskcmd },
1378#ifdef CONFIG_ASH_ALIAS
1379 { BUILTIN_REGULAR "unalias", unaliascmd },
1380#endif
1381 { BUILTIN_SPEC_REG "unset", unsetcmd },
1382 { BUILTIN_REGULAR "wait", waitcmd },
1383};
1384
1385#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1386
1387
1388
1389struct cmdentry {
1390 int cmdtype;
1391 union param {
1392 int index;
1393 const struct builtincmd *cmd;
1394 struct funcnode *func;
1395 } u;
1396};
1397
1398
1399/* action to find_command() */
1400#define DO_ERR 0x01 /* prints errors */
1401#define DO_ABS 0x02 /* checks absolute paths */
1402#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1403#define DO_ALTPATH 0x08 /* using alternate path */
1404#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1405
1406static const char *pathopt; /* set by padvance */
1407
1408static void shellexec(char **, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001409 ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00001410static char *padvance(const char **, const char *);
1411static void find_command(char *, struct cmdentry *, int, const char *);
1412static struct builtincmd *find_builtin(const char *);
1413static void hashcd(void);
1414static void changepath(const char *);
1415static void defun(char *, union node *);
1416static void unsetfunc(const char *);
1417
Eric Andersened9ecf72004-06-22 08:29:45 +00001418#ifdef CONFIG_ASH_MATH_SUPPORT_64
1419typedef int64_t arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001420#define arith_t_type (long long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001421#else
1422typedef long arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001423#define arith_t_type (long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001424#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001425
1426#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001427static arith_t dash_arith(const char *);
1428static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001429#endif
1430
Eric Andersen16767e22004-03-16 05:14:10 +00001431#ifdef CONFIG_ASH_RANDOM_SUPPORT
1432static unsigned long rseed;
1433static void change_random(const char *);
1434# ifndef DYNAMIC_VAR
1435# define DYNAMIC_VAR
1436# endif
1437#endif
1438
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001439/* init.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001440
1441static void reset(void);
1442
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001443/* var.h */
Eric Andersen2870d962001-07-02 17:27:21 +00001444
1445/*
1446 * Shell variables.
1447 */
1448
1449/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001450#define VEXPORT 0x01 /* variable is exported */
1451#define VREADONLY 0x02 /* variable cannot be modified */
1452#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1453#define VTEXTFIXED 0x08 /* text is statically allocated */
1454#define VSTACK 0x10 /* text is allocated on the stack */
1455#define VUNSET 0x20 /* the variable is not set */
1456#define VNOFUNC 0x40 /* don't call the callback function */
1457#define VNOSET 0x80 /* do not set variable - just readonly test */
1458#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001459#ifdef DYNAMIC_VAR
1460# define VDYNAMIC 0x200 /* dynamic variable */
1461# else
1462# define VDYNAMIC 0
1463#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001464
1465struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001466 struct var *next; /* next entry in hash list */
1467 int flags; /* flags are defined above */
1468 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001469 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001470 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001471};
1472
1473struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001474 struct localvar *next; /* next local variable in list */
1475 struct var *vp; /* the variable that was made local */
1476 int flags; /* saved flags */
1477 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001478};
1479
1480
Eric Andersen2870d962001-07-02 17:27:21 +00001481static struct localvar *localvars;
1482
Eric Andersenc470f442003-07-28 09:56:35 +00001483/*
1484 * Shell variables.
1485 */
1486
1487#ifdef CONFIG_ASH_GETOPTS
1488static void getoptsreset(const char *);
1489#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001490
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001491#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001492#include <locale.h>
1493static void change_lc_all(const char *value);
1494static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001495#endif
1496
Eric Andersenef02f822004-03-11 13:34:24 +00001497
Eric Andersen2870d962001-07-02 17:27:21 +00001498#define VTABSIZE 39
1499
Eric Andersen90898442003-08-06 11:20:52 +00001500static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001501#ifdef IFS_BROKEN
1502static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001503#define defifs (defifsvar + 4)
1504#else
Eric Andersenc470f442003-07-28 09:56:35 +00001505static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001506#endif
1507
Eric Andersenc470f442003-07-28 09:56:35 +00001508
1509static struct var varinit[] = {
1510#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001511 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001512#else
Eric Andersen16767e22004-03-16 05:14:10 +00001513 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001514#endif
1515
1516#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001517 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1518 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001519#endif
1520
Eric Andersen16767e22004-03-16 05:14:10 +00001521 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1522 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1523 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1524 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001525#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001526 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1527#endif
1528#ifdef CONFIG_ASH_RANDOM_SUPPORT
1529 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001530#endif
1531#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001532 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1533 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001534#endif
1535#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001536 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001537#endif
1538};
1539
1540#define vifs varinit[0]
1541#ifdef CONFIG_ASH_MAIL
1542#define vmail (&vifs)[1]
1543#define vmpath (&vmail)[1]
1544#else
1545#define vmpath vifs
1546#endif
1547#define vpath (&vmpath)[1]
1548#define vps1 (&vpath)[1]
1549#define vps2 (&vps1)[1]
1550#define vps4 (&vps2)[1]
1551#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001552#ifdef CONFIG_ASH_GETOPTS
1553#define vrandom (&voptind)[1]
1554#else
1555#define vrandom (&vps4)[1]
1556#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001557#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001558
1559/*
1560 * The following macros access the values of the above variables.
1561 * They have to skip over the name. They return the null string
1562 * for unset variables.
1563 */
1564
1565#define ifsval() (vifs.text + 4)
1566#define ifsset() ((vifs.flags & VUNSET) == 0)
1567#define mailval() (vmail.text + 5)
1568#define mpathval() (vmpath.text + 9)
1569#define pathval() (vpath.text + 5)
1570#define ps1val() (vps1.text + 4)
1571#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001572#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001573#define optindval() (voptind.text + 7)
1574
1575#define mpathset() ((vmpath.flags & VUNSET) == 0)
1576
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001577static void setvar(const char *, const char *, int);
1578static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001579static void listsetvar(struct strlist *, int);
1580static char *lookupvar(const char *);
1581static char *bltinlookup(const char *);
1582static char **listvars(int, int, char ***);
1583#define environment() listvars(VEXPORT, VUNSET, 0)
1584static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001585static void poplocalvars(void);
1586static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001587#ifdef CONFIG_ASH_GETOPTS
1588static int setvarsafe(const char *, const char *, int);
1589#endif
1590static int varcmp(const char *, const char *);
1591static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001592
1593
Eric Andersenc470f442003-07-28 09:56:35 +00001594static inline int varequal(const char *a, const char *b) {
1595 return !varcmp(a, b);
1596}
Eric Andersen2870d962001-07-02 17:27:21 +00001597
1598
Eric Andersenc470f442003-07-28 09:56:35 +00001599static int loopnest; /* current loop nesting level */
1600
Eric Andersenc470f442003-07-28 09:56:35 +00001601/*
1602 * The parsefile structure pointed to by the global variable parsefile
1603 * contains information about the current file being read.
1604 */
1605
1606
1607struct redirtab {
1608 struct redirtab *next;
1609 int renamed[10];
1610 int nullredirs;
1611};
1612
1613static struct redirtab *redirlist;
1614static int nullredirs;
1615
1616extern char **environ;
1617
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001618/* output.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001619
1620
1621static void outstr(const char *, FILE *);
1622static void outcslow(int, FILE *);
1623static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001624static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001625static int out1fmt(const char *, ...)
1626 __attribute__((__format__(__printf__,1,2)));
1627static int fmtstr(char *, size_t, const char *, ...)
1628 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001629
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001630static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001631
Eric Andersenc470f442003-07-28 09:56:35 +00001632
1633static void out1str(const char *p)
1634{
1635 outstr(p, stdout);
1636}
1637
1638static void out2str(const char *p)
1639{
1640 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001641 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001642}
1643
1644/*
1645 * Initialization code.
1646 */
1647
1648/*
1649 * This routine initializes the builtin variables.
1650 */
1651
1652static inline void
1653initvar(void)
1654{
1655 struct var *vp;
1656 struct var *end;
1657 struct var **vpp;
1658
1659 /*
1660 * PS1 depends on uid
1661 */
1662#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1663 vps1.text = "PS1=\\w \\$ ";
1664#else
1665 if (!geteuid())
1666 vps1.text = "PS1=# ";
1667#endif
1668 vp = varinit;
1669 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1670 do {
1671 vpp = hashvar(vp->text);
1672 vp->next = *vpp;
1673 *vpp = vp;
1674 } while (++vp < end);
1675}
1676
1677static inline void
1678init(void)
1679{
1680
1681 /* from input.c: */
1682 {
1683 basepf.nextc = basepf.buf = basebuf;
1684 }
1685
1686 /* from trap.c: */
1687 {
1688 signal(SIGCHLD, SIG_DFL);
1689 }
1690
1691 /* from var.c: */
1692 {
1693 char **envp;
1694 char ppid[32];
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001695 const char *p;
1696 struct stat st1, st2;
Eric Andersenc470f442003-07-28 09:56:35 +00001697
1698 initvar();
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001699 for (envp = environ ; envp && *envp ; envp++) {
Eric Andersenc470f442003-07-28 09:56:35 +00001700 if (strchr(*envp, '=')) {
1701 setvareq(*envp, VEXPORT|VTEXTFIXED);
1702 }
1703 }
1704
1705 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1706 setvar("PPID", ppid, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001707
1708 p = lookupvar("PWD");
1709 if (p)
1710 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1711 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1712 p = 0;
1713 setpwd(p, 0);
Eric Andersenc470f442003-07-28 09:56:35 +00001714 }
1715}
1716
1717/* PEOF (the end of file marker) */
1718
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001719enum {
1720 INPUT_PUSH_FILE = 1,
1721 INPUT_NOFILE_OK = 2,
1722};
1723
Eric Andersenc470f442003-07-28 09:56:35 +00001724/*
1725 * The input line number. Input.c just defines this variable, and saves
1726 * and restores it when files are pushed and popped. The user of this
1727 * package must set its value.
1728 */
1729
1730static int pgetc(void);
1731static int pgetc2(void);
1732static int preadbuffer(void);
1733static void pungetc(void);
1734static void pushstring(char *, void *);
1735static void popstring(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001736static void setinputfd(int, int);
1737static void setinputstring(char *);
1738static void popfile(void);
1739static void popallfiles(void);
1740static void closescript(void);
1741
1742
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001743/* jobs.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001744
1745
1746/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1747#define FORK_FG 0
1748#define FORK_BG 1
1749#define FORK_NOJOB 2
1750
1751/* mode flags for showjob(s) */
1752#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1753#define SHOW_PID 0x04 /* include process pid */
1754#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1755
1756
1757/*
1758 * A job structure contains information about a job. A job is either a
1759 * single process or a set of processes contained in a pipeline. In the
1760 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1761 * array of pids.
1762 */
1763
1764struct procstat {
1765 pid_t pid; /* process id */
1766 int status; /* last process status from wait() */
1767 char *cmd; /* text of command being run */
1768};
1769
1770struct job {
1771 struct procstat ps0; /* status of process */
1772 struct procstat *ps; /* status or processes when more than one */
1773#if JOBS
1774 int stopstatus; /* status of a stopped job */
1775#endif
1776 uint32_t
1777 nprocs: 16, /* number of processes */
1778 state: 8,
1779#define JOBRUNNING 0 /* at least one proc running */
1780#define JOBSTOPPED 1 /* all procs are stopped */
1781#define JOBDONE 2 /* all procs are completed */
1782#if JOBS
1783 sigint: 1, /* job was killed by SIGINT */
1784 jobctl: 1, /* job running under job control */
1785#endif
1786 waited: 1, /* true if this entry has been waited for */
1787 used: 1, /* true if this entry is in used */
1788 changed: 1; /* true if status has changed */
1789 struct job *prev_job; /* previous job */
1790};
1791
1792static pid_t backgndpid; /* pid of last background process */
1793static int job_warning; /* user was warned about stopped jobs */
1794#if JOBS
1795static int jobctl; /* true if doing job control */
1796#endif
1797
1798static struct job *makejob(union node *, int);
1799static int forkshell(struct job *, union node *, int);
1800static int waitforjob(struct job *);
1801static int stoppedjobs(void);
1802
1803#if ! JOBS
1804#define setjobctl(on) /* do nothing */
1805#else
1806static void setjobctl(int);
1807static void showjobs(FILE *, int);
1808#endif
1809
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001810/* main.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001811
1812
1813/* pid of main shell */
1814static int rootpid;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001815/* shell level: 0 for the main shell, 1 for its children, and so on */
1816static int shlvl;
1817#define rootshell (!shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00001818
1819static void readcmdfile(char *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001820static int cmdloop(int);
Eric Andersenc470f442003-07-28 09:56:35 +00001821
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001822/* memalloc.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001823
1824
1825struct stackmark {
1826 struct stack_block *stackp;
1827 char *stacknxt;
1828 size_t stacknleft;
1829 struct stackmark *marknext;
1830};
1831
1832/* minimum size of a block */
1833#define MINSIZE SHELL_ALIGN(504)
1834
1835struct stack_block {
1836 struct stack_block *prev;
1837 char space[MINSIZE];
1838};
1839
1840static struct stack_block stackbase;
1841static struct stack_block *stackp = &stackbase;
1842static struct stackmark *markp;
1843static char *stacknxt = stackbase.space;
1844static size_t stacknleft = MINSIZE;
1845static char *sstrend = stackbase.space + MINSIZE;
1846static int herefd = -1;
1847
1848
1849static pointer ckmalloc(size_t);
1850static pointer ckrealloc(pointer, size_t);
1851static char *savestr(const char *);
1852static pointer stalloc(size_t);
1853static void stunalloc(pointer);
1854static void setstackmark(struct stackmark *);
1855static void popstackmark(struct stackmark *);
1856static void growstackblock(void);
1857static void *growstackstr(void);
1858static char *makestrspace(size_t, char *);
1859static char *stnputs(const char *, size_t, char *);
1860static char *stputs(const char *, char *);
1861
1862
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001863static inline char *_STPUTC(int c, char *p) {
Eric Andersenc470f442003-07-28 09:56:35 +00001864 if (p == sstrend)
1865 p = growstackstr();
1866 *p++ = c;
1867 return p;
1868}
1869
1870#define stackblock() ((void *)stacknxt)
1871#define stackblocksize() stacknleft
1872#define STARTSTACKSTR(p) ((p) = stackblock())
1873#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1874#define CHECKSTRSPACE(n, p) \
1875 ({ \
1876 char *q = (p); \
1877 size_t l = (n); \
1878 size_t m = sstrend - q; \
1879 if (l > m) \
1880 (p) = makestrspace(l, q); \
1881 0; \
1882 })
1883#define USTPUTC(c, p) (*p++ = (c))
1884#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1885#define STUNPUTC(p) (--p)
1886#define STTOPC(p) p[-1]
1887#define STADJUST(amount, p) (p += (amount))
1888
1889#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1890#define ungrabstackstr(s, p) stunalloc((s))
1891#define stackstrend() ((void *)sstrend)
1892
1893#define ckfree(p) free((pointer)(p))
1894
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001895/* mystring.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001896
1897
1898#define DOLATSTRLEN 4
1899
1900static char *prefix(const char *, const char *);
1901static int number(const char *);
1902static int is_number(const char *);
1903static char *single_quote(const char *);
1904static char *sstrdup(const char *);
1905
1906#define equal(s1, s2) (strcmp(s1, s2) == 0)
1907#define scopy(s1, s2) ((void)strcpy(s2, s1))
1908
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001909/* options.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001910
1911struct shparam {
1912 int nparam; /* # of positional parameters (without $0) */
1913 unsigned char malloc; /* if parameter list dynamically allocated */
1914 char **p; /* parameter list */
1915#ifdef CONFIG_ASH_GETOPTS
1916 int optind; /* next parameter to be processed by getopts */
1917 int optoff; /* used by getopts */
1918#endif
1919};
1920
1921
1922#define eflag optlist[0]
1923#define fflag optlist[1]
1924#define Iflag optlist[2]
1925#define iflag optlist[3]
1926#define mflag optlist[4]
1927#define nflag optlist[5]
1928#define sflag optlist[6]
1929#define xflag optlist[7]
1930#define vflag optlist[8]
1931#define Cflag optlist[9]
1932#define aflag optlist[10]
1933#define bflag optlist[11]
1934#define uflag optlist[12]
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001935#define viflag optlist[13]
Eric Andersenc470f442003-07-28 09:56:35 +00001936
1937#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001938#define nolog optlist[14]
1939#define debug optlist[15]
Paul Fox3f11b1b2005-08-04 19:04:46 +00001940#endif
1941
1942#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1943#define setvimode(on) viflag = 0 /* forcibly keep the option off */
Eric Andersenc470f442003-07-28 09:56:35 +00001944#endif
1945
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001946/* options.c */
Eric Andersenc470f442003-07-28 09:56:35 +00001947
1948
Paul Fox3f11b1b2005-08-04 19:04:46 +00001949static const char *const optletters_optnames[] = {
Eric Andersenc470f442003-07-28 09:56:35 +00001950 "e" "errexit",
1951 "f" "noglob",
1952 "I" "ignoreeof",
1953 "i" "interactive",
1954 "m" "monitor",
1955 "n" "noexec",
1956 "s" "stdin",
1957 "x" "xtrace",
1958 "v" "verbose",
1959 "C" "noclobber",
1960 "a" "allexport",
1961 "b" "notify",
1962 "u" "nounset",
Paul Fox3f11b1b2005-08-04 19:04:46 +00001963 "\0" "vi",
Eric Andersenc470f442003-07-28 09:56:35 +00001964#ifdef DEBUG
1965 "\0" "nolog",
1966 "\0" "debug",
1967#endif
1968};
1969
1970#define optletters(n) optletters_optnames[(n)][0]
1971#define optnames(n) (&optletters_optnames[(n)][1])
1972
Paul Fox3f11b1b2005-08-04 19:04:46 +00001973#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001974
1975static char optlist[NOPTS];
1976
1977
1978static char *arg0; /* value of $0 */
1979static struct shparam shellparam; /* $@ current positional parameters */
1980static char **argptr; /* argument list for builtin commands */
1981static char *optionarg; /* set by nextopt (like getopt) */
1982static char *optptr; /* used by nextopt */
1983
1984static char *minusc; /* argument to -c option */
1985
1986
1987static void procargs(int, char **);
1988static void optschanged(void);
1989static void setparam(char **);
1990static void freeparam(volatile struct shparam *);
1991static int shiftcmd(int, char **);
1992static int setcmd(int, char **);
1993static int nextopt(const char *);
1994
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001995/* redir.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001996
1997/* flags passed to redirect */
1998#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001999#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00002000
2001union node;
2002static void redirect(union node *, int);
2003static void popredir(int);
2004static void clearredir(int);
2005static int copyfd(int, int);
2006static int redirectsafe(union node *, int);
2007
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002008/* show.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002009
2010
2011#ifdef DEBUG
2012static void showtree(union node *);
2013static void trace(const char *, ...);
2014static void tracev(const char *, va_list);
2015static void trargs(char **);
2016static void trputc(int);
2017static void trputs(const char *);
2018static void opentrace(void);
2019#endif
2020
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002021/* trap.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002022
2023
2024/* trap handler commands */
2025static char *trap[NSIG];
2026/* current value of signal */
2027static char sigmode[NSIG - 1];
2028/* indicates specified signal received */
2029static char gotsig[NSIG - 1];
2030
2031static void clear_traps(void);
2032static void setsignal(int);
2033static void ignoresig(int);
2034static void onsig(int);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002035static int dotrap(void);
Eric Andersenc470f442003-07-28 09:56:35 +00002036static void setinteractive(int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002037static void exitshell(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00002038
2039/*
2040 * This routine is called when an error or an interrupt occurs in an
2041 * interactive shell and control is returned to the main command loop.
2042 */
2043
2044static void
2045reset(void)
2046{
2047 /* from eval.c: */
2048 {
2049 evalskip = 0;
2050 loopnest = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002051 }
2052
2053 /* from input.c: */
2054 {
2055 parselleft = parsenleft = 0; /* clear input buffer */
2056 popallfiles();
2057 }
2058
2059 /* from parser.c: */
2060 {
2061 tokpushback = 0;
2062 checkkwd = 0;
2063 }
2064
2065 /* from redir.c: */
2066 {
2067 clearredir(0);
2068 }
2069
2070}
2071
2072#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002073static struct alias *atab[ATABSIZE];
2074
Eric Andersenc470f442003-07-28 09:56:35 +00002075static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002076static struct alias *freealias(struct alias *);
2077static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002078
Eric Andersenc470f442003-07-28 09:56:35 +00002079static void
2080setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002081{
2082 struct alias *ap, **app;
2083
2084 app = __lookupalias(name);
2085 ap = *app;
2086 INTOFF;
2087 if (ap) {
2088 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002089 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002090 }
Eric Andersenc470f442003-07-28 09:56:35 +00002091 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002092 ap->flag &= ~ALIASDEAD;
2093 } else {
2094 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002095 ap = ckmalloc(sizeof (struct alias));
2096 ap->name = savestr(name);
2097 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002098 ap->flag = 0;
2099 ap->next = 0;
2100 *app = ap;
2101 }
2102 INTON;
2103}
2104
Eric Andersenc470f442003-07-28 09:56:35 +00002105static int
2106unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002107{
Eric Andersencb57d552001-06-28 07:25:16 +00002108 struct alias **app;
2109
2110 app = __lookupalias(name);
2111
2112 if (*app) {
2113 INTOFF;
2114 *app = freealias(*app);
2115 INTON;
2116 return (0);
2117 }
2118
2119 return (1);
2120}
2121
Eric Andersenc470f442003-07-28 09:56:35 +00002122static void
2123rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002124{
Eric Andersencb57d552001-06-28 07:25:16 +00002125 struct alias *ap, **app;
2126 int i;
2127
2128 INTOFF;
2129 for (i = 0; i < ATABSIZE; i++) {
2130 app = &atab[i];
2131 for (ap = *app; ap; ap = *app) {
2132 *app = freealias(*app);
2133 if (ap == *app) {
2134 app = &ap->next;
2135 }
2136 }
2137 }
2138 INTON;
2139}
2140
Eric Andersenc470f442003-07-28 09:56:35 +00002141static struct alias *
2142lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002143{
Eric Andersenc470f442003-07-28 09:56:35 +00002144 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002145
Eric Andersenc470f442003-07-28 09:56:35 +00002146 if (check && ap && (ap->flag & ALIASINUSE))
2147 return (NULL);
2148 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002149}
2150
Eric Andersencb57d552001-06-28 07:25:16 +00002151/*
2152 * TODO - sort output
2153 */
Eric Andersenc470f442003-07-28 09:56:35 +00002154static int
2155aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002156{
2157 char *n, *v;
2158 int ret = 0;
2159 struct alias *ap;
2160
2161 if (argc == 1) {
2162 int i;
2163
2164 for (i = 0; i < ATABSIZE; i++)
2165 for (ap = atab[i]; ap; ap = ap->next) {
2166 printalias(ap);
2167 }
2168 return (0);
2169 }
2170 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002171 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002172 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002173 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002174 ret = 1;
2175 } else
2176 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002177 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002178 *v++ = '\0';
2179 setalias(n, v);
2180 }
2181 }
2182
2183 return (ret);
2184}
2185
Eric Andersenc470f442003-07-28 09:56:35 +00002186static int
2187unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002188{
2189 int i;
2190
2191 while ((i = nextopt("a")) != '\0') {
2192 if (i == 'a') {
2193 rmaliases();
2194 return (0);
2195 }
2196 }
2197 for (i = 0; *argptr; argptr++) {
2198 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002199 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002200 i = 1;
2201 }
2202 }
2203
2204 return (i);
2205}
2206
Eric Andersenc470f442003-07-28 09:56:35 +00002207static struct alias *
2208freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002209 struct alias *next;
2210
2211 if (ap->flag & ALIASINUSE) {
2212 ap->flag |= ALIASDEAD;
2213 return ap;
2214 }
2215
2216 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002217 ckfree(ap->name);
2218 ckfree(ap->val);
2219 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002220 return next;
2221}
2222
Eric Andersenc470f442003-07-28 09:56:35 +00002223static void
2224printalias(const struct alias *ap) {
2225 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2226}
Eric Andersencb57d552001-06-28 07:25:16 +00002227
Eric Andersenc470f442003-07-28 09:56:35 +00002228static struct alias **
2229__lookupalias(const char *name) {
2230 unsigned int hashval;
2231 struct alias **app;
2232 const char *p;
2233 unsigned int ch;
2234
2235 p = name;
2236
2237 ch = (unsigned char)*p;
2238 hashval = ch << 4;
2239 while (ch) {
2240 hashval += ch;
2241 ch = (unsigned char)*++p;
2242 }
2243 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002244
2245 for (; *app; app = &(*app)->next) {
2246 if (equal(name, (*app)->name)) {
2247 break;
2248 }
2249 }
2250
2251 return app;
2252}
Eric Andersenc470f442003-07-28 09:56:35 +00002253#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002254
Eric Andersencb57d552001-06-28 07:25:16 +00002255
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002256/* cd.c */
Eric Andersen2870d962001-07-02 17:27:21 +00002257
Eric Andersencb57d552001-06-28 07:25:16 +00002258/*
Eric Andersenc470f442003-07-28 09:56:35 +00002259 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002260 */
2261
Eric Andersenc470f442003-07-28 09:56:35 +00002262#define CD_PHYSICAL 1
2263#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002264
Eric Andersenc470f442003-07-28 09:56:35 +00002265static int docd(const char *, int);
2266static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002267
Eric Andersenc470f442003-07-28 09:56:35 +00002268static char *curdir = nullstr; /* current working directory */
2269static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002270
Eric Andersenc470f442003-07-28 09:56:35 +00002271static int
2272cdopt(void)
2273{
2274 int flags = 0;
2275 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002276
Eric Andersenc470f442003-07-28 09:56:35 +00002277 j = 'L';
2278 while ((i = nextopt("LP"))) {
2279 if (i != j) {
2280 flags ^= CD_PHYSICAL;
2281 j = i;
2282 }
2283 }
Eric Andersencb57d552001-06-28 07:25:16 +00002284
Eric Andersenc470f442003-07-28 09:56:35 +00002285 return flags;
2286}
Eric Andersen2870d962001-07-02 17:27:21 +00002287
Eric Andersenc470f442003-07-28 09:56:35 +00002288static int
2289cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002290{
2291 const char *dest;
2292 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002293 const char *p;
2294 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002295 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002296 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002297
Eric Andersenc470f442003-07-28 09:56:35 +00002298 flags = cdopt();
2299 dest = *argptr;
2300 if (!dest)
2301 dest = bltinlookup(homestr);
2302 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002303 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002304 flags |= CD_PRINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002305 }
Eric Andersenc470f442003-07-28 09:56:35 +00002306 if (!dest)
2307 dest = nullstr;
2308 if (*dest == '/')
2309 goto step7;
2310 if (*dest == '.') {
2311 c = dest[1];
2312dotdot:
2313 switch (c) {
2314 case '\0':
2315 case '/':
2316 goto step6;
2317 case '.':
2318 c = dest[2];
2319 if (c != '.')
2320 goto dotdot;
2321 }
2322 }
2323 if (!*dest)
2324 dest = ".";
2325 if (!(path = bltinlookup("CDPATH"))) {
2326step6:
2327step7:
2328 p = dest;
2329 goto docd;
2330 }
2331 do {
2332 c = *path;
2333 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002334 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002335 if (c && c != ':')
2336 flags |= CD_PRINT;
2337docd:
2338 if (!docd(p, flags))
2339 goto out;
2340 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002341 }
Eric Andersenc470f442003-07-28 09:56:35 +00002342 } while (path);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002343 sh_error("can't cd to %s", dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002344 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002345out:
2346 if (flags & CD_PRINT)
2347 out1fmt(snlfmt, curdir);
2348 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002349}
2350
2351
2352/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002353 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002354 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002355 */
2356
Eric Andersenc470f442003-07-28 09:56:35 +00002357static inline const char *
2358updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002359{
Eric Andersenc470f442003-07-28 09:56:35 +00002360 char *new;
2361 char *p;
2362 char *cdcomppath;
2363 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002364
Eric Andersenc470f442003-07-28 09:56:35 +00002365 cdcomppath = sstrdup(dir);
2366 STARTSTACKSTR(new);
2367 if (*dir != '/') {
2368 if (curdir == nullstr)
2369 return 0;
2370 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002371 }
Eric Andersenc470f442003-07-28 09:56:35 +00002372 new = makestrspace(strlen(dir) + 2, new);
2373 lim = stackblock() + 1;
2374 if (*dir != '/') {
2375 if (new[-1] != '/')
2376 USTPUTC('/', new);
2377 if (new > lim && *lim == '/')
2378 lim++;
2379 } else {
2380 USTPUTC('/', new);
2381 cdcomppath++;
2382 if (dir[1] == '/' && dir[2] != '/') {
2383 USTPUTC('/', new);
2384 cdcomppath++;
2385 lim++;
2386 }
2387 }
2388 p = strtok(cdcomppath, "/");
2389 while (p) {
2390 switch(*p) {
2391 case '.':
2392 if (p[1] == '.' && p[2] == '\0') {
2393 while (new > lim) {
2394 STUNPUTC(new);
2395 if (new[-1] == '/')
2396 break;
2397 }
2398 break;
2399 } else if (p[1] == '\0')
2400 break;
2401 /* fall through */
2402 default:
2403 new = stputs(p, new);
2404 USTPUTC('/', new);
2405 }
2406 p = strtok(0, "/");
2407 }
2408 if (new > lim)
2409 STUNPUTC(new);
2410 *new = 0;
2411 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002412}
2413
2414/*
Eric Andersenc470f442003-07-28 09:56:35 +00002415 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2416 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002417 */
2418
Eric Andersenc470f442003-07-28 09:56:35 +00002419static int
2420docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002421{
Eric Andersenc470f442003-07-28 09:56:35 +00002422 const char *dir = 0;
2423 int err;
2424
2425 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2426
Eric Andersencb57d552001-06-28 07:25:16 +00002427 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002428 if (!(flags & CD_PHYSICAL)) {
2429 dir = updatepwd(dest);
2430 if (dir)
2431 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002432 }
Eric Andersenc470f442003-07-28 09:56:35 +00002433 err = chdir(dest);
2434 if (err)
2435 goto out;
2436 setpwd(dir, 1);
2437 hashcd();
2438out:
Eric Andersencb57d552001-06-28 07:25:16 +00002439 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002440 return err;
2441}
2442
2443/*
2444 * Find out what the current directory is. If we already know the current
2445 * directory, this routine returns immediately.
2446 */
2447static inline char *
2448getpwd(void)
2449{
2450 char *dir = getcwd(0, 0);
2451 return dir ? dir : nullstr;
2452}
2453
2454static int
2455pwdcmd(int argc, char **argv)
2456{
2457 int flags;
2458 const char *dir = curdir;
2459
2460 flags = cdopt();
2461 if (flags) {
2462 if (physdir == nullstr)
2463 setpwd(dir, 0);
2464 dir = physdir;
2465 }
2466 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002467 return 0;
2468}
2469
Eric Andersenc470f442003-07-28 09:56:35 +00002470static void
2471setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002472{
Eric Andersenc470f442003-07-28 09:56:35 +00002473 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002474
Eric Andersenc470f442003-07-28 09:56:35 +00002475 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002476
Eric Andersencb57d552001-06-28 07:25:16 +00002477 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002478 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002479 }
2480 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002481 if (physdir != nullstr) {
2482 if (physdir != oldcur)
2483 free(physdir);
2484 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002485 }
Eric Andersenc470f442003-07-28 09:56:35 +00002486 if (oldcur == val || !val) {
2487 char *s = getpwd();
2488 physdir = s;
2489 if (!val)
2490 dir = s;
2491 } else
2492 dir = savestr(val);
2493 if (oldcur != dir && oldcur != nullstr) {
2494 free(oldcur);
2495 }
2496 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002497 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002498 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002499}
2500
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002501/* error.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002502
Eric Andersencb57d552001-06-28 07:25:16 +00002503/*
2504 * Errors and exceptions.
2505 */
2506
2507/*
2508 * Code to handle exceptions in C.
2509 */
2510
Eric Andersen2870d962001-07-02 17:27:21 +00002511
Eric Andersencb57d552001-06-28 07:25:16 +00002512
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002513static void exverror(int, const char *, va_list)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002514 ATTRIBUTE_NORETURN;
Eric Andersencb57d552001-06-28 07:25:16 +00002515
2516/*
2517 * Called to raise an exception. Since C doesn't include exceptions, we
2518 * just do a longjmp to the exception handler. The type of exception is
2519 * stored in the global variable "exception".
2520 */
2521
Eric Andersenc470f442003-07-28 09:56:35 +00002522static void
2523exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002524{
2525#ifdef DEBUG
2526 if (handler == NULL)
2527 abort();
2528#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002529 INTOFF;
2530
Eric Andersencb57d552001-06-28 07:25:16 +00002531 exception = e;
2532 longjmp(handler->loc, 1);
2533}
2534
2535
2536/*
2537 * Called from trap.c when a SIGINT is received. (If the user specifies
2538 * that SIGINT is to be trapped or ignored using the trap builtin, then
2539 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002540 * are held using the INTOFF macro. (The test for iflag is just
2541 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002542 */
2543
Eric Andersenc470f442003-07-28 09:56:35 +00002544static void
2545onint(void) {
2546 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002547
Eric Andersencb57d552001-06-28 07:25:16 +00002548 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002549 i = EXSIG;
2550 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2551 if (!(rootshell && iflag)) {
2552 signal(SIGINT, SIG_DFL);
2553 raise(SIGINT);
2554 }
2555 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002556 }
Eric Andersenc470f442003-07-28 09:56:35 +00002557 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002558 /* NOTREACHED */
2559}
2560
Eric Andersenc470f442003-07-28 09:56:35 +00002561static void
2562exvwarning(const char *msg, va_list ap)
2563{
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002564 FILE *errs;
Eric Andersencb57d552001-06-28 07:25:16 +00002565
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002566 errs = stderr;
2567 fprintf(errs, "%s: ", arg0);
2568 if (commandname) {
2569 const char *fmt = (!iflag || parsefile->fd) ?
2570 "%s: %d: " : "%s: ";
2571 fprintf(errs, fmt, commandname, startlinno);
2572 }
2573 vfprintf(errs, msg, ap);
2574 outcslow('\n', errs);
Eric Andersenc470f442003-07-28 09:56:35 +00002575}
Eric Andersen2870d962001-07-02 17:27:21 +00002576
Eric Andersencb57d552001-06-28 07:25:16 +00002577/*
Eric Andersenc470f442003-07-28 09:56:35 +00002578 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002579 * is not NULL then error prints an error message using printf style
2580 * formatting. It then raises the error exception.
2581 */
Eric Andersenc470f442003-07-28 09:56:35 +00002582static void
2583exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002584{
Eric Andersencb57d552001-06-28 07:25:16 +00002585#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002586 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002587 TRACE(("exverror(%d, \"", cond));
2588 TRACEV((msg, ap));
2589 TRACE(("\") pid=%d\n", getpid()));
2590 } else
2591 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2592 if (msg)
2593#endif
2594 exvwarning(msg, ap);
2595
2596 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002597 exraise(cond);
2598 /* NOTREACHED */
2599}
2600
2601
Eric Andersenc470f442003-07-28 09:56:35 +00002602static void
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002603sh_error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002604{
Eric Andersencb57d552001-06-28 07:25:16 +00002605 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002606
Eric Andersencb57d552001-06-28 07:25:16 +00002607 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002608 exverror(EXERROR, msg, ap);
2609 /* NOTREACHED */
2610 va_end(ap);
2611}
2612
2613
Eric Andersenc470f442003-07-28 09:56:35 +00002614static void
2615exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002616{
Eric Andersencb57d552001-06-28 07:25:16 +00002617 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002618
Eric Andersencb57d552001-06-28 07:25:16 +00002619 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002620 exverror(cond, msg, ap);
2621 /* NOTREACHED */
2622 va_end(ap);
2623}
2624
Eric Andersencb57d552001-06-28 07:25:16 +00002625/*
Eric Andersenc470f442003-07-28 09:56:35 +00002626 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002627 */
2628
Eric Andersenc470f442003-07-28 09:56:35 +00002629static void
2630sh_warnx(const char *fmt, ...)
2631{
2632 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002633
Eric Andersenc470f442003-07-28 09:56:35 +00002634 va_start(ap, fmt);
2635 exvwarning(fmt, ap);
2636 va_end(ap);
2637}
Eric Andersen2870d962001-07-02 17:27:21 +00002638
Eric Andersencb57d552001-06-28 07:25:16 +00002639
2640/*
2641 * Return a string describing an error. The returned string may be a
2642 * pointer to a static buffer that will be overwritten on the next call.
2643 * Action describes the operation that got the error.
2644 */
2645
Eric Andersenc470f442003-07-28 09:56:35 +00002646static const char *
2647errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002648{
Eric Andersenc470f442003-07-28 09:56:35 +00002649 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002650
Eric Andersenc470f442003-07-28 09:56:35 +00002651 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002652 }
Eric Andersenc470f442003-07-28 09:56:35 +00002653 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002654}
2655
2656
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002657/* eval.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002658
2659/*
2660 * Evaluate a command.
2661 */
Eric Andersencb57d552001-06-28 07:25:16 +00002662
2663/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002664#define EV_EXIT 01 /* exit after evaluating tree */
2665#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2666#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002667
2668
Eric Andersenc470f442003-07-28 09:56:35 +00002669static void evalloop(union node *, int);
2670static void evalfor(union node *, int);
2671static void evalcase(union node *, int);
2672static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002673static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002674static void evalpipe(union node *, int);
2675static void evalcommand(union node *, int);
2676static int evalbltin(const struct builtincmd *, int, char **);
2677static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002678static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002679static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002680
Eric Andersenc470f442003-07-28 09:56:35 +00002681
2682static const struct builtincmd bltin = {
2683 "\0\0", bltincmd
2684};
2685
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002686
Eric Andersencb57d552001-06-28 07:25:16 +00002687/*
2688 * Called to reset things after an exception.
2689 */
2690
Eric Andersencb57d552001-06-28 07:25:16 +00002691/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002692 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002693 */
2694
Eric Andersenc470f442003-07-28 09:56:35 +00002695static int
2696evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002697{
Eric Andersen2870d962001-07-02 17:27:21 +00002698 char *p;
2699 char *concat;
2700 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002701
Eric Andersen2870d962001-07-02 17:27:21 +00002702 if (argc > 1) {
2703 p = argv[1];
2704 if (argc > 2) {
2705 STARTSTACKSTR(concat);
2706 ap = argv + 2;
2707 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002708 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002709 if ((p = *ap++) == NULL)
2710 break;
2711 STPUTC(' ', concat);
2712 }
2713 STPUTC('\0', concat);
2714 p = grabstackstr(concat);
2715 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002716 evalstring(p, ~SKIPEVAL);
2717
Eric Andersen2870d962001-07-02 17:27:21 +00002718 }
2719 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002720}
2721
Eric Andersenc470f442003-07-28 09:56:35 +00002722
Eric Andersencb57d552001-06-28 07:25:16 +00002723/*
2724 * Execute a command or commands contained in a string.
2725 */
2726
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002727static int
2728evalstring(char *s, int mask)
Eric Andersen2870d962001-07-02 17:27:21 +00002729{
Eric Andersencb57d552001-06-28 07:25:16 +00002730 union node *n;
2731 struct stackmark smark;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002732 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002733
Eric Andersencb57d552001-06-28 07:25:16 +00002734 setinputstring(s);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002735 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002736
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002737 skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002738 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002739 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002740 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002741 skip = evalskip;
2742 if (skip)
Eric Andersenc470f442003-07-28 09:56:35 +00002743 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002744 }
2745 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002746
2747 skip &= mask;
2748 evalskip = skip;
2749 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002750}
2751
Eric Andersenc470f442003-07-28 09:56:35 +00002752
Eric Andersen62483552001-07-10 06:09:16 +00002753
2754/*
Eric Andersenc470f442003-07-28 09:56:35 +00002755 * Evaluate a parse tree. The value is left in the global variable
2756 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002757 */
2758
Eric Andersenc470f442003-07-28 09:56:35 +00002759static void
2760evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002761{
Eric Andersenc470f442003-07-28 09:56:35 +00002762 int checkexit = 0;
2763 void (*evalfn)(union node *, int);
2764 unsigned isor;
2765 int status;
2766 if (n == NULL) {
2767 TRACE(("evaltree(NULL) called\n"));
2768 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002769 }
Eric Andersenc470f442003-07-28 09:56:35 +00002770 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2771 getpid(), n, n->type, flags));
2772 switch (n->type) {
2773 default:
2774#ifdef DEBUG
2775 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002776 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002777 break;
2778#endif
2779 case NNOT:
2780 evaltree(n->nnot.com, EV_TESTED);
2781 status = !exitstatus;
2782 goto setstatus;
2783 case NREDIR:
2784 expredir(n->nredir.redirect);
2785 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2786 if (!status) {
2787 evaltree(n->nredir.n, flags & EV_TESTED);
2788 status = exitstatus;
2789 }
2790 popredir(0);
2791 goto setstatus;
2792 case NCMD:
2793 evalfn = evalcommand;
2794checkexit:
2795 if (eflag && !(flags & EV_TESTED))
2796 checkexit = ~0;
2797 goto calleval;
2798 case NFOR:
2799 evalfn = evalfor;
2800 goto calleval;
2801 case NWHILE:
2802 case NUNTIL:
2803 evalfn = evalloop;
2804 goto calleval;
2805 case NSUBSHELL:
2806 case NBACKGND:
2807 evalfn = evalsubshell;
2808 goto calleval;
2809 case NPIPE:
2810 evalfn = evalpipe;
2811 goto checkexit;
2812 case NCASE:
2813 evalfn = evalcase;
2814 goto calleval;
2815 case NAND:
2816 case NOR:
2817 case NSEMI:
2818#if NAND + 1 != NOR
2819#error NAND + 1 != NOR
2820#endif
2821#if NOR + 1 != NSEMI
2822#error NOR + 1 != NSEMI
2823#endif
2824 isor = n->type - NAND;
2825 evaltree(
2826 n->nbinary.ch1,
2827 (flags | ((isor >> 1) - 1)) & EV_TESTED
2828 );
2829 if (!exitstatus == isor)
2830 break;
2831 if (!evalskip) {
2832 n = n->nbinary.ch2;
2833evaln:
2834 evalfn = evaltree;
2835calleval:
2836 evalfn(n, flags);
2837 break;
2838 }
2839 break;
2840 case NIF:
2841 evaltree(n->nif.test, EV_TESTED);
2842 if (evalskip)
2843 break;
2844 if (exitstatus == 0) {
2845 n = n->nif.ifpart;
2846 goto evaln;
2847 } else if (n->nif.elsepart) {
2848 n = n->nif.elsepart;
2849 goto evaln;
2850 }
2851 goto success;
2852 case NDEFUN:
2853 defun(n->narg.text, n->narg.next);
2854success:
2855 status = 0;
2856setstatus:
2857 exitstatus = status;
2858 break;
2859 }
2860out:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002861 if ((checkexit & exitstatus))
2862 evalskip |= SKIPEVAL;
2863 else if (pendingsigs && dotrap())
2864 goto exexit;
2865
2866 if (flags & EV_EXIT) {
2867exexit:
Eric Andersenc470f442003-07-28 09:56:35 +00002868 exraise(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002869 }
Eric Andersen62483552001-07-10 06:09:16 +00002870}
2871
Eric Andersenc470f442003-07-28 09:56:35 +00002872
2873#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2874static
2875#endif
2876void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2877
2878
2879static void
2880evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002881{
2882 int status;
2883
2884 loopnest++;
2885 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002886 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002887 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002888 int i;
2889
Eric Andersencb57d552001-06-28 07:25:16 +00002890 evaltree(n->nbinary.ch1, EV_TESTED);
2891 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002892skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002893 evalskip = 0;
2894 continue;
2895 }
2896 if (evalskip == SKIPBREAK && --skipcount <= 0)
2897 evalskip = 0;
2898 break;
2899 }
Eric Andersenc470f442003-07-28 09:56:35 +00002900 i = exitstatus;
2901 if (n->type != NWHILE)
2902 i = !i;
2903 if (i != 0)
2904 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002905 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002906 status = exitstatus;
2907 if (evalskip)
2908 goto skipping;
2909 }
2910 loopnest--;
2911 exitstatus = status;
2912}
2913
Eric Andersenc470f442003-07-28 09:56:35 +00002914
2915
2916static void
2917evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002918{
2919 struct arglist arglist;
2920 union node *argp;
2921 struct strlist *sp;
2922 struct stackmark smark;
2923
2924 setstackmark(&smark);
2925 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002926 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002927 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002928 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002929 if (evalskip)
2930 goto out;
2931 }
2932 *arglist.lastp = NULL;
2933
2934 exitstatus = 0;
2935 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002936 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002937 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002938 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002939 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002940 if (evalskip) {
2941 if (evalskip == SKIPCONT && --skipcount <= 0) {
2942 evalskip = 0;
2943 continue;
2944 }
2945 if (evalskip == SKIPBREAK && --skipcount <= 0)
2946 evalskip = 0;
2947 break;
2948 }
2949 }
2950 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002951out:
Eric Andersencb57d552001-06-28 07:25:16 +00002952 popstackmark(&smark);
2953}
2954
Eric Andersenc470f442003-07-28 09:56:35 +00002955
2956
2957static void
2958evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002959{
2960 union node *cp;
2961 union node *patp;
2962 struct arglist arglist;
2963 struct stackmark smark;
2964
2965 setstackmark(&smark);
2966 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002967 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002968 exitstatus = 0;
2969 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2970 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002971 if (casematch(patp, arglist.list->text)) {
2972 if (evalskip == 0) {
2973 evaltree(cp->nclist.body, flags);
2974 }
2975 goto out;
2976 }
2977 }
2978 }
Eric Andersenc470f442003-07-28 09:56:35 +00002979out:
Eric Andersencb57d552001-06-28 07:25:16 +00002980 popstackmark(&smark);
2981}
2982
Eric Andersenc470f442003-07-28 09:56:35 +00002983
2984
2985/*
2986 * Kick off a subshell to evaluate a tree.
2987 */
2988
2989static void
2990evalsubshell(union node *n, int flags)
2991{
2992 struct job *jp;
2993 int backgnd = (n->type == NBACKGND);
2994 int status;
2995
2996 expredir(n->nredir.redirect);
2997 if (!backgnd && flags & EV_EXIT && !trap[0])
2998 goto nofork;
2999 INTOFF;
3000 jp = makejob(n, 1);
3001 if (forkshell(jp, n, backgnd) == 0) {
3002 INTON;
3003 flags |= EV_EXIT;
3004 if (backgnd)
3005 flags &=~ EV_TESTED;
3006nofork:
3007 redirect(n->nredir.redirect, 0);
3008 evaltreenr(n->nredir.n, flags);
3009 /* never returns */
3010 }
3011 status = 0;
3012 if (! backgnd)
3013 status = waitforjob(jp);
3014 exitstatus = status;
3015 INTON;
3016}
3017
3018
3019
3020/*
3021 * Compute the names of the files in a redirection list.
3022 */
3023
3024static void
3025expredir(union node *n)
3026{
3027 union node *redir;
3028
3029 for (redir = n ; redir ; redir = redir->nfile.next) {
3030 struct arglist fn;
3031 fn.lastp = &fn.list;
3032 switch (redir->type) {
3033 case NFROMTO:
3034 case NFROM:
3035 case NTO:
3036 case NCLOBBER:
3037 case NAPPEND:
3038 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3039 redir->nfile.expfname = fn.list->text;
3040 break;
3041 case NFROMFD:
3042 case NTOFD:
3043 if (redir->ndup.vname) {
3044 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3045 fixredir(redir, fn.list->text, 1);
3046 }
3047 break;
3048 }
3049 }
3050}
3051
3052
3053
Eric Andersencb57d552001-06-28 07:25:16 +00003054/*
Eric Andersencb57d552001-06-28 07:25:16 +00003055 * Evaluate a pipeline. All the processes in the pipeline are children
3056 * of the process creating the pipeline. (This differs from some versions
3057 * of the shell, which make the last process in a pipeline the parent
3058 * of all the rest.)
3059 */
3060
Eric Andersenc470f442003-07-28 09:56:35 +00003061static void
3062evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003063{
3064 struct job *jp;
3065 struct nodelist *lp;
3066 int pipelen;
3067 int prevfd;
3068 int pip[2];
3069
Eric Andersenc470f442003-07-28 09:56:35 +00003070 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003071 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003072 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003073 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003074 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003075 INTOFF;
3076 jp = makejob(n, pipelen);
3077 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003078 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003079 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003080 pip[1] = -1;
3081 if (lp->next) {
3082 if (pipe(pip) < 0) {
3083 close(prevfd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003084 sh_error("Pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00003085 }
3086 }
3087 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3088 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003089 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003090 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003091 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003092 if (prevfd > 0) {
3093 dup2(prevfd, 0);
3094 close(prevfd);
3095 }
3096 if (pip[1] > 1) {
3097 dup2(pip[1], 1);
3098 close(pip[1]);
3099 }
Eric Andersenc470f442003-07-28 09:56:35 +00003100 evaltreenr(lp->n, flags);
3101 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003102 }
3103 if (prevfd >= 0)
3104 close(prevfd);
3105 prevfd = pip[0];
3106 close(pip[1]);
3107 }
Eric Andersencb57d552001-06-28 07:25:16 +00003108 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003109 exitstatus = waitforjob(jp);
3110 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003111 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003112 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003113}
3114
Eric Andersen62483552001-07-10 06:09:16 +00003115
3116
3117/*
3118 * Execute a command inside back quotes. If it's a builtin command, we
3119 * want to save its output in a block obtained from malloc. Otherwise
3120 * we fork off a subprocess and get the output of the command via a pipe.
3121 * Should be called with interrupts off.
3122 */
3123
Eric Andersenc470f442003-07-28 09:56:35 +00003124static void
3125evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003126{
Eric Andersenc470f442003-07-28 09:56:35 +00003127 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003128
Eric Andersen62483552001-07-10 06:09:16 +00003129 result->fd = -1;
3130 result->buf = NULL;
3131 result->nleft = 0;
3132 result->jp = NULL;
3133 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003134 goto out;
3135 }
Eric Andersenc470f442003-07-28 09:56:35 +00003136
3137 saveherefd = herefd;
3138 herefd = -1;
3139
3140 {
3141 int pip[2];
3142 struct job *jp;
3143
3144 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003145 sh_error("Pipe call failed");
Eric Andersenc470f442003-07-28 09:56:35 +00003146 jp = makejob(n, 1);
3147 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3148 FORCEINTON;
3149 close(pip[0]);
3150 if (pip[1] != 1) {
3151 close(1);
3152 copyfd(pip[1], 1);
3153 close(pip[1]);
3154 }
3155 eflag = 0;
3156 evaltreenr(n, EV_EXIT);
3157 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003158 }
Eric Andersenc470f442003-07-28 09:56:35 +00003159 close(pip[1]);
3160 result->fd = pip[0];
3161 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003162 }
Eric Andersenc470f442003-07-28 09:56:35 +00003163 herefd = saveherefd;
3164out:
Eric Andersen62483552001-07-10 06:09:16 +00003165 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003166 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003167}
3168
Eric Andersenc470f442003-07-28 09:56:35 +00003169#ifdef CONFIG_ASH_CMDCMD
3170static inline char **
3171parse_command_args(char **argv, const char **path)
3172{
3173 char *cp, c;
3174
3175 for (;;) {
3176 cp = *++argv;
3177 if (!cp)
3178 return 0;
3179 if (*cp++ != '-')
3180 break;
3181 if (!(c = *cp++))
3182 break;
3183 if (c == '-' && !*cp) {
3184 argv++;
3185 break;
3186 }
3187 do {
3188 switch (c) {
3189 case 'p':
3190 *path = defpath;
3191 break;
3192 default:
3193 /* run 'typecmd' for other options */
3194 return 0;
3195 }
3196 } while ((c = *cp++));
3197 }
3198 return argv;
3199}
3200#endif
3201
Paul Foxc3850c82005-07-20 18:23:39 +00003202static inline int
3203isassignment(const char *p)
3204{
3205 const char *q = endofname(p);
3206 if (p == q)
3207 return 0;
3208 return *q == '=';
3209}
Eric Andersen62483552001-07-10 06:09:16 +00003210
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003211#ifdef CONFIG_ASH_EXPAND_PRMT
3212static const char *expandstr(const char *ps);
3213#else
3214#define expandstr(s) s
3215#endif
3216
Eric Andersen62483552001-07-10 06:09:16 +00003217/*
3218 * Execute a simple command.
3219 */
Eric Andersencb57d552001-06-28 07:25:16 +00003220
Eric Andersenc470f442003-07-28 09:56:35 +00003221static void
3222evalcommand(union node *cmd, int flags)
3223{
3224 struct stackmark smark;
3225 union node *argp;
3226 struct arglist arglist;
3227 struct arglist varlist;
3228 char **argv;
3229 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003230 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003231 struct cmdentry cmdentry;
3232 struct job *jp;
3233 char *lastarg;
3234 const char *path;
3235 int spclbltin;
3236 int cmd_is_exec;
3237 int status;
3238 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003239 struct builtincmd *bcmd;
3240 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003241
3242 /* First expand the arguments. */
3243 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3244 setstackmark(&smark);
3245 back_exitstatus = 0;
3246
3247 cmdentry.cmdtype = CMDBUILTIN;
3248 cmdentry.u.cmd = &bltin;
3249 varlist.lastp = &varlist.list;
3250 *varlist.lastp = NULL;
3251 arglist.lastp = &arglist.list;
3252 *arglist.lastp = NULL;
3253
3254 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003255 if (cmd->ncmd.args)
3256 {
3257 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3258 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3259 }
3260
Eric Andersenc470f442003-07-28 09:56:35 +00003261 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3262 struct strlist **spp;
3263
3264 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003265 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00003266 expandarg(argp, &arglist, EXP_VARTILDE);
3267 else
3268 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3269
Eric Andersenc470f442003-07-28 09:56:35 +00003270 for (sp = *spp; sp; sp = sp->next)
3271 argc++;
3272 }
3273
3274 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3275 for (sp = arglist.list ; sp ; sp = sp->next) {
3276 TRACE(("evalcommand arg: %s\n", sp->text));
3277 *nargv++ = sp->text;
3278 }
3279 *nargv = NULL;
3280
3281 lastarg = NULL;
3282 if (iflag && funcnest == 0 && argc > 0)
3283 lastarg = nargv[-1];
3284
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003285 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003286 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003287 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003288
3289 path = vpath.text;
3290 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3291 struct strlist **spp;
3292 char *p;
3293
3294 spp = varlist.lastp;
3295 expandarg(argp, &varlist, EXP_VARTILDE);
3296
3297 /*
3298 * Modify the command lookup path, if a PATH= assignment
3299 * is present
3300 */
3301 p = (*spp)->text;
3302 if (varequal(p, path))
3303 path = p;
3304 }
3305
3306 /* Print the command if xflag is set. */
3307 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003308 int n;
3309 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003310
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003311 p++;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003312 dprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003313
3314 sp = varlist.list;
3315 for(n = 0; n < 2; n++) {
3316 while (sp) {
3317 dprintf(preverrout_fd, p, sp->text);
3318 sp = sp->next;
3319 if(*p == '%') {
3320 p--;
3321 }
3322 }
3323 sp = arglist.list;
3324 }
Rob Landley53437472006-07-16 08:14:35 +00003325 full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003326 }
3327
3328 cmd_is_exec = 0;
3329 spclbltin = -1;
3330
3331 /* Now locate the command. */
3332 if (argc) {
3333 const char *oldpath;
3334 int cmd_flag = DO_ERR;
3335
3336 path += 5;
3337 oldpath = path;
3338 for (;;) {
3339 find_command(argv[0], &cmdentry, cmd_flag, path);
3340 if (cmdentry.cmdtype == CMDUNKNOWN) {
3341 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003342 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003343 goto bail;
3344 }
3345
3346 /* implement bltin and command here */
3347 if (cmdentry.cmdtype != CMDBUILTIN)
3348 break;
3349 if (spclbltin < 0)
3350 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3351 if (cmdentry.u.cmd == EXECCMD)
3352 cmd_is_exec++;
3353#ifdef CONFIG_ASH_CMDCMD
3354 if (cmdentry.u.cmd == COMMANDCMD) {
3355
3356 path = oldpath;
3357 nargv = parse_command_args(argv, &path);
3358 if (!nargv)
3359 break;
3360 argc -= nargv - argv;
3361 argv = nargv;
3362 cmd_flag |= DO_NOFUNC;
3363 } else
3364#endif
3365 break;
3366 }
3367 }
3368
3369 if (status) {
3370 /* We have a redirection error. */
3371 if (spclbltin > 0)
3372 exraise(EXERROR);
3373bail:
3374 exitstatus = status;
3375 goto out;
3376 }
3377
3378 /* Execute the command. */
3379 switch (cmdentry.cmdtype) {
3380 default:
3381 /* Fork off a child process if necessary. */
3382 if (!(flags & EV_EXIT) || trap[0]) {
3383 INTOFF;
3384 jp = makejob(cmd, 1);
3385 if (forkshell(jp, cmd, FORK_FG) != 0) {
3386 exitstatus = waitforjob(jp);
3387 INTON;
3388 break;
3389 }
3390 FORCEINTON;
3391 }
3392 listsetvar(varlist.list, VEXPORT|VSTACK);
3393 shellexec(argv, path, cmdentry.u.index);
3394 /* NOTREACHED */
3395
3396 case CMDBUILTIN:
3397 cmdenviron = varlist.list;
3398 if (cmdenviron) {
3399 struct strlist *list = cmdenviron;
3400 int i = VNOSET;
3401 if (spclbltin > 0 || argc == 0) {
3402 i = 0;
3403 if (cmd_is_exec && argc > 1)
3404 i = VEXPORT;
3405 }
3406 listsetvar(list, i);
3407 }
3408 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3409 int exit_status;
3410 int i, j;
3411
3412 i = exception;
3413 if (i == EXEXIT)
3414 goto raise;
3415
3416 exit_status = 2;
3417 j = 0;
3418 if (i == EXINT)
3419 j = SIGINT;
3420 if (i == EXSIG)
3421 j = pendingsigs;
3422 if (j)
3423 exit_status = j + 128;
3424 exitstatus = exit_status;
3425
3426 if (i == EXINT || spclbltin > 0) {
3427raise:
3428 longjmp(handler->loc, 1);
3429 }
3430 FORCEINTON;
3431 }
3432 break;
3433
3434 case CMDFUNCTION:
3435 listsetvar(varlist.list, 0);
3436 if (evalfun(cmdentry.u.func, argc, argv, flags))
3437 goto raise;
3438 break;
3439 }
3440
3441out:
3442 popredir(cmd_is_exec);
3443 if (lastarg)
3444 /* dsl: I think this is intended to be used to support
3445 * '_' in 'vi' command mode during line editing...
3446 * However I implemented that within libedit itself.
3447 */
3448 setvar("_", lastarg, 0);
3449 popstackmark(&smark);
3450}
3451
3452static int
3453evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3454 char *volatile savecmdname;
3455 struct jmploc *volatile savehandler;
3456 struct jmploc jmploc;
3457 int i;
3458
3459 savecmdname = commandname;
3460 if ((i = setjmp(jmploc.loc)))
3461 goto cmddone;
3462 savehandler = handler;
3463 handler = &jmploc;
3464 commandname = argv[0];
3465 argptr = argv + 1;
3466 optptr = NULL; /* initialize nextopt */
3467 exitstatus = (*cmd->builtin)(argc, argv);
3468 flushall();
3469cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003470 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00003471 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003472 commandname = savecmdname;
3473 exsig = 0;
3474 handler = savehandler;
3475
3476 return i;
3477}
3478
3479static int
3480evalfun(struct funcnode *func, int argc, char **argv, int flags)
3481{
3482 volatile struct shparam saveparam;
3483 struct localvar *volatile savelocalvars;
3484 struct jmploc *volatile savehandler;
3485 struct jmploc jmploc;
3486 int e;
3487
3488 saveparam = shellparam;
3489 savelocalvars = localvars;
3490 if ((e = setjmp(jmploc.loc))) {
3491 goto funcdone;
3492 }
3493 INTOFF;
3494 savehandler = handler;
3495 handler = &jmploc;
3496 localvars = NULL;
3497 shellparam.malloc = 0;
3498 func->count++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003499 funcnest++;
Eric Andersenc470f442003-07-28 09:56:35 +00003500 INTON;
3501 shellparam.nparam = argc - 1;
3502 shellparam.p = argv + 1;
3503#ifdef CONFIG_ASH_GETOPTS
3504 shellparam.optind = 1;
3505 shellparam.optoff = -1;
3506#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003507 evaltree(&func->n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00003508funcdone:
3509 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003510 funcnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00003511 freefunc(func);
3512 poplocalvars();
3513 localvars = savelocalvars;
3514 freeparam(&shellparam);
3515 shellparam = saveparam;
3516 handler = savehandler;
3517 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003518 evalskip &= ~SKIPFUNC;
Eric Andersenc470f442003-07-28 09:56:35 +00003519 return e;
3520}
3521
3522
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003523static inline int
3524goodname(const char *p)
3525{
3526 return !*endofname(p);
3527}
3528
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003529/*
3530 * Search for a command. This is called before we fork so that the
3531 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003532 * the child. The check for "goodname" is an overly conservative
3533 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003534 */
3535
Eric Andersenc470f442003-07-28 09:56:35 +00003536static void
3537prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003538{
3539 struct cmdentry entry;
3540
3541 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003542 if (goodname(n->ncmd.args->narg.text))
3543 find_command(n->ncmd.args->narg.text, &entry, 0,
3544 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003545}
3546
Eric Andersencb57d552001-06-28 07:25:16 +00003547
Eric Andersenc470f442003-07-28 09:56:35 +00003548
Eric Andersencb57d552001-06-28 07:25:16 +00003549/*
3550 * Builtin commands. Builtin commands whose functions are closely
3551 * tied to evaluation are implemented here.
3552 */
3553
3554/*
Eric Andersenc470f442003-07-28 09:56:35 +00003555 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003556 */
3557
Eric Andersenc470f442003-07-28 09:56:35 +00003558static int
3559bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003560{
3561 /*
3562 * Preserve exitstatus of a previous possible redirection
3563 * as POSIX mandates
3564 */
Eric Andersenc470f442003-07-28 09:56:35 +00003565 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003566}
3567
3568
3569/*
3570 * Handle break and continue commands. Break, continue, and return are
3571 * all handled by setting the evalskip flag. The evaluation routines
3572 * above all check this flag, and if it is set they start skipping
3573 * commands rather than executing them. The variable skipcount is
3574 * the number of loops to break/continue, or the number of function
3575 * levels to return. (The latter is always 1.) It should probably
3576 * be an error to break out of more loops than exist, but it isn't
3577 * in the standard shell so we don't make it one here.
3578 */
3579
Eric Andersenc470f442003-07-28 09:56:35 +00003580static int
3581breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003582{
3583 int n = argc > 1 ? number(argv[1]) : 1;
3584
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003585 if (n <= 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003586 sh_error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003587 if (n > loopnest)
3588 n = loopnest;
3589 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003590 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003591 skipcount = n;
3592 }
3593 return 0;
3594}
3595
3596
3597/*
3598 * The return command.
3599 */
3600
Eric Andersenc470f442003-07-28 09:56:35 +00003601static int
3602returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003603{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003604 /*
3605 * If called outside a function, do what ksh does;
3606 * skip the rest of the file.
3607 */
3608 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
3609 return argv[1] ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003610}
3611
3612
Eric Andersenc470f442003-07-28 09:56:35 +00003613static int
3614falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003615{
3616 return 1;
3617}
3618
Eric Andersenc470f442003-07-28 09:56:35 +00003619
3620static int
3621truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003622{
3623 return 0;
3624}
Eric Andersen2870d962001-07-02 17:27:21 +00003625
Eric Andersencb57d552001-06-28 07:25:16 +00003626
Eric Andersenc470f442003-07-28 09:56:35 +00003627static int
3628execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003629{
3630 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003631 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003632 mflag = 0;
3633 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003634 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003635 }
3636 return 0;
3637}
3638
Eric Andersenc470f442003-07-28 09:56:35 +00003639
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003640/* exec.c */
Eric Andersenc470f442003-07-28 09:56:35 +00003641
3642/*
3643 * When commands are first encountered, they are entered in a hash table.
3644 * This ensures that a full path search will not have to be done for them
3645 * on each invocation.
3646 *
3647 * We should investigate converting to a linear search, even though that
3648 * would make the command name "hash" a misnomer.
3649 */
3650
3651#define CMDTABLESIZE 31 /* should be prime */
3652#define ARB 1 /* actual size determined at run time */
3653
3654
3655
3656struct tblentry {
3657 struct tblentry *next; /* next entry in hash chain */
3658 union param param; /* definition of builtin function */
3659 short cmdtype; /* index identifying command */
3660 char rehash; /* if set, cd done since entry created */
3661 char cmdname[ARB]; /* name of command */
3662};
3663
3664
3665static struct tblentry *cmdtable[CMDTABLESIZE];
3666static int builtinloc = -1; /* index in path of %builtin, or -1 */
3667
3668
3669static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003670static void clearcmdentry(int);
3671static struct tblentry *cmdlookup(const char *, int);
3672static void delete_cmd_entry(void);
3673
Eric Andersencb57d552001-06-28 07:25:16 +00003674
3675/*
3676 * Exec a program. Never returns. If you change this routine, you may
3677 * have to change the find_command routine as well.
3678 */
3679
Eric Andersenc470f442003-07-28 09:56:35 +00003680static void
3681shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003682{
3683 char *cmdname;
3684 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003685 char **envp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003686 int exerrno;
Eric Andersencb57d552001-06-28 07:25:16 +00003687
Eric Andersenc470f442003-07-28 09:56:35 +00003688 clearredir(1);
3689 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003690 if (strchr(argv[0], '/') != NULL
3691#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3692 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003693#endif
3694 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003695 tryexec(argv[0], argv, envp);
3696 e = errno;
3697 } else {
3698 e = ENOENT;
3699 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3700 if (--idx < 0 && pathopt == NULL) {
3701 tryexec(cmdname, argv, envp);
3702 if (errno != ENOENT && errno != ENOTDIR)
3703 e = errno;
3704 }
3705 stunalloc(cmdname);
3706 }
3707 }
3708
3709 /* Map to POSIX errors */
3710 switch (e) {
3711 case EACCES:
3712 exerrno = 126;
3713 break;
3714 case ENOENT:
3715 exerrno = 127;
3716 break;
3717 default:
3718 exerrno = 2;
3719 break;
3720 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003721 exitstatus = exerrno;
Eric Andersenc470f442003-07-28 09:56:35 +00003722 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3723 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003724 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3725 /* NOTREACHED */
3726}
3727
Eric Andersen2870d962001-07-02 17:27:21 +00003728
Eric Andersenc470f442003-07-28 09:56:35 +00003729static void
3730tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003731{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003732 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003733#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003734 if(find_applet_by_name(cmd) != NULL) {
3735 /* re-exec ourselves with the new arguments */
Rob Landleya34b48a2006-06-14 01:27:01 +00003736 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp);
Rob Landley0fcd9432005-05-07 08:27:34 +00003737 /* If they called chroot or otherwise made the binary no longer
3738 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003739 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003740#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003741
3742repeat:
3743#ifdef SYSV
3744 do {
3745 execve(cmd, argv, envp);
3746 } while (errno == EINTR);
3747#else
Eric Andersencb57d552001-06-28 07:25:16 +00003748 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003749#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003750 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003751 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003752 } else if (errno == ENOEXEC) {
3753 char **ap;
3754 char **new;
3755
Eric Andersenc470f442003-07-28 09:56:35 +00003756 for (ap = argv; *ap; ap++)
3757 ;
3758 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003759 ap[1] = cmd;
3760 *ap = cmd = (char *)DEFAULT_SHELL;
3761 ap += 2;
3762 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003763 while ((*ap++ = *argv++))
3764 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003765 argv = new;
3766 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003767 }
Eric Andersencb57d552001-06-28 07:25:16 +00003768}
3769
Eric Andersenc470f442003-07-28 09:56:35 +00003770
Eric Andersencb57d552001-06-28 07:25:16 +00003771
3772/*
3773 * Do a path search. The variable path (passed by reference) should be
3774 * set to the start of the path before the first call; padvance will update
3775 * this value as it proceeds. Successive calls to padvance will return
3776 * the possible path expansions in sequence. If an option (indicated by
3777 * a percent sign) appears in the path entry then the global variable
3778 * pathopt will be set to point to it; otherwise pathopt will be set to
3779 * NULL.
3780 */
3781
Eric Andersenc470f442003-07-28 09:56:35 +00003782static char *
3783padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003784{
Eric Andersencb57d552001-06-28 07:25:16 +00003785 const char *p;
3786 char *q;
3787 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003788 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003789
3790 if (*path == NULL)
3791 return NULL;
3792 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003793 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3794 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003795 while (stackblocksize() < len)
3796 growstackblock();
3797 q = stackblock();
3798 if (p != start) {
3799 memcpy(q, start, p - start);
3800 q += p - start;
3801 *q++ = '/';
3802 }
3803 strcpy(q, name);
3804 pathopt = NULL;
3805 if (*p == '%') {
3806 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003807 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003808 }
3809 if (*p == ':')
3810 *path = p + 1;
3811 else
3812 *path = NULL;
3813 return stalloc(len);
3814}
3815
3816
Eric Andersencb57d552001-06-28 07:25:16 +00003817/*** Command hashing code ***/
3818
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003819static void
3820printentry(struct tblentry *cmdp)
3821{
3822 int idx;
3823 const char *path;
3824 char *name;
3825
3826 idx = cmdp->param.index;
3827 path = pathval();
3828 do {
3829 name = padvance(&path, cmdp->cmdname);
3830 stunalloc(name);
3831 } while (--idx >= 0);
3832 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3833}
3834
Eric Andersenc470f442003-07-28 09:56:35 +00003835
3836static int
3837hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003838{
3839 struct tblentry **pp;
3840 struct tblentry *cmdp;
3841 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003842 struct cmdentry entry;
3843 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003844
Eric Andersenc470f442003-07-28 09:56:35 +00003845 while ((c = nextopt("r")) != '\0') {
3846 clearcmdentry(0);
3847 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003848 }
3849 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003850 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3851 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3852 if (cmdp->cmdtype == CMDNORMAL)
3853 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003854 }
3855 }
3856 return 0;
3857 }
3858 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003859 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003860 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003861 && (cmdp->cmdtype == CMDNORMAL
3862 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003863 delete_cmd_entry();
3864 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003865 if (entry.cmdtype == CMDUNKNOWN)
3866 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003867 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003868 }
3869 return c;
3870}
3871
Eric Andersenc470f442003-07-28 09:56:35 +00003872
Eric Andersencb57d552001-06-28 07:25:16 +00003873/*
3874 * Resolve a command name. If you change this routine, you may have to
3875 * change the shellexec routine as well.
3876 */
3877
3878static void
Eric Andersenc470f442003-07-28 09:56:35 +00003879find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003880{
3881 struct tblentry *cmdp;
3882 int idx;
3883 int prev;
3884 char *fullname;
3885 struct stat statb;
3886 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003887 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003888 struct builtincmd *bcmd;
3889
Eric Andersenc470f442003-07-28 09:56:35 +00003890 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003891 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003892 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003893 if (act & DO_ABS) {
3894 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003895#ifdef SYSV
3896 if (errno == EINTR)
3897 continue;
3898#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003899 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003900 return;
3901 }
Eric Andersencb57d552001-06-28 07:25:16 +00003902 }
3903 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003904 return;
3905 }
3906
Eric Andersenbf8bf102002-09-17 08:41:08 +00003907#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3908 if (find_applet_by_name(name)) {
3909 entry->cmdtype = CMDNORMAL;
3910 entry->u.index = -1;
3911 return;
3912 }
3913#endif
3914
Eric Andersenc470f442003-07-28 09:56:35 +00003915 updatetbl = (path == pathval());
3916 if (!updatetbl) {
3917 act |= DO_ALTPATH;
3918 if (strstr(path, "%builtin") != NULL)
3919 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003920 }
3921
Eric Andersenc470f442003-07-28 09:56:35 +00003922 /* If name is in the table, check answer will be ok */
3923 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3924 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003925
Eric Andersenc470f442003-07-28 09:56:35 +00003926 switch (cmdp->cmdtype) {
3927 default:
3928#if DEBUG
3929 abort();
3930#endif
3931 case CMDNORMAL:
3932 bit = DO_ALTPATH;
3933 break;
3934 case CMDFUNCTION:
3935 bit = DO_NOFUNC;
3936 break;
3937 case CMDBUILTIN:
3938 bit = DO_ALTBLTIN;
3939 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003940 }
Eric Andersenc470f442003-07-28 09:56:35 +00003941 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003942 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003943 cmdp = NULL;
3944 } else if (cmdp->rehash == 0)
3945 /* if not invalidated by cd, we're done */
3946 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003947 }
3948
3949 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003950 bcmd = find_builtin(name);
3951 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3952 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3953 )))
3954 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003955
3956 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003957 prev = -1; /* where to start */
3958 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003959 if (cmdp->cmdtype == CMDBUILTIN)
3960 prev = builtinloc;
3961 else
3962 prev = cmdp->param.index;
3963 }
3964
3965 e = ENOENT;
3966 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003967loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003968 while ((fullname = padvance(&path, name)) != NULL) {
3969 stunalloc(fullname);
3970 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003971 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003972 if (prefix(pathopt, "builtin")) {
3973 if (bcmd)
3974 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003975 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003976 } else if (!(act & DO_NOFUNC) &&
3977 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003978 /* handled below */
3979 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003980 /* ignore unimplemented options */
3981 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003982 }
3983 }
3984 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003985 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003986 if (idx < prev)
3987 continue;
3988 TRACE(("searchexec \"%s\": no change\n", name));
3989 goto success;
3990 }
3991 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003992#ifdef SYSV
3993 if (errno == EINTR)
3994 continue;
3995#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003996 if (errno != ENOENT && errno != ENOTDIR)
3997 e = errno;
3998 goto loop;
3999 }
Eric Andersenc470f442003-07-28 09:56:35 +00004000 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004001 if (!S_ISREG(statb.st_mode))
4002 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004003 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004004 stalloc(strlen(fullname) + 1);
4005 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004006 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4007 cmdp->cmdtype != CMDFUNCTION)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004008 sh_error("%s not defined in %s", name, fullname);
Eric Andersencb57d552001-06-28 07:25:16 +00004009 stunalloc(fullname);
4010 goto success;
4011 }
Eric Andersencb57d552001-06-28 07:25:16 +00004012 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004013 if (!updatetbl) {
4014 entry->cmdtype = CMDNORMAL;
4015 entry->u.index = idx;
4016 return;
4017 }
4018 INTOFF;
4019 cmdp = cmdlookup(name, 1);
4020 cmdp->cmdtype = CMDNORMAL;
4021 cmdp->param.index = idx;
4022 INTON;
4023 goto success;
4024 }
4025
4026 /* We failed. If there was an entry for this command, delete it */
4027 if (cmdp && updatetbl)
4028 delete_cmd_entry();
4029 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004030 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004031 entry->cmdtype = CMDUNKNOWN;
4032 return;
4033
Eric Andersenc470f442003-07-28 09:56:35 +00004034builtin_success:
4035 if (!updatetbl) {
4036 entry->cmdtype = CMDBUILTIN;
4037 entry->u.cmd = bcmd;
4038 return;
4039 }
4040 INTOFF;
4041 cmdp = cmdlookup(name, 1);
4042 cmdp->cmdtype = CMDBUILTIN;
4043 cmdp->param.cmd = bcmd;
4044 INTON;
4045success:
Eric Andersencb57d552001-06-28 07:25:16 +00004046 cmdp->rehash = 0;
4047 entry->cmdtype = cmdp->cmdtype;
4048 entry->u = cmdp->param;
4049}
4050
4051
Eric Andersenc470f442003-07-28 09:56:35 +00004052/*
4053 * Wrapper around strcmp for qsort/bsearch/...
4054 */
4055static int pstrcmp(const void *a, const void *b)
4056{
4057 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4058}
Eric Andersencb57d552001-06-28 07:25:16 +00004059
4060/*
4061 * Search the table of builtin commands.
4062 */
4063
Eric Andersenc470f442003-07-28 09:56:35 +00004064static struct builtincmd *
4065find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004066{
4067 struct builtincmd *bp;
4068
Eric Andersenc470f442003-07-28 09:56:35 +00004069 bp = bsearch(
4070 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4071 pstrcmp
4072 );
Eric Andersencb57d552001-06-28 07:25:16 +00004073 return bp;
4074}
4075
4076
Eric Andersenc470f442003-07-28 09:56:35 +00004077
Eric Andersencb57d552001-06-28 07:25:16 +00004078/*
4079 * Called when a cd is done. Marks all commands so the next time they
4080 * are executed they will be rehashed.
4081 */
4082
Eric Andersenc470f442003-07-28 09:56:35 +00004083static void
4084hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004085{
Eric Andersencb57d552001-06-28 07:25:16 +00004086 struct tblentry **pp;
4087 struct tblentry *cmdp;
4088
Eric Andersenc470f442003-07-28 09:56:35 +00004089 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4090 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4091 if (cmdp->cmdtype == CMDNORMAL || (
4092 cmdp->cmdtype == CMDBUILTIN &&
4093 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4094 builtinloc > 0
4095 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004096 cmdp->rehash = 1;
4097 }
4098 }
4099}
4100
4101
4102
4103/*
Eric Andersenc470f442003-07-28 09:56:35 +00004104 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004105 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004106 * pathval() still returns the old value at this point.
4107 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004108 */
4109
Eric Andersenc470f442003-07-28 09:56:35 +00004110static void
4111changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004112{
Eric Andersenc470f442003-07-28 09:56:35 +00004113 const char *old, *new;
4114 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004115 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004116 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004117
Eric Andersenc470f442003-07-28 09:56:35 +00004118 old = pathval();
4119 new = newval;
4120 firstchange = 9999; /* assume no change */
4121 idx = 0;
4122 idx_bltin = -1;
4123 for (;;) {
4124 if (*old != *new) {
4125 firstchange = idx;
4126 if ((*old == '\0' && *new == ':')
4127 || (*old == ':' && *new == '\0'))
4128 firstchange++;
4129 old = new; /* ignore subsequent differences */
4130 }
4131 if (*new == '\0')
4132 break;
4133 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4134 idx_bltin = idx;
4135 if (*new == ':') {
4136 idx++;
4137 }
4138 new++, old++;
4139 }
4140 if (builtinloc < 0 && idx_bltin >= 0)
4141 builtinloc = idx_bltin; /* zap builtins */
4142 if (builtinloc >= 0 && idx_bltin < 0)
4143 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004144 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004145 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004146}
4147
4148
4149/*
4150 * Clear out command entries. The argument specifies the first entry in
4151 * PATH which has changed.
4152 */
4153
Eric Andersenc470f442003-07-28 09:56:35 +00004154static void
4155clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004156{
4157 struct tblentry **tblp;
4158 struct tblentry **pp;
4159 struct tblentry *cmdp;
4160
4161 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004162 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004163 pp = tblp;
4164 while ((cmdp = *pp) != NULL) {
4165 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004166 cmdp->param.index >= firstchange)
4167 || (cmdp->cmdtype == CMDBUILTIN &&
4168 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004169 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004170 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004171 } else {
4172 pp = &cmdp->next;
4173 }
4174 }
4175 }
4176 INTON;
4177}
4178
4179
Eric Andersenc470f442003-07-28 09:56:35 +00004180
Eric Andersencb57d552001-06-28 07:25:16 +00004181/*
Eric Andersencb57d552001-06-28 07:25:16 +00004182 * Locate a command in the command hash table. If "add" is nonzero,
4183 * add the command to the table if it is not already present. The
4184 * variable "lastcmdentry" is set to point to the address of the link
4185 * pointing to the entry, so that delete_cmd_entry can delete the
4186 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004187 *
4188 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004189 */
4190
Eric Andersen2870d962001-07-02 17:27:21 +00004191static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004192
Eric Andersenc470f442003-07-28 09:56:35 +00004193
4194static struct tblentry *
4195cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004196{
Eric Andersenc470f442003-07-28 09:56:35 +00004197 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004198 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004199 struct tblentry *cmdp;
4200 struct tblentry **pp;
4201
4202 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004203 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004204 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004205 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004206 hashval &= 0x7FFF;
4207 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004208 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004209 if (equal(cmdp->cmdname, name))
4210 break;
4211 pp = &cmdp->next;
4212 }
4213 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004214 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4215 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004216 cmdp->next = NULL;
4217 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004218 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004219 }
4220 lastcmdentry = pp;
4221 return cmdp;
4222}
4223
4224/*
4225 * Delete the command entry returned on the last lookup.
4226 */
4227
Eric Andersenc470f442003-07-28 09:56:35 +00004228static void
4229delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004230{
Eric Andersencb57d552001-06-28 07:25:16 +00004231 struct tblentry *cmdp;
4232
4233 INTOFF;
4234 cmdp = *lastcmdentry;
4235 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004236 if (cmdp->cmdtype == CMDFUNCTION)
4237 freefunc(cmdp->param.func);
4238 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004239 INTON;
4240}
4241
4242
Eric Andersenc470f442003-07-28 09:56:35 +00004243/*
4244 * Add a new command entry, replacing any existing command entry for
4245 * the same name - except special builtins.
4246 */
Eric Andersencb57d552001-06-28 07:25:16 +00004247
Eric Andersenc470f442003-07-28 09:56:35 +00004248static inline void
4249addcmdentry(char *name, struct cmdentry *entry)
4250{
4251 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004252
Eric Andersenc470f442003-07-28 09:56:35 +00004253 cmdp = cmdlookup(name, 1);
4254 if (cmdp->cmdtype == CMDFUNCTION) {
4255 freefunc(cmdp->param.func);
4256 }
4257 cmdp->cmdtype = entry->cmdtype;
4258 cmdp->param = entry->u;
4259 cmdp->rehash = 0;
4260}
Eric Andersencb57d552001-06-28 07:25:16 +00004261
Eric Andersenc470f442003-07-28 09:56:35 +00004262/*
4263 * Make a copy of a parse tree.
4264 */
Eric Andersencb57d552001-06-28 07:25:16 +00004265
Eric Andersenc470f442003-07-28 09:56:35 +00004266static inline struct funcnode *
4267copyfunc(union node *n)
4268{
4269 struct funcnode *f;
4270 size_t blocksize;
4271
4272 funcblocksize = offsetof(struct funcnode, n);
4273 funcstringsize = 0;
4274 calcsize(n);
4275 blocksize = funcblocksize;
4276 f = ckmalloc(blocksize + funcstringsize);
4277 funcblock = (char *) f + offsetof(struct funcnode, n);
4278 funcstring = (char *) f + blocksize;
4279 copynode(n);
4280 f->count = 0;
4281 return f;
4282}
4283
4284/*
4285 * Define a shell function.
4286 */
4287
4288static void
4289defun(char *name, union node *func)
4290{
4291 struct cmdentry entry;
4292
4293 INTOFF;
4294 entry.cmdtype = CMDFUNCTION;
4295 entry.u.func = copyfunc(func);
4296 addcmdentry(name, &entry);
4297 INTON;
4298}
Eric Andersencb57d552001-06-28 07:25:16 +00004299
4300
4301/*
4302 * Delete a function if it exists.
4303 */
4304
Eric Andersenc470f442003-07-28 09:56:35 +00004305static void
4306unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004307{
Eric Andersencb57d552001-06-28 07:25:16 +00004308 struct tblentry *cmdp;
4309
Eric Andersenc470f442003-07-28 09:56:35 +00004310 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4311 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004312 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004313}
4314
Eric Andersen2870d962001-07-02 17:27:21 +00004315/*
Eric Andersencb57d552001-06-28 07:25:16 +00004316 * Locate and print what a word is...
4317 */
4318
Eric Andersenc470f442003-07-28 09:56:35 +00004319
4320#ifdef CONFIG_ASH_CMDCMD
4321static int
4322describe_command(char *command, int describe_command_verbose)
4323#else
4324#define describe_command_verbose 1
4325static int
4326describe_command(char *command)
4327#endif
4328{
4329 struct cmdentry entry;
4330 struct tblentry *cmdp;
4331#ifdef CONFIG_ASH_ALIAS
4332 const struct alias *ap;
4333#endif
4334 const char *path = pathval();
4335
4336 if (describe_command_verbose) {
4337 out1str(command);
4338 }
4339
4340 /* First look at the keywords */
4341 if (findkwd(command)) {
4342 out1str(describe_command_verbose ? " is a shell keyword" : command);
4343 goto out;
4344 }
4345
4346#ifdef CONFIG_ASH_ALIAS
4347 /* Then look at the aliases */
4348 if ((ap = lookupalias(command, 0)) != NULL) {
4349 if (describe_command_verbose) {
4350 out1fmt(" is an alias for %s", ap->val);
4351 } else {
4352 out1str("alias ");
4353 printalias(ap);
4354 return 0;
4355 }
4356 goto out;
4357 }
4358#endif
4359 /* Then check if it is a tracked alias */
4360 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4361 entry.cmdtype = cmdp->cmdtype;
4362 entry.u = cmdp->param;
4363 } else {
4364 /* Finally use brute force */
4365 find_command(command, &entry, DO_ABS, path);
4366 }
4367
4368 switch (entry.cmdtype) {
4369 case CMDNORMAL: {
4370 int j = entry.u.index;
4371 char *p;
4372 if (j == -1) {
4373 p = command;
4374 } else {
4375 do {
4376 p = padvance(&path, command);
4377 stunalloc(p);
4378 } while (--j >= 0);
4379 }
4380 if (describe_command_verbose) {
4381 out1fmt(" is%s %s",
4382 (cmdp ? " a tracked alias for" : nullstr), p
4383 );
4384 } else {
4385 out1str(p);
4386 }
4387 break;
4388 }
4389
4390 case CMDFUNCTION:
4391 if (describe_command_verbose) {
4392 out1str(" is a shell function");
4393 } else {
4394 out1str(command);
4395 }
4396 break;
4397
4398 case CMDBUILTIN:
4399 if (describe_command_verbose) {
4400 out1fmt(" is a %sshell builtin",
4401 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4402 "special " : nullstr
4403 );
4404 } else {
4405 out1str(command);
4406 }
4407 break;
4408
4409 default:
4410 if (describe_command_verbose) {
4411 out1str(": not found\n");
4412 }
4413 return 127;
4414 }
4415
4416out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004417 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004418 return 0;
4419}
4420
4421static int
4422typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004423{
4424 int i;
4425 int err = 0;
4426
4427 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004428#ifdef CONFIG_ASH_CMDCMD
4429 err |= describe_command(argv[i], 1);
4430#else
4431 err |= describe_command(argv[i]);
4432#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004433 }
4434 return err;
4435}
4436
Eric Andersend35c5df2002-01-09 15:37:36 +00004437#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004438static int
4439commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004440{
4441 int c;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004442 enum {
4443 VERIFY_BRIEF = 1,
4444 VERIFY_VERBOSE = 2,
4445 } verify = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004446
4447 while ((c = nextopt("pvV")) != '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004448 if (c == 'V')
4449 verify |= VERIFY_VERBOSE;
4450 else if (c == 'v')
4451 verify |= VERIFY_BRIEF;
Eric Andersenc470f442003-07-28 09:56:35 +00004452#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004453 else if (c != 'p')
4454 abort();
Eric Andersenc470f442003-07-28 09:56:35 +00004455#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004456 if (verify)
4457 return describe_command(*argptr, verify - VERIFY_BRIEF);
Eric Andersencb57d552001-06-28 07:25:16 +00004458
4459 return 0;
4460}
Eric Andersen2870d962001-07-02 17:27:21 +00004461#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004462
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004463/* expand.c */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004464
Eric Andersencb57d552001-06-28 07:25:16 +00004465/*
4466 * Routines to expand arguments to commands. We have to deal with
4467 * backquotes, shell variables, and file metacharacters.
4468 */
Eric Andersenc470f442003-07-28 09:56:35 +00004469
Eric Andersencb57d552001-06-28 07:25:16 +00004470/*
4471 * _rmescape() flags
4472 */
Eric Andersenc470f442003-07-28 09:56:35 +00004473#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4474#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4475#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4476#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4477#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004478
4479/*
4480 * Structure specifying which parts of the string should be searched
4481 * for IFS characters.
4482 */
4483
4484struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004485 struct ifsregion *next; /* next region in list */
4486 int begoff; /* offset of start of region */
4487 int endoff; /* offset of end of region */
4488 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004489};
4490
Eric Andersenc470f442003-07-28 09:56:35 +00004491/* output of current string */
4492static char *expdest;
4493/* list of back quote expressions */
4494static struct nodelist *argbackq;
4495/* first struct in list of ifs regions */
4496static struct ifsregion ifsfirst;
4497/* last struct in list */
4498static struct ifsregion *ifslastp;
4499/* holds expanded arg list */
4500static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004501
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004502static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004503static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004504static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004505static const char *subevalvar(char *, char *, int, int, int, int, int);
4506static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004507static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004508static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004509static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004510static void recordregion(int, int, int);
4511static void removerecordregions(int);
4512static void ifsbreakup(char *, struct arglist *);
4513static void ifsfree(void);
4514static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004515static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004516
Eric Andersened9ecf72004-06-22 08:29:45 +00004517static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004518static size_t esclen(const char *, const char *);
4519static char *scanleft(char *, char *, char *, char *, int, int);
4520static char *scanright(char *, char *, char *, char *, int, int);
4521static void varunset(const char *, const char *, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00004522 ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004523
Eric Andersenc470f442003-07-28 09:56:35 +00004524
4525#define pmatch(a, b) !fnmatch((a), (b), 0)
4526/*
Eric Andersen90898442003-08-06 11:20:52 +00004527 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004528 *
4529 * Returns an stalloced string.
4530 */
4531
4532static inline char *
4533preglob(const char *pattern, int quoted, int flag) {
4534 flag |= RMESCAPE_GLOB;
4535 if (quoted) {
4536 flag |= RMESCAPE_QUOTED;
4537 }
4538 return _rmescapes((char *)pattern, flag);
4539}
4540
4541
4542static size_t
4543esclen(const char *start, const char *p) {
4544 size_t esc = 0;
4545
4546 while (p > start && *--p == CTLESC) {
4547 esc++;
4548 }
4549 return esc;
4550}
4551
Eric Andersencb57d552001-06-28 07:25:16 +00004552
4553/*
4554 * Expand shell variables and backquotes inside a here document.
4555 */
4556
Eric Andersenc470f442003-07-28 09:56:35 +00004557static inline void
4558expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004559{
Eric Andersencb57d552001-06-28 07:25:16 +00004560 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004561 expandarg(arg, (struct arglist *)NULL, 0);
Rob Landley53437472006-07-16 08:14:35 +00004562 full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004563}
4564
4565
4566/*
4567 * Perform variable substitution and command substitution on an argument,
4568 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4569 * perform splitting and file name expansion. When arglist is NULL, perform
4570 * here document expansion.
4571 */
4572
Eric Andersenc470f442003-07-28 09:56:35 +00004573void
4574expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004575{
4576 struct strlist *sp;
4577 char *p;
4578
4579 argbackq = arg->narg.backquote;
4580 STARTSTACKSTR(expdest);
4581 ifsfirst.next = NULL;
4582 ifslastp = NULL;
4583 argstr(arg->narg.text, flag);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004584 p = _STPUTC('\0', expdest);
4585 expdest = p - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004586 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004587 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004588 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004589 p = grabstackstr(p);
Eric Andersencb57d552001-06-28 07:25:16 +00004590 exparg.lastp = &exparg.list;
4591 /*
4592 * TODO - EXP_REDIR
4593 */
4594 if (flag & EXP_FULL) {
4595 ifsbreakup(p, &exparg);
4596 *exparg.lastp = NULL;
4597 exparg.lastp = &exparg.list;
4598 expandmeta(exparg.list, flag);
4599 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004600 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004601 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004602 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004603 sp->text = p;
4604 *exparg.lastp = sp;
4605 exparg.lastp = &sp->next;
4606 }
Eric Andersenc470f442003-07-28 09:56:35 +00004607 if (ifsfirst.next)
4608 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004609 *exparg.lastp = NULL;
4610 if (exparg.list) {
4611 *arglist->lastp = exparg.list;
4612 arglist->lastp = exparg.lastp;
4613 }
4614}
4615
4616
Eric Andersenc470f442003-07-28 09:56:35 +00004617/*
4618 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4619 * characters to allow for further processing. Otherwise treat
4620 * $@ like $* since no splitting will be performed.
4621 */
4622
4623static void
4624argstr(char *p, int flag)
4625{
4626 static const char spclchars[] = {
4627 '=',
4628 ':',
4629 CTLQUOTEMARK,
4630 CTLENDVAR,
4631 CTLESC,
4632 CTLVAR,
4633 CTLBACKQ,
4634 CTLBACKQ | CTLQUOTE,
4635#ifdef CONFIG_ASH_MATH_SUPPORT
4636 CTLENDARI,
4637#endif
4638 0
4639 };
4640 const char *reject = spclchars;
4641 int c;
4642 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4643 int breakall = flag & EXP_WORD;
4644 int inquotes;
4645 size_t length;
4646 int startloc;
4647
4648 if (!(flag & EXP_VARTILDE)) {
4649 reject += 2;
4650 } else if (flag & EXP_VARTILDE2) {
4651 reject++;
4652 }
4653 inquotes = 0;
4654 length = 0;
4655 if (flag & EXP_TILDE) {
4656 char *q;
4657
4658 flag &= ~EXP_TILDE;
4659tilde:
4660 q = p;
4661 if (*q == CTLESC && (flag & EXP_QWORD))
4662 q++;
4663 if (*q == '~')
4664 p = exptilde(p, q, flag);
4665 }
4666start:
4667 startloc = expdest - (char *)stackblock();
4668 for (;;) {
4669 length += strcspn(p + length, reject);
4670 c = p[length];
4671 if (c && (!(c & 0x80)
4672#ifdef CONFIG_ASH_MATH_SUPPORT
4673 || c == CTLENDARI
4674#endif
4675 )) {
4676 /* c == '=' || c == ':' || c == CTLENDARI */
4677 length++;
4678 }
4679 if (length > 0) {
4680 int newloc;
4681 expdest = stnputs(p, length, expdest);
4682 newloc = expdest - (char *)stackblock();
4683 if (breakall && !inquotes && newloc > startloc) {
4684 recordregion(startloc, newloc, 0);
4685 }
4686 startloc = newloc;
4687 }
4688 p += length + 1;
4689 length = 0;
4690
4691 switch (c) {
4692 case '\0':
4693 goto breakloop;
4694 case '=':
4695 if (flag & EXP_VARTILDE2) {
4696 p--;
4697 continue;
4698 }
4699 flag |= EXP_VARTILDE2;
4700 reject++;
4701 /* fall through */
4702 case ':':
4703 /*
4704 * sort of a hack - expand tildes in variable
4705 * assignments (after the first '=' and after ':'s).
4706 */
4707 if (*--p == '~') {
4708 goto tilde;
4709 }
4710 continue;
4711 }
4712
4713 switch (c) {
4714 case CTLENDVAR: /* ??? */
4715 goto breakloop;
4716 case CTLQUOTEMARK:
4717 /* "$@" syntax adherence hack */
4718 if (
4719 !inquotes &&
4720 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4721 (p[4] == CTLQUOTEMARK || (
4722 p[4] == CTLENDVAR &&
4723 p[5] == CTLQUOTEMARK
4724 ))
4725 ) {
4726 p = evalvar(p + 1, flag) + 1;
4727 goto start;
4728 }
4729 inquotes = !inquotes;
4730addquote:
4731 if (quotes) {
4732 p--;
4733 length++;
4734 startloc++;
4735 }
4736 break;
4737 case CTLESC:
4738 startloc++;
4739 length++;
4740 goto addquote;
4741 case CTLVAR:
4742 p = evalvar(p, flag);
4743 goto start;
4744 case CTLBACKQ:
4745 c = 0;
4746 case CTLBACKQ|CTLQUOTE:
4747 expbackq(argbackq->n, c, quotes);
4748 argbackq = argbackq->next;
4749 goto start;
4750#ifdef CONFIG_ASH_MATH_SUPPORT
4751 case CTLENDARI:
4752 p--;
4753 expari(quotes);
4754 goto start;
4755#endif
4756 }
4757 }
4758breakloop:
4759 ;
4760}
4761
4762static char *
4763exptilde(char *startp, char *p, int flag)
4764{
4765 char c;
4766 char *name;
4767 struct passwd *pw;
4768 const char *home;
4769 int quotes = flag & (EXP_FULL | EXP_CASE);
4770 int startloc;
4771
4772 name = p + 1;
4773
4774 while ((c = *++p) != '\0') {
4775 switch(c) {
4776 case CTLESC:
4777 return (startp);
4778 case CTLQUOTEMARK:
4779 return (startp);
4780 case ':':
4781 if (flag & EXP_VARTILDE)
4782 goto done;
4783 break;
4784 case '/':
4785 case CTLENDVAR:
4786 goto done;
4787 }
4788 }
4789done:
4790 *p = '\0';
4791 if (*name == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004792 home = lookupvar(homestr);
Eric Andersenc470f442003-07-28 09:56:35 +00004793 } else {
4794 if ((pw = getpwnam(name)) == NULL)
4795 goto lose;
4796 home = pw->pw_dir;
4797 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004798 if (!home || !*home)
Eric Andersenc470f442003-07-28 09:56:35 +00004799 goto lose;
4800 *p = c;
4801 startloc = expdest - (char *)stackblock();
4802 strtodest(home, SQSYNTAX, quotes);
4803 recordregion(startloc, expdest - (char *)stackblock(), 0);
4804 return (p);
4805lose:
4806 *p = c;
4807 return (startp);
4808}
4809
4810
4811static void
4812removerecordregions(int endoff)
4813{
4814 if (ifslastp == NULL)
4815 return;
4816
4817 if (ifsfirst.endoff > endoff) {
4818 while (ifsfirst.next != NULL) {
4819 struct ifsregion *ifsp;
4820 INTOFF;
4821 ifsp = ifsfirst.next->next;
4822 ckfree(ifsfirst.next);
4823 ifsfirst.next = ifsp;
4824 INTON;
4825 }
4826 if (ifsfirst.begoff > endoff)
4827 ifslastp = NULL;
4828 else {
4829 ifslastp = &ifsfirst;
4830 ifsfirst.endoff = endoff;
4831 }
4832 return;
4833 }
4834
4835 ifslastp = &ifsfirst;
4836 while (ifslastp->next && ifslastp->next->begoff < endoff)
4837 ifslastp=ifslastp->next;
4838 while (ifslastp->next != NULL) {
4839 struct ifsregion *ifsp;
4840 INTOFF;
4841 ifsp = ifslastp->next->next;
4842 ckfree(ifslastp->next);
4843 ifslastp->next = ifsp;
4844 INTON;
4845 }
4846 if (ifslastp->endoff > endoff)
4847 ifslastp->endoff = endoff;
4848}
4849
4850
4851#ifdef CONFIG_ASH_MATH_SUPPORT
4852/*
4853 * Expand arithmetic expression. Backup to start of expression,
4854 * evaluate, place result in (backed up) result, adjust string position.
4855 */
4856void
4857expari(int quotes)
4858{
4859 char *p, *start;
4860 int begoff;
4861 int flag;
4862 int len;
4863
4864 /* ifsfree(); */
4865
4866 /*
4867 * This routine is slightly over-complicated for
4868 * efficiency. Next we scan backwards looking for the
4869 * start of arithmetic.
4870 */
4871 start = stackblock();
4872 p = expdest - 1;
4873 *p = '\0';
4874 p--;
4875 do {
4876 int esc;
4877
4878 while (*p != CTLARI) {
4879 p--;
4880#ifdef DEBUG
4881 if (p < start) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004882 sh_error("missing CTLARI (shouldn't happen)");
Eric Andersenc470f442003-07-28 09:56:35 +00004883 }
4884#endif
4885 }
4886
4887 esc = esclen(start, p);
4888 if (!(esc % 2)) {
4889 break;
4890 }
4891
4892 p -= esc + 1;
4893 } while (1);
4894
4895 begoff = p - start;
4896
4897 removerecordregions(begoff);
4898
4899 flag = p[1];
4900
4901 expdest = p;
4902
4903 if (quotes)
4904 rmescapes(p + 2);
4905
4906 len = cvtnum(dash_arith(p + 2));
4907
4908 if (flag != '"')
4909 recordregion(begoff, begoff + len, 0);
4910}
4911#endif
4912
4913/*
4914 * Expand stuff in backwards quotes.
4915 */
4916
4917static void
4918expbackq(union node *cmd, int quoted, int quotes)
4919{
4920 struct backcmd in;
4921 int i;
4922 char buf[128];
4923 char *p;
4924 char *dest;
4925 int startloc;
4926 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4927 struct stackmark smark;
4928
4929 INTOFF;
4930 setstackmark(&smark);
4931 dest = expdest;
4932 startloc = dest - (char *)stackblock();
4933 grabstackstr(dest);
4934 evalbackcmd(cmd, (struct backcmd *) &in);
4935 popstackmark(&smark);
4936
4937 p = in.buf;
4938 i = in.nleft;
4939 if (i == 0)
4940 goto read;
4941 for (;;) {
4942 memtodest(p, i, syntax, quotes);
4943read:
4944 if (in.fd < 0)
4945 break;
4946 i = safe_read(in.fd, buf, sizeof buf);
4947 TRACE(("expbackq: read returns %d\n", i));
4948 if (i <= 0)
4949 break;
4950 p = buf;
4951 }
4952
4953 if (in.buf)
4954 ckfree(in.buf);
4955 if (in.fd >= 0) {
4956 close(in.fd);
4957 back_exitstatus = waitforjob(in.jp);
4958 }
4959 INTON;
4960
4961 /* Eat all trailing newlines */
4962 dest = expdest;
4963 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4964 STUNPUTC(dest);
4965 expdest = dest;
4966
4967 if (quoted == 0)
4968 recordregion(startloc, dest - (char *)stackblock(), 0);
4969 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4970 (dest - (char *)stackblock()) - startloc,
4971 (dest - (char *)stackblock()) - startloc,
4972 stackblock() + startloc));
4973}
4974
4975
4976static char *
Eric Andersen90898442003-08-06 11:20:52 +00004977scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4978 int zero)
4979{
Eric Andersenc470f442003-07-28 09:56:35 +00004980 char *loc;
4981 char *loc2;
4982 char c;
4983
4984 loc = startp;
4985 loc2 = rmesc;
4986 do {
4987 int match;
4988 const char *s = loc2;
4989 c = *loc2;
4990 if (zero) {
4991 *loc2 = '\0';
4992 s = rmesc;
4993 }
4994 match = pmatch(str, s);
4995 *loc2 = c;
4996 if (match)
4997 return loc;
4998 if (quotes && *loc == CTLESC)
4999 loc++;
5000 loc++;
5001 loc2++;
5002 } while (c);
5003 return 0;
5004}
5005
5006
5007static char *
Eric Andersen90898442003-08-06 11:20:52 +00005008scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5009 int zero)
5010{
Eric Andersenc470f442003-07-28 09:56:35 +00005011 int esc = 0;
5012 char *loc;
5013 char *loc2;
5014
5015 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5016 int match;
5017 char c = *loc2;
5018 const char *s = loc2;
5019 if (zero) {
5020 *loc2 = '\0';
5021 s = rmesc;
5022 }
5023 match = pmatch(str, s);
5024 *loc2 = c;
5025 if (match)
5026 return loc;
5027 loc--;
5028 if (quotes) {
5029 if (--esc < 0) {
5030 esc = esclen(startp, loc);
5031 }
5032 if (esc % 2) {
5033 esc--;
5034 loc--;
5035 }
5036 }
5037 }
5038 return 0;
5039}
5040
5041static const char *
5042subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5043{
5044 char *startp;
5045 char *loc;
5046 int saveherefd = herefd;
5047 struct nodelist *saveargbackq = argbackq;
5048 int amount;
5049 char *rmesc, *rmescend;
5050 int zero;
5051 char *(*scan)(char *, char *, char *, char *, int , int);
5052
5053 herefd = -1;
5054 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5055 STPUTC('\0', expdest);
5056 herefd = saveherefd;
5057 argbackq = saveargbackq;
5058 startp = stackblock() + startloc;
5059
5060 switch (subtype) {
5061 case VSASSIGN:
5062 setvar(str, startp, 0);
5063 amount = startp - expdest;
5064 STADJUST(amount, expdest);
5065 return startp;
5066
5067 case VSQUESTION:
5068 varunset(p, str, startp, varflags);
5069 /* NOTREACHED */
5070 }
5071
5072 subtype -= VSTRIMRIGHT;
5073#ifdef DEBUG
5074 if (subtype < 0 || subtype > 3)
5075 abort();
5076#endif
5077
5078 rmesc = startp;
5079 rmescend = stackblock() + strloc;
5080 if (quotes) {
5081 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5082 if (rmesc != startp) {
5083 rmescend = expdest;
5084 startp = stackblock() + startloc;
5085 }
5086 }
5087 rmescend--;
5088 str = stackblock() + strloc;
5089 preglob(str, varflags & VSQUOTE, 0);
5090
5091 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5092 zero = subtype >> 1;
5093 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5094 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5095
5096 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5097 if (loc) {
5098 if (zero) {
5099 memmove(startp, loc, str - loc);
5100 loc = startp + (str - loc) - 1;
5101 }
5102 *loc = '\0';
5103 amount = loc - expdest;
5104 STADJUST(amount, expdest);
5105 }
5106 return loc;
5107}
5108
5109
Eric Andersen62483552001-07-10 06:09:16 +00005110/*
5111 * Expand a variable, and return a pointer to the next character in the
5112 * input string.
5113 */
Eric Andersenc470f442003-07-28 09:56:35 +00005114static char *
5115evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005116{
5117 int subtype;
5118 int varflags;
5119 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005120 int patloc;
5121 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005122 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005123 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005124 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005125 int quotes;
5126 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005127
Eric Andersenc470f442003-07-28 09:56:35 +00005128 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005129 varflags = *p++;
5130 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005131 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005132 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005133 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005134 startloc = expdest - (char *)stackblock();
5135 p = strchr(p, '=') + 1;
5136
Eric Andersenc470f442003-07-28 09:56:35 +00005137again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005138 varlen = varvalue(var, varflags, flag);
5139 if (varflags & VSNUL)
5140 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005141
Glenn L McGrath76620622004-01-13 10:19:37 +00005142 if (subtype == VSPLUS) {
5143 varlen = -1 - varlen;
5144 goto vsplus;
5145 }
Eric Andersen62483552001-07-10 06:09:16 +00005146
Eric Andersenc470f442003-07-28 09:56:35 +00005147 if (subtype == VSMINUS) {
5148vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005149 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005150 argstr(
5151 p, flag | EXP_TILDE |
5152 (quoted ? EXP_QWORD : EXP_WORD)
5153 );
5154 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005155 }
5156 if (easy)
5157 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005158 goto end;
5159 }
Eric Andersen62483552001-07-10 06:09:16 +00005160
Eric Andersenc470f442003-07-28 09:56:35 +00005161 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005162 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005163 if (subevalvar(p, var, 0, subtype, startloc,
5164 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005165 varflags &= ~VSNUL;
5166 /*
5167 * Remove any recorded regions beyond
5168 * start of variable
5169 */
5170 removerecordregions(startloc);
5171 goto again;
5172 }
Eric Andersenc470f442003-07-28 09:56:35 +00005173 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005174 }
5175 if (easy)
5176 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005177 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005178 }
5179
Glenn L McGrath76620622004-01-13 10:19:37 +00005180 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005181 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005182
Eric Andersenc470f442003-07-28 09:56:35 +00005183 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005184 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005185 goto record;
5186 }
5187
5188 if (subtype == VSNORMAL) {
5189 if (!easy)
5190 goto end;
5191record:
5192 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5193 goto end;
5194 }
5195
5196#ifdef DEBUG
5197 switch (subtype) {
5198 case VSTRIMLEFT:
5199 case VSTRIMLEFTMAX:
5200 case VSTRIMRIGHT:
5201 case VSTRIMRIGHTMAX:
5202 break;
5203 default:
5204 abort();
5205 }
5206#endif
5207
Glenn L McGrath76620622004-01-13 10:19:37 +00005208 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005209 /*
5210 * Terminate the string and start recording the pattern
5211 * right after it
5212 */
5213 STPUTC('\0', expdest);
5214 patloc = expdest - (char *)stackblock();
5215 if (subevalvar(p, NULL, patloc, subtype,
5216 startloc, varflags, quotes) == 0) {
5217 int amount = expdest - (
5218 (char *)stackblock() + patloc - 1
5219 );
5220 STADJUST(-amount, expdest);
5221 }
5222 /* Remove any recorded regions beyond start of variable */
5223 removerecordregions(startloc);
5224 goto record;
5225 }
5226
5227end:
5228 if (subtype != VSNORMAL) { /* skip to end of alternative */
5229 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005230 for (;;) {
5231 if ((c = *p++) == CTLESC)
5232 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005233 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005234 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005235 argbackq = argbackq->next;
5236 } else if (c == CTLVAR) {
5237 if ((*p++ & VSTYPE) != VSNORMAL)
5238 nesting++;
5239 } else if (c == CTLENDVAR) {
5240 if (--nesting == 0)
5241 break;
5242 }
5243 }
5244 }
5245 return p;
5246}
5247
Eric Andersencb57d552001-06-28 07:25:16 +00005248
Eric Andersencb57d552001-06-28 07:25:16 +00005249/*
5250 * Put a string on the stack.
5251 */
5252
Eric Andersenc470f442003-07-28 09:56:35 +00005253static void
5254memtodest(const char *p, size_t len, int syntax, int quotes) {
5255 char *q = expdest;
5256
5257 q = makestrspace(len * 2, q);
5258
5259 while (len--) {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005260 int c = SC2INT(*p++);
Eric Andersenc470f442003-07-28 09:56:35 +00005261 if (!c)
5262 continue;
5263 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5264 USTPUTC(CTLESC, q);
5265 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005266 }
Eric Andersenc470f442003-07-28 09:56:35 +00005267
5268 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005269}
5270
Eric Andersenc470f442003-07-28 09:56:35 +00005271
5272static void
5273strtodest(const char *p, int syntax, int quotes)
5274{
5275 memtodest(p, strlen(p), syntax, quotes);
5276}
5277
5278
Eric Andersencb57d552001-06-28 07:25:16 +00005279/*
5280 * Add the value of a specialized variable to the stack string.
5281 */
5282
Glenn L McGrath76620622004-01-13 10:19:37 +00005283static ssize_t
5284varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005285{
5286 int num;
5287 char *p;
5288 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005289 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005290 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005291 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005292 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005293 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005294 int quoted = varflags & VSQUOTE;
5295 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005296 int quotes = flags & (EXP_FULL | EXP_CASE);
5297
Glenn L McGrath76620622004-01-13 10:19:37 +00005298 if (quoted && (flags & EXP_FULL))
5299 sep = 1 << CHAR_BIT;
5300
Eric Andersencb57d552001-06-28 07:25:16 +00005301 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5302 switch (*name) {
5303 case '$':
5304 num = rootpid;
5305 goto numvar;
5306 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005307 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005308 goto numvar;
5309 case '#':
5310 num = shellparam.nparam;
5311 goto numvar;
5312 case '!':
5313 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005314 if (num == 0)
5315 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005316numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005317 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005318 break;
5319 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005320 p = makestrspace(NOPTS, expdest);
5321 for (i = NOPTS - 1; i >= 0; i--) {
5322 if (optlist[i]) {
5323 USTPUTC(optletters(i), p);
5324 len++;
5325 }
Eric Andersencb57d552001-06-28 07:25:16 +00005326 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005327 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005328 break;
5329 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005330 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005331 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005332 /* fall through */
5333 case '*':
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005334 sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005335 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5336 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005337param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005338 if (!(ap = shellparam.p))
5339 return -1;
5340 while ((p = *ap++)) {
5341 size_t partlen;
5342
5343 partlen = strlen(p);
Glenn L McGrath76620622004-01-13 10:19:37 +00005344 len += partlen;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00005345
5346 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5347 memtodest(p, partlen, syntax, quotes);
5348
5349 if (*ap && sep) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005350 char *q;
5351
5352 len++;
5353 if (subtype == VSPLUS || subtype == VSLENGTH) {
5354 continue;
5355 }
5356 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005357 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005358 STPUTC(CTLESC, q);
5359 STPUTC(sep, q);
5360 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005361 }
5362 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005363 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005364 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005365 case '1':
5366 case '2':
5367 case '3':
5368 case '4':
5369 case '5':
5370 case '6':
5371 case '7':
5372 case '8':
5373 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005374 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005375 if (num < 0 || num > shellparam.nparam)
5376 return -1;
5377 p = num ? shellparam.p[num - 1] : arg0;
5378 goto value;
5379 default:
5380 p = lookupvar(name);
5381value:
5382 if (!p)
5383 return -1;
5384
5385 len = strlen(p);
5386 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5387 memtodest(p, len, syntax, quotes);
5388 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005389 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005390
5391 if (subtype == VSPLUS || subtype == VSLENGTH)
5392 STADJUST(-len, expdest);
5393 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005394}
5395
5396
Eric Andersencb57d552001-06-28 07:25:16 +00005397/*
5398 * Record the fact that we have to scan this region of the
5399 * string for IFS characters.
5400 */
5401
Eric Andersenc470f442003-07-28 09:56:35 +00005402static void
5403recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005404{
5405 struct ifsregion *ifsp;
5406
5407 if (ifslastp == NULL) {
5408 ifsp = &ifsfirst;
5409 } else {
5410 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005411 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005412 ifsp->next = NULL;
5413 ifslastp->next = ifsp;
5414 INTON;
5415 }
5416 ifslastp = ifsp;
5417 ifslastp->begoff = start;
5418 ifslastp->endoff = end;
5419 ifslastp->nulonly = nulonly;
5420}
5421
5422
Eric Andersencb57d552001-06-28 07:25:16 +00005423/*
5424 * Break the argument string into pieces based upon IFS and add the
5425 * strings to the argument list. The regions of the string to be
5426 * searched for IFS characters have been stored by recordregion.
5427 */
Eric Andersenc470f442003-07-28 09:56:35 +00005428static void
5429ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005430{
Eric Andersencb57d552001-06-28 07:25:16 +00005431 struct ifsregion *ifsp;
5432 struct strlist *sp;
5433 char *start;
5434 char *p;
5435 char *q;
5436 const char *ifs, *realifs;
5437 int ifsspc;
5438 int nulonly;
5439
5440
5441 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005442 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005443 ifsspc = 0;
5444 nulonly = 0;
5445 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005446 ifsp = &ifsfirst;
5447 do {
5448 p = string + ifsp->begoff;
5449 nulonly = ifsp->nulonly;
5450 ifs = nulonly ? nullstr : realifs;
5451 ifsspc = 0;
5452 while (p < string + ifsp->endoff) {
5453 q = p;
5454 if (*p == CTLESC)
5455 p++;
5456 if (strchr(ifs, *p)) {
5457 if (!nulonly)
5458 ifsspc = (strchr(defifs, *p) != NULL);
5459 /* Ignore IFS whitespace at start */
5460 if (q == start && ifsspc) {
5461 p++;
5462 start = p;
5463 continue;
5464 }
5465 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005466 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005467 sp->text = start;
5468 *arglist->lastp = sp;
5469 arglist->lastp = &sp->next;
5470 p++;
5471 if (!nulonly) {
5472 for (;;) {
5473 if (p >= string + ifsp->endoff) {
5474 break;
5475 }
5476 q = p;
5477 if (*p == CTLESC)
5478 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005479 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005480 p = q;
5481 break;
5482 } else if (strchr(defifs, *p) == NULL) {
5483 if (ifsspc) {
5484 p++;
5485 ifsspc = 0;
5486 } else {
5487 p = q;
5488 break;
5489 }
5490 } else
5491 p++;
5492 }
5493 }
5494 start = p;
5495 } else
5496 p++;
5497 }
5498 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005499 if (nulonly)
5500 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005501 }
5502
Eric Andersenc470f442003-07-28 09:56:35 +00005503 if (!*start)
5504 return;
5505
5506add:
5507 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005508 sp->text = start;
5509 *arglist->lastp = sp;
5510 arglist->lastp = &sp->next;
5511}
5512
Eric Andersenc470f442003-07-28 09:56:35 +00005513static void
5514ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005515{
Eric Andersenc470f442003-07-28 09:56:35 +00005516 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005517
Eric Andersenc470f442003-07-28 09:56:35 +00005518 INTOFF;
5519 p = ifsfirst.next;
5520 do {
5521 struct ifsregion *ifsp;
5522 ifsp = p->next;
5523 ckfree(p);
5524 p = ifsp;
5525 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005526 ifslastp = NULL;
5527 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005528 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005529}
5530
Eric Andersen90898442003-08-06 11:20:52 +00005531static void expmeta(char *, char *);
5532static struct strlist *expsort(struct strlist *);
5533static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005534
Eric Andersen90898442003-08-06 11:20:52 +00005535static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005536
Eric Andersencb57d552001-06-28 07:25:16 +00005537
Eric Andersenc470f442003-07-28 09:56:35 +00005538static void
Eric Andersen90898442003-08-06 11:20:52 +00005539expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005540{
Eric Andersen90898442003-08-06 11:20:52 +00005541 static const char metachars[] = {
5542 '*', '?', '[', 0
5543 };
Eric Andersencb57d552001-06-28 07:25:16 +00005544 /* TODO - EXP_REDIR */
5545
5546 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005547 struct strlist **savelastp;
5548 struct strlist *sp;
5549 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005550
Eric Andersencb57d552001-06-28 07:25:16 +00005551 if (fflag)
5552 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005553 if (!strpbrk(str->text, metachars))
5554 goto nometa;
5555 savelastp = exparg.lastp;
5556
Eric Andersencb57d552001-06-28 07:25:16 +00005557 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005558 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005559 {
5560 int i = strlen(str->text);
5561 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5562 }
5563
5564 expmeta(expdir, p);
5565 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005566 if (p != str->text)
5567 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005568 INTON;
5569 if (exparg.lastp == savelastp) {
5570 /*
5571 * no matches
5572 */
Eric Andersenc470f442003-07-28 09:56:35 +00005573nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005574 *exparg.lastp = str;
5575 rmescapes(str->text);
5576 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005577 } else {
5578 *exparg.lastp = NULL;
5579 *savelastp = sp = expsort(*savelastp);
5580 while (sp->next != NULL)
5581 sp = sp->next;
5582 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005583 }
5584 str = str->next;
5585 }
5586}
5587
Eric Andersencb57d552001-06-28 07:25:16 +00005588/*
Eric Andersenc470f442003-07-28 09:56:35 +00005589 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005590 */
5591
Eric Andersenc470f442003-07-28 09:56:35 +00005592static void
Eric Andersen90898442003-08-06 11:20:52 +00005593addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005594{
Eric Andersencb57d552001-06-28 07:25:16 +00005595 struct strlist *sp;
5596
Eric Andersenc470f442003-07-28 09:56:35 +00005597 sp = (struct strlist *)stalloc(sizeof *sp);
5598 sp->text = sstrdup(name);
5599 *exparg.lastp = sp;
5600 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005601}
5602
5603
Eric Andersencb57d552001-06-28 07:25:16 +00005604/*
Eric Andersen90898442003-08-06 11:20:52 +00005605 * Do metacharacter (i.e. *, ?, [...]) expansion.
5606 */
5607
5608static void
5609expmeta(char *enddir, char *name)
5610{
5611 char *p;
5612 const char *cp;
5613 char *start;
5614 char *endname;
5615 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005616 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005617 DIR *dirp;
5618 struct dirent *dp;
5619 int atend;
5620 int matchdot;
5621
5622 metaflag = 0;
5623 start = name;
5624 for (p = name; *p; p++) {
5625 if (*p == '*' || *p == '?')
5626 metaflag = 1;
5627 else if (*p == '[') {
5628 char *q = p + 1;
5629 if (*q == '!')
5630 q++;
5631 for (;;) {
5632 if (*q == '\\')
5633 q++;
5634 if (*q == '/' || *q == '\0')
5635 break;
5636 if (*++q == ']') {
5637 metaflag = 1;
5638 break;
5639 }
5640 }
5641 } else if (*p == '\\')
5642 p++;
5643 else if (*p == '/') {
5644 if (metaflag)
5645 goto out;
5646 start = p + 1;
5647 }
5648 }
5649out:
5650 if (metaflag == 0) { /* we've reached the end of the file name */
5651 if (enddir != expdir)
5652 metaflag++;
5653 p = name;
5654 do {
5655 if (*p == '\\')
5656 p++;
5657 *enddir++ = *p;
5658 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005659 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005660 addfname(expdir);
5661 return;
5662 }
5663 endname = p;
5664 if (name < start) {
5665 p = name;
5666 do {
5667 if (*p == '\\')
5668 p++;
5669 *enddir++ = *p++;
5670 } while (p < start);
5671 }
5672 if (enddir == expdir) {
5673 cp = ".";
5674 } else if (enddir == expdir + 1 && *expdir == '/') {
5675 cp = "/";
5676 } else {
5677 cp = expdir;
5678 enddir[-1] = '\0';
5679 }
5680 if ((dirp = opendir(cp)) == NULL)
5681 return;
5682 if (enddir != expdir)
5683 enddir[-1] = '/';
5684 if (*endname == 0) {
5685 atend = 1;
5686 } else {
5687 atend = 0;
5688 *endname++ = '\0';
5689 }
5690 matchdot = 0;
5691 p = start;
5692 if (*p == '\\')
5693 p++;
5694 if (*p == '.')
5695 matchdot++;
5696 while (! intpending && (dp = readdir(dirp)) != NULL) {
5697 if (dp->d_name[0] == '.' && ! matchdot)
5698 continue;
5699 if (pmatch(start, dp->d_name)) {
5700 if (atend) {
5701 scopy(dp->d_name, enddir);
5702 addfname(expdir);
5703 } else {
5704 for (p = enddir, cp = dp->d_name;
5705 (*p++ = *cp++) != '\0';)
5706 continue;
5707 p[-1] = '/';
5708 expmeta(p, endname);
5709 }
5710 }
5711 }
5712 closedir(dirp);
5713 if (! atend)
5714 endname[-1] = '/';
5715}
5716
5717/*
5718 * Sort the results of file name expansion. It calculates the number of
5719 * strings to sort and then calls msort (short for merge sort) to do the
5720 * work.
5721 */
5722
5723static struct strlist *
5724expsort(struct strlist *str)
5725{
5726 int len;
5727 struct strlist *sp;
5728
5729 len = 0;
5730 for (sp = str ; sp ; sp = sp->next)
5731 len++;
5732 return msort(str, len);
5733}
5734
5735
5736static struct strlist *
5737msort(struct strlist *list, int len)
5738{
5739 struct strlist *p, *q = NULL;
5740 struct strlist **lpp;
5741 int half;
5742 int n;
5743
5744 if (len <= 1)
5745 return list;
5746 half = len >> 1;
5747 p = list;
5748 for (n = half ; --n >= 0 ; ) {
5749 q = p;
5750 p = p->next;
5751 }
5752 q->next = NULL; /* terminate first half of list */
5753 q = msort(list, half); /* sort first half of list */
5754 p = msort(p, len - half); /* sort second half */
5755 lpp = &list;
5756 for (;;) {
5757#ifdef CONFIG_LOCALE_SUPPORT
5758 if (strcoll(p->text, q->text) < 0)
5759#else
5760 if (strcmp(p->text, q->text) < 0)
5761#endif
5762 {
5763 *lpp = p;
5764 lpp = &p->next;
5765 if ((p = *lpp) == NULL) {
5766 *lpp = q;
5767 break;
5768 }
5769 } else {
5770 *lpp = q;
5771 lpp = &q->next;
5772 if ((q = *lpp) == NULL) {
5773 *lpp = p;
5774 break;
5775 }
5776 }
5777 }
5778 return list;
5779}
5780
5781
5782/*
Eric Andersencb57d552001-06-28 07:25:16 +00005783 * Returns true if the pattern matches the string.
5784 */
5785
Eric Andersenc470f442003-07-28 09:56:35 +00005786static inline int
5787patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005788{
Eric Andersenc470f442003-07-28 09:56:35 +00005789 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005790}
5791
5792
Eric Andersencb57d552001-06-28 07:25:16 +00005793/*
5794 * Remove any CTLESC characters from a string.
5795 */
5796
Eric Andersenc470f442003-07-28 09:56:35 +00005797static char *
5798_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005799{
5800 char *p, *q, *r;
5801 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005802 unsigned inquotes;
5803 int notescaped;
5804 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005805
5806 p = strpbrk(str, qchars);
5807 if (!p) {
5808 return str;
5809 }
5810 q = p;
5811 r = str;
5812 if (flag & RMESCAPE_ALLOC) {
5813 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005814 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005815
Eric Andersenc470f442003-07-28 09:56:35 +00005816 if (flag & RMESCAPE_GROW) {
5817 r = makestrspace(fulllen, expdest);
5818 } else if (flag & RMESCAPE_HEAP) {
5819 r = ckmalloc(fulllen);
5820 } else {
5821 r = stalloc(fulllen);
5822 }
5823 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005824 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005825 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005826 }
5827 }
Eric Andersenc470f442003-07-28 09:56:35 +00005828 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5829 globbing = flag & RMESCAPE_GLOB;
5830 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005831 while (*p) {
5832 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005833 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005834 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005835 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005836 continue;
5837 }
Eric Andersenc470f442003-07-28 09:56:35 +00005838 if (*p == '\\') {
5839 /* naked back slash */
5840 notescaped = 0;
5841 goto copy;
5842 }
Eric Andersencb57d552001-06-28 07:25:16 +00005843 if (*p == CTLESC) {
5844 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005845 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005846 *q++ = '\\';
5847 }
5848 }
Eric Andersenc470f442003-07-28 09:56:35 +00005849 notescaped = globbing;
5850copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005851 *q++ = *p++;
5852 }
5853 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005854 if (flag & RMESCAPE_GROW) {
5855 expdest = r;
5856 STADJUST(q - r + 1, expdest);
5857 }
Eric Andersencb57d552001-06-28 07:25:16 +00005858 return r;
5859}
Eric Andersencb57d552001-06-28 07:25:16 +00005860
5861
Eric Andersencb57d552001-06-28 07:25:16 +00005862/*
5863 * See if a pattern matches in a case statement.
5864 */
5865
Eric Andersenc470f442003-07-28 09:56:35 +00005866int
5867casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005868{
Eric Andersencb57d552001-06-28 07:25:16 +00005869 struct stackmark smark;
5870 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005871
5872 setstackmark(&smark);
5873 argbackq = pattern->narg.backquote;
5874 STARTSTACKSTR(expdest);
5875 ifslastp = NULL;
5876 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005877 STACKSTRNUL(expdest);
5878 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005879 popstackmark(&smark);
5880 return result;
5881}
5882
5883/*
5884 * Our own itoa().
5885 */
5886
Eric Andersenc470f442003-07-28 09:56:35 +00005887static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005888cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005889{
Eric Andersencb57d552001-06-28 07:25:16 +00005890 int len;
5891
Eric Andersenc470f442003-07-28 09:56:35 +00005892 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005893#ifdef CONFIG_ASH_MATH_SUPPORT_64
5894 len = fmtstr(expdest, 32, "%lld", (long long) num);
5895#else
Eric Andersenc470f442003-07-28 09:56:35 +00005896 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005897#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005898 STADJUST(len, expdest);
5899 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005900}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005901
Eric Andersenc470f442003-07-28 09:56:35 +00005902static void
5903varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005904{
Eric Andersenc470f442003-07-28 09:56:35 +00005905 const char *msg;
5906 const char *tail;
5907
5908 tail = nullstr;
5909 msg = "parameter not set";
5910 if (umsg) {
5911 if (*end == CTLENDVAR) {
5912 if (varflags & VSNUL)
5913 tail = " or null";
5914 } else
5915 msg = umsg;
5916 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005917 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005918}
Eric Andersen90898442003-08-06 11:20:52 +00005919
5920
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005921/* input.c */
Eric Andersencb57d552001-06-28 07:25:16 +00005922
Eric Andersencb57d552001-06-28 07:25:16 +00005923/*
Eric Andersen90898442003-08-06 11:20:52 +00005924 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005925 */
5926
Eric Andersenc470f442003-07-28 09:56:35 +00005927#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005928
Eric Andersenc470f442003-07-28 09:56:35 +00005929static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005930
Eric Andersencb57d552001-06-28 07:25:16 +00005931/*
Eric Andersenc470f442003-07-28 09:56:35 +00005932 * Read a character from the script, returning PEOF on end of file.
5933 * Nul characters in the input are silently discarded.
5934 */
5935
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005936
5937#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
Eric Andersenc470f442003-07-28 09:56:35 +00005938
5939#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5940#define pgetc_macro() pgetc()
5941static int
5942pgetc(void)
5943{
5944 return pgetc_as_macro();
5945}
5946#else
5947#define pgetc_macro() pgetc_as_macro()
5948static int
5949pgetc(void)
5950{
5951 return pgetc_macro();
5952}
5953#endif
5954
5955
5956/*
5957 * Same as pgetc(), but ignores PEOA.
5958 */
5959#ifdef CONFIG_ASH_ALIAS
5960static int pgetc2(void)
5961{
5962 int c;
5963
5964 do {
5965 c = pgetc_macro();
5966 } while (c == PEOA);
5967 return c;
5968}
5969#else
5970static inline int pgetc2(void)
5971{
5972 return pgetc_macro();
5973}
5974#endif
5975
Glenn L McGrath28939ad2004-07-21 10:20:19 +00005976/*
5977 * Read a line from the script.
5978 */
5979
5980static inline char *
5981pfgets(char *line, int len)
5982{
5983 char *p = line;
5984 int nleft = len;
5985 int c;
5986
5987 while (--nleft > 0) {
5988 c = pgetc2();
5989 if (c == PEOF) {
5990 if (p == line)
5991 return NULL;
5992 break;
5993 }
5994 *p++ = c;
5995 if (c == '\n')
5996 break;
5997 }
5998 *p = '\0';
5999 return line;
6000}
6001
6002
Eric Andersenc470f442003-07-28 09:56:35 +00006003
6004#ifdef CONFIG_FEATURE_COMMAND_EDITING
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006005#ifdef CONFIG_ASH_EXPAND_PRMT
6006static char *cmdedit_prompt;
6007#else
Eric Andersenc470f442003-07-28 09:56:35 +00006008static const char *cmdedit_prompt;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006009#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006010static inline void putprompt(const char *s)
6011{
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006012#ifdef CONFIG_ASH_EXPAND_PRMT
6013 free(cmdedit_prompt);
Rob Landleyd921b2e2006-08-03 15:41:12 +00006014 cmdedit_prompt = xstrdup(s);
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006015#else
Eric Andersenc470f442003-07-28 09:56:35 +00006016 cmdedit_prompt = s;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006017#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006018}
6019#else
6020static inline void putprompt(const char *s)
6021{
6022 out2str(s);
6023}
6024#endif
6025
6026static inline int
6027preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006028{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006029 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006030 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006031 parsenextc = buf;
6032
Eric Andersenc470f442003-07-28 09:56:35 +00006033retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006034#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006035 if (!iflag || parsefile->fd)
6036 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6037 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006038#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006039 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006040#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006041 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6042 if(nr == 0) {
6043 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006044 if(trap[SIGINT]) {
6045 buf[0] = '\n';
6046 buf[1] = 0;
6047 raise(SIGINT);
6048 return 1;
6049 }
Eric Andersenc470f442003-07-28 09:56:35 +00006050 goto retry;
6051 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006052 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006053 /* Ctrl+D presend */
6054 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006055 }
Eric Andersencb57d552001-06-28 07:25:16 +00006056 }
6057#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006058 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006059#endif
6060
6061 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006062 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6063 int flags = fcntl(0, F_GETFL, 0);
6064 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006065 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006066 if (fcntl(0, F_SETFL, flags) >= 0) {
6067 out2str("sh: turning off NDELAY mode\n");
6068 goto retry;
6069 }
6070 }
6071 }
6072 }
6073 return nr;
6074}
6075
6076/*
6077 * Refill the input buffer and return the next input character:
6078 *
6079 * 1) If a string was pushed back on the input, pop it;
6080 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6081 * from a string so we can't refill the buffer, return EOF.
6082 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6083 * 4) Process input up to the next newline, deleting nul characters.
6084 */
6085
Eric Andersenc470f442003-07-28 09:56:35 +00006086int
6087preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006088{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006089 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00006090 int more;
6091 char savec;
6092
6093 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006094#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006095 if (parsenleft == -1 && parsefile->strpush->ap &&
6096 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006097 return PEOA;
6098 }
Eric Andersen2870d962001-07-02 17:27:21 +00006099#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006100 popstring();
6101 if (--parsenleft >= 0)
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006102 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006103 }
6104 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6105 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006106 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006107
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006108 more = parselleft;
6109 if (more <= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006110again:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006111 if ((more = preadfd()) <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006112 parselleft = parsenleft = EOF_NLEFT;
6113 return PEOF;
6114 }
6115 }
6116
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006117 q = parsenextc;
Eric Andersencb57d552001-06-28 07:25:16 +00006118
6119 /* delete nul characters */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006120 for (;;) {
6121 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00006122
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006123 more--;
6124 c = *q;
Eric Andersenc470f442003-07-28 09:56:35 +00006125
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006126 if (!c)
6127 memmove(q, q + 1, more);
6128 else {
6129 q++;
6130 if (c == '\n') {
6131 parsenleft = q - parsenextc - 1;
6132 break;
6133 }
Eric Andersencb57d552001-06-28 07:25:16 +00006134 }
6135
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006136 if (more <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006137 parsenleft = q - parsenextc - 1;
6138 if (parsenleft < 0)
6139 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006140 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006141 }
6142 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006143 parselleft = more;
Eric Andersencb57d552001-06-28 07:25:16 +00006144
6145 savec = *q;
6146 *q = '\0';
6147
6148 if (vflag) {
6149 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006150 }
6151
6152 *q = savec;
6153
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006154 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006155}
6156
Eric Andersenc470f442003-07-28 09:56:35 +00006157/*
6158 * Undo the last call to pgetc. Only one character may be pushed back.
6159 * PEOF may be pushed back.
6160 */
6161
6162void
6163pungetc(void)
6164{
6165 parsenleft++;
6166 parsenextc--;
6167}
Eric Andersencb57d552001-06-28 07:25:16 +00006168
6169/*
6170 * Push a string back onto the input at this current parsefile level.
6171 * We handle aliases this way.
6172 */
Eric Andersenc470f442003-07-28 09:56:35 +00006173void
6174pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006175{
Eric Andersencb57d552001-06-28 07:25:16 +00006176 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006177 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006178
Eric Andersenc470f442003-07-28 09:56:35 +00006179 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006180 INTOFF;
6181/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6182 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006183 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006184 sp->prev = parsefile->strpush;
6185 parsefile->strpush = sp;
6186 } else
6187 sp = parsefile->strpush = &(parsefile->basestrpush);
6188 sp->prevstring = parsenextc;
6189 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006190#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006191 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006192 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006193 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006194 sp->string = s;
6195 }
Eric Andersen2870d962001-07-02 17:27:21 +00006196#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006197 parsenextc = s;
6198 parsenleft = len;
6199 INTON;
6200}
6201
Eric Andersenc470f442003-07-28 09:56:35 +00006202void
6203popstring(void)
6204{
6205 struct strpush *sp = parsefile->strpush;
6206
6207 INTOFF;
6208#ifdef CONFIG_ASH_ALIAS
6209 if (sp->ap) {
6210 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6211 checkkwd |= CHKALIAS;
6212 }
6213 if (sp->string != sp->ap->val) {
6214 ckfree(sp->string);
6215 }
6216 sp->ap->flag &= ~ALIASINUSE;
6217 if (sp->ap->flag & ALIASDEAD) {
6218 unalias(sp->ap->name);
6219 }
6220 }
6221#endif
6222 parsenextc = sp->prevstring;
6223 parsenleft = sp->prevnleft;
6224/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6225 parsefile->strpush = sp->prev;
6226 if (sp != &(parsefile->basestrpush))
6227 ckfree(sp);
6228 INTON;
6229}
6230
6231/*
6232 * Set the input to take input from a file. If push is set, push the
6233 * old input onto the stack first.
6234 */
6235
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006236static int
6237setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00006238{
6239 int fd;
6240 int fd2;
6241
6242 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006243 if ((fd = open(fname, O_RDONLY)) < 0) {
6244 if (flags & INPUT_NOFILE_OK)
6245 goto out;
6246 sh_error("Can't open %s", fname);
6247 }
Eric Andersenc470f442003-07-28 09:56:35 +00006248 if (fd < 10) {
6249 fd2 = copyfd(fd, 10);
6250 close(fd);
6251 if (fd2 < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006252 sh_error("Out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +00006253 fd = fd2;
6254 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006255 setinputfd(fd, flags & INPUT_PUSH_FILE);
6256out:
Eric Andersenc470f442003-07-28 09:56:35 +00006257 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006258 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +00006259}
6260
6261
6262/*
6263 * Like setinputfile, but takes an open file descriptor. Call this with
6264 * interrupts off.
6265 */
6266
6267static void
6268setinputfd(int fd, int push)
6269{
6270 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6271 if (push) {
6272 pushfile();
6273 parsefile->buf = 0;
6274 }
6275 parsefile->fd = fd;
6276 if (parsefile->buf == NULL)
6277 parsefile->buf = ckmalloc(IBUFSIZ);
6278 parselleft = parsenleft = 0;
6279 plinno = 1;
6280}
6281
Eric Andersencb57d552001-06-28 07:25:16 +00006282
Eric Andersencb57d552001-06-28 07:25:16 +00006283/*
6284 * Like setinputfile, but takes input from a string.
6285 */
6286
Eric Andersenc470f442003-07-28 09:56:35 +00006287static void
6288setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006289{
Eric Andersencb57d552001-06-28 07:25:16 +00006290 INTOFF;
6291 pushfile();
6292 parsenextc = string;
6293 parsenleft = strlen(string);
6294 parsefile->buf = NULL;
6295 plinno = 1;
6296 INTON;
6297}
6298
6299
Eric Andersencb57d552001-06-28 07:25:16 +00006300/*
6301 * To handle the "." command, a stack of input files is used. Pushfile
6302 * adds a new entry to the stack and popfile restores the previous level.
6303 */
6304
Eric Andersenc470f442003-07-28 09:56:35 +00006305static void
6306pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006307{
Eric Andersencb57d552001-06-28 07:25:16 +00006308 struct parsefile *pf;
6309
6310 parsefile->nleft = parsenleft;
6311 parsefile->lleft = parselleft;
6312 parsefile->nextc = parsenextc;
6313 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006314 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006315 pf->prev = parsefile;
6316 pf->fd = -1;
6317 pf->strpush = NULL;
6318 pf->basestrpush.prev = NULL;
6319 parsefile = pf;
6320}
6321
Eric Andersenc470f442003-07-28 09:56:35 +00006322
6323static void
6324popfile(void)
6325{
6326 struct parsefile *pf = parsefile;
6327
6328 INTOFF;
6329 if (pf->fd >= 0)
6330 close(pf->fd);
6331 if (pf->buf)
6332 ckfree(pf->buf);
6333 while (pf->strpush)
6334 popstring();
6335 parsefile = pf->prev;
6336 ckfree(pf);
6337 parsenleft = parsefile->nleft;
6338 parselleft = parsefile->lleft;
6339 parsenextc = parsefile->nextc;
6340 plinno = parsefile->linno;
6341 INTON;
6342}
Eric Andersencb57d552001-06-28 07:25:16 +00006343
6344
Eric Andersen2870d962001-07-02 17:27:21 +00006345/*
Eric Andersenc470f442003-07-28 09:56:35 +00006346 * Return to top level.
6347 */
Eric Andersen2870d962001-07-02 17:27:21 +00006348
Eric Andersenc470f442003-07-28 09:56:35 +00006349static void
6350popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006351{
Eric Andersenc470f442003-07-28 09:56:35 +00006352 while (parsefile != &basepf)
6353 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006354}
6355
Eric Andersen2870d962001-07-02 17:27:21 +00006356
Eric Andersenc470f442003-07-28 09:56:35 +00006357/*
6358 * Close the file(s) that the shell is reading commands from. Called
6359 * after a fork is done.
6360 */
6361
6362static void
6363closescript(void)
6364{
6365 popallfiles();
6366 if (parsefile->fd > 0) {
6367 close(parsefile->fd);
6368 parsefile->fd = 0;
6369 }
6370}
Eric Andersenc470f442003-07-28 09:56:35 +00006371
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006372/* jobs.c */
Eric Andersenc470f442003-07-28 09:56:35 +00006373
6374/* mode flags for set_curjob */
6375#define CUR_DELETE 2
6376#define CUR_RUNNING 1
6377#define CUR_STOPPED 0
6378
6379/* mode flags for dowait */
6380#define DOWAIT_NORMAL 0
6381#define DOWAIT_BLOCK 1
6382
6383/* array of jobs */
6384static struct job *jobtab;
6385/* size of array */
6386static unsigned njobs;
6387#if JOBS
6388/* pgrp of shell on invocation */
6389static int initialpgrp;
6390static int ttyfd = -1;
6391#endif
6392/* current job */
6393static struct job *curjob;
6394/* number of presumed living untracked jobs */
6395static int jobless;
6396
6397static void set_curjob(struct job *, unsigned);
6398#if JOBS
6399static int restartjob(struct job *, int);
6400static void xtcsetpgrp(int, pid_t);
6401static char *commandtext(union node *);
6402static void cmdlist(union node *, int);
6403static void cmdtxt(union node *);
6404static void cmdputs(const char *);
6405static void showpipe(struct job *, FILE *);
6406#endif
6407static int sprint_status(char *, int, int);
6408static void freejob(struct job *);
6409static struct job *getjob(const char *, int);
6410static struct job *growjobtab(void);
6411static void forkchild(struct job *, union node *, int);
6412static void forkparent(struct job *, union node *, int, pid_t);
6413static int dowait(int, struct job *);
6414static int getstatus(struct job *);
6415
6416static void
6417set_curjob(struct job *jp, unsigned mode)
6418{
6419 struct job *jp1;
6420 struct job **jpp, **curp;
6421
6422 /* first remove from list */
6423 jpp = curp = &curjob;
6424 do {
6425 jp1 = *jpp;
6426 if (jp1 == jp)
6427 break;
6428 jpp = &jp1->prev_job;
6429 } while (1);
6430 *jpp = jp1->prev_job;
6431
6432 /* Then re-insert in correct position */
6433 jpp = curp;
6434 switch (mode) {
6435 default:
6436#ifdef DEBUG
6437 abort();
6438#endif
6439 case CUR_DELETE:
6440 /* job being deleted */
6441 break;
6442 case CUR_RUNNING:
6443 /* newly created job or backgrounded job,
6444 put after all stopped jobs. */
6445 do {
6446 jp1 = *jpp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006447#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006448 if (!jp1 || jp1->state != JOBSTOPPED)
6449#endif
6450 break;
6451 jpp = &jp1->prev_job;
6452 } while (1);
6453 /* FALLTHROUGH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006454#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006455 case CUR_STOPPED:
6456#endif
6457 /* newly stopped job - becomes curjob */
6458 jp->prev_job = *jpp;
6459 *jpp = jp;
6460 break;
6461 }
6462}
6463
6464#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006465/*
6466 * Turn job control on and off.
6467 *
6468 * Note: This code assumes that the third arg to ioctl is a character
6469 * pointer, which is true on Berkeley systems but not System V. Since
6470 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006471 *
6472 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006473 */
6474
Eric Andersenc470f442003-07-28 09:56:35 +00006475void
6476setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006477{
Eric Andersenc470f442003-07-28 09:56:35 +00006478 int fd;
6479 int pgrp;
6480
6481 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006482 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006483 if (on) {
6484 int ofd;
6485 ofd = fd = open(_PATH_TTY, O_RDWR);
6486 if (fd < 0) {
6487 fd += 3;
6488 while (!isatty(fd) && --fd >= 0)
6489 ;
6490 }
6491 fd = fcntl(fd, F_DUPFD, 10);
6492 close(ofd);
6493 if (fd < 0)
6494 goto out;
6495 fcntl(fd, F_SETFD, FD_CLOEXEC);
6496 do { /* while we are in the background */
6497 if ((pgrp = tcgetpgrp(fd)) < 0) {
6498out:
6499 sh_warnx("can't access tty; job control turned off");
6500 mflag = on = 0;
6501 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006502 }
Eric Andersenc470f442003-07-28 09:56:35 +00006503 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006504 break;
6505 killpg(0, SIGTTIN);
6506 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006507 initialpgrp = pgrp;
6508
Eric Andersencb57d552001-06-28 07:25:16 +00006509 setsignal(SIGTSTP);
6510 setsignal(SIGTTOU);
6511 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006512 pgrp = rootpid;
6513 setpgid(0, pgrp);
6514 xtcsetpgrp(fd, pgrp);
6515 } else {
6516 /* turning job control off */
6517 fd = ttyfd;
6518 pgrp = initialpgrp;
6519 xtcsetpgrp(fd, pgrp);
6520 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006521 setsignal(SIGTSTP);
6522 setsignal(SIGTTOU);
6523 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006524close:
6525 close(fd);
6526 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006527 }
Eric Andersenc470f442003-07-28 09:56:35 +00006528 ttyfd = fd;
6529 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006530}
Eric Andersencb57d552001-06-28 07:25:16 +00006531
Eric Andersenc470f442003-07-28 09:56:35 +00006532static int
Eric Andersen90898442003-08-06 11:20:52 +00006533killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006534{
6535 int signo = -1;
6536 int list = 0;
6537 int i;
6538 pid_t pid;
6539 struct job *jp;
6540
6541 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006542usage:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006543 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006544"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6545"kill -l [exitstatus]"
6546 );
Eric Andersencb57d552001-06-28 07:25:16 +00006547 }
6548
Eric Andersenc470f442003-07-28 09:56:35 +00006549 if (**++argv == '-') {
Rob Landleyc9c1a412006-07-12 19:17:55 +00006550 signo = get_signum(*argv + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006551 if (signo < 0) {
6552 int c;
6553
6554 while ((c = nextopt("ls:")) != '\0')
6555 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006556 default:
6557#ifdef DEBUG
6558 abort();
6559#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006560 case 'l':
6561 list = 1;
6562 break;
6563 case 's':
Rob Landleyc9c1a412006-07-12 19:17:55 +00006564 signo = get_signum(optionarg);
Eric Andersencb57d552001-06-28 07:25:16 +00006565 if (signo < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006566 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006567 "invalid signal number or name: %s",
6568 optionarg
6569 );
Eric Andersencb57d552001-06-28 07:25:16 +00006570 }
Eric Andersen2870d962001-07-02 17:27:21 +00006571 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006572 }
Eric Andersenc470f442003-07-28 09:56:35 +00006573 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006574 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006575 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006576 }
6577
6578 if (!list && signo < 0)
6579 signo = SIGTERM;
6580
Eric Andersenc470f442003-07-28 09:56:35 +00006581 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006582 goto usage;
6583 }
6584
6585 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006586 const char *name;
6587
Eric Andersenc470f442003-07-28 09:56:35 +00006588 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006589 for (i = 1; i < NSIG; i++) {
Rob Landleyc9c1a412006-07-12 19:17:55 +00006590 name = get_signame(i);
6591 if (isdigit(*name))
Eric Andersenc470f442003-07-28 09:56:35 +00006592 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006593 }
6594 return 0;
6595 }
Rob Landleyc9c1a412006-07-12 19:17:55 +00006596 name = get_signame(signo);
6597 if (isdigit(*name))
Eric Andersenc470f442003-07-28 09:56:35 +00006598 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006599 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006600 sh_error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006601 return 0;
6602 }
6603
Eric Andersenc470f442003-07-28 09:56:35 +00006604 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006605 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006606 if (**argv == '%') {
6607 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006608 pid = -jp->ps[0].pid;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006609 } else {
6610 pid = **argv == '-' ?
6611 -number(*argv + 1) : number(*argv);
6612 }
Eric Andersenc470f442003-07-28 09:56:35 +00006613 if (kill(pid, signo) != 0) {
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006614 sh_warnx("(%d) - %m", pid);
Eric Andersenc470f442003-07-28 09:56:35 +00006615 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006616 }
Eric Andersenc470f442003-07-28 09:56:35 +00006617 } while (*++argv);
6618
6619 return i;
6620}
6621#endif /* JOBS */
6622
6623#if defined(JOBS) || defined(DEBUG)
6624static int
6625jobno(const struct job *jp)
6626{
6627 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006628}
6629#endif
6630
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006631#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006632static int
6633fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006634{
Eric Andersenc470f442003-07-28 09:56:35 +00006635 struct job *jp;
6636 FILE *out;
6637 int mode;
6638 int retval;
6639
6640 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6641 nextopt(nullstr);
6642 argv = argptr;
6643 out = stdout;
6644 do {
6645 jp = getjob(*argv, 1);
6646 if (mode == FORK_BG) {
6647 set_curjob(jp, CUR_RUNNING);
6648 fprintf(out, "[%d] ", jobno(jp));
6649 }
6650 outstr(jp->ps->cmd, out);
6651 showpipe(jp, out);
6652 retval = restartjob(jp, mode);
6653 } while (*argv && *++argv);
6654 return retval;
6655}
6656
6657static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6658
6659
6660static int
6661restartjob(struct job *jp, int mode)
6662{
6663 struct procstat *ps;
6664 int i;
6665 int status;
6666 pid_t pgid;
6667
6668 INTOFF;
6669 if (jp->state == JOBDONE)
6670 goto out;
6671 jp->state = JOBRUNNING;
6672 pgid = jp->ps->pid;
6673 if (mode == FORK_FG)
6674 xtcsetpgrp(ttyfd, pgid);
6675 killpg(pgid, SIGCONT);
6676 ps = jp->ps;
6677 i = jp->nprocs;
6678 do {
6679 if (WIFSTOPPED(ps->status)) {
6680 ps->status = -1;
6681 }
6682 } while (ps++, --i);
6683out:
6684 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6685 INTON;
6686 return status;
6687}
6688#endif
6689
6690static int
6691sprint_status(char *s, int status, int sigonly)
6692{
6693 int col;
6694 int st;
6695
6696 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006697 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006698#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006699 if (WIFSTOPPED(status))
6700 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006701 else
Eric Andersenc470f442003-07-28 09:56:35 +00006702#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006703 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006704 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006705 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006706 goto out;
6707#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006708 if (WIFSTOPPED(status))
6709 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006710#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006711 }
6712 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006713 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006714 if (WCOREDUMP(status)) {
6715 col += fmtstr(s + col, 16, " (core dumped)");
6716 }
6717 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006718 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006719 if (st)
6720 col = fmtstr(s, 16, "Done(%d)", st);
6721 else
6722 col = fmtstr(s, 16, "Done");
6723 }
6724
6725out:
6726 return col;
6727}
6728
6729#if JOBS
6730static void
6731showjob(FILE *out, struct job *jp, int mode)
6732{
6733 struct procstat *ps;
6734 struct procstat *psend;
6735 int col;
6736 int indent;
6737 char s[80];
6738
6739 ps = jp->ps;
6740
6741 if (mode & SHOW_PGID) {
6742 /* just output process (group) id of pipeline */
6743 fprintf(out, "%d\n", ps->pid);
6744 return;
6745 }
6746
6747 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6748 indent = col;
6749
6750 if (jp == curjob)
6751 s[col - 2] = '+';
6752 else if (curjob && jp == curjob->prev_job)
6753 s[col - 2] = '-';
6754
6755 if (mode & SHOW_PID)
6756 col += fmtstr(s + col, 16, "%d ", ps->pid);
6757
6758 psend = ps + jp->nprocs;
6759
6760 if (jp->state == JOBRUNNING) {
6761 scopy("Running", s + col);
6762 col += strlen("Running");
6763 } else {
6764 int status = psend[-1].status;
6765#if JOBS
6766 if (jp->state == JOBSTOPPED)
6767 status = jp->stopstatus;
6768#endif
6769 col += sprint_status(s + col, status, 0);
6770 }
6771
6772 goto start;
6773
6774 do {
6775 /* for each process */
6776 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6777
6778start:
Eric Andersen90898442003-08-06 11:20:52 +00006779 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006780 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6781 );
6782 if (!(mode & SHOW_PID)) {
6783 showpipe(jp, out);
6784 break;
6785 }
6786 if (++ps == psend) {
6787 outcslow('\n', out);
6788 break;
6789 }
6790 } while (1);
6791
6792 jp->changed = 0;
6793
6794 if (jp->state == JOBDONE) {
6795 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6796 freejob(jp);
6797 }
6798}
6799
6800
6801static int
6802jobscmd(int argc, char **argv)
6803{
6804 int mode, m;
6805 FILE *out;
6806
6807 mode = 0;
6808 while ((m = nextopt("lp")))
6809 if (m == 'l')
6810 mode = SHOW_PID;
6811 else
6812 mode = SHOW_PGID;
6813
6814 out = stdout;
6815 argv = argptr;
6816 if (*argv)
6817 do
6818 showjob(out, getjob(*argv,0), mode);
6819 while (*++argv);
6820 else
6821 showjobs(out, mode);
6822
Eric Andersencb57d552001-06-28 07:25:16 +00006823 return 0;
6824}
6825
6826
6827/*
6828 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6829 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006830 */
6831
Eric Andersenc470f442003-07-28 09:56:35 +00006832static void
6833showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006834{
Eric Andersencb57d552001-06-28 07:25:16 +00006835 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006836
Eric Andersenc470f442003-07-28 09:56:35 +00006837 TRACE(("showjobs(%x) called\n", mode));
6838
6839 /* If not even one one job changed, there is nothing to do */
6840 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6841 continue;
6842
6843 for (jp = curjob; jp; jp = jp->prev_job) {
6844 if (!(mode & SHOW_CHANGED) || jp->changed)
6845 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006846 }
6847}
Eric Andersenc470f442003-07-28 09:56:35 +00006848#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006849
6850/*
6851 * Mark a job structure as unused.
6852 */
6853
Eric Andersenc470f442003-07-28 09:56:35 +00006854static void
6855freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006856{
Eric Andersenc470f442003-07-28 09:56:35 +00006857 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006858 int i;
6859
6860 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006861 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006862 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006863 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006864 }
6865 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006866 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006867 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006868 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006869 INTON;
6870}
6871
6872
Eric Andersenc470f442003-07-28 09:56:35 +00006873static int
6874waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006875{
6876 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006877 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006878 struct job *jp;
6879
Eric Andersenc470f442003-07-28 09:56:35 +00006880 EXSIGON();
6881
6882 nextopt(nullstr);
6883 retval = 0;
6884
6885 argv = argptr;
6886 if (!*argv) {
6887 /* wait for all jobs */
6888 for (;;) {
6889 jp = curjob;
6890 while (1) {
6891 if (!jp) {
6892 /* no running procs */
6893 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006894 }
Eric Andersenc470f442003-07-28 09:56:35 +00006895 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006896 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006897 jp->waited = 1;
6898 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006899 }
Eric Andersenc470f442003-07-28 09:56:35 +00006900 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006901 }
6902 }
Eric Andersenc470f442003-07-28 09:56:35 +00006903
6904 retval = 127;
6905 do {
6906 if (**argv != '%') {
6907 pid_t pid = number(*argv);
6908 job = curjob;
6909 goto start;
6910 do {
6911 if (job->ps[job->nprocs - 1].pid == pid)
6912 break;
6913 job = job->prev_job;
6914start:
6915 if (!job)
6916 goto repeat;
6917 } while (1);
6918 } else
6919 job = getjob(*argv, 0);
6920 /* loop until process terminated or stopped */
6921 while (job->state == JOBRUNNING)
6922 dowait(DOWAIT_BLOCK, 0);
6923 job->waited = 1;
6924 retval = getstatus(job);
6925repeat:
6926 ;
6927 } while (*++argv);
6928
6929out:
6930 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006931}
6932
6933
Eric Andersencb57d552001-06-28 07:25:16 +00006934/*
6935 * Convert a job name to a job structure.
6936 */
6937
Eric Andersenc470f442003-07-28 09:56:35 +00006938static struct job *
6939getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006940{
Eric Andersencb57d552001-06-28 07:25:16 +00006941 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006942 struct job *found;
6943 const char *err_msg = "No such job: %s";
6944 unsigned num;
6945 int c;
6946 const char *p;
6947 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006948
Eric Andersenc470f442003-07-28 09:56:35 +00006949 jp = curjob;
6950 p = name;
6951 if (!p)
6952 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006953
Eric Andersenc470f442003-07-28 09:56:35 +00006954 if (*p != '%')
6955 goto err;
6956
6957 c = *++p;
6958 if (!c)
6959 goto currentjob;
6960
6961 if (!p[1]) {
6962 if (c == '+' || c == '%') {
6963currentjob:
6964 err_msg = "No current job";
6965 goto check;
6966 } else if (c == '-') {
6967 if (jp)
6968 jp = jp->prev_job;
6969 err_msg = "No previous job";
6970check:
6971 if (!jp)
6972 goto err;
6973 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006974 }
6975 }
Eric Andersenc470f442003-07-28 09:56:35 +00006976
6977 if (is_number(p)) {
6978 num = atoi(p);
6979 if (num < njobs) {
6980 jp = jobtab + num - 1;
6981 if (jp->used)
6982 goto gotit;
6983 goto err;
6984 }
6985 }
6986
6987 match = prefix;
6988 if (*p == '?') {
6989 match = strstr;
6990 p++;
6991 }
6992
6993 found = 0;
6994 while (1) {
6995 if (!jp)
6996 goto err;
6997 if (match(jp->ps[0].cmd, p)) {
6998 if (found)
6999 goto err;
7000 found = jp;
7001 err_msg = "%s: ambiguous";
7002 }
7003 jp = jp->prev_job;
7004 }
7005
7006gotit:
7007#if JOBS
7008 err_msg = "job %s not created under job control";
7009 if (getctl && jp->jobctl == 0)
7010 goto err;
7011#endif
7012 return jp;
7013err:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007014 sh_error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007015}
7016
7017
Eric Andersencb57d552001-06-28 07:25:16 +00007018/*
Eric Andersenc470f442003-07-28 09:56:35 +00007019 * Return a new job structure.
7020 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007021 */
7022
Eric Andersenc470f442003-07-28 09:56:35 +00007023static struct job *
7024makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007025{
7026 int i;
7027 struct job *jp;
7028
Eric Andersenc470f442003-07-28 09:56:35 +00007029 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007030 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007031 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007032 break;
7033 }
7034 if (jp->used == 0)
7035 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007036 if (jp->state != JOBDONE || !jp->waited)
7037 continue;
7038#if JOBS
7039 if (jobctl)
7040 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007041#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007042 freejob(jp);
7043 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007044 }
Eric Andersenc470f442003-07-28 09:56:35 +00007045 memset(jp, 0, sizeof(*jp));
7046#if JOBS
7047 if (jobctl)
7048 jp->jobctl = 1;
7049#endif
7050 jp->prev_job = curjob;
7051 curjob = jp;
7052 jp->used = 1;
7053 jp->ps = &jp->ps0;
7054 if (nprocs > 1) {
7055 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7056 }
7057 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7058 jobno(jp)));
7059 return jp;
7060}
7061
7062static struct job *
7063growjobtab(void)
7064{
7065 size_t len;
7066 ptrdiff_t offset;
7067 struct job *jp, *jq;
7068
7069 len = njobs * sizeof(*jp);
7070 jq = jobtab;
7071 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7072
7073 offset = (char *)jp - (char *)jq;
7074 if (offset) {
7075 /* Relocate pointers */
7076 size_t l = len;
7077
7078 jq = (struct job *)((char *)jq + l);
7079 while (l) {
7080 l -= sizeof(*jp);
7081 jq--;
7082#define joff(p) ((struct job *)((char *)(p) + l))
7083#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007084 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007085 jmove(joff(jp)->ps);
7086 if (joff(jp)->prev_job)
7087 jmove(joff(jp)->prev_job);
7088 }
7089 if (curjob)
7090 jmove(curjob);
7091#undef joff
7092#undef jmove
7093 }
7094
7095 njobs += 4;
7096 jobtab = jp;
7097 jp = (struct job *)((char *)jp + len);
7098 jq = jp + 3;
7099 do {
7100 jq->used = 0;
7101 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007102 return jp;
7103}
7104
7105
7106/*
Eric Andersenc470f442003-07-28 09:56:35 +00007107 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007108 * own process group. Jp is a job structure that the job is to be added to.
7109 * N is the command that will be evaluated by the child. Both jp and n may
7110 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007111 * FORK_FG - Fork off a foreground process.
7112 * FORK_BG - Fork off a background process.
7113 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7114 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007115 *
7116 * When job control is turned off, background processes have their standard
7117 * input redirected to /dev/null (except for the second and later processes
7118 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007119 *
7120 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007121 */
7122
Eric Andersenc470f442003-07-28 09:56:35 +00007123static inline void
7124forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007125{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007126 int oldlvl;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007127
Eric Andersenc470f442003-07-28 09:56:35 +00007128 TRACE(("Child shell %d\n", getpid()));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007129 oldlvl = shlvl;
7130 shlvl++;
Eric Andersenc470f442003-07-28 09:56:35 +00007131
7132 closescript();
7133 clear_traps();
7134#if JOBS
7135 /* do job control only in root shell */
7136 jobctl = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007137 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007138 pid_t pgrp;
7139
7140 if (jp->nprocs == 0)
7141 pgrp = getpid();
7142 else
7143 pgrp = jp->ps[0].pid;
7144 /* This can fail because we are doing it in the parent also */
7145 (void)setpgid(0, pgrp);
7146 if (mode == FORK_FG)
7147 xtcsetpgrp(ttyfd, pgrp);
7148 setsignal(SIGTSTP);
7149 setsignal(SIGTTOU);
7150 } else
Eric Andersen62483552001-07-10 06:09:16 +00007151#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007152 if (mode == FORK_BG) {
7153 ignoresig(SIGINT);
7154 ignoresig(SIGQUIT);
7155 if (jp->nprocs == 0) {
7156 close(0);
Bernhard Reutner-Fischer0a8812b2006-05-19 13:12:21 +00007157 if (open(bb_dev_null, O_RDONLY) != 0)
7158 sh_error("Can't open %s", bb_dev_null);
Eric Andersencb57d552001-06-28 07:25:16 +00007159 }
Eric Andersencb57d552001-06-28 07:25:16 +00007160 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007161 if (!oldlvl && iflag) {
Eric Andersenc470f442003-07-28 09:56:35 +00007162 setsignal(SIGINT);
7163 setsignal(SIGQUIT);
7164 setsignal(SIGTERM);
7165 }
7166 for (jp = curjob; jp; jp = jp->prev_job)
7167 freejob(jp);
7168 jobless = 0;
7169}
7170
7171static inline void
7172forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7173{
7174 TRACE(("In parent shell: child = %d\n", pid));
7175 if (!jp) {
7176 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7177 jobless++;
7178 return;
7179 }
7180#if JOBS
7181 if (mode != FORK_NOJOB && jp->jobctl) {
7182 int pgrp;
7183
7184 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007185 pgrp = pid;
7186 else
7187 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007188 /* This can fail because we are doing it in the child also */
7189 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007190 }
Eric Andersen62483552001-07-10 06:09:16 +00007191#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007192 if (mode == FORK_BG) {
7193 backgndpid = pid; /* set $! */
7194 set_curjob(jp, CUR_RUNNING);
7195 }
Eric Andersencb57d552001-06-28 07:25:16 +00007196 if (jp) {
7197 struct procstat *ps = &jp->ps[jp->nprocs++];
7198 ps->pid = pid;
7199 ps->status = -1;
7200 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007201#if JOBS
7202 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007203 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007204#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007205 }
Eric Andersencb57d552001-06-28 07:25:16 +00007206}
7207
Eric Andersenc470f442003-07-28 09:56:35 +00007208static int
7209forkshell(struct job *jp, union node *n, int mode)
7210{
7211 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007212
Eric Andersenc470f442003-07-28 09:56:35 +00007213 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7214 pid = fork();
7215 if (pid < 0) {
7216 TRACE(("Fork failed, errno=%d", errno));
7217 if (jp)
7218 freejob(jp);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007219 sh_error("Cannot fork");
Eric Andersenc470f442003-07-28 09:56:35 +00007220 }
7221 if (pid == 0)
7222 forkchild(jp, n, mode);
7223 else
7224 forkparent(jp, n, mode, pid);
7225 return pid;
7226}
Eric Andersencb57d552001-06-28 07:25:16 +00007227
7228/*
7229 * Wait for job to finish.
7230 *
7231 * Under job control we have the problem that while a child process is
7232 * running interrupts generated by the user are sent to the child but not
7233 * to the shell. This means that an infinite loop started by an inter-
7234 * active user may be hard to kill. With job control turned off, an
7235 * interactive user may place an interactive program inside a loop. If
7236 * the interactive program catches interrupts, the user doesn't want
7237 * these interrupts to also abort the loop. The approach we take here
7238 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007239 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007240 * signal if the child process was terminated by an interrupt signal.
7241 * Unfortunately, some programs want to do a bit of cleanup and then
7242 * exit on interrupt; unless these processes terminate themselves by
7243 * sending a signal to themselves (instead of calling exit) they will
7244 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007245 *
7246 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007247 */
7248
Eric Andersenc470f442003-07-28 09:56:35 +00007249int
7250waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007251{
Eric Andersencb57d552001-06-28 07:25:16 +00007252 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007253
Eric Andersenc470f442003-07-28 09:56:35 +00007254 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7255 while (jp->state == JOBRUNNING) {
7256 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007257 }
Eric Andersenc470f442003-07-28 09:56:35 +00007258 st = getstatus(jp);
7259#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007260 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007261 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007262 /*
7263 * This is truly gross.
7264 * If we're doing job control, then we did a TIOCSPGRP which
7265 * caused us (the shell) to no longer be in the controlling
7266 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7267 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007268 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007269 */
Eric Andersenc470f442003-07-28 09:56:35 +00007270 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007271 raise(SIGINT);
7272 }
Eric Andersen2870d962001-07-02 17:27:21 +00007273 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007274#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007275 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007276 return st;
7277}
7278
7279
Eric Andersen62483552001-07-10 06:09:16 +00007280/*
7281 * Do a wait system call. If job control is compiled in, we accept
7282 * stopped processes. If block is zero, we return a value of zero
7283 * rather than blocking.
7284 *
7285 * System V doesn't have a non-blocking wait system call. It does
7286 * have a SIGCLD signal that is sent to a process when one of it's
7287 * children dies. The obvious way to use SIGCLD would be to install
7288 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7289 * was received, and have waitproc bump another counter when it got
7290 * the status of a process. Waitproc would then know that a wait
7291 * system call would not block if the two counters were different.
7292 * This approach doesn't work because if a process has children that
7293 * have not been waited for, System V will send it a SIGCLD when it
7294 * installs a signal handler for SIGCLD. What this means is that when
7295 * a child exits, the shell will be sent SIGCLD signals continuously
7296 * until is runs out of stack space, unless it does a wait call before
7297 * restoring the signal handler. The code below takes advantage of
7298 * this (mis)feature by installing a signal handler for SIGCLD and
7299 * then checking to see whether it was called. If there are any
7300 * children to be waited for, it will be.
7301 *
Eric Andersenc470f442003-07-28 09:56:35 +00007302 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7303 * waits at all. In this case, the user will not be informed when
7304 * a background process until the next time she runs a real program
7305 * (as opposed to running a builtin command or just typing return),
7306 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007307 */
7308
Eric Andersenc470f442003-07-28 09:56:35 +00007309static inline int
7310waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007311{
Eric Andersenc470f442003-07-28 09:56:35 +00007312 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007313
Eric Andersenc470f442003-07-28 09:56:35 +00007314#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007315 if (jobctl)
7316 flags |= WUNTRACED;
7317#endif
7318 if (block == 0)
7319 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007320 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007321}
7322
Eric Andersenc470f442003-07-28 09:56:35 +00007323/*
7324 * Wait for a process to terminate.
7325 */
7326
7327static int
7328dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007329{
7330 int pid;
7331 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007332 struct job *jp;
7333 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007334 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007335
7336 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007337 pid = waitproc(block, &status);
7338 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007339 if (pid <= 0)
7340 return pid;
7341 INTOFF;
7342 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007343 for (jp = curjob; jp; jp = jp->prev_job) {
7344 struct procstat *sp;
7345 struct procstat *spend;
7346 if (jp->state == JOBDONE)
7347 continue;
7348 state = JOBDONE;
7349 spend = jp->ps + jp->nprocs;
7350 sp = jp->ps;
7351 do {
7352 if (sp->pid == pid) {
7353 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7354 sp->status = status;
7355 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007356 }
Eric Andersenc470f442003-07-28 09:56:35 +00007357 if (sp->status == -1)
7358 state = JOBRUNNING;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007359#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007360 if (state == JOBRUNNING)
7361 continue;
7362 if (WIFSTOPPED(sp->status)) {
7363 jp->stopstatus = sp->status;
7364 state = JOBSTOPPED;
7365 }
Eric Andersencb57d552001-06-28 07:25:16 +00007366#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007367 } while (++sp < spend);
7368 if (thisjob)
7369 goto gotjob;
7370 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007371#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007372 if (!WIFSTOPPED(status))
7373#endif
7374
7375 jobless--;
7376 goto out;
7377
7378gotjob:
7379 if (state != JOBRUNNING) {
7380 thisjob->changed = 1;
7381
7382 if (thisjob->state != state) {
7383 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7384 thisjob->state = state;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007385#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007386 if (state == JOBSTOPPED) {
7387 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007388 }
Eric Andersenc470f442003-07-28 09:56:35 +00007389#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007390 }
7391 }
Eric Andersencb57d552001-06-28 07:25:16 +00007392
Eric Andersenc470f442003-07-28 09:56:35 +00007393out:
7394 INTON;
7395
7396 if (thisjob && thisjob == job) {
7397 char s[48 + 1];
7398 int len;
7399
7400 len = sprint_status(s, status, 1);
7401 if (len) {
7402 s[len] = '\n';
7403 s[len + 1] = 0;
7404 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007405 }
Eric Andersencb57d552001-06-28 07:25:16 +00007406 }
7407 return pid;
7408}
7409
7410
Eric Andersencb57d552001-06-28 07:25:16 +00007411/*
7412 * return 1 if there are stopped jobs, otherwise 0
7413 */
Eric Andersen90898442003-08-06 11:20:52 +00007414
Eric Andersenc470f442003-07-28 09:56:35 +00007415int
7416stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007417{
Eric Andersencb57d552001-06-28 07:25:16 +00007418 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007419 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007420
Eric Andersenc470f442003-07-28 09:56:35 +00007421 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007422 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007423 goto out;
7424 jp = curjob;
7425 if (jp && jp->state == JOBSTOPPED) {
7426 out2str("You have stopped jobs.\n");
7427 job_warning = 2;
7428 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007429 }
7430
Eric Andersenc470f442003-07-28 09:56:35 +00007431out:
7432 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007433}
7434
7435/*
7436 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007437 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007438 */
7439
Eric Andersenc470f442003-07-28 09:56:35 +00007440#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007441static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007442
Eric Andersenc470f442003-07-28 09:56:35 +00007443static char *
7444commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007445{
Eric Andersenc470f442003-07-28 09:56:35 +00007446 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007447
Eric Andersenc470f442003-07-28 09:56:35 +00007448 STARTSTACKSTR(cmdnextc);
7449 cmdtxt(n);
7450 name = stackblock();
7451 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7452 name, cmdnextc, cmdnextc));
7453 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007454}
7455
Eric Andersenc470f442003-07-28 09:56:35 +00007456static void
7457cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007458{
Eric Andersencb57d552001-06-28 07:25:16 +00007459 union node *np;
7460 struct nodelist *lp;
7461 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007462 char s[2];
7463
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007464 if (!n)
7465 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007466 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007467 default:
7468#if DEBUG
7469 abort();
7470#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007471 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007472 lp = n->npipe.cmdlist;
7473 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007474 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007475 lp = lp->next;
7476 if (!lp)
7477 break;
7478 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007479 }
7480 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007481 case NSEMI:
7482 p = "; ";
7483 goto binop;
7484 case NAND:
7485 p = " && ";
7486 goto binop;
7487 case NOR:
7488 p = " || ";
7489binop:
7490 cmdtxt(n->nbinary.ch1);
7491 cmdputs(p);
7492 n = n->nbinary.ch2;
7493 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007494 case NREDIR:
7495 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007496 n = n->nredir.n;
7497 goto donode;
7498 case NNOT:
7499 cmdputs("!");
7500 n = n->nnot.com;
7501donode:
7502 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007503 break;
7504 case NIF:
7505 cmdputs("if ");
7506 cmdtxt(n->nif.test);
7507 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007508 n = n->nif.ifpart;
7509 if (n->nif.elsepart) {
7510 cmdtxt(n);
7511 cmdputs("; else ");
7512 n = n->nif.elsepart;
7513 }
7514 p = "; fi";
7515 goto dotail;
7516 case NSUBSHELL:
7517 cmdputs("(");
7518 n = n->nredir.n;
7519 p = ")";
7520 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007521 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007522 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007523 goto until;
7524 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007525 p = "until ";
7526until:
7527 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007528 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007529 n = n->nbinary.ch2;
7530 p = "; done";
7531dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007532 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007533dotail:
7534 cmdtxt(n);
7535 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007536 case NFOR:
7537 cmdputs("for ");
7538 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007539 cmdputs(" in ");
7540 cmdlist(n->nfor.args, 1);
7541 n = n->nfor.body;
7542 p = "; done";
7543 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007544 case NDEFUN:
7545 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007546 p = "() { ... }";
7547 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007548 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007549 cmdlist(n->ncmd.args, 1);
7550 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007551 break;
7552 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007553 p = n->narg.text;
7554dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007555 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007556 break;
7557 case NHERE:
7558 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007559 p = "<<...";
7560 goto dotail2;
7561 case NCASE:
7562 cmdputs("case ");
7563 cmdputs(n->ncase.expr->narg.text);
7564 cmdputs(" in ");
7565 for (np = n->ncase.cases; np; np = np->nclist.next) {
7566 cmdtxt(np->nclist.pattern);
7567 cmdputs(") ");
7568 cmdtxt(np->nclist.body);
7569 cmdputs(";; ");
7570 }
7571 p = "esac";
7572 goto dotail2;
7573 case NTO:
7574 p = ">";
7575 goto redir;
7576 case NCLOBBER:
7577 p = ">|";
7578 goto redir;
7579 case NAPPEND:
7580 p = ">>";
7581 goto redir;
7582 case NTOFD:
7583 p = ">&";
7584 goto redir;
7585 case NFROM:
7586 p = "<";
7587 goto redir;
7588 case NFROMFD:
7589 p = "<&";
7590 goto redir;
7591 case NFROMTO:
7592 p = "<>";
7593redir:
7594 s[0] = n->nfile.fd + '0';
7595 s[1] = '\0';
7596 cmdputs(s);
7597 cmdputs(p);
7598 if (n->type == NTOFD || n->type == NFROMFD) {
7599 s[0] = n->ndup.dupfd + '0';
7600 p = s;
7601 goto dotail2;
7602 } else {
7603 n = n->nfile.fname;
7604 goto donode;
7605 }
Eric Andersencb57d552001-06-28 07:25:16 +00007606 }
7607}
Eric Andersencb57d552001-06-28 07:25:16 +00007608
Eric Andersenc470f442003-07-28 09:56:35 +00007609static void
7610cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007611{
Eric Andersenc470f442003-07-28 09:56:35 +00007612 for (; np; np = np->narg.next) {
7613 if (!sep)
7614 cmdputs(spcstr);
7615 cmdtxt(np);
7616 if (sep && np->narg.next)
7617 cmdputs(spcstr);
7618 }
Eric Andersencb57d552001-06-28 07:25:16 +00007619}
7620
Eric Andersenc470f442003-07-28 09:56:35 +00007621static void
7622cmdputs(const char *s)
7623{
7624 const char *p, *str;
7625 char c, cc[2] = " ";
7626 char *nextc;
7627 int subtype = 0;
7628 int quoted = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007629 static const char vstype[VSTYPE + 1][4] = {
7630 "", "}", "-", "+", "?", "=",
7631 "%", "%%", "#", "##"
Eric Andersenc470f442003-07-28 09:56:35 +00007632 };
Eric Andersenc470f442003-07-28 09:56:35 +00007633 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7634 p = s;
7635 while ((c = *p++) != 0) {
7636 str = 0;
7637 switch (c) {
7638 case CTLESC:
7639 c = *p++;
7640 break;
7641 case CTLVAR:
7642 subtype = *p++;
7643 if ((subtype & VSTYPE) == VSLENGTH)
7644 str = "${#";
7645 else
7646 str = "${";
7647 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7648 quoted ^= 1;
7649 c = '"';
7650 } else
7651 goto dostr;
7652 break;
7653 case CTLENDVAR:
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007654 str = "\"}" + !(quoted & 1);
Eric Andersenc470f442003-07-28 09:56:35 +00007655 quoted >>= 1;
7656 subtype = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007657 goto dostr;
Eric Andersenc470f442003-07-28 09:56:35 +00007658 case CTLBACKQ:
7659 str = "$(...)";
7660 goto dostr;
7661 case CTLBACKQ+CTLQUOTE:
7662 str = "\"$(...)\"";
7663 goto dostr;
7664#ifdef CONFIG_ASH_MATH_SUPPORT
7665 case CTLARI:
7666 str = "$((";
7667 goto dostr;
7668 case CTLENDARI:
7669 str = "))";
7670 goto dostr;
7671#endif
7672 case CTLQUOTEMARK:
7673 quoted ^= 1;
7674 c = '"';
7675 break;
7676 case '=':
7677 if (subtype == 0)
7678 break;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007679 if ((subtype & VSTYPE) != VSNORMAL)
7680 quoted <<= 1;
Eric Andersenc470f442003-07-28 09:56:35 +00007681 str = vstype[subtype & VSTYPE];
7682 if (subtype & VSNUL)
7683 c = ':';
7684 else
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007685 goto checkstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007686 break;
7687 case '\'':
7688 case '\\':
7689 case '"':
7690 case '$':
7691 /* These can only happen inside quotes */
7692 cc[0] = c;
7693 str = cc;
7694 c = '\\';
7695 break;
7696 default:
7697 break;
7698 }
7699 USTPUTC(c, nextc);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007700checkstr:
Eric Andersenc470f442003-07-28 09:56:35 +00007701 if (!str)
7702 continue;
7703dostr:
7704 while ((c = *str++)) {
7705 USTPUTC(c, nextc);
7706 }
7707 }
7708 if (quoted & 1) {
7709 USTPUTC('"', nextc);
7710 }
7711 *nextc = 0;
7712 cmdnextc = nextc;
7713}
7714
7715
7716static void
7717showpipe(struct job *jp, FILE *out)
7718{
7719 struct procstat *sp;
7720 struct procstat *spend;
7721
7722 spend = jp->ps + jp->nprocs;
7723 for (sp = jp->ps + 1; sp < spend; sp++)
7724 fprintf(out, " | %s", sp->cmd);
7725 outcslow('\n', out);
7726 flushall();
7727}
7728
7729static void
7730xtcsetpgrp(int fd, pid_t pgrp)
7731{
7732 if (tcsetpgrp(fd, pgrp))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007733 sh_error("Cannot set tty process group (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +00007734}
7735#endif /* JOBS */
7736
7737static int
7738getstatus(struct job *job) {
7739 int status;
7740 int retval;
7741
7742 status = job->ps[job->nprocs - 1].status;
7743 retval = WEXITSTATUS(status);
7744 if (!WIFEXITED(status)) {
7745#if JOBS
7746 retval = WSTOPSIG(status);
7747 if (!WIFSTOPPED(status))
7748#endif
7749 {
7750 /* XXX: limits number of signals */
7751 retval = WTERMSIG(status);
7752#if JOBS
7753 if (retval == SIGINT)
7754 job->sigint = 1;
7755#endif
7756 }
7757 retval += 128;
7758 }
7759 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7760 jobno(job), job->nprocs, status, retval));
7761 return retval;
7762}
7763
Eric Andersend35c5df2002-01-09 15:37:36 +00007764#ifdef CONFIG_ASH_MAIL
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007765/* mail.c */
Eric Andersenec074692001-10-31 11:05:49 +00007766
Eric Andersencb57d552001-06-28 07:25:16 +00007767/*
Eric Andersenc470f442003-07-28 09:56:35 +00007768 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007769 */
7770
Eric Andersencb57d552001-06-28 07:25:16 +00007771#define MAXMBOXES 10
7772
Eric Andersenc470f442003-07-28 09:56:35 +00007773/* times of mailboxes */
7774static time_t mailtime[MAXMBOXES];
7775/* Set if MAIL or MAILPATH is changed. */
7776static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007777
7778
7779
7780/*
Eric Andersenc470f442003-07-28 09:56:35 +00007781 * Print appropriate message(s) if mail has arrived.
7782 * If mail_var_path_changed is set,
7783 * then the value of MAIL has mail_var_path_changed,
7784 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007785 */
7786
Eric Andersenc470f442003-07-28 09:56:35 +00007787static void
7788chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007789{
Eric Andersencb57d552001-06-28 07:25:16 +00007790 const char *mpath;
7791 char *p;
7792 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007793 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007794 struct stackmark smark;
7795 struct stat statb;
7796
Eric Andersencb57d552001-06-28 07:25:16 +00007797 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007798 mpath = mpathset() ? mpathval() : mailval();
7799 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007800 p = padvance(&mpath, nullstr);
7801 if (p == NULL)
7802 break;
7803 if (*p == '\0')
7804 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007805 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007806#ifdef DEBUG
7807 if (q[-1] != '/')
7808 abort();
7809#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007810 q[-1] = '\0'; /* delete trailing '/' */
7811 if (stat(p, &statb) < 0) {
7812 *mtp = 0;
7813 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007814 }
Eric Andersenc470f442003-07-28 09:56:35 +00007815 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7816 fprintf(
7817 stderr, snlfmt,
7818 pathopt ? pathopt : "you have mail"
7819 );
7820 }
7821 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007822 }
Eric Andersenc470f442003-07-28 09:56:35 +00007823 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007824 popstackmark(&smark);
7825}
Eric Andersencb57d552001-06-28 07:25:16 +00007826
Eric Andersenec074692001-10-31 11:05:49 +00007827
Eric Andersenc470f442003-07-28 09:56:35 +00007828static void
7829changemail(const char *val)
7830{
7831 mail_var_path_changed++;
7832}
7833
7834#endif /* CONFIG_ASH_MAIL */
7835
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007836/* main.c */
Eric Andersenc470f442003-07-28 09:56:35 +00007837
Eric Andersencb57d552001-06-28 07:25:16 +00007838
Eric Andersencb57d552001-06-28 07:25:16 +00007839#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007840static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007841extern int etext();
7842#endif
7843
Eric Andersenc470f442003-07-28 09:56:35 +00007844static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007845
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007846static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007847
Eric Andersencb57d552001-06-28 07:25:16 +00007848/*
7849 * Main routine. We initialize things, parse the arguments, execute
7850 * profiles if we're a login shell, and then call cmdloop to execute
7851 * commands. The setjmp call sets up the location to jump to when an
7852 * exception occurs. When an exception occurs the variable "state"
7853 * is used to figure out how far we had gotten.
7854 */
7855
Eric Andersenc470f442003-07-28 09:56:35 +00007856int
7857ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007858{
Eric Andersenc470f442003-07-28 09:56:35 +00007859 char *shinit;
7860 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007861 struct jmploc jmploc;
7862 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007863
Eric Andersenc470f442003-07-28 09:56:35 +00007864#ifdef __GLIBC__
7865 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007866#endif
7867
Eric Andersencb57d552001-06-28 07:25:16 +00007868#if PROFILE
7869 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7870#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007871 state = 0;
7872 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007873 int e;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007874 int s;
Eric Andersenc470f442003-07-28 09:56:35 +00007875
Eric Andersencb57d552001-06-28 07:25:16 +00007876 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007877
7878 e = exception;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007879 if (e == EXERROR)
7880 exitstatus = 2;
7881 s = state;
7882 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00007883 exitshell();
7884
Eric Andersen90898442003-08-06 11:20:52 +00007885 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007886 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007887 }
7888 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007889 FORCEINTON; /* enable interrupts */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007890 if (s == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00007891 goto state1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007892 else if (s == 2)
Eric Andersencb57d552001-06-28 07:25:16 +00007893 goto state2;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007894 else if (s == 3)
Eric Andersencb57d552001-06-28 07:25:16 +00007895 goto state3;
7896 else
7897 goto state4;
7898 }
7899 handler = &jmploc;
7900#ifdef DEBUG
7901 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007902 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007903#endif
7904 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007905
7906#ifdef CONFIG_ASH_RANDOM_SUPPORT
7907 rseed = rootpid + ((time_t)time((time_t *)0));
7908#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007909 init();
7910 setstackmark(&smark);
7911 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007912#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7913 if ( iflag ) {
7914 const char *hp = lookupvar("HISTFILE");
7915
7916 if(hp == NULL ) {
7917 hp = lookupvar("HOME");
7918 if(hp != NULL) {
7919 char *defhp = concat_path_file(hp, ".ash_history");
7920 setvar("HISTFILE", defhp, 0);
7921 free(defhp);
7922 }
7923 }
7924 }
7925#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007926 if (argv[0] && argv[0][0] == '-')
7927 isloginsh = 1;
7928 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007929 state = 1;
7930 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007931state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007932 state = 2;
7933 read_profile(".profile");
7934 }
Eric Andersenc470f442003-07-28 09:56:35 +00007935state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007936 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007937 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007938#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007939 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007940#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007941 iflag
7942 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007943 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007944 read_profile(shinit);
7945 }
Eric Andersencb57d552001-06-28 07:25:16 +00007946 }
Eric Andersenc470f442003-07-28 09:56:35 +00007947state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007948 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007949 if (minusc)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007950 evalstring(minusc, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007951
7952 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007953#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007954 if ( iflag ) {
7955 const char *hp = lookupvar("HISTFILE");
7956
7957 if(hp != NULL )
7958 load_history ( hp );
7959 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007960#endif
Eric Andersen90898442003-08-06 11:20:52 +00007961state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007962 cmdloop(1);
7963 }
7964#if PROFILE
7965 monitor(0);
7966#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007967#if GPROF
7968 {
7969 extern void _mcleanup(void);
7970 _mcleanup();
7971 }
7972#endif
7973 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007974 /* NOTREACHED */
7975}
7976
7977
7978/*
7979 * Read and execute commands. "Top" is nonzero for the top level command
7980 * loop; it turns on prompting if the shell is interactive.
7981 */
7982
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007983static int
Eric Andersenc470f442003-07-28 09:56:35 +00007984cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007985{
7986 union node *n;
7987 struct stackmark smark;
7988 int inter;
7989 int numeof = 0;
7990
7991 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00007992 for (;;) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007993 int skip;
7994
Glenn L McGrath76620622004-01-13 10:19:37 +00007995 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007996#if JOBS
7997 if (jobctl)
7998 showjobs(stderr, SHOW_CHANGED);
7999#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008000 inter = 0;
8001 if (iflag && top) {
8002 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008003#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008004 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008005#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008006 }
8007 n = parsecmd(inter);
8008 /* showtree(n); DEBUG */
8009 if (n == NEOF) {
8010 if (!top || numeof >= 50)
8011 break;
8012 if (!stoppedjobs()) {
8013 if (!Iflag)
8014 break;
8015 out2str("\nUse \"exit\" to leave shell.\n");
8016 }
8017 numeof++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008018 } else if (nflag == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008019 job_warning = (job_warning == 2) ? 1 : 0;
8020 numeof = 0;
8021 evaltree(n, 0);
8022 }
8023 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008024 skip = evalskip;
8025
8026 if (skip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008027 evalskip = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008028 return skip & SKIPEVAL;
Eric Andersencb57d552001-06-28 07:25:16 +00008029 }
8030 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008031
8032 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008033}
8034
8035
Eric Andersencb57d552001-06-28 07:25:16 +00008036/*
8037 * Read /etc/profile or .profile. Return on error.
8038 */
8039
Eric Andersenc470f442003-07-28 09:56:35 +00008040static void
8041read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008042{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008043 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008044
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008045 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008046 return;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008047
8048 skip = cmdloop(0);
Eric Andersencb57d552001-06-28 07:25:16 +00008049 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008050
8051 if (skip)
8052 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00008053}
8054
8055
Eric Andersencb57d552001-06-28 07:25:16 +00008056/*
8057 * Read a file containing shell functions.
8058 */
8059
Eric Andersenc470f442003-07-28 09:56:35 +00008060static void
8061readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008062{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008063 setinputfile(name, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008064 cmdloop(0);
8065 popfile();
8066}
8067
8068
Eric Andersencb57d552001-06-28 07:25:16 +00008069/*
Eric Andersenc470f442003-07-28 09:56:35 +00008070 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008071 * search for the file, which is necessary to find sub-commands.
8072 */
8073
Eric Andersenc470f442003-07-28 09:56:35 +00008074static inline char *
8075find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008076{
8077 char *fullname;
8078 const char *path = pathval();
8079 struct stat statb;
8080
8081 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008082 if (strchr(name, '/'))
8083 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008084
Eric Andersenc470f442003-07-28 09:56:35 +00008085 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008086 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8087 /*
8088 * Don't bother freeing here, since it will
8089 * be freed by the caller.
8090 */
8091 return fullname;
8092 }
8093 stunalloc(fullname);
8094 }
8095
8096 /* not found in the PATH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008097 sh_error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008098 /* NOTREACHED */
8099}
8100
Eric Andersen1e6aba92004-04-12 19:12:13 +00008101static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008102{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008103 struct strlist *sp;
8104 volatile struct shparam saveparam;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008105 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008106
Eric Andersen1e6aba92004-04-12 19:12:13 +00008107 for (sp = cmdenviron; sp; sp = sp->next)
Rob Landleyd921b2e2006-08-03 15:41:12 +00008108 setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008109
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00008110 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008111 char *fullname;
Eric Andersencb57d552001-06-28 07:25:16 +00008112
Eric Andersencb57d552001-06-28 07:25:16 +00008113 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008114
8115 if (argc > 2) {
8116 saveparam = shellparam;
8117 shellparam.malloc = 0;
8118 shellparam.nparam = argc - 2;
8119 shellparam.p = argv + 2;
8120 };
8121
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008122 setinputfile(fullname, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008123 commandname = fullname;
8124 cmdloop(0);
8125 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008126
8127 if (argc > 2) {
8128 freeparam(&shellparam);
8129 shellparam = saveparam;
8130 };
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008131 status = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00008132 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008133 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008134}
8135
8136
Eric Andersenc470f442003-07-28 09:56:35 +00008137static int
8138exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008139{
8140 if (stoppedjobs())
8141 return 0;
8142 if (argc > 1)
8143 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008144 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008145 /* NOTREACHED */
8146}
Eric Andersen62483552001-07-10 06:09:16 +00008147
Paul Fox0b621582005-08-09 19:38:05 +00008148#ifdef CONFIG_ASH_BUILTIN_ECHO
8149static int
8150echocmd(int argc, char **argv)
8151{
8152 return bb_echo(argc, argv);
8153}
8154#endif
Paul Fox6ab03782006-06-08 21:37:26 +00008155
8156#ifdef CONFIG_ASH_BUILTIN_TEST
8157static int
8158testcmd(int argc, char **argv)
8159{
8160 return bb_test(argc, argv);
8161}
8162#endif
8163
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008164/* memalloc.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008165
8166/*
Eric Andersen90898442003-08-06 11:20:52 +00008167 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008168 */
8169
8170static pointer
8171ckrealloc(pointer p, size_t nbytes)
8172{
8173 p = realloc(p, nbytes);
8174 if (p == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008175 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008176 return p;
8177}
8178
Eric Andersen90898442003-08-06 11:20:52 +00008179static pointer
8180ckmalloc(size_t nbytes)
8181{
8182 return ckrealloc(NULL, nbytes);
8183}
Eric Andersenc470f442003-07-28 09:56:35 +00008184
8185/*
8186 * Make a copy of a string in safe storage.
8187 */
8188
8189static char *
8190savestr(const char *s)
8191{
8192 char *p = strdup(s);
8193 if (!p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008194 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008195 return p;
8196}
8197
8198
8199/*
8200 * Parse trees for commands are allocated in lifo order, so we use a stack
8201 * to make this more efficient, and also to avoid all sorts of exception
8202 * handling code to handle interrupts in the middle of a parse.
8203 *
8204 * The size 504 was chosen because the Ultrix malloc handles that size
8205 * well.
8206 */
8207
8208
8209static pointer
8210stalloc(size_t nbytes)
8211{
8212 char *p;
8213 size_t aligned;
8214
8215 aligned = SHELL_ALIGN(nbytes);
8216 if (aligned > stacknleft) {
8217 size_t len;
8218 size_t blocksize;
8219 struct stack_block *sp;
8220
8221 blocksize = aligned;
8222 if (blocksize < MINSIZE)
8223 blocksize = MINSIZE;
8224 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8225 if (len < blocksize)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008226 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008227 INTOFF;
8228 sp = ckmalloc(len);
8229 sp->prev = stackp;
8230 stacknxt = sp->space;
8231 stacknleft = blocksize;
8232 sstrend = stacknxt + blocksize;
8233 stackp = sp;
8234 INTON;
8235 }
8236 p = stacknxt;
8237 stacknxt += aligned;
8238 stacknleft -= aligned;
8239 return p;
8240}
8241
8242
8243void
8244stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008245{
Eric Andersencb57d552001-06-28 07:25:16 +00008246#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008247 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008248 write(2, "stunalloc\n", 10);
8249 abort();
8250 }
8251#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008252 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008253 stacknxt = p;
8254}
8255
8256
Eric Andersenc470f442003-07-28 09:56:35 +00008257void
8258setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008259{
Eric Andersencb57d552001-06-28 07:25:16 +00008260 mark->stackp = stackp;
8261 mark->stacknxt = stacknxt;
8262 mark->stacknleft = stacknleft;
8263 mark->marknext = markp;
8264 markp = mark;
8265}
8266
8267
Eric Andersenc470f442003-07-28 09:56:35 +00008268void
8269popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008270{
Eric Andersencb57d552001-06-28 07:25:16 +00008271 struct stack_block *sp;
8272
8273 INTOFF;
8274 markp = mark->marknext;
8275 while (stackp != mark->stackp) {
8276 sp = stackp;
8277 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008278 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008279 }
8280 stacknxt = mark->stacknxt;
8281 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008282 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008283 INTON;
8284}
8285
8286
8287/*
8288 * When the parser reads in a string, it wants to stick the string on the
8289 * stack and only adjust the stack pointer when it knows how big the
8290 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8291 * of space on top of the stack and stackblocklen returns the length of
8292 * this block. Growstackblock will grow this space by at least one byte,
8293 * possibly moving it (like realloc). Grabstackblock actually allocates the
8294 * part of the block that has been used.
8295 */
8296
Eric Andersenc470f442003-07-28 09:56:35 +00008297void
8298growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008299{
Eric Andersenc470f442003-07-28 09:56:35 +00008300 size_t newlen;
8301
8302 newlen = stacknleft * 2;
8303 if (newlen < stacknleft)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008304 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008305 if (newlen < 128)
8306 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008307
8308 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008309 struct stack_block *oldstackp;
8310 struct stackmark *xmark;
8311 struct stack_block *sp;
8312 struct stack_block *prevstackp;
8313 size_t grosslen;
8314
Eric Andersencb57d552001-06-28 07:25:16 +00008315 INTOFF;
8316 oldstackp = stackp;
8317 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008318 prevstackp = sp->prev;
8319 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8320 sp = ckrealloc((pointer)sp, grosslen);
8321 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008322 stackp = sp;
8323 stacknxt = sp->space;
8324 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008325 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008326
Eric Andersenc470f442003-07-28 09:56:35 +00008327 /*
8328 * Stack marks pointing to the start of the old block
8329 * must be relocated to point to the new block
8330 */
8331 xmark = markp;
8332 while (xmark != NULL && xmark->stackp == oldstackp) {
8333 xmark->stackp = stackp;
8334 xmark->stacknxt = stacknxt;
8335 xmark->stacknleft = stacknleft;
8336 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008337 }
8338 INTON;
8339 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008340 char *oldspace = stacknxt;
8341 int oldlen = stacknleft;
8342 char *p = stalloc(newlen);
8343
8344 /* free the space we just allocated */
8345 stacknxt = memcpy(p, oldspace, oldlen);
8346 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008347 }
8348}
8349
Eric Andersenc470f442003-07-28 09:56:35 +00008350static inline void
8351grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008352{
Eric Andersenc470f442003-07-28 09:56:35 +00008353 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008354 stacknxt += len;
8355 stacknleft -= len;
8356}
8357
Eric Andersencb57d552001-06-28 07:25:16 +00008358/*
Eric Andersenc470f442003-07-28 09:56:35 +00008359 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008360 * The user declares a variable of type STACKSTR, which may be declared
8361 * to be a register. The macro STARTSTACKSTR initializes things. Then
8362 * the user uses the macro STPUTC to add characters to the string. In
8363 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8364 * grown as necessary. When the user is done, she can just leave the
8365 * string there and refer to it using stackblock(). Or she can allocate
8366 * the space for it using grabstackstr(). If it is necessary to allow
8367 * someone else to use the stack temporarily and then continue to grow
8368 * the string, the user should use grabstack to allocate the space, and
8369 * then call ungrabstr(p) to return to the previous mode of operation.
8370 *
8371 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8372 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8373 * is space for at least one character.
8374 */
8375
Eric Andersenc470f442003-07-28 09:56:35 +00008376void *
8377growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008378{
Eric Andersenc470f442003-07-28 09:56:35 +00008379 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008380 if (herefd >= 0 && len >= 1024) {
Rob Landley53437472006-07-16 08:14:35 +00008381 full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008382 return stackblock();
8383 }
8384 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008385 return stackblock() + len;
8386}
8387
Eric Andersencb57d552001-06-28 07:25:16 +00008388/*
8389 * Called from CHECKSTRSPACE.
8390 */
8391
Eric Andersenc470f442003-07-28 09:56:35 +00008392char *
8393makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008394{
Eric Andersenc470f442003-07-28 09:56:35 +00008395 size_t len = p - stacknxt;
8396 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008397
Eric Andersenc470f442003-07-28 09:56:35 +00008398 for (;;) {
8399 size_t nleft;
8400
8401 size = stackblocksize();
8402 nleft = size - len;
8403 if (nleft >= newlen)
8404 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008405 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008406 }
Eric Andersencb57d552001-06-28 07:25:16 +00008407 return stackblock() + len;
8408}
8409
Eric Andersenc470f442003-07-28 09:56:35 +00008410char *
8411stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008412{
Eric Andersenc470f442003-07-28 09:56:35 +00008413 p = makestrspace(n, p);
8414 p = mempcpy(p, s, n);
8415 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008416}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008417
Eric Andersenc470f442003-07-28 09:56:35 +00008418char *
8419stputs(const char *s, char *p)
8420{
8421 return stnputs(s, strlen(s), p);
8422}
8423
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008424/* mystring.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008425
Eric Andersencb57d552001-06-28 07:25:16 +00008426/*
Eric Andersenc470f442003-07-28 09:56:35 +00008427 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008428 *
Eric Andersenc470f442003-07-28 09:56:35 +00008429 * number(s) Convert a string of digits to an integer.
8430 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008431 */
8432
Eric Andersencb57d552001-06-28 07:25:16 +00008433/*
8434 * prefix -- see if pfx is a prefix of string.
8435 */
8436
Eric Andersenc470f442003-07-28 09:56:35 +00008437char *
8438prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008439{
Eric Andersencb57d552001-06-28 07:25:16 +00008440 while (*pfx) {
8441 if (*pfx++ != *string++)
8442 return 0;
8443 }
Eric Andersenc470f442003-07-28 09:56:35 +00008444 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008445}
8446
8447
8448/*
8449 * Convert a string of digits to an integer, printing an error message on
8450 * failure.
8451 */
8452
Eric Andersenc470f442003-07-28 09:56:35 +00008453int
8454number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008455{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008456
Eric Andersenc470f442003-07-28 09:56:35 +00008457 if (! is_number(s))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008458 sh_error(illnum, s);
Eric Andersenc470f442003-07-28 09:56:35 +00008459 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008460}
8461
Eric Andersenc470f442003-07-28 09:56:35 +00008462
Eric Andersenc470f442003-07-28 09:56:35 +00008463/*
8464 * Check for a valid number. This should be elsewhere.
8465 */
8466
8467int
8468is_number(const char *p)
8469{
8470 do {
8471 if (! is_digit(*p))
8472 return 0;
8473 } while (*++p != '\0');
8474 return 1;
8475}
8476
8477
Eric Andersencb57d552001-06-28 07:25:16 +00008478/*
8479 * Produce a possibly single quoted string suitable as input to the shell.
8480 * The return string is allocated on the stack.
8481 */
8482
Eric Andersenc470f442003-07-28 09:56:35 +00008483char *
8484single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008485 char *p;
8486
8487 STARTSTACKSTR(p);
8488
8489 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008490 char *q;
8491 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008492
Eric Andersenc470f442003-07-28 09:56:35 +00008493 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008494
Eric Andersenc470f442003-07-28 09:56:35 +00008495 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008496
Eric Andersenc470f442003-07-28 09:56:35 +00008497 *q++ = '\'';
8498 q = mempcpy(q, s, len);
8499 *q++ = '\'';
8500 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008501
Eric Andersenc470f442003-07-28 09:56:35 +00008502 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008503
Eric Andersenc470f442003-07-28 09:56:35 +00008504 len = strspn(s, "'");
8505 if (!len)
8506 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008507
Eric Andersenc470f442003-07-28 09:56:35 +00008508 q = p = makestrspace(len + 3, p);
8509
8510 *q++ = '"';
8511 q = mempcpy(q, s, len);
8512 *q++ = '"';
8513 s += len;
8514
8515 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008516 } while (*s);
8517
8518 USTPUTC(0, p);
8519
Eric Andersenc470f442003-07-28 09:56:35 +00008520 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008521}
8522
8523/*
Eric Andersenc470f442003-07-28 09:56:35 +00008524 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008525 */
8526
Eric Andersenc470f442003-07-28 09:56:35 +00008527char *
8528sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008529{
Eric Andersenc470f442003-07-28 09:56:35 +00008530 size_t len = strlen(p) + 1;
8531 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008532}
Eric Andersenc470f442003-07-28 09:56:35 +00008533
8534
8535static void
8536calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008537{
Eric Andersenc470f442003-07-28 09:56:35 +00008538 if (n == NULL)
8539 return;
8540 funcblocksize += nodesize[n->type];
8541 switch (n->type) {
8542 case NCMD:
8543 calcsize(n->ncmd.redirect);
8544 calcsize(n->ncmd.args);
8545 calcsize(n->ncmd.assign);
8546 break;
8547 case NPIPE:
8548 sizenodelist(n->npipe.cmdlist);
8549 break;
8550 case NREDIR:
8551 case NBACKGND:
8552 case NSUBSHELL:
8553 calcsize(n->nredir.redirect);
8554 calcsize(n->nredir.n);
8555 break;
8556 case NAND:
8557 case NOR:
8558 case NSEMI:
8559 case NWHILE:
8560 case NUNTIL:
8561 calcsize(n->nbinary.ch2);
8562 calcsize(n->nbinary.ch1);
8563 break;
8564 case NIF:
8565 calcsize(n->nif.elsepart);
8566 calcsize(n->nif.ifpart);
8567 calcsize(n->nif.test);
8568 break;
8569 case NFOR:
8570 funcstringsize += strlen(n->nfor.var) + 1;
8571 calcsize(n->nfor.body);
8572 calcsize(n->nfor.args);
8573 break;
8574 case NCASE:
8575 calcsize(n->ncase.cases);
8576 calcsize(n->ncase.expr);
8577 break;
8578 case NCLIST:
8579 calcsize(n->nclist.body);
8580 calcsize(n->nclist.pattern);
8581 calcsize(n->nclist.next);
8582 break;
8583 case NDEFUN:
8584 case NARG:
8585 sizenodelist(n->narg.backquote);
8586 funcstringsize += strlen(n->narg.text) + 1;
8587 calcsize(n->narg.next);
8588 break;
8589 case NTO:
8590 case NCLOBBER:
8591 case NFROM:
8592 case NFROMTO:
8593 case NAPPEND:
8594 calcsize(n->nfile.fname);
8595 calcsize(n->nfile.next);
8596 break;
8597 case NTOFD:
8598 case NFROMFD:
8599 calcsize(n->ndup.vname);
8600 calcsize(n->ndup.next);
8601 break;
8602 case NHERE:
8603 case NXHERE:
8604 calcsize(n->nhere.doc);
8605 calcsize(n->nhere.next);
8606 break;
8607 case NNOT:
8608 calcsize(n->nnot.com);
8609 break;
8610 };
Eric Andersencb57d552001-06-28 07:25:16 +00008611}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008612
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008613
Eric Andersenc470f442003-07-28 09:56:35 +00008614static void
8615sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008616{
8617 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008618 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008619 calcsize(lp->n);
8620 lp = lp->next;
8621 }
8622}
Eric Andersencb57d552001-06-28 07:25:16 +00008623
8624
Eric Andersenc470f442003-07-28 09:56:35 +00008625static union node *
8626copynode(union node *n)
8627{
8628 union node *new;
8629
8630 if (n == NULL)
8631 return NULL;
8632 new = funcblock;
8633 funcblock = (char *) funcblock + nodesize[n->type];
8634 switch (n->type) {
8635 case NCMD:
8636 new->ncmd.redirect = copynode(n->ncmd.redirect);
8637 new->ncmd.args = copynode(n->ncmd.args);
8638 new->ncmd.assign = copynode(n->ncmd.assign);
8639 break;
8640 case NPIPE:
8641 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8642 new->npipe.backgnd = n->npipe.backgnd;
8643 break;
8644 case NREDIR:
8645 case NBACKGND:
8646 case NSUBSHELL:
8647 new->nredir.redirect = copynode(n->nredir.redirect);
8648 new->nredir.n = copynode(n->nredir.n);
8649 break;
8650 case NAND:
8651 case NOR:
8652 case NSEMI:
8653 case NWHILE:
8654 case NUNTIL:
8655 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8656 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8657 break;
8658 case NIF:
8659 new->nif.elsepart = copynode(n->nif.elsepart);
8660 new->nif.ifpart = copynode(n->nif.ifpart);
8661 new->nif.test = copynode(n->nif.test);
8662 break;
8663 case NFOR:
8664 new->nfor.var = nodesavestr(n->nfor.var);
8665 new->nfor.body = copynode(n->nfor.body);
8666 new->nfor.args = copynode(n->nfor.args);
8667 break;
8668 case NCASE:
8669 new->ncase.cases = copynode(n->ncase.cases);
8670 new->ncase.expr = copynode(n->ncase.expr);
8671 break;
8672 case NCLIST:
8673 new->nclist.body = copynode(n->nclist.body);
8674 new->nclist.pattern = copynode(n->nclist.pattern);
8675 new->nclist.next = copynode(n->nclist.next);
8676 break;
8677 case NDEFUN:
8678 case NARG:
8679 new->narg.backquote = copynodelist(n->narg.backquote);
8680 new->narg.text = nodesavestr(n->narg.text);
8681 new->narg.next = copynode(n->narg.next);
8682 break;
8683 case NTO:
8684 case NCLOBBER:
8685 case NFROM:
8686 case NFROMTO:
8687 case NAPPEND:
8688 new->nfile.fname = copynode(n->nfile.fname);
8689 new->nfile.fd = n->nfile.fd;
8690 new->nfile.next = copynode(n->nfile.next);
8691 break;
8692 case NTOFD:
8693 case NFROMFD:
8694 new->ndup.vname = copynode(n->ndup.vname);
8695 new->ndup.dupfd = n->ndup.dupfd;
8696 new->ndup.fd = n->ndup.fd;
8697 new->ndup.next = copynode(n->ndup.next);
8698 break;
8699 case NHERE:
8700 case NXHERE:
8701 new->nhere.doc = copynode(n->nhere.doc);
8702 new->nhere.fd = n->nhere.fd;
8703 new->nhere.next = copynode(n->nhere.next);
8704 break;
8705 case NNOT:
8706 new->nnot.com = copynode(n->nnot.com);
8707 break;
8708 };
8709 new->type = n->type;
8710 return new;
8711}
8712
8713
8714static struct nodelist *
8715copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008716{
8717 struct nodelist *start;
8718 struct nodelist **lpp;
8719
8720 lpp = &start;
8721 while (lp) {
8722 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008723 funcblock = (char *) funcblock +
8724 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008725 (*lpp)->n = copynode(lp->n);
8726 lp = lp->next;
8727 lpp = &(*lpp)->next;
8728 }
8729 *lpp = NULL;
8730 return start;
8731}
8732
8733
Eric Andersenc470f442003-07-28 09:56:35 +00008734static char *
8735nodesavestr(char *s)
8736{
8737 char *rtn = funcstring;
8738
8739 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008740 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008741}
8742
Eric Andersenc470f442003-07-28 09:56:35 +00008743
Eric Andersenc470f442003-07-28 09:56:35 +00008744/*
8745 * Free a parse tree.
8746 */
8747
8748static void
8749freefunc(struct funcnode *f)
8750{
8751 if (f && --f->count < 0)
8752 ckfree(f);
8753}
8754
8755
8756static void options(int);
8757static void setoption(int, int);
8758
Eric Andersencb57d552001-06-28 07:25:16 +00008759
Eric Andersencb57d552001-06-28 07:25:16 +00008760/*
8761 * Process the shell command line arguments.
8762 */
8763
Eric Andersenc470f442003-07-28 09:56:35 +00008764void
8765procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008766{
8767 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008768 const char *xminusc;
8769 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008770
Eric Andersenc470f442003-07-28 09:56:35 +00008771 xargv = argv;
8772 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008773 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008774 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008775 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008776 optlist[i] = 2;
8777 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008778 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008779 xargv = argptr;
8780 xminusc = minusc;
8781 if (*xargv == NULL) {
8782 if (xminusc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +00008783 sh_error(bb_msg_requires_arg, "-c");
Eric Andersencb57d552001-06-28 07:25:16 +00008784 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008785 }
Eric Andersencb57d552001-06-28 07:25:16 +00008786 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8787 iflag = 1;
8788 if (mflag == 2)
8789 mflag = iflag;
8790 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008791 if (optlist[i] == 2)
8792 optlist[i] = 0;
8793#if DEBUG == 2
8794 debug = 1;
8795#endif
8796 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8797 if (xminusc) {
8798 minusc = *xargv++;
8799 if (*xargv)
8800 goto setarg0;
8801 } else if (!sflag) {
8802 setinputfile(*xargv, 0);
8803setarg0:
8804 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008805 commandname = arg0;
8806 }
Eric Andersencb57d552001-06-28 07:25:16 +00008807
Eric Andersenc470f442003-07-28 09:56:35 +00008808 shellparam.p = xargv;
8809#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008810 shellparam.optind = 1;
8811 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008812#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008813 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008814 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008815 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008816 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008817 }
8818 optschanged();
8819}
8820
8821
Eric Andersenc470f442003-07-28 09:56:35 +00008822void
8823optschanged(void)
8824{
8825#ifdef DEBUG
8826 opentrace();
8827#endif
8828 setinteractive(iflag);
8829 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008830 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008831}
Eric Andersencb57d552001-06-28 07:25:16 +00008832
Eric Andersenc470f442003-07-28 09:56:35 +00008833static inline void
8834minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008835{
8836 int i;
8837
8838 if (name == NULL) {
8839 out1str("Current option settings\n");
8840 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008841 out1fmt("%-16s%s\n", optnames(i),
8842 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008843 } else {
8844 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008845 if (equal(name, optnames(i))) {
8846 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008847 return;
8848 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008849 sh_error("Illegal option -o %s", name);
Eric Andersen62483552001-07-10 06:09:16 +00008850 }
8851}
8852
Eric Andersenc470f442003-07-28 09:56:35 +00008853/*
8854 * Process shell options. The global variable argptr contains a pointer
8855 * to the argument list; we advance it past the options.
8856 */
Eric Andersen62483552001-07-10 06:09:16 +00008857
Eric Andersenc470f442003-07-28 09:56:35 +00008858static void
8859options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008860{
8861 char *p;
8862 int val;
8863 int c;
8864
8865 if (cmdline)
8866 minusc = NULL;
8867 while ((p = *argptr) != NULL) {
8868 argptr++;
8869 if ((c = *p++) == '-') {
8870 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008871 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8872 if (!cmdline) {
8873 /* "-" means turn off -x and -v */
8874 if (p[0] == '\0')
8875 xflag = vflag = 0;
8876 /* "--" means reset params */
8877 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008878 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008879 }
Eric Andersenc470f442003-07-28 09:56:35 +00008880 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008881 }
8882 } else if (c == '+') {
8883 val = 0;
8884 } else {
8885 argptr--;
8886 break;
8887 }
8888 while ((c = *p++) != '\0') {
8889 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008890 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008891 } else if (c == 'o') {
8892 minus_o(*argptr, val);
8893 if (*argptr)
8894 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008895 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008896 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008897 isloginsh = 1;
8898 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008899 } else {
8900 setoption(c, val);
8901 }
8902 }
8903 }
8904}
8905
Eric Andersencb57d552001-06-28 07:25:16 +00008906
Eric Andersenc470f442003-07-28 09:56:35 +00008907static void
8908setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008909{
Eric Andersencb57d552001-06-28 07:25:16 +00008910 int i;
8911
8912 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008913 if (optletters(i) == flag) {
8914 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008915 return;
8916 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008917 sh_error("Illegal option -%c", flag);
Eric Andersencb57d552001-06-28 07:25:16 +00008918 /* NOTREACHED */
8919}
8920
8921
8922
Eric Andersencb57d552001-06-28 07:25:16 +00008923/*
8924 * Set the shell parameters.
8925 */
8926
Eric Andersenc470f442003-07-28 09:56:35 +00008927void
8928setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008929{
Eric Andersencb57d552001-06-28 07:25:16 +00008930 char **newparam;
8931 char **ap;
8932 int nparam;
8933
Eric Andersenc470f442003-07-28 09:56:35 +00008934 for (nparam = 0 ; argv[nparam] ; nparam++);
8935 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008936 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008937 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008938 }
8939 *ap = NULL;
8940 freeparam(&shellparam);
8941 shellparam.malloc = 1;
8942 shellparam.nparam = nparam;
8943 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008944#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008945 shellparam.optind = 1;
8946 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008947#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008948}
8949
8950
8951/*
8952 * Free the list of positional parameters.
8953 */
8954
Eric Andersenc470f442003-07-28 09:56:35 +00008955void
8956freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008957{
Eric Andersencb57d552001-06-28 07:25:16 +00008958 char **ap;
8959
8960 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008961 for (ap = param->p ; *ap ; ap++)
8962 ckfree(*ap);
8963 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008964 }
8965}
8966
8967
8968
8969/*
8970 * The shift builtin command.
8971 */
8972
Eric Andersenc470f442003-07-28 09:56:35 +00008973int
8974shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008975{
8976 int n;
8977 char **ap1, **ap2;
8978
8979 n = 1;
8980 if (argc > 1)
8981 n = number(argv[1]);
8982 if (n > shellparam.nparam)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008983 sh_error("can't shift that many");
Eric Andersencb57d552001-06-28 07:25:16 +00008984 INTOFF;
8985 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008986 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008987 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008988 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008989 }
8990 ap2 = shellparam.p;
8991 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008992#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008993 shellparam.optind = 1;
8994 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008995#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008996 INTON;
8997 return 0;
8998}
8999
9000
9001
9002/*
9003 * The set command builtin.
9004 */
9005
Eric Andersenc470f442003-07-28 09:56:35 +00009006int
9007setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009008{
9009 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009010 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009011 INTOFF;
9012 options(0);
9013 optschanged();
9014 if (*argptr != NULL) {
9015 setparam(argptr);
9016 }
9017 INTON;
9018 return 0;
9019}
9020
9021
Eric Andersenc470f442003-07-28 09:56:35 +00009022#ifdef CONFIG_ASH_GETOPTS
9023static void
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00009024getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009025{
9026 shellparam.optind = number(value);
9027 shellparam.optoff = -1;
9028}
Eric Andersenc470f442003-07-28 09:56:35 +00009029#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009030
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009031#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009032static void change_lc_all(const char *value)
9033{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009034 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009035 setlocale(LC_ALL, value);
9036}
9037
9038static void change_lc_ctype(const char *value)
9039{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009040 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009041 setlocale(LC_CTYPE, value);
9042}
9043
9044#endif
9045
Eric Andersen16767e22004-03-16 05:14:10 +00009046#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009047/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009048static void change_random(const char *value)
9049{
Eric Andersen16767e22004-03-16 05:14:10 +00009050 if(value == NULL) {
9051 /* "get", generate */
9052 char buf[16];
9053
9054 rseed = rseed * 1103515245 + 12345;
9055 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9056 /* set without recursion */
9057 setvar(vrandom.text, buf, VNOFUNC);
9058 vrandom.flags &= ~VNOFUNC;
9059 } else {
9060 /* set/reset */
9061 rseed = strtoul(value, (char **)NULL, 10);
9062 }
Eric Andersenef02f822004-03-11 13:34:24 +00009063}
Eric Andersen16767e22004-03-16 05:14:10 +00009064#endif
9065
Eric Andersenef02f822004-03-11 13:34:24 +00009066
Eric Andersend35c5df2002-01-09 15:37:36 +00009067#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009068static int
Eric Andersenc470f442003-07-28 09:56:35 +00009069getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009070{
9071 char *p, *q;
9072 char c = '?';
9073 int done = 0;
9074 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009075 char s[12];
9076 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009077
Eric Andersena48b0a32003-10-22 10:56:47 +00009078 if(*param_optind < 1)
9079 return 1;
9080 optnext = optfirst + *param_optind - 1;
9081
9082 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009083 p = NULL;
9084 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009085 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009086 if (p == NULL || *p == '\0') {
9087 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009088 p = *optnext;
9089 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009090atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009091 p = NULL;
9092 done = 1;
9093 goto out;
9094 }
9095 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009096 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009097 goto atend;
9098 }
9099
9100 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009101 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009102 if (*q == '\0') {
9103 if (optstr[0] == ':') {
9104 s[0] = c;
9105 s[1] = '\0';
9106 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009107 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009108 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009109 (void) unsetvar("OPTARG");
9110 }
9111 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009112 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009113 }
9114 if (*++q == ':')
9115 q++;
9116 }
9117
9118 if (*++q == ':') {
9119 if (*p == '\0' && (p = *optnext) == NULL) {
9120 if (optstr[0] == ':') {
9121 s[0] = c;
9122 s[1] = '\0';
9123 err |= setvarsafe("OPTARG", s, 0);
9124 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009125 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009126 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009127 (void) unsetvar("OPTARG");
9128 c = '?';
9129 }
Eric Andersenc470f442003-07-28 09:56:35 +00009130 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009131 }
9132
9133 if (p == *optnext)
9134 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009135 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009136 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009137 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009138 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009139
Eric Andersenc470f442003-07-28 09:56:35 +00009140out:
Eric Andersencb57d552001-06-28 07:25:16 +00009141 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009142 *param_optind = optnext - optfirst + 1;
9143 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009144 err |= setvarsafe("OPTIND", s, VNOFUNC);
9145 s[0] = c;
9146 s[1] = '\0';
9147 err |= setvarsafe(optvar, s, 0);
9148 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009149 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009150 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009151 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009152 exraise(EXERROR);
9153 }
9154 return done;
9155}
Eric Andersenc470f442003-07-28 09:56:35 +00009156
9157/*
9158 * The getopts builtin. Shellparam.optnext points to the next argument
9159 * to be processed. Shellparam.optptr points to the next character to
9160 * be processed in the current argument. If shellparam.optnext is NULL,
9161 * then it's the first time getopts has been called.
9162 */
9163
9164int
9165getoptscmd(int argc, char **argv)
9166{
9167 char **optbase;
9168
9169 if (argc < 3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009170 sh_error("Usage: getopts optstring var [arg]");
Eric Andersenc470f442003-07-28 09:56:35 +00009171 else if (argc == 3) {
9172 optbase = shellparam.p;
9173 if (shellparam.optind > shellparam.nparam + 1) {
9174 shellparam.optind = 1;
9175 shellparam.optoff = -1;
9176 }
9177 }
9178 else {
9179 optbase = &argv[3];
9180 if (shellparam.optind > argc - 2) {
9181 shellparam.optind = 1;
9182 shellparam.optoff = -1;
9183 }
9184 }
9185
9186 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9187 &shellparam.optoff);
9188}
9189#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009190
9191/*
9192 * XXX - should get rid of. have all builtins use getopt(3). the
9193 * library getopt must have the BSD extension static variable "optreset"
9194 * otherwise it can't be used within the shell safely.
9195 *
9196 * Standard option processing (a la getopt) for builtin routines. The
9197 * only argument that is passed to nextopt is the option string; the
9198 * other arguments are unnecessary. It return the character, or '\0' on
9199 * end of input.
9200 */
9201
Eric Andersenc470f442003-07-28 09:56:35 +00009202static int
9203nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009204{
Eric Andersencb57d552001-06-28 07:25:16 +00009205 char *p;
9206 const char *q;
9207 char c;
9208
9209 if ((p = optptr) == NULL || *p == '\0') {
9210 p = *argptr;
9211 if (p == NULL || *p != '-' || *++p == '\0')
9212 return '\0';
9213 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009214 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009215 return '\0';
9216 }
9217 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009218 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009219 if (*q == '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009220 sh_error("Illegal option -%c", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009221 if (*++q == ':')
9222 q++;
9223 }
9224 if (*++q == ':') {
9225 if (*p == '\0' && (p = *argptr++) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009226 sh_error("No arg for -%c option", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009227 optionarg = p;
9228 p = NULL;
9229 }
9230 optptr = p;
9231 return c;
9232}
9233
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009234
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009235/* output.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009236
Eric Andersenc470f442003-07-28 09:56:35 +00009237void
9238outstr(const char *p, FILE *file)
9239{
9240 INTOFF;
9241 fputs(p, file);
9242 INTON;
9243}
9244
9245void
9246flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009247{
Eric Andersencb57d552001-06-28 07:25:16 +00009248 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009249 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009250 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009251 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009252}
9253
Eric Andersenc470f442003-07-28 09:56:35 +00009254void
Eric Andersen16767e22004-03-16 05:14:10 +00009255flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009256{
9257 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009258 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009259 INTON;
9260}
9261
9262static void
9263outcslow(int c, FILE *dest)
9264{
9265 INTOFF;
9266 putc(c, dest);
9267 fflush(dest);
9268 INTON;
9269}
9270
9271
9272static int
9273out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009274{
9275 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009276 int r;
9277
9278 INTOFF;
9279 va_start(ap, fmt);
9280 r = vprintf(fmt, ap);
9281 va_end(ap);
9282 INTON;
9283 return r;
9284}
9285
9286
9287int
9288fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9289{
9290 va_list ap;
9291 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009292
Eric Andersencb57d552001-06-28 07:25:16 +00009293 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009294 INTOFF;
9295 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009296 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009297 INTON;
9298 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009299}
9300
Eric Andersenc470f442003-07-28 09:56:35 +00009301
Eric Andersencb57d552001-06-28 07:25:16 +00009302
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009303/* parser.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009304
9305
Eric Andersencb57d552001-06-28 07:25:16 +00009306/*
9307 * Shell command parser.
9308 */
9309
9310#define EOFMARKLEN 79
9311
9312
Eric Andersencb57d552001-06-28 07:25:16 +00009313struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009314 struct heredoc *next; /* next here document in list */
9315 union node *here; /* redirection node */
9316 char *eofmark; /* string indicating end of input */
9317 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009318};
9319
9320
9321
Eric Andersenc470f442003-07-28 09:56:35 +00009322static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009323
9324
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009325static union node *list(int);
9326static union node *andor(void);
9327static union node *pipeline(void);
9328static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009329static union node *simplecmd(void);
9330static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009331static void parsefname(void);
9332static void parseheredoc(void);
9333static char peektoken(void);
9334static int readtoken(void);
9335static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009336static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009337static int noexpand(char *);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00009338static void synexpect(int) ATTRIBUTE_NORETURN;
9339static void synerror(const char *) ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009340static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009341
9342
Eric Andersenc470f442003-07-28 09:56:35 +00009343
Eric Andersenc470f442003-07-28 09:56:35 +00009344
Eric Andersencb57d552001-06-28 07:25:16 +00009345/*
9346 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9347 * valid parse tree indicating a blank line.)
9348 */
9349
Eric Andersenc470f442003-07-28 09:56:35 +00009350union node *
9351parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009352{
9353 int t;
9354
9355 tokpushback = 0;
9356 doprompt = interact;
9357 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009358 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009359 needprompt = 0;
9360 t = readtoken();
9361 if (t == TEOF)
9362 return NEOF;
9363 if (t == TNL)
9364 return NULL;
9365 tokpushback++;
9366 return list(1);
9367}
9368
9369
Eric Andersenc470f442003-07-28 09:56:35 +00009370static union node *
9371list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009372{
9373 union node *n1, *n2, *n3;
9374 int tok;
9375
Eric Andersenc470f442003-07-28 09:56:35 +00009376 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9377 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009378 return NULL;
9379 n1 = NULL;
9380 for (;;) {
9381 n2 = andor();
9382 tok = readtoken();
9383 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009384 if (n2->type == NPIPE) {
9385 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009386 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009387 if (n2->type != NREDIR) {
9388 n3 = stalloc(sizeof(struct nredir));
9389 n3->nredir.n = n2;
9390 n3->nredir.redirect = NULL;
9391 n2 = n3;
9392 }
9393 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009394 }
9395 }
9396 if (n1 == NULL) {
9397 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009398 }
9399 else {
9400 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009401 n3->type = NSEMI;
9402 n3->nbinary.ch1 = n1;
9403 n3->nbinary.ch2 = n2;
9404 n1 = n3;
9405 }
9406 switch (tok) {
9407 case TBACKGND:
9408 case TSEMI:
9409 tok = readtoken();
9410 /* fall through */
9411 case TNL:
9412 if (tok == TNL) {
9413 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009414 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009415 return n1;
9416 } else {
9417 tokpushback++;
9418 }
Eric Andersenc470f442003-07-28 09:56:35 +00009419 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009420 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009421 return n1;
9422 break;
9423 case TEOF:
9424 if (heredoclist)
9425 parseheredoc();
9426 else
Eric Andersenc470f442003-07-28 09:56:35 +00009427 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009428 return n1;
9429 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009430 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009431 synexpect(-1);
9432 tokpushback++;
9433 return n1;
9434 }
9435 }
9436}
9437
9438
9439
Eric Andersenc470f442003-07-28 09:56:35 +00009440static union node *
9441andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009442{
Eric Andersencb57d552001-06-28 07:25:16 +00009443 union node *n1, *n2, *n3;
9444 int t;
9445
Eric Andersencb57d552001-06-28 07:25:16 +00009446 n1 = pipeline();
9447 for (;;) {
9448 if ((t = readtoken()) == TAND) {
9449 t = NAND;
9450 } else if (t == TOR) {
9451 t = NOR;
9452 } else {
9453 tokpushback++;
9454 return n1;
9455 }
Eric Andersenc470f442003-07-28 09:56:35 +00009456 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009457 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009458 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009459 n3->type = t;
9460 n3->nbinary.ch1 = n1;
9461 n3->nbinary.ch2 = n2;
9462 n1 = n3;
9463 }
9464}
9465
9466
9467
Eric Andersenc470f442003-07-28 09:56:35 +00009468static union node *
9469pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009470{
Eric Andersencb57d552001-06-28 07:25:16 +00009471 union node *n1, *n2, *pipenode;
9472 struct nodelist *lp, *prev;
9473 int negate;
9474
9475 negate = 0;
9476 TRACE(("pipeline: entered\n"));
9477 if (readtoken() == TNOT) {
9478 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009479 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009480 } else
9481 tokpushback++;
9482 n1 = command();
9483 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009484 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009485 pipenode->type = NPIPE;
9486 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009487 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009488 pipenode->npipe.cmdlist = lp;
9489 lp->n = n1;
9490 do {
9491 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009492 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9493 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009494 lp->n = command();
9495 prev->next = lp;
9496 } while (readtoken() == TPIPE);
9497 lp->next = NULL;
9498 n1 = pipenode;
9499 }
9500 tokpushback++;
9501 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009502 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009503 n2->type = NNOT;
9504 n2->nnot.com = n1;
9505 return n2;
9506 } else
9507 return n1;
9508}
9509
9510
9511
Eric Andersenc470f442003-07-28 09:56:35 +00009512static union node *
9513command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009514{
Eric Andersencb57d552001-06-28 07:25:16 +00009515 union node *n1, *n2;
9516 union node *ap, **app;
9517 union node *cp, **cpp;
9518 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009519 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009520 int t;
9521
9522 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009523 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009524
Eric Andersencb57d552001-06-28 07:25:16 +00009525 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009526 default:
9527 synexpect(-1);
9528 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009529 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009530 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009531 n1->type = NIF;
9532 n1->nif.test = list(0);
9533 if (readtoken() != TTHEN)
9534 synexpect(TTHEN);
9535 n1->nif.ifpart = list(0);
9536 n2 = n1;
9537 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009538 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009539 n2 = n2->nif.elsepart;
9540 n2->type = NIF;
9541 n2->nif.test = list(0);
9542 if (readtoken() != TTHEN)
9543 synexpect(TTHEN);
9544 n2->nif.ifpart = list(0);
9545 }
9546 if (lasttoken == TELSE)
9547 n2->nif.elsepart = list(0);
9548 else {
9549 n2->nif.elsepart = NULL;
9550 tokpushback++;
9551 }
Eric Andersenc470f442003-07-28 09:56:35 +00009552 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009553 break;
9554 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009555 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009556 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009557 n1 = (union node *)stalloc(sizeof (struct nbinary));
9558 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009559 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009560 if ((got=readtoken()) != TDO) {
9561TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009562 synexpect(TDO);
9563 }
9564 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009565 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009566 break;
9567 }
9568 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009569 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009570 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009571 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009572 n1->type = NFOR;
9573 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009574 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009575 if (readtoken() == TIN) {
9576 app = &ap;
9577 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009578 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009579 n2->type = NARG;
9580 n2->narg.text = wordtext;
9581 n2->narg.backquote = backquotelist;
9582 *app = n2;
9583 app = &n2->narg.next;
9584 }
9585 *app = NULL;
9586 n1->nfor.args = ap;
9587 if (lasttoken != TNL && lasttoken != TSEMI)
9588 synexpect(-1);
9589 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009590 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009591 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009592 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009593 n2->narg.backquote = NULL;
9594 n2->narg.next = NULL;
9595 n1->nfor.args = n2;
9596 /*
9597 * Newline or semicolon here is optional (but note
9598 * that the original Bourne shell only allowed NL).
9599 */
9600 if (lasttoken != TNL && lasttoken != TSEMI)
9601 tokpushback++;
9602 }
Eric Andersenc470f442003-07-28 09:56:35 +00009603 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009604 if (readtoken() != TDO)
9605 synexpect(TDO);
9606 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009607 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009608 break;
9609 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009610 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009611 n1->type = NCASE;
9612 if (readtoken() != TWORD)
9613 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009614 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009615 n2->type = NARG;
9616 n2->narg.text = wordtext;
9617 n2->narg.backquote = backquotelist;
9618 n2->narg.next = NULL;
9619 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009620 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009621 } while (readtoken() == TNL);
9622 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009623 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009624 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009625next_case:
9626 checkkwd = CHKNL | CHKKWD;
9627 t = readtoken();
9628 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009629 if (lasttoken == TLP)
9630 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009631 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009632 cp->type = NCLIST;
9633 app = &cp->nclist.pattern;
9634 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009635 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009636 ap->type = NARG;
9637 ap->narg.text = wordtext;
9638 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009639 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009640 break;
9641 app = &ap->narg.next;
9642 readtoken();
9643 }
9644 ap->narg.next = NULL;
9645 if (lasttoken != TRP)
9646 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009647 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009648
Eric Andersenc470f442003-07-28 09:56:35 +00009649 cpp = &cp->nclist.next;
9650
9651 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009652 if ((t = readtoken()) != TESAC) {
9653 if (t != TENDCASE)
9654 synexpect(TENDCASE);
9655 else
Eric Andersenc470f442003-07-28 09:56:35 +00009656 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009657 }
Eric Andersenc470f442003-07-28 09:56:35 +00009658 }
Eric Andersencb57d552001-06-28 07:25:16 +00009659 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009660 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009661 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009662 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009663 n1->type = NSUBSHELL;
9664 n1->nredir.n = list(0);
9665 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009666 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009667 break;
9668 case TBEGIN:
9669 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009670 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009671 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009672 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009673 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009674 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009675 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009676 }
9677
Eric Andersenc470f442003-07-28 09:56:35 +00009678 if (readtoken() != t)
9679 synexpect(t);
9680
9681redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009682 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009683 checkkwd = CHKKWD | CHKALIAS;
9684 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009685 while (readtoken() == TREDIR) {
9686 *rpp = n2 = redirnode;
9687 rpp = &n2->nfile.next;
9688 parsefname();
9689 }
9690 tokpushback++;
9691 *rpp = NULL;
9692 if (redir) {
9693 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009694 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009695 n2->type = NREDIR;
9696 n2->nredir.n = n1;
9697 n1 = n2;
9698 }
9699 n1->nredir.redirect = redir;
9700 }
9701
9702 return n1;
9703}
9704
9705
Eric Andersenc470f442003-07-28 09:56:35 +00009706static union node *
9707simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009708 union node *args, **app;
9709 union node *n = NULL;
9710 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009711 union node **rpp, *redir;
9712 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009713
9714 args = NULL;
9715 app = &args;
9716 vars = NULL;
9717 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009718 redir = NULL;
9719 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009720
Eric Andersenc470f442003-07-28 09:56:35 +00009721 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009722 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009723 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009724 switch (readtoken()) {
9725 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009726 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009727 n->type = NARG;
9728 n->narg.text = wordtext;
9729 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009730 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009731 *vpp = n;
9732 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009733 } else {
9734 *app = n;
9735 app = &n->narg.next;
9736 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009737 }
9738 break;
9739 case TREDIR:
9740 *rpp = n = redirnode;
9741 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009742 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009743 break;
9744 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009745 if (
9746 args && app == &args->narg.next &&
9747 !vars && !redir
9748 ) {
9749 struct builtincmd *bcmd;
9750 const char *name;
9751
Eric Andersencb57d552001-06-28 07:25:16 +00009752 /* We have a function */
9753 if (readtoken() != TRP)
9754 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009755 name = n->narg.text;
9756 if (
9757 !goodname(name) || (
9758 (bcmd = find_builtin(name)) &&
9759 IS_BUILTIN_SPECIAL(bcmd)
9760 )
9761 )
9762 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009763 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009764 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009765 n->narg.next = command();
9766 return n;
9767 }
9768 /* fall through */
9769 default:
9770 tokpushback++;
9771 goto out;
9772 }
9773 }
Eric Andersenc470f442003-07-28 09:56:35 +00009774out:
Eric Andersencb57d552001-06-28 07:25:16 +00009775 *app = NULL;
9776 *vpp = NULL;
9777 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009778 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009779 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009780 n->ncmd.args = args;
9781 n->ncmd.assign = vars;
9782 n->ncmd.redirect = redir;
9783 return n;
9784}
9785
Eric Andersenc470f442003-07-28 09:56:35 +00009786static union node *
9787makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009788{
Eric Andersencb57d552001-06-28 07:25:16 +00009789 union node *n;
9790
Eric Andersenc470f442003-07-28 09:56:35 +00009791 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009792 n->type = NARG;
9793 n->narg.next = NULL;
9794 n->narg.text = wordtext;
9795 n->narg.backquote = backquotelist;
9796 return n;
9797}
9798
Eric Andersenc470f442003-07-28 09:56:35 +00009799void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009800{
Eric Andersencb57d552001-06-28 07:25:16 +00009801 TRACE(("Fix redir %s %d\n", text, err));
9802 if (!err)
9803 n->ndup.vname = NULL;
9804
9805 if (is_digit(text[0]) && text[1] == '\0')
9806 n->ndup.dupfd = digit_val(text[0]);
9807 else if (text[0] == '-' && text[1] == '\0')
9808 n->ndup.dupfd = -1;
9809 else {
9810
9811 if (err)
9812 synerror("Bad fd number");
9813 else
9814 n->ndup.vname = makename();
9815 }
9816}
9817
9818
Eric Andersenc470f442003-07-28 09:56:35 +00009819static void
9820parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009821{
Eric Andersencb57d552001-06-28 07:25:16 +00009822 union node *n = redirnode;
9823
9824 if (readtoken() != TWORD)
9825 synexpect(-1);
9826 if (n->type == NHERE) {
9827 struct heredoc *here = heredoc;
9828 struct heredoc *p;
9829 int i;
9830
9831 if (quoteflag == 0)
9832 n->type = NXHERE;
9833 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009834 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009835 synerror("Illegal eof marker for << redirection");
9836 rmescapes(wordtext);
9837 here->eofmark = wordtext;
9838 here->next = NULL;
9839 if (heredoclist == NULL)
9840 heredoclist = here;
9841 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009842 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009843 p->next = here;
9844 }
9845 } else if (n->type == NTOFD || n->type == NFROMFD) {
9846 fixredir(n, wordtext, 0);
9847 } else {
9848 n->nfile.fname = makename();
9849 }
9850}
9851
9852
9853/*
9854 * Input any here documents.
9855 */
9856
Eric Andersenc470f442003-07-28 09:56:35 +00009857static void
9858parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009859{
Eric Andersencb57d552001-06-28 07:25:16 +00009860 struct heredoc *here;
9861 union node *n;
9862
Eric Andersenc470f442003-07-28 09:56:35 +00009863 here = heredoclist;
9864 heredoclist = 0;
9865
9866 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009867 if (needprompt) {
9868 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009869 }
Eric Andersenc470f442003-07-28 09:56:35 +00009870 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9871 here->eofmark, here->striptabs);
9872 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009873 n->narg.type = NARG;
9874 n->narg.next = NULL;
9875 n->narg.text = wordtext;
9876 n->narg.backquote = backquotelist;
9877 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009878 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009879 }
9880}
9881
Eric Andersenc470f442003-07-28 09:56:35 +00009882static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009883{
Eric Andersencb57d552001-06-28 07:25:16 +00009884 int t;
9885
9886 t = readtoken();
9887 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009888 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009889}
9890
Eric Andersenc470f442003-07-28 09:56:35 +00009891static int
9892readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009893{
Eric Andersencb57d552001-06-28 07:25:16 +00009894 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009895#ifdef DEBUG
9896 int alreadyseen = tokpushback;
9897#endif
9898
Eric Andersend35c5df2002-01-09 15:37:36 +00009899#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009900top:
Eric Andersen2870d962001-07-02 17:27:21 +00009901#endif
9902
Eric Andersencb57d552001-06-28 07:25:16 +00009903 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009904
Eric Andersenc470f442003-07-28 09:56:35 +00009905 /*
9906 * eat newlines
9907 */
9908 if (checkkwd & CHKNL) {
9909 while (t == TNL) {
9910 parseheredoc();
9911 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009912 }
9913 }
9914
Eric Andersenc470f442003-07-28 09:56:35 +00009915 if (t != TWORD || quoteflag) {
9916 goto out;
9917 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009918
Eric Andersenc470f442003-07-28 09:56:35 +00009919 /*
9920 * check for keywords
9921 */
9922 if (checkkwd & CHKKWD) {
9923 const char *const *pp;
9924
9925 if ((pp = findkwd(wordtext))) {
9926 lasttoken = t = pp - tokname_array;
9927 TRACE(("keyword %s recognized\n", tokname(t)));
9928 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009929 }
Eric Andersenc470f442003-07-28 09:56:35 +00009930 }
9931
9932 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009933#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009934 struct alias *ap;
9935 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009936 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009937 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009938 }
Eric Andersencb57d552001-06-28 07:25:16 +00009939 goto top;
9940 }
Eric Andersen2870d962001-07-02 17:27:21 +00009941#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009942 }
Eric Andersenc470f442003-07-28 09:56:35 +00009943out:
9944 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009945#ifdef DEBUG
9946 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009947 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009948 else
Eric Andersenc470f442003-07-28 09:56:35 +00009949 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009950#endif
9951 return (t);
9952}
9953
9954
9955/*
9956 * Read the next input token.
9957 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009958 * backquotes. We set quoteflag to true if any part of the word was
9959 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009960 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009961 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009962 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009963 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009964 *
9965 * [Change comment: here documents and internal procedures]
9966 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9967 * word parsing code into a separate routine. In this case, readtoken
9968 * doesn't need to have any internal procedures, but parseword does.
9969 * We could also make parseoperator in essence the main routine, and
9970 * have parseword (readtoken1?) handle both words and redirection.]
9971 */
9972
Eric Andersen81fe1232003-07-29 06:38:40 +00009973#define NEW_xxreadtoken
9974#ifdef NEW_xxreadtoken
9975
9976/* singles must be first! */
9977static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9978
9979static const char xxreadtoken_tokens[] = {
9980 TNL, TLP, TRP, /* only single occurrence allowed */
9981 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9982 TEOF, /* corresponds to trailing nul */
9983 TAND, TOR, TENDCASE, /* if double occurrence */
9984};
9985
9986#define xxreadtoken_doubles \
9987 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9988#define xxreadtoken_singles \
9989 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9990
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00009991static int xxreadtoken(void)
Eric Andersen81fe1232003-07-29 06:38:40 +00009992{
9993 int c;
9994
9995 if (tokpushback) {
9996 tokpushback = 0;
9997 return lasttoken;
9998 }
9999 if (needprompt) {
10000 setprompt(2);
Eric Andersen81fe1232003-07-29 06:38:40 +000010001 }
10002 startlinno = plinno;
10003 for (;;) { /* until token or start of word found */
10004 c = pgetc_macro();
10005
10006 if ((c != ' ') && (c != '\t')
10007#ifdef CONFIG_ASH_ALIAS
10008 && (c != PEOA)
10009#endif
10010 ) {
10011 if (c == '#') {
10012 while ((c = pgetc()) != '\n' && c != PEOF);
10013 pungetc();
10014 } else if (c == '\\') {
10015 if (pgetc() != '\n') {
10016 pungetc();
10017 goto READTOKEN1;
10018 }
10019 startlinno = ++plinno;
10020 if (doprompt)
10021 setprompt(2);
10022 } else {
10023 const char *p
10024 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10025
10026 if (c != PEOF) {
10027 if (c == '\n') {
10028 plinno++;
10029 needprompt = doprompt;
10030 }
10031
10032 p = strchr(xxreadtoken_chars, c);
10033 if (p == NULL) {
10034 READTOKEN1:
10035 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10036 }
10037
10038 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10039 if (pgetc() == *p) { /* double occurrence? */
10040 p += xxreadtoken_doubles + 1;
10041 } else {
10042 pungetc();
10043 }
10044 }
10045 }
10046
10047 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10048 }
10049 }
10050 }
10051}
10052
10053
10054#else
Eric Andersen2870d962001-07-02 17:27:21 +000010055#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010056
Eric Andersenc470f442003-07-28 09:56:35 +000010057static int
10058xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010059{
Eric Andersencb57d552001-06-28 07:25:16 +000010060 int c;
10061
10062 if (tokpushback) {
10063 tokpushback = 0;
10064 return lasttoken;
10065 }
10066 if (needprompt) {
10067 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010068 }
10069 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010070 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010071 c = pgetc_macro();
10072 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010073 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010074#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010075 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010076#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010077 continue;
10078 case '#':
10079 while ((c = pgetc()) != '\n' && c != PEOF);
10080 pungetc();
10081 continue;
10082 case '\\':
10083 if (pgetc() == '\n') {
10084 startlinno = ++plinno;
10085 if (doprompt)
10086 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010087 continue;
10088 }
10089 pungetc();
10090 goto breakloop;
10091 case '\n':
10092 plinno++;
10093 needprompt = doprompt;
10094 RETURN(TNL);
10095 case PEOF:
10096 RETURN(TEOF);
10097 case '&':
10098 if (pgetc() == '&')
10099 RETURN(TAND);
10100 pungetc();
10101 RETURN(TBACKGND);
10102 case '|':
10103 if (pgetc() == '|')
10104 RETURN(TOR);
10105 pungetc();
10106 RETURN(TPIPE);
10107 case ';':
10108 if (pgetc() == ';')
10109 RETURN(TENDCASE);
10110 pungetc();
10111 RETURN(TSEMI);
10112 case '(':
10113 RETURN(TLP);
10114 case ')':
10115 RETURN(TRP);
10116 default:
10117 goto breakloop;
10118 }
10119 }
Eric Andersenc470f442003-07-28 09:56:35 +000010120breakloop:
10121 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010122#undef RETURN
10123}
Eric Andersen81fe1232003-07-29 06:38:40 +000010124#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010125
Eric Andersencb57d552001-06-28 07:25:16 +000010126
Eric Andersencb57d552001-06-28 07:25:16 +000010127/*
10128 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10129 * is not NULL, read a here document. In the latter case, eofmark is the
10130 * word which marks the end of the document and striptabs is true if
10131 * leading tabs should be stripped from the document. The argument firstc
10132 * is the first character of the input token or document.
10133 *
10134 * Because C does not have internal subroutines, I have simulated them
10135 * using goto's to implement the subroutine linkage. The following macros
10136 * will run code that appears at the end of readtoken1.
10137 */
10138
Eric Andersen2870d962001-07-02 17:27:21 +000010139#define CHECKEND() {goto checkend; checkend_return:;}
10140#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10141#define PARSESUB() {goto parsesub; parsesub_return:;}
10142#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10143#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10144#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010145
10146static int
Eric Andersenc470f442003-07-28 09:56:35 +000010147readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010148{
Eric Andersencb57d552001-06-28 07:25:16 +000010149 int c = firstc;
10150 char *out;
10151 int len;
10152 char line[EOFMARKLEN + 1];
Eric Andersena68ea1c2006-01-30 22:48:39 +000010153 struct nodelist *bqlist = 0;
10154 int quotef = 0;
10155 int dblquote = 0;
10156 int varnest = 0; /* levels of variables expansion */
10157 int arinest = 0; /* levels of arithmetic expansion */
10158 int parenlevel = 0; /* levels of parens in arithmetic */
10159 int dqvarnest = 0; /* levels of variables expansion within double quotes */
10160 int oldstyle = 0;
10161 int prevsyntax = 0; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010162#if __GNUC__
10163 /* Avoid longjmp clobbering */
10164 (void) &out;
10165 (void) &quotef;
10166 (void) &dblquote;
10167 (void) &varnest;
10168 (void) &arinest;
10169 (void) &parenlevel;
10170 (void) &dqvarnest;
10171 (void) &oldstyle;
10172 (void) &prevsyntax;
10173 (void) &syntax;
10174#endif
10175
10176 startlinno = plinno;
10177 dblquote = 0;
10178 if (syntax == DQSYNTAX)
10179 dblquote = 1;
10180 quotef = 0;
10181 bqlist = NULL;
10182 varnest = 0;
10183 arinest = 0;
10184 parenlevel = 0;
10185 dqvarnest = 0;
10186
10187 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010188 loop: { /* for each line, until end of word */
10189 CHECKEND(); /* set c to PEOF if at end of here document */
10190 for (;;) { /* until end of line or end of word */
10191 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10192 switch(SIT(c, syntax)) {
10193 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010194 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010195 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010196 USTPUTC(c, out);
10197 plinno++;
10198 if (doprompt)
10199 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010200 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010201 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010202 case CWORD:
10203 USTPUTC(c, out);
10204 break;
10205 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010206 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010207 USTPUTC(CTLESC, out);
10208 USTPUTC(c, out);
10209 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010210 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010211 c = pgetc2();
10212 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010213 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010214 USTPUTC('\\', out);
10215 pungetc();
10216 } else if (c == '\n') {
10217 if (doprompt)
10218 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010219 } else {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010220 if (dblquote &&
Eric Andersenc470f442003-07-28 09:56:35 +000010221 c != '\\' && c != '`' &&
10222 c != '$' && (
10223 c != '"' ||
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010224 eofmark != NULL)
Eric Andersenc470f442003-07-28 09:56:35 +000010225 ) {
10226 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010227 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010228 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010229 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010230 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010231 USTPUTC(c, out);
10232 quotef++;
10233 }
10234 break;
10235 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010236 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010237quotemark:
10238 if (eofmark == NULL) {
10239 USTPUTC(CTLQUOTEMARK, out);
10240 }
Eric Andersencb57d552001-06-28 07:25:16 +000010241 break;
10242 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010243 syntax = DQSYNTAX;
10244 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010245 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010246 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010247 if (eofmark != NULL && arinest == 0 &&
10248 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010249 USTPUTC(c, out);
10250 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010251 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010252 syntax = BASESYNTAX;
10253 dblquote = 0;
10254 }
10255 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010256 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010257 }
10258 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010259 case CVAR: /* '$' */
10260 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010261 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010262 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010263 if (varnest > 0) {
10264 varnest--;
10265 if (dqvarnest > 0) {
10266 dqvarnest--;
10267 }
10268 USTPUTC(CTLENDVAR, out);
10269 } else {
10270 USTPUTC(c, out);
10271 }
10272 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010273#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010274 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010275 parenlevel++;
10276 USTPUTC(c, out);
10277 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010278 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010279 if (parenlevel > 0) {
10280 USTPUTC(c, out);
10281 --parenlevel;
10282 } else {
10283 if (pgetc() == ')') {
10284 if (--arinest == 0) {
10285 USTPUTC(CTLENDARI, out);
10286 syntax = prevsyntax;
10287 if (syntax == DQSYNTAX)
10288 dblquote = 1;
10289 else
10290 dblquote = 0;
10291 } else
10292 USTPUTC(')', out);
10293 } else {
10294 /*
10295 * unbalanced parens
10296 * (don't 2nd guess - no error)
10297 */
10298 pungetc();
10299 USTPUTC(')', out);
10300 }
10301 }
10302 break;
10303#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010304 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010305 PARSEBACKQOLD();
10306 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010307 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010308 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010309 case CIGN:
10310 break;
10311 default:
10312 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010313 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010314#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010315 if (c != PEOA)
10316#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010317 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010318
Eric Andersencb57d552001-06-28 07:25:16 +000010319 }
10320 c = pgetc_macro();
10321 }
10322 }
Eric Andersenc470f442003-07-28 09:56:35 +000010323endword:
10324#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010325 if (syntax == ARISYNTAX)
10326 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010327#endif
10328 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010329 synerror("Unterminated quoted string");
10330 if (varnest != 0) {
10331 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010332 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010333 synerror("Missing '}'");
10334 }
10335 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010336 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010337 out = stackblock();
10338 if (eofmark == NULL) {
10339 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010340 && quotef == 0
10341 && len <= 2
10342 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010343 PARSEREDIR();
10344 return lasttoken = TREDIR;
10345 } else {
10346 pungetc();
10347 }
10348 }
10349 quoteflag = quotef;
10350 backquotelist = bqlist;
10351 grabstackblock(len);
10352 wordtext = out;
10353 return lasttoken = TWORD;
10354/* end of readtoken routine */
10355
10356
10357
10358/*
10359 * Check to see whether we are at the end of the here document. When this
10360 * is called, c is set to the first character of the next input line. If
10361 * we are at the end of the here document, this routine sets the c to PEOF.
10362 */
10363
Eric Andersenc470f442003-07-28 09:56:35 +000010364checkend: {
10365 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010366#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010367 if (c == PEOA) {
10368 c = pgetc2();
10369 }
10370#endif
10371 if (striptabs) {
10372 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010373 c = pgetc2();
10374 }
Eric Andersenc470f442003-07-28 09:56:35 +000010375 }
10376 if (c == *eofmark) {
10377 if (pfgets(line, sizeof line) != NULL) {
10378 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010379
Eric Andersenc470f442003-07-28 09:56:35 +000010380 p = line;
10381 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10382 if (*p == '\n' && *q == '\0') {
10383 c = PEOF;
10384 plinno++;
10385 needprompt = doprompt;
10386 } else {
10387 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010388 }
10389 }
10390 }
10391 }
Eric Andersenc470f442003-07-28 09:56:35 +000010392 goto checkend_return;
10393}
Eric Andersencb57d552001-06-28 07:25:16 +000010394
10395
10396/*
10397 * Parse a redirection operator. The variable "out" points to a string
10398 * specifying the fd to be redirected. The variable "c" contains the
10399 * first character of the redirection operator.
10400 */
10401
Eric Andersenc470f442003-07-28 09:56:35 +000010402parseredir: {
10403 char fd = *out;
10404 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010405
Eric Andersenc470f442003-07-28 09:56:35 +000010406 np = (union node *)stalloc(sizeof (struct nfile));
10407 if (c == '>') {
10408 np->nfile.fd = 1;
10409 c = pgetc();
10410 if (c == '>')
10411 np->type = NAPPEND;
10412 else if (c == '|')
10413 np->type = NCLOBBER;
10414 else if (c == '&')
10415 np->type = NTOFD;
10416 else {
10417 np->type = NTO;
10418 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010419 }
Eric Andersenc470f442003-07-28 09:56:35 +000010420 } else { /* c == '<' */
10421 np->nfile.fd = 0;
10422 switch (c = pgetc()) {
10423 case '<':
10424 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10425 np = (union node *)stalloc(sizeof (struct nhere));
10426 np->nfile.fd = 0;
10427 }
10428 np->type = NHERE;
10429 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10430 heredoc->here = np;
10431 if ((c = pgetc()) == '-') {
10432 heredoc->striptabs = 1;
10433 } else {
10434 heredoc->striptabs = 0;
10435 pungetc();
10436 }
10437 break;
10438
10439 case '&':
10440 np->type = NFROMFD;
10441 break;
10442
10443 case '>':
10444 np->type = NFROMTO;
10445 break;
10446
10447 default:
10448 np->type = NFROM;
10449 pungetc();
10450 break;
10451 }
Eric Andersencb57d552001-06-28 07:25:16 +000010452 }
Eric Andersenc470f442003-07-28 09:56:35 +000010453 if (fd != '\0')
10454 np->nfile.fd = digit_val(fd);
10455 redirnode = np;
10456 goto parseredir_return;
10457}
Eric Andersencb57d552001-06-28 07:25:16 +000010458
10459
10460/*
10461 * Parse a substitution. At this point, we have read the dollar sign
10462 * and nothing else.
10463 */
10464
Eric Andersenc470f442003-07-28 09:56:35 +000010465parsesub: {
10466 int subtype;
10467 int typeloc;
10468 int flags;
10469 char *p;
10470 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010471
Eric Andersenc470f442003-07-28 09:56:35 +000010472 c = pgetc();
10473 if (
10474 c <= PEOA_OR_PEOF ||
10475 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10476 ) {
10477 USTPUTC('$', out);
10478 pungetc();
10479 } else if (c == '(') { /* $(command) or $((arith)) */
10480 if (pgetc() == '(') {
10481#ifdef CONFIG_ASH_MATH_SUPPORT
10482 PARSEARITH();
10483#else
10484 synerror("We unsupport $((arith))");
10485#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010486 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010487 pungetc();
10488 PARSEBACKQNEW();
10489 }
10490 } else {
10491 USTPUTC(CTLVAR, out);
10492 typeloc = out - (char *)stackblock();
10493 USTPUTC(VSNORMAL, out);
10494 subtype = VSNORMAL;
10495 if (c == '{') {
10496 c = pgetc();
10497 if (c == '#') {
10498 if ((c = pgetc()) == '}')
10499 c = '#';
10500 else
10501 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010502 }
Eric Andersenc470f442003-07-28 09:56:35 +000010503 else
10504 subtype = 0;
10505 }
10506 if (c > PEOA_OR_PEOF && is_name(c)) {
10507 do {
10508 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010509 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010510 } while (c > PEOA_OR_PEOF && is_in_name(c));
10511 } else if (is_digit(c)) {
10512 do {
10513 STPUTC(c, out);
10514 c = pgetc();
10515 } while (is_digit(c));
10516 }
10517 else if (is_special(c)) {
10518 USTPUTC(c, out);
10519 c = pgetc();
10520 }
10521 else
10522badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010523
Eric Andersenc470f442003-07-28 09:56:35 +000010524 STPUTC('=', out);
10525 flags = 0;
10526 if (subtype == 0) {
10527 switch (c) {
10528 case ':':
10529 flags = VSNUL;
10530 c = pgetc();
10531 /*FALLTHROUGH*/
10532 default:
10533 p = strchr(types, c);
10534 if (p == NULL)
10535 goto badsub;
10536 subtype = p - types + VSNORMAL;
10537 break;
10538 case '%':
10539 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010540 {
10541 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010542 subtype = c == '#' ? VSTRIMLEFT :
10543 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010544 c = pgetc();
10545 if (c == cc)
10546 subtype++;
10547 else
10548 pungetc();
10549 break;
10550 }
10551 }
Eric Andersenc470f442003-07-28 09:56:35 +000010552 } else {
10553 pungetc();
10554 }
10555 if (dblquote || arinest)
10556 flags |= VSQUOTE;
10557 *((char *)stackblock() + typeloc) = subtype | flags;
10558 if (subtype != VSNORMAL) {
10559 varnest++;
10560 if (dblquote || arinest) {
10561 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010562 }
10563 }
10564 }
Eric Andersenc470f442003-07-28 09:56:35 +000010565 goto parsesub_return;
10566}
Eric Andersencb57d552001-06-28 07:25:16 +000010567
10568
10569/*
10570 * Called to parse command substitutions. Newstyle is set if the command
10571 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10572 * list of commands (passed by reference), and savelen is the number of
10573 * characters on the top of the stack which must be preserved.
10574 */
10575
Eric Andersenc470f442003-07-28 09:56:35 +000010576parsebackq: {
10577 struct nodelist **nlpp;
10578 int savepbq;
10579 union node *n;
10580 char *volatile str;
10581 struct jmploc jmploc;
10582 struct jmploc *volatile savehandler;
10583 size_t savelen;
Eric Andersena68ea1c2006-01-30 22:48:39 +000010584 int saveprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010585#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010586 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010587#endif
10588
Eric Andersenc470f442003-07-28 09:56:35 +000010589 savepbq = parsebackquote;
10590 if (setjmp(jmploc.loc)) {
10591 if (str)
10592 ckfree(str);
10593 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010594 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010595 longjmp(handler->loc, 1);
10596 }
10597 INTOFF;
10598 str = NULL;
10599 savelen = out - (char *)stackblock();
10600 if (savelen > 0) {
10601 str = ckmalloc(savelen);
10602 memcpy(str, stackblock(), savelen);
10603 }
10604 savehandler = handler;
10605 handler = &jmploc;
10606 INTON;
10607 if (oldstyle) {
10608 /* We must read until the closing backquote, giving special
10609 treatment to some slashes, and then push the string and
10610 reread it as input, interpreting it normally. */
10611 char *pout;
10612 int pc;
10613 size_t psavelen;
10614 char *pstr;
10615
10616
10617 STARTSTACKSTR(pout);
10618 for (;;) {
10619 if (needprompt) {
10620 setprompt(2);
Eric Andersenc470f442003-07-28 09:56:35 +000010621 }
10622 switch (pc = pgetc()) {
10623 case '`':
10624 goto done;
10625
10626 case '\\':
10627 if ((pc = pgetc()) == '\n') {
10628 plinno++;
10629 if (doprompt)
10630 setprompt(2);
10631 /*
10632 * If eating a newline, avoid putting
10633 * the newline into the new character
10634 * stream (via the STPUTC after the
10635 * switch).
10636 */
10637 continue;
10638 }
10639 if (pc != '\\' && pc != '`' && pc != '$'
10640 && (!dblquote || pc != '"'))
10641 STPUTC('\\', pout);
10642 if (pc > PEOA_OR_PEOF) {
10643 break;
10644 }
10645 /* fall through */
10646
10647 case PEOF:
10648#ifdef CONFIG_ASH_ALIAS
10649 case PEOA:
10650#endif
10651 startlinno = plinno;
10652 synerror("EOF in backquote substitution");
10653
10654 case '\n':
10655 plinno++;
10656 needprompt = doprompt;
10657 break;
10658
10659 default:
10660 break;
10661 }
10662 STPUTC(pc, pout);
10663 }
10664done:
10665 STPUTC('\0', pout);
10666 psavelen = pout - (char *)stackblock();
10667 if (psavelen > 0) {
10668 pstr = grabstackstr(pout);
10669 setinputstring(pstr);
10670 }
10671 }
10672 nlpp = &bqlist;
10673 while (*nlpp)
10674 nlpp = &(*nlpp)->next;
10675 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10676 (*nlpp)->next = NULL;
10677 parsebackquote = oldstyle;
10678
10679 if (oldstyle) {
10680 saveprompt = doprompt;
10681 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010682 }
10683
Eric Andersenc470f442003-07-28 09:56:35 +000010684 n = list(2);
10685
10686 if (oldstyle)
10687 doprompt = saveprompt;
10688 else {
10689 if (readtoken() != TRP)
10690 synexpect(TRP);
10691 }
10692
10693 (*nlpp)->n = n;
10694 if (oldstyle) {
10695 /*
10696 * Start reading from old file again, ignoring any pushed back
10697 * tokens left from the backquote parsing
10698 */
10699 popfile();
10700 tokpushback = 0;
10701 }
10702 while (stackblocksize() <= savelen)
10703 growstackblock();
10704 STARTSTACKSTR(out);
10705 if (str) {
10706 memcpy(out, str, savelen);
10707 STADJUST(savelen, out);
10708 INTOFF;
10709 ckfree(str);
10710 str = NULL;
10711 INTON;
10712 }
10713 parsebackquote = savepbq;
10714 handler = savehandler;
10715 if (arinest || dblquote)
10716 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10717 else
10718 USTPUTC(CTLBACKQ, out);
10719 if (oldstyle)
10720 goto parsebackq_oldreturn;
10721 else
10722 goto parsebackq_newreturn;
10723}
10724
10725#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010726/*
10727 * Parse an arithmetic expansion (indicate start of one and set state)
10728 */
Eric Andersenc470f442003-07-28 09:56:35 +000010729parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010730
Eric Andersenc470f442003-07-28 09:56:35 +000010731 if (++arinest == 1) {
10732 prevsyntax = syntax;
10733 syntax = ARISYNTAX;
10734 USTPUTC(CTLARI, out);
10735 if (dblquote)
10736 USTPUTC('"',out);
10737 else
10738 USTPUTC(' ',out);
10739 } else {
10740 /*
10741 * we collapse embedded arithmetic expansion to
10742 * parenthesis, which should be equivalent
10743 */
10744 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010745 }
Eric Andersenc470f442003-07-28 09:56:35 +000010746 goto parsearith_return;
10747}
10748#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010749
Eric Andersenc470f442003-07-28 09:56:35 +000010750} /* end of readtoken */
10751
Eric Andersencb57d552001-06-28 07:25:16 +000010752
10753
Eric Andersencb57d552001-06-28 07:25:16 +000010754/*
10755 * Returns true if the text contains nothing to expand (no dollar signs
10756 * or backquotes).
10757 */
10758
Eric Andersenc470f442003-07-28 09:56:35 +000010759static int
10760noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010761{
Eric Andersencb57d552001-06-28 07:25:16 +000010762 char *p;
10763 char c;
10764
10765 p = text;
10766 while ((c = *p++) != '\0') {
10767 if (c == CTLQUOTEMARK)
10768 continue;
10769 if (c == CTLESC)
10770 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010771 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010772 return 0;
10773 }
10774 return 1;
10775}
10776
10777
10778/*
Eric Andersenc470f442003-07-28 09:56:35 +000010779 * Return of a legal variable name (a letter or underscore followed by zero or
10780 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010781 */
10782
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010783static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010784endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010785{
Eric Andersenc470f442003-07-28 09:56:35 +000010786 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010787
Eric Andersenc470f442003-07-28 09:56:35 +000010788 p = (char *) name;
10789 if (! is_name(*p))
10790 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010791 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010792 if (! is_in_name(*p))
10793 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010794 }
Eric Andersenc470f442003-07-28 09:56:35 +000010795 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010796}
10797
10798
10799/*
10800 * Called when an unexpected token is read during the parse. The argument
10801 * is the token that is expected, or -1 if more than one type of token can
10802 * occur at this point.
10803 */
10804
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010805static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010806{
10807 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010808 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010809
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010810 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10811 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010812 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010813 synerror(msg);
10814 /* NOTREACHED */
10815}
10816
Eric Andersenc470f442003-07-28 09:56:35 +000010817static void
10818synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010819{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010820 sh_error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010821 /* NOTREACHED */
10822}
10823
Eric Andersencb57d552001-06-28 07:25:16 +000010824
10825/*
10826 * called by editline -- any expansions to the prompt
10827 * should be added here.
10828 */
Eric Andersenc470f442003-07-28 09:56:35 +000010829
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010830#ifdef CONFIG_ASH_EXPAND_PRMT
10831static const char *
10832expandstr(const char *ps)
10833{
10834 union node n;
10835
10836 /* XXX Fix (char *) cast. */
10837 setinputstring((char *)ps);
10838 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10839 popfile();
10840
10841 n.narg.type = NARG;
10842 n.narg.next = NULL;
10843 n.narg.text = wordtext;
10844 n.narg.backquote = backquotelist;
10845
10846 expandarg(&n, NULL, 0);
10847 return stackblock();
10848}
10849#endif
10850
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010851static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010852{
Eric Andersenc470f442003-07-28 09:56:35 +000010853 const char *prompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010854#ifdef CONFIG_ASH_EXPAND_PRMT
10855 struct stackmark smark;
10856#endif
10857
10858 needprompt = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010859
10860 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010861 case 1:
10862 prompt = ps1val();
10863 break;
10864 case 2:
10865 prompt = ps2val();
10866 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010867 default: /* 0 */
10868 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010869 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010870#ifdef CONFIG_ASH_EXPAND_PRMT
10871 setstackmark(&smark);
10872 stalloc(stackblocksize());
10873#endif
10874 putprompt(expandstr(prompt));
10875#ifdef CONFIG_ASH_EXPAND_PRMT
10876 popstackmark(&smark);
10877#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010878}
10879
Eric Andersencb57d552001-06-28 07:25:16 +000010880
Eric Andersenc470f442003-07-28 09:56:35 +000010881static const char *const *findkwd(const char *s)
10882{
10883 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010884 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010885 sizeof(const char *), pstrcmp);
10886}
10887
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010888/* redir.c */
Eric Andersenc470f442003-07-28 09:56:35 +000010889
Eric Andersencb57d552001-06-28 07:25:16 +000010890/*
10891 * Code for dealing with input/output redirection.
10892 */
10893
Eric Andersenc470f442003-07-28 09:56:35 +000010894#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010895#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010896# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010897#else
10898# define PIPESIZE PIPE_BUF
10899#endif
10900
Eric Andersen62483552001-07-10 06:09:16 +000010901/*
10902 * Open a file in noclobber mode.
10903 * The code was copied from bash.
10904 */
Eric Andersenc470f442003-07-28 09:56:35 +000010905static inline int
10906noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010907{
10908 int r, fd;
10909 struct stat finfo, finfo2;
10910
10911 /*
10912 * If the file exists and is a regular file, return an error
10913 * immediately.
10914 */
10915 r = stat(fname, &finfo);
10916 if (r == 0 && S_ISREG(finfo.st_mode)) {
10917 errno = EEXIST;
10918 return -1;
10919 }
10920
10921 /*
10922 * If the file was not present (r != 0), make sure we open it
10923 * exclusively so that if it is created before we open it, our open
10924 * will fail. Make sure that we do not truncate an existing file.
10925 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10926 * file was not a regular file, we leave O_EXCL off.
10927 */
10928 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010929 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10930 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010931
10932 /* If the open failed, return the file descriptor right away. */
10933 if (fd < 0)
10934 return fd;
10935
10936 /*
10937 * OK, the open succeeded, but the file may have been changed from a
10938 * non-regular file to a regular file between the stat and the open.
10939 * We are assuming that the O_EXCL open handles the case where FILENAME
10940 * did not exist and is symlinked to an existing file between the stat
10941 * and open.
10942 */
10943
10944 /*
10945 * If we can open it and fstat the file descriptor, and neither check
10946 * revealed that it was a regular file, and the file has not been
10947 * replaced, return the file descriptor.
10948 */
Eric Andersenc470f442003-07-28 09:56:35 +000010949 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10950 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010951 return fd;
10952
10953 /* The file has been replaced. badness. */
10954 close(fd);
10955 errno = EEXIST;
10956 return -1;
10957}
Eric Andersencb57d552001-06-28 07:25:16 +000010958
10959/*
Eric Andersen62483552001-07-10 06:09:16 +000010960 * Handle here documents. Normally we fork off a process to write the
10961 * data to a pipe. If the document is short, we can stuff the data in
10962 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010963 */
10964
Eric Andersenc470f442003-07-28 09:56:35 +000010965static inline int
10966openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010967{
10968 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010969 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010970
Eric Andersen62483552001-07-10 06:09:16 +000010971 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010972 sh_error("Pipe call failed");
Eric Andersen62483552001-07-10 06:09:16 +000010973 if (redir->type == NHERE) {
10974 len = strlen(redir->nhere.doc->narg.text);
10975 if (len <= PIPESIZE) {
Rob Landley53437472006-07-16 08:14:35 +000010976 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010977 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010978 }
Eric Andersencb57d552001-06-28 07:25:16 +000010979 }
Eric Andersenc470f442003-07-28 09:56:35 +000010980 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010981 close(pip[0]);
10982 signal(SIGINT, SIG_IGN);
10983 signal(SIGQUIT, SIG_IGN);
10984 signal(SIGHUP, SIG_IGN);
10985#ifdef SIGTSTP
10986 signal(SIGTSTP, SIG_IGN);
10987#endif
10988 signal(SIGPIPE, SIG_DFL);
10989 if (redir->type == NHERE)
Rob Landley53437472006-07-16 08:14:35 +000010990 full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010991 else
10992 expandhere(redir->nhere.doc, pip[1]);
10993 _exit(0);
10994 }
Eric Andersenc470f442003-07-28 09:56:35 +000010995out:
Eric Andersen62483552001-07-10 06:09:16 +000010996 close(pip[1]);
10997 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010998}
10999
Eric Andersenc470f442003-07-28 09:56:35 +000011000static int
11001openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011002{
Eric Andersencb57d552001-06-28 07:25:16 +000011003 char *fname;
11004 int f;
11005
11006 switch (redir->nfile.type) {
11007 case NFROM:
11008 fname = redir->nfile.expfname;
11009 if ((f = open(fname, O_RDONLY)) < 0)
11010 goto eopen;
11011 break;
11012 case NFROMTO:
11013 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011014 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011015 goto ecreate;
11016 break;
11017 case NTO:
11018 /* Take care of noclobber mode. */
11019 if (Cflag) {
11020 fname = redir->nfile.expfname;
11021 if ((f = noclobberopen(fname)) < 0)
11022 goto ecreate;
11023 break;
11024 }
Eric Andersenc470f442003-07-28 09:56:35 +000011025 /* FALLTHROUGH */
11026 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011027 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011028 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011029 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011030 break;
11031 case NAPPEND:
11032 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011033 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011034 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011035 break;
11036 default:
11037#ifdef DEBUG
11038 abort();
11039#endif
11040 /* Fall through to eliminate warning. */
11041 case NTOFD:
11042 case NFROMFD:
11043 f = -1;
11044 break;
11045 case NHERE:
11046 case NXHERE:
11047 f = openhere(redir);
11048 break;
11049 }
11050
11051 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011052ecreate:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011053 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011054eopen:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011055 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
Eric Andersencb57d552001-06-28 07:25:16 +000011056}
11057
Eric Andersenc470f442003-07-28 09:56:35 +000011058static inline void
11059dupredirect(union node *redir, int f)
11060{
11061 int fd = redir->nfile.fd;
11062
11063 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11064 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11065 copyfd(redir->ndup.dupfd, fd);
11066 }
11067 return;
11068 }
11069
11070 if (f != fd) {
11071 copyfd(f, fd);
11072 close(f);
11073 }
11074 return;
11075}
Eric Andersencb57d552001-06-28 07:25:16 +000011076
Eric Andersen62483552001-07-10 06:09:16 +000011077/*
11078 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11079 * old file descriptors are stashed away so that the redirection can be
11080 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11081 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011082 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011083 */
11084
Eric Andersenc470f442003-07-28 09:56:35 +000011085static void
11086redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011087{
11088 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011089 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011090 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011091 int fd;
11092 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011093 int *p;
11094 nullredirs++;
11095 if (!redir) {
11096 return;
Eric Andersen62483552001-07-10 06:09:16 +000011097 }
Eric Andersenc470f442003-07-28 09:56:35 +000011098 sv = NULL;
11099 INTOFF;
11100 if (flags & REDIR_PUSH) {
11101 struct redirtab *q;
11102 q = ckmalloc(sizeof (struct redirtab));
11103 q->next = redirlist;
11104 redirlist = q;
11105 q->nullredirs = nullredirs - 1;
11106 for (i = 0 ; i < 10 ; i++)
11107 q->renamed[i] = EMPTY;
11108 nullredirs = 0;
11109 sv = q;
11110 }
11111 n = redir;
11112 do {
Eric Andersen62483552001-07-10 06:09:16 +000011113 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011114 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011115 n->ndup.dupfd == fd)
11116 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011117
Eric Andersen62483552001-07-10 06:09:16 +000011118 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011119 if (fd == newfd)
11120 continue;
11121 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11122 i = fcntl(fd, F_DUPFD, 10);
11123
11124 if (i == -1) {
11125 i = errno;
11126 if (i != EBADF) {
11127 close(newfd);
11128 errno = i;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011129 sh_error("%d: %m", fd);
Eric Andersen62483552001-07-10 06:09:16 +000011130 /* NOTREACHED */
11131 }
Eric Andersenc470f442003-07-28 09:56:35 +000011132 } else {
11133 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011134 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011135 }
Eric Andersenc470f442003-07-28 09:56:35 +000011136 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011137 close(fd);
11138 }
Eric Andersenc470f442003-07-28 09:56:35 +000011139 dupredirect(n, newfd);
11140 } while ((n = n->nfile.next));
11141 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011142 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11143 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011144}
11145
11146
Eric Andersencb57d552001-06-28 07:25:16 +000011147/*
11148 * Undo the effects of the last redirection.
11149 */
11150
Eric Andersenc470f442003-07-28 09:56:35 +000011151void
11152popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011153{
Eric Andersenc470f442003-07-28 09:56:35 +000011154 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011155 int i;
11156
Eric Andersenc470f442003-07-28 09:56:35 +000011157 if (--nullredirs >= 0)
11158 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011159 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011160 rp = redirlist;
11161 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011162 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011163 if (!drop) {
11164 close(i);
11165 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011166 }
Eric Andersenc470f442003-07-28 09:56:35 +000011167 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011168 }
11169 }
11170 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011171 nullredirs = rp->nullredirs;
11172 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011173 INTON;
11174}
11175
11176/*
Eric Andersenc470f442003-07-28 09:56:35 +000011177 * Undo all redirections. Called on error or interrupt.
11178 */
11179
11180/*
Eric Andersencb57d552001-06-28 07:25:16 +000011181 * Discard all saved file descriptors.
11182 */
11183
Eric Andersenc470f442003-07-28 09:56:35 +000011184void
11185clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011186{
Eric Andersenc470f442003-07-28 09:56:35 +000011187 for (;;) {
11188 nullredirs = 0;
11189 if (!redirlist)
11190 break;
11191 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011192 }
Eric Andersencb57d552001-06-28 07:25:16 +000011193}
11194
11195
Eric Andersencb57d552001-06-28 07:25:16 +000011196/*
11197 * Copy a file descriptor to be >= to. Returns -1
11198 * if the source file descriptor is closed, EMPTY if there are no unused
11199 * file descriptors left.
11200 */
11201
Eric Andersenc470f442003-07-28 09:56:35 +000011202int
11203copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011204{
11205 int newfd;
11206
11207 newfd = fcntl(from, F_DUPFD, to);
11208 if (newfd < 0) {
11209 if (errno == EMFILE)
11210 return EMPTY;
11211 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011212 sh_error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011213 }
11214 return newfd;
11215}
11216
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011217
Eric Andersenc470f442003-07-28 09:56:35 +000011218int
11219redirectsafe(union node *redir, int flags)
11220{
11221 int err;
11222 volatile int saveint;
11223 struct jmploc *volatile savehandler = handler;
11224 struct jmploc jmploc;
11225
11226 SAVEINT(saveint);
11227 if (!(err = setjmp(jmploc.loc) * 2)) {
11228 handler = &jmploc;
11229 redirect(redir, flags);
11230 }
11231 handler = savehandler;
11232 if (err && exception != EXERROR)
11233 longjmp(handler->loc, 1);
11234 RESTOREINT(saveint);
11235 return err;
11236}
11237
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011238/* show.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011239
11240#ifdef DEBUG
11241static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011242static void shcmd(union node *, FILE *);
11243static void sharg(union node *, FILE *);
11244static void indent(int, char *, FILE *);
11245static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011246
11247
Eric Andersenc470f442003-07-28 09:56:35 +000011248void
11249showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011250{
11251 trputs("showtree called\n");
11252 shtree(n, 1, NULL, stdout);
11253}
Eric Andersencb57d552001-06-28 07:25:16 +000011254
Eric Andersenc470f442003-07-28 09:56:35 +000011255
11256static void
11257shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011258{
11259 struct nodelist *lp;
11260 const char *s;
11261
11262 if (n == NULL)
11263 return;
11264
11265 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011266 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011267 case NSEMI:
11268 s = "; ";
11269 goto binop;
11270 case NAND:
11271 s = " && ";
11272 goto binop;
11273 case NOR:
11274 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011275binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011276 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011277 /* if (ind < 0) */
11278 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011279 shtree(n->nbinary.ch2, ind, NULL, fp);
11280 break;
11281 case NCMD:
11282 shcmd(n, fp);
11283 if (ind >= 0)
11284 putc('\n', fp);
11285 break;
11286 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011287 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011288 shcmd(lp->n, fp);
11289 if (lp->next)
11290 fputs(" | ", fp);
11291 }
11292 if (n->npipe.backgnd)
11293 fputs(" &", fp);
11294 if (ind >= 0)
11295 putc('\n', fp);
11296 break;
11297 default:
11298 fprintf(fp, "<node type %d>", n->type);
11299 if (ind >= 0)
11300 putc('\n', fp);
11301 break;
11302 }
11303}
11304
11305
Eric Andersenc470f442003-07-28 09:56:35 +000011306static void
11307shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011308{
11309 union node *np;
11310 int first;
11311 const char *s;
11312 int dftfd;
11313
11314 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011315 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11316 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011317 putchar(' ');
11318 sharg(np, fp);
11319 first = 0;
11320 }
Eric Andersenc470f442003-07-28 09:56:35 +000011321 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11322 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011323 putchar(' ');
11324 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011325 case NTO: s = ">"; dftfd = 1; break;
11326 case NCLOBBER: s = ">|"; dftfd = 1; break;
11327 case NAPPEND: s = ">>"; dftfd = 1; break;
11328 case NTOFD: s = ">&"; dftfd = 1; break;
11329 case NFROM: s = "<"; dftfd = 0; break;
11330 case NFROMFD: s = "<&"; dftfd = 0; break;
11331 case NFROMTO: s = "<>"; dftfd = 0; break;
11332 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011333 }
11334 if (np->nfile.fd != dftfd)
11335 fprintf(fp, "%d", np->nfile.fd);
11336 fputs(s, fp);
11337 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11338 fprintf(fp, "%d", np->ndup.dupfd);
11339 } else {
11340 sharg(np->nfile.fname, fp);
11341 }
11342 first = 0;
11343 }
11344}
11345
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011346
Eric Andersenc470f442003-07-28 09:56:35 +000011347
11348static void
11349sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011350{
Eric Andersencb57d552001-06-28 07:25:16 +000011351 char *p;
11352 struct nodelist *bqlist;
11353 int subtype;
11354
11355 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011356 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011357 abort();
11358 }
11359 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011360 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011361 switch (*p) {
11362 case CTLESC:
11363 putc(*++p, fp);
11364 break;
11365 case CTLVAR:
11366 putc('$', fp);
11367 putc('{', fp);
11368 subtype = *++p;
11369 if (subtype == VSLENGTH)
11370 putc('#', fp);
11371
11372 while (*p != '=')
11373 putc(*p++, fp);
11374
11375 if (subtype & VSNUL)
11376 putc(':', fp);
11377
11378 switch (subtype & VSTYPE) {
11379 case VSNORMAL:
11380 putc('}', fp);
11381 break;
11382 case VSMINUS:
11383 putc('-', fp);
11384 break;
11385 case VSPLUS:
11386 putc('+', fp);
11387 break;
11388 case VSQUESTION:
11389 putc('?', fp);
11390 break;
11391 case VSASSIGN:
11392 putc('=', fp);
11393 break;
11394 case VSTRIMLEFT:
11395 putc('#', fp);
11396 break;
11397 case VSTRIMLEFTMAX:
11398 putc('#', fp);
11399 putc('#', fp);
11400 break;
11401 case VSTRIMRIGHT:
11402 putc('%', fp);
11403 break;
11404 case VSTRIMRIGHTMAX:
11405 putc('%', fp);
11406 putc('%', fp);
11407 break;
11408 case VSLENGTH:
11409 break;
11410 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011411 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011412 }
11413 break;
11414 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011415 putc('}', fp);
11416 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011417 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011418 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011419 putc('$', fp);
11420 putc('(', fp);
11421 shtree(bqlist->n, -1, NULL, fp);
11422 putc(')', fp);
11423 break;
11424 default:
11425 putc(*p, fp);
11426 break;
11427 }
11428 }
11429}
11430
11431
Eric Andersenc470f442003-07-28 09:56:35 +000011432static void
11433indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011434{
11435 int i;
11436
Eric Andersenc470f442003-07-28 09:56:35 +000011437 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011438 if (pfx && i == amount - 1)
11439 fputs(pfx, fp);
11440 putc('\t', fp);
11441 }
11442}
Eric Andersencb57d552001-06-28 07:25:16 +000011443
Eric Andersenc470f442003-07-28 09:56:35 +000011444
11445
11446/*
11447 * Debugging stuff.
11448 */
11449
11450
Eric Andersencb57d552001-06-28 07:25:16 +000011451FILE *tracefile;
11452
Eric Andersencb57d552001-06-28 07:25:16 +000011453
Eric Andersenc470f442003-07-28 09:56:35 +000011454void
11455trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011456{
Eric Andersenc470f442003-07-28 09:56:35 +000011457 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011458 return;
11459 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011460}
11461
Eric Andersenc470f442003-07-28 09:56:35 +000011462void
11463trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011464{
11465 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011466
Eric Andersenc470f442003-07-28 09:56:35 +000011467 if (debug != 1)
11468 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011469 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011470 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011471 va_end(va);
11472}
11473
Eric Andersenc470f442003-07-28 09:56:35 +000011474void
11475tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011476{
Eric Andersenc470f442003-07-28 09:56:35 +000011477 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011478 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011479 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011480}
11481
11482
Eric Andersenc470f442003-07-28 09:56:35 +000011483void
11484trputs(const char *s)
11485{
11486 if (debug != 1)
11487 return;
11488 fputs(s, tracefile);
11489}
11490
11491
11492static void
11493trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011494{
11495 char *p;
11496 char c;
11497
Eric Andersenc470f442003-07-28 09:56:35 +000011498 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011499 return;
11500 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011501 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011502 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011503 case '\n': c = 'n'; goto backslash;
11504 case '\t': c = 't'; goto backslash;
11505 case '\r': c = 'r'; goto backslash;
11506 case '"': c = '"'; goto backslash;
11507 case '\\': c = '\\'; goto backslash;
11508 case CTLESC: c = 'e'; goto backslash;
11509 case CTLVAR: c = 'v'; goto backslash;
11510 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11511 case CTLBACKQ: c = 'q'; goto backslash;
11512 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11513backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011514 putc(c, tracefile);
11515 break;
11516 default:
11517 if (*p >= ' ' && *p <= '~')
11518 putc(*p, tracefile);
11519 else {
11520 putc('\\', tracefile);
11521 putc(*p >> 6 & 03, tracefile);
11522 putc(*p >> 3 & 07, tracefile);
11523 putc(*p & 07, tracefile);
11524 }
11525 break;
11526 }
11527 }
11528 putc('"', tracefile);
11529}
11530
11531
Eric Andersenc470f442003-07-28 09:56:35 +000011532void
11533trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011534{
Eric Andersenc470f442003-07-28 09:56:35 +000011535 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011536 return;
11537 while (*ap) {
11538 trstring(*ap++);
11539 if (*ap)
11540 putc(' ', tracefile);
11541 else
11542 putc('\n', tracefile);
11543 }
Eric Andersencb57d552001-06-28 07:25:16 +000011544}
11545
11546
Eric Andersenc470f442003-07-28 09:56:35 +000011547void
11548opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011549{
Eric Andersencb57d552001-06-28 07:25:16 +000011550 char s[100];
11551#ifdef O_APPEND
11552 int flags;
11553#endif
11554
Eric Andersenc470f442003-07-28 09:56:35 +000011555 if (debug != 1) {
11556 if (tracefile)
11557 fflush(tracefile);
11558 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011559 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011560 }
Eric Andersenc470f442003-07-28 09:56:35 +000011561 scopy("./trace", s);
11562 if (tracefile) {
11563 if (!freopen(s, "a", tracefile)) {
11564 fprintf(stderr, "Can't re-open %s\n", s);
11565 debug = 0;
11566 return;
11567 }
11568 } else {
11569 if ((tracefile = fopen(s, "a")) == NULL) {
11570 fprintf(stderr, "Can't open %s\n", s);
11571 debug = 0;
11572 return;
11573 }
11574 }
Eric Andersencb57d552001-06-28 07:25:16 +000011575#ifdef O_APPEND
11576 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11577 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11578#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011579 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011580 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011581}
Eric Andersenc470f442003-07-28 09:56:35 +000011582#endif /* DEBUG */
11583
11584
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011585/* trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011586
11587/*
11588 * Sigmode records the current value of the signal handlers for the various
11589 * modes. A value of zero means that the current handler is not known.
11590 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11591 */
11592
11593#define S_DFL 1 /* default signal handling (SIG_DFL) */
11594#define S_CATCH 2 /* signal is caught */
11595#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11596#define S_HARD_IGN 4 /* signal is ignored permenantly */
11597#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11598
Eric Andersencb57d552001-06-28 07:25:16 +000011599
11600
11601/*
Eric Andersencb57d552001-06-28 07:25:16 +000011602 * The trap builtin.
11603 */
11604
Eric Andersenc470f442003-07-28 09:56:35 +000011605int
11606trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011607{
11608 char *action;
11609 char **ap;
11610 int signo;
11611
Eric Andersenc470f442003-07-28 09:56:35 +000011612 nextopt(nullstr);
11613 ap = argptr;
11614 if (!*ap) {
11615 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011616 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011617 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011618
Rob Landleyc9c1a412006-07-12 19:17:55 +000011619 sn = get_signame(signo);
Eric Andersenc470f442003-07-28 09:56:35 +000011620 out1fmt("trap -- %s %s\n",
11621 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011622 }
11623 }
11624 return 0;
11625 }
Eric Andersenc470f442003-07-28 09:56:35 +000011626 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011627 action = NULL;
11628 else
11629 action = *ap++;
11630 while (*ap) {
Rob Landleyc9c1a412006-07-12 19:17:55 +000011631 if ((signo = get_signum(*ap)) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011632 sh_error("%s: bad trap", *ap);
Eric Andersencb57d552001-06-28 07:25:16 +000011633 INTOFF;
11634 if (action) {
11635 if (action[0] == '-' && action[1] == '\0')
11636 action = NULL;
11637 else
Eric Andersenc470f442003-07-28 09:56:35 +000011638 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011639 }
Eric Andersenc470f442003-07-28 09:56:35 +000011640 if (trap[signo])
11641 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011642 trap[signo] = action;
11643 if (signo != 0)
11644 setsignal(signo);
11645 INTON;
11646 ap++;
11647 }
11648 return 0;
11649}
11650
11651
Eric Andersenc470f442003-07-28 09:56:35 +000011652/*
11653 * Clear traps on a fork.
11654 */
11655
11656void
11657clear_traps(void)
11658{
11659 char **tp;
11660
11661 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11662 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11663 INTOFF;
11664 ckfree(*tp);
11665 *tp = NULL;
11666 if (tp != &trap[0])
11667 setsignal(tp - trap);
11668 INTON;
11669 }
11670 }
11671}
11672
11673
Eric Andersencb57d552001-06-28 07:25:16 +000011674/*
11675 * Set the signal handler for the specified signal. The routine figures
11676 * out what it should be set to.
11677 */
11678
Eric Andersenc470f442003-07-28 09:56:35 +000011679void
11680setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011681{
11682 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011683 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011684 struct sigaction act;
11685
11686 if ((t = trap[signo]) == NULL)
11687 action = S_DFL;
11688 else if (*t != '\0')
11689 action = S_CATCH;
11690 else
11691 action = S_IGN;
11692 if (rootshell && action == S_DFL) {
11693 switch (signo) {
11694 case SIGINT:
11695 if (iflag || minusc || sflag == 0)
11696 action = S_CATCH;
11697 break;
11698 case SIGQUIT:
11699#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011700 if (debug)
11701 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011702#endif
11703 /* FALLTHROUGH */
11704 case SIGTERM:
11705 if (iflag)
11706 action = S_IGN;
11707 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011708#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011709 case SIGTSTP:
11710 case SIGTTOU:
11711 if (mflag)
11712 action = S_IGN;
11713 break;
11714#endif
11715 }
11716 }
11717
11718 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011719 tsig = *t;
11720 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011721 /*
11722 * current setting unknown
11723 */
11724 if (sigaction(signo, 0, &act) == -1) {
11725 /*
11726 * Pretend it worked; maybe we should give a warning
11727 * here, but other shells don't. We don't alter
11728 * sigmode, so that we retry every time.
11729 */
11730 return;
11731 }
11732 if (act.sa_handler == SIG_IGN) {
11733 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011734 signo == SIGTTIN || signo == SIGTTOU)) {
11735 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011736 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011737 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011738 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011739 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011740 }
11741 }
Eric Andersenc470f442003-07-28 09:56:35 +000011742 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011743 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011744 switch (action) {
11745 case S_CATCH:
11746 act.sa_handler = onsig;
11747 break;
11748 case S_IGN:
11749 act.sa_handler = SIG_IGN;
11750 break;
11751 default:
11752 act.sa_handler = SIG_DFL;
11753 }
Eric Andersencb57d552001-06-28 07:25:16 +000011754 *t = action;
11755 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011756 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011757 sigaction(signo, &act, 0);
11758}
11759
11760/*
11761 * Ignore a signal.
11762 */
11763
Eric Andersenc470f442003-07-28 09:56:35 +000011764void
11765ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011766{
11767 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11768 signal(signo, SIG_IGN);
11769 }
11770 sigmode[signo - 1] = S_HARD_IGN;
11771}
11772
11773
Eric Andersencb57d552001-06-28 07:25:16 +000011774/*
11775 * Signal handler.
11776 */
11777
Eric Andersenc470f442003-07-28 09:56:35 +000011778void
11779onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011780{
Eric Andersencb57d552001-06-28 07:25:16 +000011781 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011782 pendingsigs = signo;
11783
11784 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11785 if (!suppressint)
11786 onint();
11787 intpending = 1;
11788 }
Eric Andersencb57d552001-06-28 07:25:16 +000011789}
11790
11791
Eric Andersencb57d552001-06-28 07:25:16 +000011792/*
11793 * Called to execute a trap. Perhaps we should avoid entering new trap
11794 * handlers while we are executing a trap handler.
11795 */
11796
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011797int
Eric Andersenc470f442003-07-28 09:56:35 +000011798dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011799{
Eric Andersenc470f442003-07-28 09:56:35 +000011800 char *p;
11801 char *q;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011802 int i;
Eric Andersencb57d552001-06-28 07:25:16 +000011803 int savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011804 int skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011805
Eric Andersenc470f442003-07-28 09:56:35 +000011806 savestatus = exitstatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011807 pendingsigs = 0;
11808 xbarrier();
11809
11810 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11811 if (!*q)
11812 continue;
11813 *q = 0;
11814
11815 p = trap[i + 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011816 if (!p)
11817 continue;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011818 skip = evalstring(p, SKIPEVAL);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011819 exitstatus = savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011820 if (skip)
11821 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011822 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011823
11824 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +000011825}
11826
Eric Andersenc470f442003-07-28 09:56:35 +000011827
Eric Andersenc470f442003-07-28 09:56:35 +000011828/*
11829 * Controls whether the shell is interactive or not.
11830 */
11831
Eric Andersenc470f442003-07-28 09:56:35 +000011832void
11833setinteractive(int on)
11834{
11835 static int is_interactive;
11836
11837 if (++on == is_interactive)
11838 return;
11839 is_interactive = on;
11840 setsignal(SIGINT);
11841 setsignal(SIGQUIT);
11842 setsignal(SIGTERM);
11843#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11844 if(is_interactive > 1) {
11845 /* Looks like they want an interactive shell */
11846 static int do_banner;
11847
11848 if(!do_banner) {
11849 out1fmt(
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +000011850 "\n\n%s Built-in shell (ash)\n"
11851 "Enter 'help' for a list of built-in commands.\n\n",
11852 BB_BANNER);
Eric Andersenc470f442003-07-28 09:56:35 +000011853 do_banner++;
11854 }
11855 }
11856#endif
11857}
11858
11859
11860#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11861/*** List the available builtins ***/
11862
11863static int helpcmd(int argc, char **argv)
11864{
11865 int col, i;
11866
11867 out1fmt("\nBuilt-in commands:\n-------------------\n");
11868 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11869 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11870 builtincmd[i].name + 1);
11871 if (col > 60) {
11872 out1fmt("\n");
11873 col = 0;
11874 }
11875 }
11876#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11877 {
11878 extern const struct BB_applet applets[];
11879 extern const size_t NUM_APPLETS;
11880
11881 for (i = 0; i < NUM_APPLETS; i++) {
11882
11883 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11884 if (col > 60) {
11885 out1fmt("\n");
11886 col = 0;
11887 }
11888 }
11889 }
11890#endif
11891 out1fmt("\n\n");
11892 return EXIT_SUCCESS;
11893}
11894#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11895
Eric Andersencb57d552001-06-28 07:25:16 +000011896/*
11897 * Called to exit the shell.
11898 */
11899
Eric Andersenc470f442003-07-28 09:56:35 +000011900void
11901exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011902{
Eric Andersenc470f442003-07-28 09:56:35 +000011903 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011904 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011905 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011906
Eric Andersenc470f442003-07-28 09:56:35 +000011907 status = exitstatus;
11908 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011909 if (setjmp(loc.loc)) {
11910 if (exception == EXEXIT)
11911 _exit(exitstatus);
Eric Andersenc470f442003-07-28 09:56:35 +000011912 goto out;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011913 }
Eric Andersenc470f442003-07-28 09:56:35 +000011914 handler = &loc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011915 if ((p = trap[0])) {
Eric Andersencb57d552001-06-28 07:25:16 +000011916 trap[0] = NULL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011917 evalstring(p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011918 }
Eric Andersencb57d552001-06-28 07:25:16 +000011919 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011920 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011921#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11922 if (iflag && rootshell) {
11923 const char *hp = lookupvar("HISTFILE");
11924
11925 if(hp != NULL )
11926 save_history ( hp );
11927 }
11928#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011929out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011930 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011931 /* NOTREACHED */
11932}
11933
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011934/* var.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011935
11936static struct var *vartab[VTABSIZE];
11937
11938static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011939static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011940
11941/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011942 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011943 */
11944
Eric Andersenc470f442003-07-28 09:56:35 +000011945
11946#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011947/*
Eric Andersenc470f442003-07-28 09:56:35 +000011948 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011949 */
11950
Eric Andersenc470f442003-07-28 09:56:35 +000011951int
11952setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011953{
Eric Andersenc470f442003-07-28 09:56:35 +000011954 int err;
11955 volatile int saveint;
11956 struct jmploc *volatile savehandler = handler;
11957 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011958
Eric Andersenc470f442003-07-28 09:56:35 +000011959 SAVEINT(saveint);
11960 if (setjmp(jmploc.loc))
11961 err = 1;
11962 else {
11963 handler = &jmploc;
11964 setvar(name, val, flags);
11965 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011966 }
Eric Andersenc470f442003-07-28 09:56:35 +000011967 handler = savehandler;
11968 RESTOREINT(saveint);
11969 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011970}
Eric Andersenc470f442003-07-28 09:56:35 +000011971#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011972
11973/*
11974 * Set the value of a variable. The flags argument is ored with the
11975 * flags of the variable. If val is NULL, the variable is unset.
11976 */
11977
Eric Andersenc470f442003-07-28 09:56:35 +000011978static void
11979setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011980{
Eric Andersenc470f442003-07-28 09:56:35 +000011981 char *p, *q;
11982 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011983 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011984 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011985
Eric Andersenc470f442003-07-28 09:56:35 +000011986 q = endofname(name);
11987 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011988 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011989 if (!namelen || p != q)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011990 sh_error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011991 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011992 if (val == NULL) {
11993 flags |= VUNSET;
11994 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011995 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011996 }
11997 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011998 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
Paul Fox8de331d2005-07-21 12:03:05 +000011999 if (val) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012000 *p++ = '=';
Eric Andersenc470f442003-07-28 09:56:35 +000012001 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000012002 }
Eric Andersenc470f442003-07-28 09:56:35 +000012003 *p = '\0';
12004 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012005 INTON;
12006}
12007
12008
Eric Andersencb57d552001-06-28 07:25:16 +000012009/*
12010 * Same as setvar except that the variable and value are passed in
12011 * the first argument as name=value. Since the first argument will
12012 * be actually stored in the table, it should not be a string that
12013 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012014 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012015 */
12016
Eric Andersenc470f442003-07-28 09:56:35 +000012017void
12018setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012019{
12020 struct var *vp, **vpp;
12021
12022 vpp = hashvar(s);
12023 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012024 vp = *findvar(vpp, s);
12025 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012026 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12027 const char *n;
12028
Eric Andersenc470f442003-07-28 09:56:35 +000012029 if (flags & VNOSAVE)
12030 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012031 n = vp->text;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012032 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012033 }
Eric Andersenc470f442003-07-28 09:56:35 +000012034
12035 if (flags & VNOSET)
12036 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012037
12038 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012039 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012040
Eric Andersenc470f442003-07-28 09:56:35 +000012041 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12042 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012043
Eric Andersenc470f442003-07-28 09:56:35 +000012044 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12045 } else {
12046 if (flags & VNOSET)
12047 return;
12048 /* not found */
12049 vp = ckmalloc(sizeof (*vp));
12050 vp->next = *vpp;
12051 vp->func = NULL;
12052 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012053 }
Eric Andersenc470f442003-07-28 09:56:35 +000012054 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12055 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012056 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012057 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012058}
12059
12060
Eric Andersencb57d552001-06-28 07:25:16 +000012061/*
12062 * Process a linked list of variable assignments.
12063 */
12064
Eric Andersenc470f442003-07-28 09:56:35 +000012065static void
12066listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012067{
Eric Andersenc470f442003-07-28 09:56:35 +000012068 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012069
Eric Andersenc470f442003-07-28 09:56:35 +000012070 if (!lp)
12071 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012072 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012073 do {
12074 setvareq(lp->text, flags);
12075 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012076 INTON;
12077}
12078
12079
Eric Andersencb57d552001-06-28 07:25:16 +000012080/*
12081 * Find the value of a variable. Returns NULL if not set.
12082 */
12083
Eric Andersenc470f442003-07-28 09:56:35 +000012084static char *
12085lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012086{
Eric Andersencb57d552001-06-28 07:25:16 +000012087 struct var *v;
12088
Eric Andersen16767e22004-03-16 05:14:10 +000012089 if ((v = *findvar(hashvar(name), name))) {
12090#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012091 /*
12092 * Dynamic variables are implemented roughly the same way they are
12093 * in bash. Namely, they're "special" so long as they aren't unset.
12094 * As soon as they're unset, they're no longer dynamic, and dynamic
12095 * lookup will no longer happen at that point. -- PFM.
12096 */
Eric Andersen16767e22004-03-16 05:14:10 +000012097 if((v->flags & VDYNAMIC))
12098 (*v->func)(NULL);
12099#endif
12100 if(!(v->flags & VUNSET))
12101 return strchrnul(v->text, '=') + 1;
12102 }
Eric Andersenef02f822004-03-11 13:34:24 +000012103
Eric Andersencb57d552001-06-28 07:25:16 +000012104 return NULL;
12105}
12106
12107
Eric Andersencb57d552001-06-28 07:25:16 +000012108/*
12109 * Search the environment of a builtin command.
12110 */
12111
Eric Andersenc470f442003-07-28 09:56:35 +000012112static char *
12113bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012114{
Eric Andersenc470f442003-07-28 09:56:35 +000012115 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012116
Eric Andersenc470f442003-07-28 09:56:35 +000012117 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012118 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012119 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012120 }
12121 return lookupvar(name);
12122}
12123
12124
Eric Andersencb57d552001-06-28 07:25:16 +000012125/*
Eric Andersenc470f442003-07-28 09:56:35 +000012126 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012127 */
12128
Eric Andersenc470f442003-07-28 09:56:35 +000012129static char **
12130listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012131{
Eric Andersencb57d552001-06-28 07:25:16 +000012132 struct var **vpp;
12133 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012134 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012135 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012136
Eric Andersenc470f442003-07-28 09:56:35 +000012137 STARTSTACKSTR(ep);
12138 vpp = vartab;
12139 mask = on | off;
12140 do {
12141 for (vp = *vpp ; vp ; vp = vp->next)
12142 if ((vp->flags & mask) == on) {
12143 if (ep == stackstrend())
12144 ep = growstackstr();
12145 *ep++ = (char *) vp->text;
12146 }
12147 } while (++vpp < vartab + VTABSIZE);
12148 if (ep == stackstrend())
12149 ep = growstackstr();
12150 if (end)
12151 *end = ep;
12152 *ep++ = NULL;
12153 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012154}
12155
12156
12157/*
Eric Andersenc470f442003-07-28 09:56:35 +000012158 * POSIX requires that 'set' (but not export or readonly) output the
12159 * variables in lexicographic order - by the locale's collating order (sigh).
12160 * Maybe we could keep them in an ordered balanced binary tree
12161 * instead of hashed lists.
12162 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012163 */
12164
Eric Andersenc470f442003-07-28 09:56:35 +000012165static int
12166showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012167{
Eric Andersenc470f442003-07-28 09:56:35 +000012168 const char *sep;
12169 char **ep, **epend;
12170
12171 ep = listvars(on, off, &epend);
12172 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12173
12174 sep = *sep_prefix ? spcstr : sep_prefix;
12175
12176 for (; ep < epend; ep++) {
12177 const char *p;
12178 const char *q;
12179
12180 p = strchrnul(*ep, '=');
12181 q = nullstr;
12182 if (*p)
12183 q = single_quote(++p);
12184
12185 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12186 }
12187
Eric Andersencb57d552001-06-28 07:25:16 +000012188 return 0;
12189}
12190
12191
12192
12193/*
12194 * The export and readonly commands.
12195 */
12196
Eric Andersenc470f442003-07-28 09:56:35 +000012197static int
12198exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012199{
12200 struct var *vp;
12201 char *name;
12202 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012203 char **aptr;
12204 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12205 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012206
Eric Andersenc470f442003-07-28 09:56:35 +000012207 notp = nextopt("p") - 'p';
12208 if (notp && ((name = *(aptr = argptr)))) {
12209 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012210 if ((p = strchr(name, '=')) != NULL) {
12211 p++;
12212 } else {
12213 if ((vp = *findvar(hashvar(name), name))) {
12214 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012215 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012216 }
12217 }
12218 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012219 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012220 } else {
12221 showvars(argv[0], flag, 0);
12222 }
12223 return 0;
12224}
12225
Eric Andersen34506362001-08-02 05:02:46 +000012226
Eric Andersencb57d552001-06-28 07:25:16 +000012227/*
Eric Andersencb57d552001-06-28 07:25:16 +000012228 * Make a variable a local variable. When a variable is made local, it's
12229 * value and flags are saved in a localvar structure. The saved values
12230 * will be restored when the shell function returns. We handle the name
12231 * "-" as a special case.
12232 */
12233
Eric Andersenc470f442003-07-28 09:56:35 +000012234static inline void
12235mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012236{
Eric Andersencb57d552001-06-28 07:25:16 +000012237 struct localvar *lvp;
12238 struct var **vpp;
12239 struct var *vp;
12240
12241 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012242 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012243 if (name[0] == '-' && name[1] == '\0') {
12244 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012245 p = ckmalloc(sizeof(optlist));
12246 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012247 vp = NULL;
12248 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012249 char *eq;
12250
Eric Andersencb57d552001-06-28 07:25:16 +000012251 vpp = hashvar(name);
12252 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012253 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012254 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012255 if (eq)
12256 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012257 else
12258 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012259 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012260 lvp->flags = VUNSET;
12261 } else {
12262 lvp->text = vp->text;
12263 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012264 vp->flags |= VSTRFIXED|VTEXTFIXED;
12265 if (eq)
12266 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012267 }
12268 }
12269 lvp->vp = vp;
12270 lvp->next = localvars;
12271 localvars = lvp;
12272 INTON;
12273}
12274
Eric Andersenc470f442003-07-28 09:56:35 +000012275/*
12276 * The "local" command.
12277 */
12278
12279static int
12280localcmd(int argc, char **argv)
12281{
12282 char *name;
12283
12284 argv = argptr;
12285 while ((name = *argv++) != NULL) {
12286 mklocal(name);
12287 }
12288 return 0;
12289}
12290
12291
Eric Andersencb57d552001-06-28 07:25:16 +000012292/*
12293 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012294 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012295 */
12296
Eric Andersenc470f442003-07-28 09:56:35 +000012297static void
12298poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012299{
Eric Andersencb57d552001-06-28 07:25:16 +000012300 struct localvar *lvp;
12301 struct var *vp;
12302
12303 while ((lvp = localvars) != NULL) {
12304 localvars = lvp->next;
12305 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012306 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12307 if (vp == NULL) { /* $- saved */
12308 memcpy(optlist, lvp->text, sizeof(optlist));
12309 ckfree(lvp->text);
12310 optschanged();
12311 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12312 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012313 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012314 if (vp->func)
12315 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12316 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12317 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012318 vp->flags = lvp->flags;
12319 vp->text = lvp->text;
12320 }
Eric Andersenc470f442003-07-28 09:56:35 +000012321 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012322 }
12323}
12324
12325
Eric Andersencb57d552001-06-28 07:25:16 +000012326/*
12327 * The unset builtin command. We unset the function before we unset the
12328 * variable to allow a function to be unset when there is a readonly variable
12329 * with the same name.
12330 */
12331
Eric Andersenc470f442003-07-28 09:56:35 +000012332int
12333unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012334{
12335 char **ap;
12336 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012337 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012338 int ret = 0;
12339
12340 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012341 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012342 }
Eric Andersencb57d552001-06-28 07:25:16 +000012343
Eric Andersenc470f442003-07-28 09:56:35 +000012344 for (ap = argptr; *ap ; ap++) {
12345 if (flag != 'f') {
12346 i = unsetvar(*ap);
12347 ret |= i;
12348 if (!(i & 2))
12349 continue;
12350 }
12351 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012352 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012353 }
Eric Andersenc470f442003-07-28 09:56:35 +000012354 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012355}
12356
12357
12358/*
12359 * Unset the specified variable.
12360 */
12361
Eric Andersenc470f442003-07-28 09:56:35 +000012362int
12363unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012364{
Eric Andersencb57d552001-06-28 07:25:16 +000012365 struct var **vpp;
12366 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012367 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012368
12369 vpp = findvar(hashvar(s), s);
12370 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012371 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012372 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012373 int flags = vp->flags;
12374
12375 retval = 1;
12376 if (flags & VREADONLY)
12377 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012378#ifdef DYNAMIC_VAR
12379 vp->flags &= ~VDYNAMIC;
12380#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012381 if (flags & VUNSET)
12382 goto ok;
12383 if ((flags & VSTRFIXED) == 0) {
12384 INTOFF;
12385 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12386 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012387 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012388 ckfree(vp);
12389 INTON;
12390 } else {
12391 setvar(s, 0, 0);
12392 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012393 }
Eric Andersenc470f442003-07-28 09:56:35 +000012394ok:
12395 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012396 }
12397
Eric Andersenc470f442003-07-28 09:56:35 +000012398out:
12399 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012400}
12401
12402
12403
12404/*
12405 * Find the appropriate entry in the hash table from the name.
12406 */
12407
Eric Andersenc470f442003-07-28 09:56:35 +000012408static struct var **
12409hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012410{
Eric Andersencb57d552001-06-28 07:25:16 +000012411 unsigned int hashval;
12412
12413 hashval = ((unsigned char) *p) << 4;
12414 while (*p && *p != '=')
12415 hashval += (unsigned char) *p++;
12416 return &vartab[hashval % VTABSIZE];
12417}
12418
12419
12420
12421/*
Eric Andersenc470f442003-07-28 09:56:35 +000012422 * Compares two strings up to the first = or '\0'. The first
12423 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012424 * either '=' or '\0'.
12425 */
12426
Eric Andersenc470f442003-07-28 09:56:35 +000012427int
12428varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012429{
Eric Andersenc470f442003-07-28 09:56:35 +000012430 int c, d;
12431
12432 while ((c = *p) == (d = *q)) {
12433 if (!c || c == '=')
12434 goto out;
12435 p++;
12436 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012437 }
Eric Andersenc470f442003-07-28 09:56:35 +000012438 if (c == '=')
12439 c = 0;
12440 if (d == '=')
12441 d = 0;
12442out:
12443 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012444}
12445
Eric Andersenc470f442003-07-28 09:56:35 +000012446static int
12447vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012448{
Eric Andersenc470f442003-07-28 09:56:35 +000012449 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012450}
12451
Eric Andersenc470f442003-07-28 09:56:35 +000012452static struct var **
12453findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012454{
12455 for (; *vpp; vpp = &(*vpp)->next) {
12456 if (varequal((*vpp)->text, name)) {
12457 break;
12458 }
12459 }
12460 return vpp;
12461}
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012462/* setmode.c */
Eric Andersencb57d552001-06-28 07:25:16 +000012463
Eric Andersenc470f442003-07-28 09:56:35 +000012464#include <sys/times.h>
12465
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012466static const unsigned char timescmd_str[] = {
12467 ' ', offsetof(struct tms, tms_utime),
12468 '\n', offsetof(struct tms, tms_stime),
12469 ' ', offsetof(struct tms, tms_cutime),
12470 '\n', offsetof(struct tms, tms_cstime),
12471 0
12472};
Eric Andersencb57d552001-06-28 07:25:16 +000012473
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012474static int timescmd(int ac, char **av)
12475{
12476 long int clk_tck, s, t;
12477 const unsigned char *p;
12478 struct tms buf;
12479
12480 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012481 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012482
12483 p = timescmd_str;
12484 do {
12485 t = *(clock_t *)(((char *) &buf) + p[1]);
12486 s = t / clk_tck;
12487 out1fmt("%ldm%ld.%.3lds%c",
12488 s/60, s%60,
12489 ((t - s * clk_tck) * 1000) / clk_tck,
12490 p[0]);
12491 } while (*(p += 2));
12492
Eric Andersencb57d552001-06-28 07:25:16 +000012493 return 0;
12494}
12495
Eric Andersend35c5df2002-01-09 15:37:36 +000012496#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012497static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012498dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012499{
Eric Andersened9ecf72004-06-22 08:29:45 +000012500 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012501 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012502
Eric Andersenc470f442003-07-28 09:56:35 +000012503 INTOFF;
12504 result = arith(s, &errcode);
12505 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012506 if (errcode == -3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012507 sh_error("exponent less than 0");
Eric Andersen90898442003-08-06 11:20:52 +000012508 else if (errcode == -2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012509 sh_error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012510 else if (errcode == -5)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012511 sh_error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012512 else
12513 synerror(s);
12514 }
12515 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012516
Eric Andersenc470f442003-07-28 09:56:35 +000012517 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012518}
Eric Andersenc470f442003-07-28 09:56:35 +000012519
12520
12521/*
Eric Andersen90898442003-08-06 11:20:52 +000012522 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12523 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12524 *
12525 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012526 */
Eric Andersen90898442003-08-06 11:20:52 +000012527
Eric Andersenc470f442003-07-28 09:56:35 +000012528static int
Eric Andersen90898442003-08-06 11:20:52 +000012529letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012530{
Eric Andersenc470f442003-07-28 09:56:35 +000012531 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012532 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012533
Eric Andersen90898442003-08-06 11:20:52 +000012534 ap = argv + 1;
12535 if(!*ap)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012536 sh_error("expression expected");
Eric Andersen90898442003-08-06 11:20:52 +000012537 for (ap = argv + 1; *ap; ap++) {
12538 i = dash_arith(*ap);
12539 }
Eric Andersenc470f442003-07-28 09:56:35 +000012540
Eric Andersen90898442003-08-06 11:20:52 +000012541 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012542}
12543#endif /* CONFIG_ASH_MATH_SUPPORT */
12544
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012545/* miscbltin.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012546
12547/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012548 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012549 */
12550
12551#undef rflag
12552
12553#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012554#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012555typedef enum __rlimit_resource rlim_t;
12556#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012557#endif
12558
12559
Eric Andersenc470f442003-07-28 09:56:35 +000012560/*
12561 * The read builtin. The -e option causes backslashes to escape the
12562 * following character.
12563 *
12564 * This uses unbuffered input, which may be avoidable in some cases.
12565 */
12566
12567static int
12568readcmd(int argc, char **argv)
12569{
12570 char **ap;
12571 int backslash;
12572 char c;
12573 int rflag;
12574 char *prompt;
12575 const char *ifs;
12576 char *p;
12577 int startword;
12578 int status;
12579 int i;
Paul Fox02eb9342005-09-07 16:56:02 +000012580#if defined(CONFIG_ASH_READ_NCHARS)
12581 int nch_flag = 0;
12582 int nchars = 0;
12583 int silent = 0;
12584 struct termios tty, old_tty;
12585#endif
12586#if defined(CONFIG_ASH_READ_TIMEOUT)
12587 fd_set set;
12588 struct timeval ts;
12589
12590 ts.tv_sec = ts.tv_usec = 0;
12591#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012592
12593 rflag = 0;
12594 prompt = NULL;
Paul Fox02eb9342005-09-07 16:56:02 +000012595#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12596 while ((i = nextopt("p:rt:n:s")) != '\0')
12597#elif defined(CONFIG_ASH_READ_NCHARS)
12598 while ((i = nextopt("p:rn:s")) != '\0')
12599#elif defined(CONFIG_ASH_READ_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012600 while ((i = nextopt("p:rt:")) != '\0')
12601#else
12602 while ((i = nextopt("p:r")) != '\0')
12603#endif
12604 {
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012605 switch(i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012606 case 'p':
Eric Andersenc470f442003-07-28 09:56:35 +000012607 prompt = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012608 break;
12609#if defined(CONFIG_ASH_READ_NCHARS)
12610 case 'n':
12611 nchars = strtol(optionarg, &p, 10);
12612 if (*p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012613 sh_error("invalid count");
Paul Fox02eb9342005-09-07 16:56:02 +000012614 nch_flag = (nchars > 0);
12615 break;
12616 case 's':
12617 silent = 1;
12618 break;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012619#endif
Paul Fox02eb9342005-09-07 16:56:02 +000012620#if defined(CONFIG_ASH_READ_TIMEOUT)
12621 case 't':
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012622 ts.tv_sec = strtol(optionarg, &p, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012623 ts.tv_usec = 0;
12624 if (*p == '.') {
12625 char *p2;
12626 if (*++p) {
12627 int scale;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012628 ts.tv_usec = strtol(p, &p2, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012629 if (*p2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012630 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012631 scale = p2 - p;
12632 /* normalize to usec */
12633 if (scale > 6)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012634 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012635 while (scale++ < 6)
12636 ts.tv_usec *= 10;
12637 }
12638 } else if (*p) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012639 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012640 }
12641 if ( ! ts.tv_sec && ! ts.tv_usec)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012642 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012643 break;
12644#endif
12645 case 'r':
12646 rflag = 1;
12647 break;
12648 default:
12649 break;
12650 }
Eric Andersenc470f442003-07-28 09:56:35 +000012651 }
12652 if (prompt && isatty(0)) {
12653 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012654 }
12655 if (*(ap = argptr) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012656 sh_error("arg count");
Eric Andersenc470f442003-07-28 09:56:35 +000012657 if ((ifs = bltinlookup("IFS")) == NULL)
12658 ifs = defifs;
Paul Fox02eb9342005-09-07 16:56:02 +000012659#if defined(CONFIG_ASH_READ_NCHARS)
12660 if (nch_flag || silent) {
12661 tcgetattr(0, &tty);
12662 old_tty = tty;
12663 if (nch_flag) {
12664 tty.c_lflag &= ~ICANON;
12665 tty.c_cc[VMIN] = nchars;
12666 }
12667 if (silent) {
12668 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12669
12670 }
12671 tcsetattr(0, TCSANOW, &tty);
12672 }
12673#endif
12674#if defined(CONFIG_ASH_READ_TIMEOUT)
12675 if (ts.tv_sec || ts.tv_usec) {
12676 FD_ZERO (&set);
12677 FD_SET (0, &set);
12678
12679 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12680 if (!i) {
12681#if defined(CONFIG_ASH_READ_NCHARS)
12682 if (nch_flag)
12683 tcsetattr(0, TCSANOW, &old_tty);
12684#endif
12685 return 1;
12686 }
12687 }
Ned Ludd2123b7c2005-02-09 21:07:23 +000012688#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012689 status = 0;
12690 startword = 1;
12691 backslash = 0;
12692 STARTSTACKSTR(p);
Paul Fox02eb9342005-09-07 16:56:02 +000012693#if defined(CONFIG_ASH_READ_NCHARS)
12694 while (!nch_flag || nchars--)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012695#else
12696 for (;;)
12697#endif
12698 {
Eric Andersenc470f442003-07-28 09:56:35 +000012699 if (read(0, &c, 1) != 1) {
12700 status = 1;
12701 break;
12702 }
12703 if (c == '\0')
12704 continue;
12705 if (backslash) {
12706 backslash = 0;
12707 if (c != '\n')
12708 goto put;
12709 continue;
12710 }
12711 if (!rflag && c == '\\') {
12712 backslash++;
12713 continue;
12714 }
12715 if (c == '\n')
12716 break;
12717 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12718 continue;
12719 }
12720 startword = 0;
12721 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12722 STACKSTRNUL(p);
12723 setvar(*ap, stackblock(), 0);
12724 ap++;
12725 startword = 1;
12726 STARTSTACKSTR(p);
12727 } else {
12728put:
12729 STPUTC(c, p);
12730 }
12731 }
Paul Fox02eb9342005-09-07 16:56:02 +000012732#if defined(CONFIG_ASH_READ_NCHARS)
12733 if (nch_flag || silent)
12734 tcsetattr(0, TCSANOW, &old_tty);
12735#endif
12736
Eric Andersenc470f442003-07-28 09:56:35 +000012737 STACKSTRNUL(p);
12738 /* Remove trailing blanks */
12739 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12740 *p = '\0';
12741 setvar(*ap, stackblock(), 0);
12742 while (*++ap != NULL)
12743 setvar(*ap, nullstr, 0);
12744 return status;
12745}
12746
12747
12748static int umaskcmd(int argc, char **argv)
12749{
12750 static const char permuser[3] = "ugo";
12751 static const char permmode[3] = "rwx";
12752 static const short int permmask[] = {
12753 S_IRUSR, S_IWUSR, S_IXUSR,
12754 S_IRGRP, S_IWGRP, S_IXGRP,
12755 S_IROTH, S_IWOTH, S_IXOTH
12756 };
12757
12758 char *ap;
12759 mode_t mask;
12760 int i;
12761 int symbolic_mode = 0;
12762
12763 while (nextopt("S") != '\0') {
12764 symbolic_mode = 1;
12765 }
12766
12767 INTOFF;
12768 mask = umask(0);
12769 umask(mask);
12770 INTON;
12771
12772 if ((ap = *argptr) == NULL) {
12773 if (symbolic_mode) {
12774 char buf[18];
12775 char *p = buf;
12776
12777 for (i = 0; i < 3; i++) {
12778 int j;
12779
12780 *p++ = permuser[i];
12781 *p++ = '=';
12782 for (j = 0; j < 3; j++) {
12783 if ((mask & permmask[3 * i + j]) == 0) {
12784 *p++ = permmode[j];
12785 }
12786 }
12787 *p++ = ',';
12788 }
12789 *--p = 0;
12790 puts(buf);
12791 } else {
12792 out1fmt("%.4o\n", mask);
12793 }
12794 } else {
12795 if (is_digit((unsigned char) *ap)) {
12796 mask = 0;
12797 do {
12798 if (*ap >= '8' || *ap < '0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012799 sh_error(illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012800 mask = (mask << 3) + (*ap - '0');
12801 } while (*++ap != '\0');
12802 umask(mask);
12803 } else {
12804 mask = ~mask & 0777;
12805 if (!bb_parse_mode(ap, &mask)) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012806 sh_error("Illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012807 }
12808 umask(~mask & 0777);
12809 }
12810 }
12811 return 0;
12812}
12813
12814/*
12815 * ulimit builtin
12816 *
12817 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12818 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12819 * ash by J.T. Conklin.
12820 *
12821 * Public domain.
12822 */
12823
12824struct limits {
12825 const char *name;
12826 int cmd;
12827 int factor; /* multiply by to get rlim_{cur,max} values */
12828 char option;
12829};
12830
12831static const struct limits limits[] = {
12832#ifdef RLIMIT_CPU
12833 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12834#endif
12835#ifdef RLIMIT_FSIZE
12836 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12837#endif
12838#ifdef RLIMIT_DATA
12839 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12840#endif
12841#ifdef RLIMIT_STACK
12842 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12843#endif
12844#ifdef RLIMIT_CORE
12845 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12846#endif
12847#ifdef RLIMIT_RSS
12848 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12849#endif
12850#ifdef RLIMIT_MEMLOCK
12851 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12852#endif
12853#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012854 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012855#endif
12856#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012857 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012858#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012859#ifdef RLIMIT_AS
12860 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012861#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012862#ifdef RLIMIT_LOCKS
12863 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012864#endif
12865 { (char *) 0, 0, 0, '\0' }
12866};
12867
Glenn L McGrath76620622004-01-13 10:19:37 +000012868enum limtype { SOFT = 0x1, HARD = 0x2 };
12869
12870static void printlim(enum limtype how, const struct rlimit *limit,
12871 const struct limits *l)
12872{
12873 rlim_t val;
12874
12875 val = limit->rlim_max;
12876 if (how & SOFT)
12877 val = limit->rlim_cur;
12878
12879 if (val == RLIM_INFINITY)
12880 out1fmt("unlimited\n");
12881 else {
12882 val /= l->factor;
12883 out1fmt("%lld\n", (long long) val);
12884 }
12885}
12886
Eric Andersenc470f442003-07-28 09:56:35 +000012887int
12888ulimitcmd(int argc, char **argv)
12889{
12890 int c;
12891 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012892 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012893 const struct limits *l;
12894 int set, all = 0;
12895 int optc, what;
12896 struct rlimit limit;
12897
12898 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012899 while ((optc = nextopt("HSa"
12900#ifdef RLIMIT_CPU
12901 "t"
12902#endif
12903#ifdef RLIMIT_FSIZE
12904 "f"
12905#endif
12906#ifdef RLIMIT_DATA
12907 "d"
12908#endif
12909#ifdef RLIMIT_STACK
12910 "s"
12911#endif
12912#ifdef RLIMIT_CORE
12913 "c"
12914#endif
12915#ifdef RLIMIT_RSS
12916 "m"
12917#endif
12918#ifdef RLIMIT_MEMLOCK
12919 "l"
12920#endif
12921#ifdef RLIMIT_NPROC
12922 "p"
12923#endif
12924#ifdef RLIMIT_NOFILE
12925 "n"
12926#endif
12927#ifdef RLIMIT_AS
12928 "v"
12929#endif
12930#ifdef RLIMIT_LOCKS
12931 "w"
12932#endif
12933 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012934 switch (optc) {
12935 case 'H':
12936 how = HARD;
12937 break;
12938 case 'S':
12939 how = SOFT;
12940 break;
12941 case 'a':
12942 all = 1;
12943 break;
12944 default:
12945 what = optc;
12946 }
12947
Glenn L McGrath76620622004-01-13 10:19:37 +000012948 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012949 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012950
12951 set = *argptr ? 1 : 0;
12952 if (set) {
12953 char *p = *argptr;
12954
12955 if (all || argptr[1])
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012956 sh_error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012957 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012958 val = RLIM_INFINITY;
12959 else {
12960 val = (rlim_t) 0;
12961
12962 while ((c = *p++) >= '0' && c <= '9')
12963 {
12964 val = (val * 10) + (long)(c - '0');
12965 if (val < (rlim_t) 0)
12966 break;
12967 }
12968 if (c)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012969 sh_error("bad number");
Eric Andersenc470f442003-07-28 09:56:35 +000012970 val *= l->factor;
12971 }
12972 }
12973 if (all) {
12974 for (l = limits; l->name; l++) {
12975 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012976 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012977 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012978 }
12979 return 0;
12980 }
12981
12982 getrlimit(l->cmd, &limit);
12983 if (set) {
12984 if (how & HARD)
12985 limit.rlim_max = val;
12986 if (how & SOFT)
12987 limit.rlim_cur = val;
12988 if (setrlimit(l->cmd, &limit) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012989 sh_error("error setting limit (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +000012990 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012991 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012992 }
12993 return 0;
12994}
12995
Eric Andersen90898442003-08-06 11:20:52 +000012996
12997#ifdef CONFIG_ASH_MATH_SUPPORT
12998
12999/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
13000
13001 Permission is hereby granted, free of charge, to any person obtaining
13002 a copy of this software and associated documentation files (the
13003 "Software"), to deal in the Software without restriction, including
13004 without limitation the rights to use, copy, modify, merge, publish,
13005 distribute, sublicense, and/or sell copies of the Software, and to
13006 permit persons to whom the Software is furnished to do so, subject to
13007 the following conditions:
13008
13009 The above copyright notice and this permission notice shall be
13010 included in all copies or substantial portions of the Software.
13011
13012 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13013 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13014 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13015 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13016 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13017 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13018 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13019*/
13020
13021/* This is my infix parser/evaluator. It is optimized for size, intended
13022 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000013023 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000013024 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000013025 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000013026 * be that which POSIX specifies for shells. */
13027
13028/* The code uses a simple two-stack algorithm. See
13029 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000013030 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000013031 * this is based (this code differs in that it applies operators immediately
13032 * to the stack instead of adding them to a queue to end up with an
13033 * expression). */
13034
13035/* To use the routine, call it with an expression string and error return
13036 * pointer */
13037
13038/*
13039 * Aug 24, 2001 Manuel Novoa III
13040 *
13041 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13042 *
13043 * 1) In arith_apply():
13044 * a) Cached values of *numptr and &(numptr[-1]).
13045 * b) Removed redundant test for zero denominator.
13046 *
13047 * 2) In arith():
13048 * a) Eliminated redundant code for processing operator tokens by moving
13049 * to a table-based implementation. Also folded handling of parens
13050 * into the table.
13051 * b) Combined all 3 loops which called arith_apply to reduce generated
13052 * code size at the cost of speed.
13053 *
13054 * 3) The following expressions were treated as valid by the original code:
13055 * 1() , 0! , 1 ( *3 ) .
13056 * These bugs have been fixed by internally enclosing the expression in
13057 * parens and then checking that all binary ops and right parens are
13058 * preceded by a valid expression (NUM_TOKEN).
13059 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013060 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013061 * ctype's isspace() if it is used by another busybox applet or if additional
13062 * whitespace chars should be considered. Look below the "#include"s for a
13063 * precompiler test.
13064 */
13065
13066/*
13067 * Aug 26, 2001 Manuel Novoa III
13068 *
13069 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13070 *
13071 * Merge in Aaron's comments previously posted to the busybox list,
13072 * modified slightly to take account of my changes to the code.
13073 *
13074 */
13075
13076/*
13077 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13078 *
13079 * - allow access to variable,
13080 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13081 * - realize assign syntax (VAR=expr, +=, *= etc)
13082 * - realize exponentiation (** operator)
13083 * - realize comma separated - expr, expr
13084 * - realise ++expr --expr expr++ expr--
13085 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013086 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013087 * - was restored loses XOR operator
13088 * - remove one goto label, added three ;-)
13089 * - protect $((num num)) as true zero expr (Manuel`s error)
13090 * - always use special isspace(), see comment from bash ;-)
13091 */
13092
13093
13094#define arith_isspace(arithval) \
13095 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13096
13097
13098typedef unsigned char operator;
13099
13100/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013101 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013102 * precedence. The ID portion is so that multiple operators can have the
13103 * same precedence, ensuring that the leftmost one is evaluated first.
13104 * Consider * and /. */
13105
13106#define tok_decl(prec,id) (((id)<<5)|(prec))
13107#define PREC(op) ((op) & 0x1F)
13108
13109#define TOK_LPAREN tok_decl(0,0)
13110
13111#define TOK_COMMA tok_decl(1,0)
13112
13113#define TOK_ASSIGN tok_decl(2,0)
13114#define TOK_AND_ASSIGN tok_decl(2,1)
13115#define TOK_OR_ASSIGN tok_decl(2,2)
13116#define TOK_XOR_ASSIGN tok_decl(2,3)
13117#define TOK_PLUS_ASSIGN tok_decl(2,4)
13118#define TOK_MINUS_ASSIGN tok_decl(2,5)
13119#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13120#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13121
13122#define TOK_MUL_ASSIGN tok_decl(3,0)
13123#define TOK_DIV_ASSIGN tok_decl(3,1)
13124#define TOK_REM_ASSIGN tok_decl(3,2)
13125
13126/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13127#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13128
13129/* conditional is right associativity too */
13130#define TOK_CONDITIONAL tok_decl(4,0)
13131#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13132
13133#define TOK_OR tok_decl(5,0)
13134
13135#define TOK_AND tok_decl(6,0)
13136
13137#define TOK_BOR tok_decl(7,0)
13138
13139#define TOK_BXOR tok_decl(8,0)
13140
13141#define TOK_BAND tok_decl(9,0)
13142
13143#define TOK_EQ tok_decl(10,0)
13144#define TOK_NE tok_decl(10,1)
13145
13146#define TOK_LT tok_decl(11,0)
13147#define TOK_GT tok_decl(11,1)
13148#define TOK_GE tok_decl(11,2)
13149#define TOK_LE tok_decl(11,3)
13150
13151#define TOK_LSHIFT tok_decl(12,0)
13152#define TOK_RSHIFT tok_decl(12,1)
13153
13154#define TOK_ADD tok_decl(13,0)
13155#define TOK_SUB tok_decl(13,1)
13156
13157#define TOK_MUL tok_decl(14,0)
13158#define TOK_DIV tok_decl(14,1)
13159#define TOK_REM tok_decl(14,2)
13160
13161/* exponent is right associativity */
13162#define TOK_EXPONENT tok_decl(15,1)
13163
13164/* For now unary operators. */
13165#define UNARYPREC 16
13166#define TOK_BNOT tok_decl(UNARYPREC,0)
13167#define TOK_NOT tok_decl(UNARYPREC,1)
13168
13169#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13170#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13171
13172#define PREC_PRE (UNARYPREC+2)
13173
13174#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13175#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13176
13177#define PREC_POST (UNARYPREC+3)
13178
13179#define TOK_POST_INC tok_decl(PREC_POST, 0)
13180#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13181
13182#define SPEC_PREC (UNARYPREC+4)
13183
13184#define TOK_NUM tok_decl(SPEC_PREC, 0)
13185#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13186
13187#define NUMPTR (*numstackptr)
13188
13189static inline int tok_have_assign(operator op)
13190{
13191 operator prec = PREC(op);
13192
13193 convert_prec_is_assing(prec);
13194 return (prec == PREC(TOK_ASSIGN) ||
13195 prec == PREC_PRE || prec == PREC_POST);
13196}
13197
13198static inline int is_right_associativity(operator prec)
13199{
13200 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13201 prec == PREC(TOK_CONDITIONAL));
13202}
13203
13204
13205typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013206 arith_t val;
13207 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013208 char contidional_second_val_initialized;
13209 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013210 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013211} v_n_t;
13212
13213
13214typedef struct CHK_VAR_RECURSIVE_LOOPED {
13215 const char *var;
13216 struct CHK_VAR_RECURSIVE_LOOPED *next;
13217} chk_var_recursive_looped_t;
13218
13219static chk_var_recursive_looped_t *prev_chk_var_recursive;
13220
13221
13222static int arith_lookup_val(v_n_t *t)
13223{
13224 if(t->var) {
13225 const char * p = lookupvar(t->var);
13226
13227 if(p) {
13228 int errcode;
13229
13230 /* recursive try as expression */
13231 chk_var_recursive_looped_t *cur;
13232 chk_var_recursive_looped_t cur_save;
13233
13234 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13235 if(strcmp(cur->var, t->var) == 0) {
13236 /* expression recursion loop detected */
13237 return -5;
13238 }
13239 }
13240 /* save current lookuped var name */
13241 cur = prev_chk_var_recursive;
13242 cur_save.var = t->var;
13243 cur_save.next = cur;
13244 prev_chk_var_recursive = &cur_save;
13245
13246 t->val = arith (p, &errcode);
13247 /* restore previous ptr after recursiving */
13248 prev_chk_var_recursive = cur;
13249 return errcode;
13250 } else {
13251 /* allow undefined var as 0 */
13252 t->val = 0;
13253 }
13254 }
13255 return 0;
13256}
13257
13258/* "applying" a token means performing it on the top elements on the integer
13259 * stack. For a unary operator it will only change the top element, but a
13260 * binary operator will pop two arguments and push a result */
13261static inline int
13262arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13263{
Eric Andersen90898442003-08-06 11:20:52 +000013264 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013265 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013266 int ret_arith_lookup_val;
13267
13268 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13269 without arguments */
13270 numptr_m1 = NUMPTR - 1;
13271
13272 /* check operand is var with noninteger value */
13273 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13274 if(ret_arith_lookup_val)
13275 return ret_arith_lookup_val;
13276
13277 rez = numptr_m1->val;
13278 if (op == TOK_UMINUS)
13279 rez *= -1;
13280 else if (op == TOK_NOT)
13281 rez = !rez;
13282 else if (op == TOK_BNOT)
13283 rez = ~rez;
13284 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13285 rez++;
13286 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13287 rez--;
13288 else if (op != TOK_UPLUS) {
13289 /* Binary operators */
13290
13291 /* check and binary operators need two arguments */
13292 if (numptr_m1 == numstack) goto err;
13293
13294 /* ... and they pop one */
13295 --NUMPTR;
13296 numptr_val = rez;
13297 if (op == TOK_CONDITIONAL) {
13298 if(! numptr_m1->contidional_second_val_initialized) {
13299 /* protect $((expr1 ? expr2)) without ": expr" */
13300 goto err;
13301 }
13302 rez = numptr_m1->contidional_second_val;
13303 } else if(numptr_m1->contidional_second_val_initialized) {
13304 /* protect $((expr1 : expr2)) without "expr ? " */
13305 goto err;
13306 }
13307 numptr_m1 = NUMPTR - 1;
13308 if(op != TOK_ASSIGN) {
13309 /* check operand is var with noninteger value for not '=' */
13310 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13311 if(ret_arith_lookup_val)
13312 return ret_arith_lookup_val;
13313 }
13314 if (op == TOK_CONDITIONAL) {
13315 numptr_m1->contidional_second_val = rez;
13316 }
13317 rez = numptr_m1->val;
13318 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13319 rez |= numptr_val;
13320 else if (op == TOK_OR)
13321 rez = numptr_val || rez;
13322 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13323 rez &= numptr_val;
13324 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13325 rez ^= numptr_val;
13326 else if (op == TOK_AND)
13327 rez = rez && numptr_val;
13328 else if (op == TOK_EQ)
13329 rez = (rez == numptr_val);
13330 else if (op == TOK_NE)
13331 rez = (rez != numptr_val);
13332 else if (op == TOK_GE)
13333 rez = (rez >= numptr_val);
13334 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13335 rez >>= numptr_val;
13336 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13337 rez <<= numptr_val;
13338 else if (op == TOK_GT)
13339 rez = (rez > numptr_val);
13340 else if (op == TOK_LT)
13341 rez = (rez < numptr_val);
13342 else if (op == TOK_LE)
13343 rez = (rez <= numptr_val);
13344 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13345 rez *= numptr_val;
13346 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13347 rez += numptr_val;
13348 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13349 rez -= numptr_val;
13350 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13351 rez = numptr_val;
13352 else if (op == TOK_CONDITIONAL_SEP) {
13353 if (numptr_m1 == numstack) {
13354 /* protect $((expr : expr)) without "expr ? " */
13355 goto err;
13356 }
13357 numptr_m1->contidional_second_val_initialized = op;
13358 numptr_m1->contidional_second_val = numptr_val;
13359 }
13360 else if (op == TOK_CONDITIONAL) {
13361 rez = rez ?
13362 numptr_val : numptr_m1->contidional_second_val;
13363 }
13364 else if(op == TOK_EXPONENT) {
13365 if(numptr_val < 0)
13366 return -3; /* exponent less than 0 */
13367 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013368 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013369
13370 if(numptr_val)
13371 while(numptr_val--)
13372 c *= rez;
13373 rez = c;
13374 }
13375 }
13376 else if(numptr_val==0) /* zero divisor check */
13377 return -2;
13378 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13379 rez /= numptr_val;
13380 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13381 rez %= numptr_val;
13382 }
13383 if(tok_have_assign(op)) {
13384 char buf[32];
13385
13386 if(numptr_m1->var == NULL) {
13387 /* Hmm, 1=2 ? */
13388 goto err;
13389 }
13390 /* save to shell variable */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013391#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersena68ea1c2006-01-30 22:48:39 +000013392 snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013393#else
Eric Andersena68ea1c2006-01-30 22:48:39 +000013394 snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013395#endif
Eric Andersen90898442003-08-06 11:20:52 +000013396 setvar(numptr_m1->var, buf, 0);
13397 /* after saving, make previous value for v++ or v-- */
13398 if(op == TOK_POST_INC)
13399 rez--;
13400 else if(op == TOK_POST_DEC)
13401 rez++;
13402 }
13403 numptr_m1->val = rez;
13404 /* protect geting var value, is number now */
13405 numptr_m1->var = NULL;
13406 return 0;
13407err: return(-1);
13408}
13409
13410/* longest must first */
13411static const char op_tokens[] = {
13412 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13413 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13414 '<','<', 0, TOK_LSHIFT,
13415 '>','>', 0, TOK_RSHIFT,
13416 '|','|', 0, TOK_OR,
13417 '&','&', 0, TOK_AND,
13418 '!','=', 0, TOK_NE,
13419 '<','=', 0, TOK_LE,
13420 '>','=', 0, TOK_GE,
13421 '=','=', 0, TOK_EQ,
13422 '|','=', 0, TOK_OR_ASSIGN,
13423 '&','=', 0, TOK_AND_ASSIGN,
13424 '*','=', 0, TOK_MUL_ASSIGN,
13425 '/','=', 0, TOK_DIV_ASSIGN,
13426 '%','=', 0, TOK_REM_ASSIGN,
13427 '+','=', 0, TOK_PLUS_ASSIGN,
13428 '-','=', 0, TOK_MINUS_ASSIGN,
13429 '-','-', 0, TOK_POST_DEC,
13430 '^','=', 0, TOK_XOR_ASSIGN,
13431 '+','+', 0, TOK_POST_INC,
13432 '*','*', 0, TOK_EXPONENT,
13433 '!', 0, TOK_NOT,
13434 '<', 0, TOK_LT,
13435 '>', 0, TOK_GT,
13436 '=', 0, TOK_ASSIGN,
13437 '|', 0, TOK_BOR,
13438 '&', 0, TOK_BAND,
13439 '*', 0, TOK_MUL,
13440 '/', 0, TOK_DIV,
13441 '%', 0, TOK_REM,
13442 '+', 0, TOK_ADD,
13443 '-', 0, TOK_SUB,
13444 '^', 0, TOK_BXOR,
13445 /* uniq */
13446 '~', 0, TOK_BNOT,
13447 ',', 0, TOK_COMMA,
13448 '?', 0, TOK_CONDITIONAL,
13449 ':', 0, TOK_CONDITIONAL_SEP,
13450 ')', 0, TOK_RPAREN,
13451 '(', 0, TOK_LPAREN,
13452 0
13453};
13454/* ptr to ")" */
13455#define endexpression &op_tokens[sizeof(op_tokens)-7]
13456
13457
Eric Andersened9ecf72004-06-22 08:29:45 +000013458static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013459{
"Robert P. J. Day"68229832006-07-01 13:08:46 +000013460 char arithval; /* Current character under analysis */
Eric Andersen90898442003-08-06 11:20:52 +000013461 operator lasttok, op;
13462 operator prec;
13463
13464 const char *p = endexpression;
13465 int errcode;
13466
13467 size_t datasizes = strlen(expr) + 2;
13468
13469 /* Stack of integers */
13470 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013471 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013472 * the reader. */
13473 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13474 *numstackptr = numstack;
13475 /* Stack of operator tokens */
13476 operator *stack = alloca((datasizes) * sizeof(operator)),
13477 *stackptr = stack;
13478
13479 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13480 *perrcode = errcode = 0;
13481
13482 while(1) {
13483 if ((arithval = *expr) == 0) {
13484 if (p == endexpression) {
13485 /* Null expression. */
13486 return 0;
13487 }
13488
13489 /* This is only reached after all tokens have been extracted from the
13490 * input stream. If there are still tokens on the operator stack, they
13491 * are to be applied in order. At the end, there should be a final
13492 * result on the integer stack */
13493
13494 if (expr != endexpression + 1) {
13495 /* If we haven't done so already, */
13496 /* append a closing right paren */
13497 expr = endexpression;
13498 /* and let the loop process it. */
13499 continue;
13500 }
13501 /* At this point, we're done with the expression. */
13502 if (numstackptr != numstack+1) {
13503 /* ... but if there isn't, it's bad */
13504 err:
13505 return (*perrcode = -1);
13506 }
13507 if(numstack->var) {
13508 /* expression is $((var)) only, lookup now */
13509 errcode = arith_lookup_val(numstack);
13510 }
13511 ret:
13512 *perrcode = errcode;
13513 return numstack->val;
13514 } else {
13515 /* Continue processing the expression. */
13516 if (arith_isspace(arithval)) {
13517 /* Skip whitespace */
13518 goto prologue;
13519 }
13520 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013521 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013522
13523 numstackptr->var = alloca(var_name_size);
13524 safe_strncpy(numstackptr->var, expr, var_name_size);
13525 expr = p;
13526 num:
13527 numstackptr->contidional_second_val_initialized = 0;
13528 numstackptr++;
13529 lasttok = TOK_NUM;
13530 continue;
13531 } else if (is_digit(arithval)) {
13532 numstackptr->var = NULL;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013533#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersenad63cb22004-10-08 09:43:34 +000013534 numstackptr->val = strtoll(expr, (char **) &expr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013535#else
13536 numstackptr->val = strtol(expr, (char **) &expr, 0);
13537#endif
Eric Andersen90898442003-08-06 11:20:52 +000013538 goto num;
13539 }
13540 for(p = op_tokens; ; p++) {
13541 const char *o;
13542
13543 if(*p == 0) {
13544 /* strange operator not found */
13545 goto err;
13546 }
13547 for(o = expr; *p && *o == *p; p++)
13548 o++;
13549 if(! *p) {
13550 /* found */
13551 expr = o - 1;
13552 break;
13553 }
13554 /* skip tail uncompared token */
13555 while(*p)
13556 p++;
13557 /* skip zero delim */
13558 p++;
13559 }
13560 op = p[1];
13561
13562 /* post grammar: a++ reduce to num */
13563 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13564 lasttok = TOK_NUM;
13565
13566 /* Plus and minus are binary (not unary) _only_ if the last
13567 * token was as number, or a right paren (which pretends to be
13568 * a number, since it evaluates to one). Think about it.
13569 * It makes sense. */
13570 if (lasttok != TOK_NUM) {
13571 switch(op) {
13572 case TOK_ADD:
13573 op = TOK_UPLUS;
13574 break;
13575 case TOK_SUB:
13576 op = TOK_UMINUS;
13577 break;
13578 case TOK_POST_INC:
13579 op = TOK_PRE_INC;
13580 break;
13581 case TOK_POST_DEC:
13582 op = TOK_PRE_DEC;
13583 break;
13584 }
13585 }
13586 /* We don't want a unary operator to cause recursive descent on the
13587 * stack, because there can be many in a row and it could cause an
13588 * operator to be evaluated before its argument is pushed onto the
13589 * integer stack. */
13590 /* But for binary operators, "apply" everything on the operator
13591 * stack until we find an operator with a lesser priority than the
13592 * one we have just extracted. */
13593 /* Left paren is given the lowest priority so it will never be
13594 * "applied" in this way.
13595 * if associativity is right and priority eq, applied also skip
13596 */
13597 prec = PREC(op);
13598 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13599 /* not left paren or unary */
13600 if (lasttok != TOK_NUM) {
13601 /* binary op must be preceded by a num */
13602 goto err;
13603 }
13604 while (stackptr != stack) {
13605 if (op == TOK_RPAREN) {
13606 /* The algorithm employed here is simple: while we don't
13607 * hit an open paren nor the bottom of the stack, pop
13608 * tokens and apply them */
13609 if (stackptr[-1] == TOK_LPAREN) {
13610 --stackptr;
13611 /* Any operator directly after a */
13612 lasttok = TOK_NUM;
13613 /* close paren should consider itself binary */
13614 goto prologue;
13615 }
13616 } else {
13617 operator prev_prec = PREC(stackptr[-1]);
13618
13619 convert_prec_is_assing(prec);
13620 convert_prec_is_assing(prev_prec);
13621 if (prev_prec < prec)
13622 break;
13623 /* check right assoc */
13624 if(prev_prec == prec && is_right_associativity(prec))
13625 break;
13626 }
13627 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13628 if(errcode) goto ret;
13629 }
13630 if (op == TOK_RPAREN) {
13631 goto err;
13632 }
13633 }
13634
13635 /* Push this operator to the stack and remember it. */
13636 *stackptr++ = lasttok = op;
13637
13638 prologue:
13639 ++expr;
13640 }
13641 }
13642}
13643#endif /* CONFIG_ASH_MATH_SUPPORT */
13644
13645
Eric Andersenc470f442003-07-28 09:56:35 +000013646#ifdef DEBUG
13647const char *bb_applet_name = "debug stuff usage";
13648int main(int argc, char **argv)
13649{
13650 return ash_main(argc, argv);
13651}
13652#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013653
Eric Andersendf82f612001-06-28 07:46:40 +000013654/*-
13655 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013656 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013657 *
13658 * This code is derived from software contributed to Berkeley by
13659 * Kenneth Almquist.
13660 *
13661 * Redistribution and use in source and binary forms, with or without
13662 * modification, are permitted provided that the following conditions
13663 * are met:
13664 * 1. Redistributions of source code must retain the above copyright
13665 * notice, this list of conditions and the following disclaimer.
13666 * 2. Redistributions in binary form must reproduce the above copyright
13667 * notice, this list of conditions and the following disclaimer in the
13668 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013669 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013670 * may be used to endorse or promote products derived from this software
13671 * without specific prior written permission.
13672 *
13673 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13674 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13675 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13676 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13677 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13678 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13679 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13680 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13681 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13682 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13683 * SUCH DAMAGE.
13684 */