blob: 3564d850be3a7da137f94fea2cb816f206c4da6d [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 Andersenc470f442003-07-28 09:56:35 +000047
Eric Andersen5bb16772001-09-06 18:00:41 +000048#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000049
Eric Andersenc470f442003-07-28 09:56:35 +000050#define PROFILE 0
51
52#ifdef DEBUG
53#define _GNU_SOURCE
54#endif
55
56#include <sys/types.h>
Eric Andersenc470f442003-07-28 09:56:35 +000057#include <sys/ioctl.h>
58#include <sys/param.h>
59#include <sys/resource.h>
60#include <sys/stat.h>
61#include <sys/time.h>
62#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>
Eric Andersenc470f442003-07-28 09:56:35 +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
84
Robert Grieblea1a63a2002-06-04 20:10:23 +000085#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +000086#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +000087
Eric Andersend35c5df2002-01-09 15:37:36 +000088#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000089#define JOBS 1
90#else
Eric Andersenca162042003-07-29 07:15:17 +000091#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +000092#endif
93
Paul Fox02eb9342005-09-07 16:56:02 +000094#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
Eric Andersencb57d552001-06-28 07:25:16 +000095#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +000096#endif
97
Eric Andersen2870d962001-07-02 17:27:21 +000098#include "cmdedit.h"
99
Eric Andersenc470f442003-07-28 09:56:35 +0000100#ifdef __GLIBC__
101/* glibc sucks */
102static int *dash_errno;
103#undef errno
104#define errno (*dash_errno)
105#endif
106
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000107#if defined(__uClinux__)
108#error "Do not even bother, ash will not run on uClinux"
109#endif
110
Eric Andersenc470f442003-07-28 09:56:35 +0000111#ifdef DEBUG
112#define _DIAGASSERT(assert_expr) assert(assert_expr)
113#else
114#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000115#endif
116
Eric Andersen2870d962001-07-02 17:27:21 +0000117
Eric Andersenc470f442003-07-28 09:56:35 +0000118#ifdef CONFIG_ASH_ALIAS
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000119/* alias.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000120
121#define ALIASINUSE 1
122#define ALIASDEAD 2
123
124struct alias {
125 struct alias *next;
126 char *name;
127 char *val;
128 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000129};
130
Eric Andersenc470f442003-07-28 09:56:35 +0000131static struct alias *lookupalias(const char *, int);
132static int aliascmd(int, char **);
133static int unaliascmd(int, char **);
134static void rmaliases(void);
135static int unalias(const char *);
136static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000137#endif
138
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000139/* cd.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000140
141
142static void setpwd(const char *, int);
143
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000144/* error.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000145
146
147/*
148 * Types of operations (passed to the errmsg routine).
149 */
150
151
152static const char not_found_msg[] = "%s: not found";
153
154
155#define E_OPEN "No such file" /* opening a file */
156#define E_CREAT "Directory nonexistent" /* creating a file */
157#define E_EXEC not_found_msg+4 /* executing a program */
158
159/*
160 * We enclose jmp_buf in a structure so that we can declare pointers to
161 * jump locations. The global variable handler contains the location to
162 * jump to when an exception occurs, and the global variable exception
Eric Andersenaff114c2004-04-14 17:51:38 +0000163 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000164 * exception handlers, the user should save the value of handler on entry
165 * to an inner scope, set handler to point to a jmploc structure for the
166 * inner scope, and restore handler on exit from the scope.
167 */
168
169struct jmploc {
170 jmp_buf loc;
171};
172
173static struct jmploc *handler;
174static int exception;
175static volatile int suppressint;
176static volatile sig_atomic_t intpending;
177
Eric Andersenc470f442003-07-28 09:56:35 +0000178/* exceptions */
179#define EXINT 0 /* SIGINT received */
180#define EXERROR 1 /* a generic error */
181#define EXSHELLPROC 2 /* execute a shell procedure */
182#define EXEXEC 3 /* command execution failed */
183#define EXEXIT 4 /* exit the shell */
184#define EXSIG 5 /* trapped signal in wait(1) */
185
186
187/* do we generate EXSIG events */
188static int exsig;
189/* last pending signal */
190static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000191
192/*
193 * These macros allow the user to suspend the handling of interrupt signals
194 * over a period of time. This is similar to SIGHOLD to or sigblock, but
195 * much more efficient and portable. (But hacking the kernel is so much
196 * more fun than worrying about efficiency and portability. :-))
197 */
198
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000199#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
Eric Andersenc470f442003-07-28 09:56:35 +0000200#define INTOFF \
201 ({ \
202 suppressint++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000203 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000204 0; \
205 })
206#define SAVEINT(v) ((v) = suppressint)
207#define RESTOREINT(v) \
208 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000209 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000210 if ((suppressint = (v)) == 0 && intpending) onint(); \
211 0; \
212 })
213#define EXSIGON() \
214 ({ \
215 exsig++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000216 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000217 if (pendingsigs) \
218 exraise(EXSIG); \
219 0; \
220 })
221/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000222
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000223
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000224static void exraise(int) ATTRIBUTE_NORETURN;
225static void onint(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000226
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000227static void sh_error(const char *, ...) ATTRIBUTE_NORETURN;
228static void exerror(int, const char *, ...) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +0000229
230static void sh_warnx(const char *, ...);
231
232#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
233static void
234inton(void) {
235 if (--suppressint == 0 && intpending) {
236 onint();
237 }
238}
239#define INTON inton()
240static void forceinton(void)
241{
242 suppressint = 0;
243 if (intpending)
244 onint();
245}
Eric Andersen3102ac42001-07-06 04:26:23 +0000246#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000247#else
Eric Andersenc470f442003-07-28 09:56:35 +0000248#define INTON \
249 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000250 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000251 if (--suppressint == 0 && intpending) onint(); \
252 0; \
253 })
254#define FORCEINTON \
255 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000256 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000257 suppressint = 0; \
258 if (intpending) onint(); \
259 0; \
260 })
261#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000262
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000263/* expand.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000264
265struct strlist {
266 struct strlist *next;
267 char *text;
268};
269
270
271struct arglist {
272 struct strlist *list;
273 struct strlist **lastp;
274};
275
Eric Andersenc470f442003-07-28 09:56:35 +0000276/*
277 * expandarg() flags
278 */
279#define EXP_FULL 0x1 /* perform word splitting & file globbing */
280#define EXP_TILDE 0x2 /* do normal tilde expansion */
281#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
282#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
283#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
284#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
285#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
286#define EXP_WORD 0x80 /* expand word in parameter expansion */
287#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
288
289
290union node;
291static void expandarg(union node *, struct arglist *, int);
292#define rmescapes(p) _rmescapes((p), 0)
293static char *_rmescapes(char *, int);
294static int casematch(union node *, char *);
295
296#ifdef CONFIG_ASH_MATH_SUPPORT
297static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000298#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000299
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000300/* eval.h */
Eric Andersen2870d962001-07-02 17:27:21 +0000301
Eric Andersenc470f442003-07-28 09:56:35 +0000302static char *commandname; /* currently executing command */
303static struct strlist *cmdenviron; /* environment for builtin command */
304static int exitstatus; /* exit status of last command */
305static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000306
Eric Andersenc470f442003-07-28 09:56:35 +0000307
308struct backcmd { /* result of evalbackcmd */
309 int fd; /* file descriptor to read from */
310 char *buf; /* buffer */
311 int nleft; /* number of chars in buffer */
312 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000313};
314
Eric Andersen62483552001-07-10 06:09:16 +0000315/*
Eric Andersenc470f442003-07-28 09:56:35 +0000316 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000317 */
Eric Andersenc470f442003-07-28 09:56:35 +0000318
319#define NCMD 0
320#define NPIPE 1
321#define NREDIR 2
322#define NBACKGND 3
323#define NSUBSHELL 4
324#define NAND 5
325#define NOR 6
326#define NSEMI 7
327#define NIF 8
328#define NWHILE 9
329#define NUNTIL 10
330#define NFOR 11
331#define NCASE 12
332#define NCLIST 13
333#define NDEFUN 14
334#define NARG 15
335#define NTO 16
336#define NCLOBBER 17
337#define NFROM 18
338#define NFROMTO 19
339#define NAPPEND 20
340#define NTOFD 21
341#define NFROMFD 22
342#define NHERE 23
343#define NXHERE 24
344#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000345
346
347
Eric Andersenc470f442003-07-28 09:56:35 +0000348struct ncmd {
349 int type;
350 union node *assign;
351 union node *args;
352 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000353};
354
355
Eric Andersenc470f442003-07-28 09:56:35 +0000356struct npipe {
357 int type;
358 int backgnd;
359 struct nodelist *cmdlist;
360};
Eric Andersen62483552001-07-10 06:09:16 +0000361
362
Eric Andersenc470f442003-07-28 09:56:35 +0000363struct nredir {
364 int type;
365 union node *n;
366 union node *redirect;
367};
Eric Andersen62483552001-07-10 06:09:16 +0000368
369
Eric Andersenc470f442003-07-28 09:56:35 +0000370struct nbinary {
371 int type;
372 union node *ch1;
373 union node *ch2;
374};
Eric Andersen2870d962001-07-02 17:27:21 +0000375
Eric Andersen2870d962001-07-02 17:27:21 +0000376
Eric Andersenc470f442003-07-28 09:56:35 +0000377struct nif {
378 int type;
379 union node *test;
380 union node *ifpart;
381 union node *elsepart;
382};
383
384
385struct nfor {
386 int type;
387 union node *args;
388 union node *body;
389 char *var;
390};
391
392
393struct ncase {
394 int type;
395 union node *expr;
396 union node *cases;
397};
398
399
400struct nclist {
401 int type;
402 union node *next;
403 union node *pattern;
404 union node *body;
405};
406
407
408struct narg {
409 int type;
410 union node *next;
411 char *text;
412 struct nodelist *backquote;
413};
414
415
416struct nfile {
417 int type;
418 union node *next;
419 int fd;
420 union node *fname;
421 char *expfname;
422};
423
424
425struct ndup {
426 int type;
427 union node *next;
428 int fd;
429 int dupfd;
430 union node *vname;
431};
432
433
434struct nhere {
435 int type;
436 union node *next;
437 int fd;
438 union node *doc;
439};
440
441
442struct nnot {
443 int type;
444 union node *com;
445};
446
447
448union node {
449 int type;
450 struct ncmd ncmd;
451 struct npipe npipe;
452 struct nredir nredir;
453 struct nbinary nbinary;
454 struct nif nif;
455 struct nfor nfor;
456 struct ncase ncase;
457 struct nclist nclist;
458 struct narg narg;
459 struct nfile nfile;
460 struct ndup ndup;
461 struct nhere nhere;
462 struct nnot nnot;
463};
464
465
466struct nodelist {
467 struct nodelist *next;
468 union node *n;
469};
470
471
472struct funcnode {
473 int count;
474 union node n;
475};
476
477
478static void freefunc(struct funcnode *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000479/* parser.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000480
481/* control characters in argument strings */
482#define CTL_FIRST '\201' /* first 'special' character */
483#define CTLESC '\201' /* escape next character */
484#define CTLVAR '\202' /* variable defn */
485#define CTLENDVAR '\203'
486#define CTLBACKQ '\204'
487#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
488/* CTLBACKQ | CTLQUOTE == '\205' */
489#define CTLARI '\206' /* arithmetic expression */
490#define CTLENDARI '\207'
491#define CTLQUOTEMARK '\210'
492#define CTL_LAST '\210' /* last 'special' character */
493
494/* variable substitution byte (follows CTLVAR) */
495#define VSTYPE 0x0f /* type of variable substitution */
496#define VSNUL 0x10 /* colon--treat the empty string as unset */
497#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
498
499/* values of VSTYPE field */
500#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
501#define VSMINUS 0x2 /* ${var-text} */
502#define VSPLUS 0x3 /* ${var+text} */
503#define VSQUESTION 0x4 /* ${var?message} */
504#define VSASSIGN 0x5 /* ${var=text} */
505#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
506#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
507#define VSTRIMLEFT 0x8 /* ${var#pattern} */
508#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
509#define VSLENGTH 0xa /* ${#var} */
510
511/* values of checkkwd variable */
512#define CHKALIAS 0x1
513#define CHKKWD 0x2
514#define CHKNL 0x4
515
516#define IBUFSIZ (BUFSIZ + 1)
517
518/*
519 * NEOF is returned by parsecmd when it encounters an end of file. It
520 * must be distinct from NULL, so we use the address of a variable that
521 * happens to be handy.
522 */
523static int plinno = 1; /* input line number */
524
525/* number of characters left in input buffer */
526static int parsenleft; /* copy of parsefile->nleft */
527static int parselleft; /* copy of parsefile->lleft */
528
529/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000530static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000531
532struct strpush {
533 struct strpush *prev; /* preceding string on stack */
534 char *prevstring;
535 int prevnleft;
536#ifdef CONFIG_ASH_ALIAS
537 struct alias *ap; /* if push was associated with an alias */
538#endif
539 char *string; /* remember the string since it may change */
540};
541
542struct parsefile {
543 struct parsefile *prev; /* preceding file on stack */
544 int linno; /* current line */
545 int fd; /* file descriptor (or -1 if string) */
546 int nleft; /* number of chars left in this line */
547 int lleft; /* number of chars left in this buffer */
548 char *nextc; /* next char in buffer */
549 char *buf; /* input buffer */
550 struct strpush *strpush; /* for pushing strings at this level */
551 struct strpush basestrpush; /* so pushing one is fast */
552};
553
Eric Andersenc470f442003-07-28 09:56:35 +0000554static struct parsefile basepf; /* top level input file */
"Vladimir N. Oleynik"6f347ef2005-10-15 10:23:55 +0000555#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
Eric Andersenc470f442003-07-28 09:56:35 +0000556static struct parsefile *parsefile = &basepf; /* current input file */
557
558
559static int tokpushback; /* last token pushed back */
560#define NEOF ((union node *)&tokpushback)
561static int parsebackquote; /* nonzero if we are inside backquotes */
562static int doprompt; /* if set, prompt the user */
563static int needprompt; /* true if interactive and at start of line */
564static int lasttoken; /* last token read */
565static char *wordtext; /* text of last word returned by readtoken */
566static int checkkwd;
567static struct nodelist *backquotelist;
568static union node *redirnode;
569static struct heredoc *heredoc;
570static int quoteflag; /* set if (part of) last token was quoted */
571static int startlinno; /* line # where last token started */
572
573static union node *parsecmd(int);
574static void fixredir(union node *, const char *, int);
575static const char *const *findkwd(const char *);
576static char *endofname(const char *);
577
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000578/* shell.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000579
580typedef void *pointer;
581
582static char nullstr[1]; /* zero length string */
583static const char spcstr[] = " ";
584static const char snlfmt[] = "%s\n";
585static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
586static const char illnum[] = "Illegal number: %s";
587static const char homestr[] = "HOME";
588
589#ifdef DEBUG
590#define TRACE(param) trace param
591#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000592#else
Eric Andersenc470f442003-07-28 09:56:35 +0000593#define TRACE(param)
594#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000595#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000596
Eric Andersenc470f442003-07-28 09:56:35 +0000597#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
598#define __builtin_expect(x, expected_value) (x)
599#endif
600
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000601#define xlikely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000602
Eric Andersenc470f442003-07-28 09:56:35 +0000603
604#define TEOF 0
605#define TNL 1
606#define TREDIR 2
607#define TWORD 3
608#define TSEMI 4
609#define TBACKGND 5
610#define TAND 6
611#define TOR 7
612#define TPIPE 8
613#define TLP 9
614#define TRP 10
615#define TENDCASE 11
616#define TENDBQUOTE 12
617#define TNOT 13
618#define TCASE 14
619#define TDO 15
620#define TDONE 16
621#define TELIF 17
622#define TELSE 18
623#define TESAC 19
624#define TFI 20
625#define TFOR 21
626#define TIF 22
627#define TIN 23
628#define TTHEN 24
629#define TUNTIL 25
630#define TWHILE 26
631#define TBEGIN 27
632#define TEND 28
633
634/* first char is indicating which tokens mark the end of a list */
635static const char *const tokname_array[] = {
636 "\1end of file",
637 "\0newline",
638 "\0redirection",
639 "\0word",
640 "\0;",
641 "\0&",
642 "\0&&",
643 "\0||",
644 "\0|",
645 "\0(",
646 "\1)",
647 "\1;;",
648 "\1`",
649#define KWDOFFSET 13
650 /* the following are keywords */
651 "\0!",
652 "\0case",
653 "\1do",
654 "\1done",
655 "\1elif",
656 "\1else",
657 "\1esac",
658 "\1fi",
659 "\0for",
660 "\0if",
661 "\0in",
662 "\1then",
663 "\0until",
664 "\0while",
665 "\0{",
666 "\1}",
667};
668
669static const char *tokname(int tok)
670{
671 static char buf[16];
672
673 if (tok >= TSEMI)
674 buf[0] = '"';
675 sprintf(buf + (tok >= TSEMI), "%s%c",
676 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
677 return buf;
678}
679
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +0000680/* machdep.h */
Eric Andersenc470f442003-07-28 09:56:35 +0000681
682/*
683 * Most machines require the value returned from malloc to be aligned
684 * in some way. The following macro will get this right on many machines.
685 */
686
687#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
688/*
689 * It appears that grabstackstr() will barf with such alignments
690 * because stalloc() will return a string allocated in a new stackblock.
691 */
692#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
693
694/*
695 * This file was generated by the mksyntax program.
696 */
697
698
699/* Syntax classes */
700#define CWORD 0 /* character is nothing special */
701#define CNL 1 /* newline character */
702#define CBACK 2 /* a backslash character */
703#define CSQUOTE 3 /* single quote */
704#define CDQUOTE 4 /* double quote */
705#define CENDQUOTE 5 /* a terminating quote */
706#define CBQUOTE 6 /* backwards single quote */
707#define CVAR 7 /* a dollar sign */
708#define CENDVAR 8 /* a '}' character */
709#define CLP 9 /* a left paren in arithmetic */
710#define CRP 10 /* a right paren in arithmetic */
711#define CENDFILE 11 /* end of file */
712#define CCTL 12 /* like CWORD, except it must be escaped */
713#define CSPCL 13 /* these terminate a word */
714#define CIGN 14 /* character should be ignored */
715
716#ifdef CONFIG_ASH_ALIAS
717#define SYNBASE 130
718#define PEOF -130
719#define PEOA -129
720#define PEOA_OR_PEOF PEOA
721#else
722#define SYNBASE 129
723#define PEOF -129
724#define PEOA_OR_PEOF PEOF
725#endif
726
727#define is_digit(c) ((unsigned)((c) - '0') <= 9)
728#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
729#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
730
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000731/* C99 say: "char" declaration may be signed or unsigned default */
732#define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int)
733
Eric Andersenc470f442003-07-28 09:56:35 +0000734/*
735 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
736 * (assuming ascii char codes, as the original implementation did)
737 */
738#define is_special(c) \
739 ( (((unsigned int)c) - 33 < 32) \
740 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
741
742#define digit_val(c) ((c) - '0')
743
744/*
745 * This file was generated by the mksyntax program.
746 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000747
Eric Andersend35c5df2002-01-09 15:37:36 +0000748#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000749#define USE_SIT_FUNCTION
750#endif
751
752/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000753#define BASESYNTAX 0 /* not in quotes */
754#define DQSYNTAX 1 /* in double quotes */
755#define SQSYNTAX 2 /* in single quotes */
756#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000757
Eric Andersenc470f442003-07-28 09:56:35 +0000758#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000759static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000760#ifdef CONFIG_ASH_ALIAS
761 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
762#endif
763 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
764 {CNL, CNL, CNL, CNL}, /* 2, \n */
765 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
766 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
767 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
768 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
769 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
770 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
771 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
772 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
773 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000774#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000775 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
776 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
777 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000778#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000779};
Eric Andersenc470f442003-07-28 09:56:35 +0000780#else
781static const char S_I_T[][3] = {
782#ifdef CONFIG_ASH_ALIAS
783 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
784#endif
785 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
786 {CNL, CNL, CNL}, /* 2, \n */
787 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
788 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
789 {CVAR, CVAR, CWORD}, /* 5, $ */
790 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
791 {CSPCL, CWORD, CWORD}, /* 7, ( */
792 {CSPCL, CWORD, CWORD}, /* 8, ) */
793 {CBACK, CBACK, CCTL}, /* 9, \ */
794 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
795 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
796#ifndef USE_SIT_FUNCTION
797 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
798 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
799 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
800#endif
801};
802#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000803
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000804#ifdef USE_SIT_FUNCTION
805
806#define U_C(c) ((unsigned char)(c))
807
808static int SIT(int c, int syntax)
809{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000810 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000811#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000812 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000813 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
814 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
815 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
816 11, 3 /* "}~" */
817 };
818#else
819 static const char syntax_index_table[] = {
820 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
821 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
822 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
823 10, 2 /* "}~" */
824 };
825#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000826 const char *s;
827 int indx;
828
Eric Andersenc470f442003-07-28 09:56:35 +0000829 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000830 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000831#ifdef CONFIG_ASH_ALIAS
832 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000833 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000834 else
835#endif
836 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
837 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000838 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000839 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000840 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000841 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000842 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000843 }
844 return S_I_T[indx][syntax];
845}
846
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +0000847#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000848
849#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
850
Eric Andersenc470f442003-07-28 09:56:35 +0000851#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000852#define CSPCL_CIGN_CIGN_CIGN 0
853#define CSPCL_CWORD_CWORD_CWORD 1
854#define CNL_CNL_CNL_CNL 2
855#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000856#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000857#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000858#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000859#define CSPCL_CWORD_CWORD_CLP 7
860#define CSPCL_CWORD_CWORD_CRP 8
861#define CBACK_CBACK_CCTL_CBACK 9
862#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
863#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
864#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
865#define CWORD_CWORD_CWORD_CWORD 13
866#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000867#else
868#define CSPCL_CWORD_CWORD_CWORD 0
869#define CNL_CNL_CNL_CNL 1
870#define CWORD_CCTL_CCTL_CWORD 2
871#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
872#define CVAR_CVAR_CWORD_CVAR 4
873#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
874#define CSPCL_CWORD_CWORD_CLP 6
875#define CSPCL_CWORD_CWORD_CRP 7
876#define CBACK_CBACK_CCTL_CBACK 8
877#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
878#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
879#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
880#define CWORD_CWORD_CWORD_CWORD 12
881#define CCTL_CCTL_CCTL_CCTL 13
882#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000883
884static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000885 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000886 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
887#ifdef CONFIG_ASH_ALIAS
888 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
889#endif
890 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
891 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
892 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
893 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
894 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
895 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
896 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
897 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
898 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000899 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
900 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
901 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
902 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
903 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
904 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
905 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
906 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
907 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
908 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
909 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
910 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
911 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
912 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
913 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
914 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
915 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
916 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
917 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
918 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
919 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
920 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
921 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
922 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
923 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
924 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
925 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
926 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
927 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
928 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
929 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
930 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
931 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
932 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
933 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
934 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
935 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
936 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
937 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
938 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
939 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
940 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
941 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
942 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
943 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
944 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
945 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
946 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
947 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
948 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
949 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
950 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
951 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
952 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
953 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
954 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
955 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
956 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
957 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
958 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
959 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
960 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
961 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
962 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
963 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
964 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
965 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
966 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
967 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
968 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
969 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
970 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
971 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
972 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
973 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
974 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
975 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
976 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
977 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
978 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
979 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
980 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
981 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
982 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
983 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
984 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
985 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
986 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
987 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
988 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
989 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
990 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
991 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
992 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
993 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
994 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
995 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
996 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
997 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
998 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
999 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1028 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1029 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1051 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001052 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001053 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1054 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1055 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1056 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001057 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001058 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1059 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1060 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1061 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1062 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1063 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1064 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1065 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1066 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1072 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1073 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1074 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1075 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1076 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1077 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1078 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1079 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1080 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1081 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1082 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1110 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1111 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1112 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1115 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1143 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1144 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1145 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001146};
1147
"Vladimir N. Oleynik"fdb871c2006-01-25 11:53:47 +00001148#endif /* USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00001149
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001150/* alias.c */
Eric Andersen2870d962001-07-02 17:27:21 +00001151
Eric Andersen2870d962001-07-02 17:27:21 +00001152
Eric Andersenc470f442003-07-28 09:56:35 +00001153#define ATABSIZE 39
1154
1155static int funcblocksize; /* size of structures in function */
1156static int funcstringsize; /* size of strings in node */
1157static pointer funcblock; /* block to allocate function from */
1158static char *funcstring; /* block to allocate strings from */
1159
1160static const short nodesize[26] = {
1161 SHELL_ALIGN(sizeof (struct ncmd)),
1162 SHELL_ALIGN(sizeof (struct npipe)),
1163 SHELL_ALIGN(sizeof (struct nredir)),
1164 SHELL_ALIGN(sizeof (struct nredir)),
1165 SHELL_ALIGN(sizeof (struct nredir)),
1166 SHELL_ALIGN(sizeof (struct nbinary)),
1167 SHELL_ALIGN(sizeof (struct nbinary)),
1168 SHELL_ALIGN(sizeof (struct nbinary)),
1169 SHELL_ALIGN(sizeof (struct nif)),
1170 SHELL_ALIGN(sizeof (struct nbinary)),
1171 SHELL_ALIGN(sizeof (struct nbinary)),
1172 SHELL_ALIGN(sizeof (struct nfor)),
1173 SHELL_ALIGN(sizeof (struct ncase)),
1174 SHELL_ALIGN(sizeof (struct nclist)),
1175 SHELL_ALIGN(sizeof (struct narg)),
1176 SHELL_ALIGN(sizeof (struct narg)),
1177 SHELL_ALIGN(sizeof (struct nfile)),
1178 SHELL_ALIGN(sizeof (struct nfile)),
1179 SHELL_ALIGN(sizeof (struct nfile)),
1180 SHELL_ALIGN(sizeof (struct nfile)),
1181 SHELL_ALIGN(sizeof (struct nfile)),
1182 SHELL_ALIGN(sizeof (struct ndup)),
1183 SHELL_ALIGN(sizeof (struct ndup)),
1184 SHELL_ALIGN(sizeof (struct nhere)),
1185 SHELL_ALIGN(sizeof (struct nhere)),
1186 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001187};
1188
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001189
Eric Andersenc470f442003-07-28 09:56:35 +00001190static void calcsize(union node *);
1191static void sizenodelist(struct nodelist *);
1192static union node *copynode(union node *);
1193static struct nodelist *copynodelist(struct nodelist *);
1194static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001195
1196
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001197static int evalstring(char *, int mask);
Eric Andersenc470f442003-07-28 09:56:35 +00001198union node; /* BLETCH for ansi C */
1199static void evaltree(union node *, int);
1200static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001201
Eric Andersenc470f442003-07-28 09:56:35 +00001202static int evalskip; /* set if we are skipping commands */
1203static int skipcount; /* number of levels to skip */
1204static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001205
1206/* reasons for skipping commands (see comment on breakcmd routine) */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001207#define SKIPBREAK (1 << 0)
1208#define SKIPCONT (1 << 1)
1209#define SKIPFUNC (1 << 2)
1210#define SKIPFILE (1 << 3)
1211#define SKIPEVAL (1 << 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001212
Eric Andersenc470f442003-07-28 09:56:35 +00001213/*
1214 * This file was generated by the mkbuiltins program.
1215 */
Eric Andersen2870d962001-07-02 17:27:21 +00001216
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001217#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001218static int bgcmd(int, char **);
1219#endif
1220static int breakcmd(int, char **);
1221static int cdcmd(int, char **);
1222#ifdef CONFIG_ASH_CMDCMD
1223static int commandcmd(int, char **);
1224#endif
1225static int dotcmd(int, char **);
1226static int evalcmd(int, char **);
Paul Fox0b621582005-08-09 19:38:05 +00001227#ifdef CONFIG_ASH_BUILTIN_ECHO
1228static int echocmd(int, char **);
1229#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001230static int execcmd(int, char **);
1231static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001232static int exportcmd(int, char **);
1233static int falsecmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001234#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001235static int fgcmd(int, char **);
1236#endif
1237#ifdef CONFIG_ASH_GETOPTS
1238static int getoptscmd(int, char **);
1239#endif
1240static int hashcmd(int, char **);
1241#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1242static int helpcmd(int argc, char **argv);
1243#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001244#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001245static int jobscmd(int, char **);
1246#endif
Eric Andersen90898442003-08-06 11:20:52 +00001247#ifdef CONFIG_ASH_MATH_SUPPORT
1248static int letcmd(int, char **);
1249#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001250static int localcmd(int, char **);
1251static int pwdcmd(int, char **);
1252static int readcmd(int, char **);
1253static int returncmd(int, char **);
1254static int setcmd(int, char **);
1255static int shiftcmd(int, char **);
1256static int timescmd(int, char **);
1257static int trapcmd(int, char **);
1258static int truecmd(int, char **);
1259static int typecmd(int, char **);
1260static int umaskcmd(int, char **);
1261static int unsetcmd(int, char **);
1262static int waitcmd(int, char **);
1263static int ulimitcmd(int, char **);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001264#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001265static int killcmd(int, char **);
1266#endif
1267
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001268/* mail.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001269
1270#ifdef CONFIG_ASH_MAIL
1271static void chkmail(void);
1272static void changemail(const char *);
1273#endif
1274
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001275/* exec.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001276
1277/* values of cmdtype */
1278#define CMDUNKNOWN -1 /* no entry in table for command */
1279#define CMDNORMAL 0 /* command is an executable program */
1280#define CMDFUNCTION 1 /* command is a shell function */
1281#define CMDBUILTIN 2 /* command is a shell builtin */
1282
1283struct builtincmd {
1284 const char *name;
1285 int (*builtin)(int, char **);
1286 /* unsigned flags; */
1287};
1288
Paul Fox0b621582005-08-09 19:38:05 +00001289
1290#define COMMANDCMD (builtincmd + 5 + \
1291 ENABLE_ASH_ALIAS + ENABLE_ASH_JOB_CONTROL)
1292#define EXECCMD (builtincmd + 7 + \
1293 ENABLE_ASH_CMDCMD + ENABLE_ASH_ALIAS + \
1294 ENABLE_ASH_BUILTIN_ECHO + ENABLE_ASH_JOB_CONTROL)
Eric Andersenc470f442003-07-28 09:56:35 +00001295
1296#define BUILTIN_NOSPEC "0"
1297#define BUILTIN_SPECIAL "1"
1298#define BUILTIN_REGULAR "2"
1299#define BUILTIN_SPEC_REG "3"
1300#define BUILTIN_ASSIGN "4"
1301#define BUILTIN_SPEC_ASSG "5"
1302#define BUILTIN_REG_ASSG "6"
1303#define BUILTIN_SPEC_REG_ASSG "7"
1304
1305#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1306#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
Paul Foxc3850c82005-07-20 18:23:39 +00001307#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001308
1309static const struct builtincmd builtincmd[] = {
1310 { BUILTIN_SPEC_REG ".", dotcmd },
1311 { BUILTIN_SPEC_REG ":", truecmd },
1312#ifdef CONFIG_ASH_ALIAS
1313 { BUILTIN_REG_ASSG "alias", aliascmd },
1314#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001315#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001316 { BUILTIN_REGULAR "bg", bgcmd },
1317#endif
1318 { BUILTIN_SPEC_REG "break", breakcmd },
1319 { BUILTIN_REGULAR "cd", cdcmd },
1320 { BUILTIN_NOSPEC "chdir", cdcmd },
1321#ifdef CONFIG_ASH_CMDCMD
1322 { BUILTIN_REGULAR "command", commandcmd },
1323#endif
1324 { BUILTIN_SPEC_REG "continue", breakcmd },
Paul Fox0b621582005-08-09 19:38:05 +00001325#ifdef CONFIG_ASH_BUILTIN_ECHO
1326 { BUILTIN_REGULAR "echo", echocmd },
1327#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001328 { BUILTIN_SPEC_REG "eval", evalcmd },
1329 { BUILTIN_SPEC_REG "exec", execcmd },
1330 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001331 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1332 { BUILTIN_REGULAR "false", falsecmd },
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001333#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001334 { BUILTIN_REGULAR "fg", fgcmd },
1335#endif
1336#ifdef CONFIG_ASH_GETOPTS
1337 { BUILTIN_REGULAR "getopts", getoptscmd },
1338#endif
1339 { BUILTIN_NOSPEC "hash", hashcmd },
1340#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1341 { BUILTIN_NOSPEC "help", helpcmd },
1342#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001343#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00001344 { BUILTIN_REGULAR "jobs", jobscmd },
1345 { BUILTIN_REGULAR "kill", killcmd },
1346#endif
1347#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001348 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001349#endif
1350 { BUILTIN_ASSIGN "local", localcmd },
1351 { BUILTIN_NOSPEC "pwd", pwdcmd },
1352 { BUILTIN_REGULAR "read", readcmd },
1353 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1354 { BUILTIN_SPEC_REG "return", returncmd },
1355 { BUILTIN_SPEC_REG "set", setcmd },
1356 { BUILTIN_SPEC_REG "shift", shiftcmd },
1357 { BUILTIN_SPEC_REG "times", timescmd },
1358 { BUILTIN_SPEC_REG "trap", trapcmd },
1359 { BUILTIN_REGULAR "true", truecmd },
1360 { BUILTIN_NOSPEC "type", typecmd },
1361 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1362 { BUILTIN_REGULAR "umask", umaskcmd },
1363#ifdef CONFIG_ASH_ALIAS
1364 { BUILTIN_REGULAR "unalias", unaliascmd },
1365#endif
1366 { BUILTIN_SPEC_REG "unset", unsetcmd },
1367 { BUILTIN_REGULAR "wait", waitcmd },
1368};
1369
1370#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1371
1372
1373
1374struct cmdentry {
1375 int cmdtype;
1376 union param {
1377 int index;
1378 const struct builtincmd *cmd;
1379 struct funcnode *func;
1380 } u;
1381};
1382
1383
1384/* action to find_command() */
1385#define DO_ERR 0x01 /* prints errors */
1386#define DO_ABS 0x02 /* checks absolute paths */
1387#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1388#define DO_ALTPATH 0x08 /* using alternate path */
1389#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1390
1391static const char *pathopt; /* set by padvance */
1392
1393static void shellexec(char **, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00001394 ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00001395static char *padvance(const char **, const char *);
1396static void find_command(char *, struct cmdentry *, int, const char *);
1397static struct builtincmd *find_builtin(const char *);
1398static void hashcd(void);
1399static void changepath(const char *);
1400static void defun(char *, union node *);
1401static void unsetfunc(const char *);
1402
Eric Andersened9ecf72004-06-22 08:29:45 +00001403#ifdef CONFIG_ASH_MATH_SUPPORT_64
1404typedef int64_t arith_t;
1405#else
1406typedef long arith_t;
1407#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001408
1409#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001410static arith_t dash_arith(const char *);
1411static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001412#endif
1413
Eric Andersen16767e22004-03-16 05:14:10 +00001414#ifdef CONFIG_ASH_RANDOM_SUPPORT
1415static unsigned long rseed;
1416static void change_random(const char *);
1417# ifndef DYNAMIC_VAR
1418# define DYNAMIC_VAR
1419# endif
1420#endif
1421
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001422/* init.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001423
1424static void reset(void);
1425
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001426/* var.h */
Eric Andersen2870d962001-07-02 17:27:21 +00001427
1428/*
1429 * Shell variables.
1430 */
1431
1432/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001433#define VEXPORT 0x01 /* variable is exported */
1434#define VREADONLY 0x02 /* variable cannot be modified */
1435#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1436#define VTEXTFIXED 0x08 /* text is statically allocated */
1437#define VSTACK 0x10 /* text is allocated on the stack */
1438#define VUNSET 0x20 /* the variable is not set */
1439#define VNOFUNC 0x40 /* don't call the callback function */
1440#define VNOSET 0x80 /* do not set variable - just readonly test */
1441#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001442#ifdef DYNAMIC_VAR
1443# define VDYNAMIC 0x200 /* dynamic variable */
1444# else
1445# define VDYNAMIC 0
1446#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001447
1448struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001449 struct var *next; /* next entry in hash list */
1450 int flags; /* flags are defined above */
1451 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001452 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001453 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001454};
1455
1456struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001457 struct localvar *next; /* next local variable in list */
1458 struct var *vp; /* the variable that was made local */
1459 int flags; /* saved flags */
1460 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001461};
1462
1463
Eric Andersen2870d962001-07-02 17:27:21 +00001464static struct localvar *localvars;
1465
Eric Andersenc470f442003-07-28 09:56:35 +00001466/*
1467 * Shell variables.
1468 */
1469
1470#ifdef CONFIG_ASH_GETOPTS
1471static void getoptsreset(const char *);
1472#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001473
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001474#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001475#include <locale.h>
1476static void change_lc_all(const char *value);
1477static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001478#endif
1479
Eric Andersenef02f822004-03-11 13:34:24 +00001480
Eric Andersen2870d962001-07-02 17:27:21 +00001481#define VTABSIZE 39
1482
Eric Andersen90898442003-08-06 11:20:52 +00001483static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001484#ifdef IFS_BROKEN
1485static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001486#define defifs (defifsvar + 4)
1487#else
Eric Andersenc470f442003-07-28 09:56:35 +00001488static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001489#endif
1490
Eric Andersenc470f442003-07-28 09:56:35 +00001491
1492static struct var varinit[] = {
1493#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001494 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001495#else
Eric Andersen16767e22004-03-16 05:14:10 +00001496 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001497#endif
1498
1499#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001500 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1501 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001502#endif
1503
Eric Andersen16767e22004-03-16 05:14:10 +00001504 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1505 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1506 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1507 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001508#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001509 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1510#endif
1511#ifdef CONFIG_ASH_RANDOM_SUPPORT
1512 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001513#endif
1514#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001515 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1516 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001517#endif
1518#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001519 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001520#endif
1521};
1522
1523#define vifs varinit[0]
1524#ifdef CONFIG_ASH_MAIL
1525#define vmail (&vifs)[1]
1526#define vmpath (&vmail)[1]
1527#else
1528#define vmpath vifs
1529#endif
1530#define vpath (&vmpath)[1]
1531#define vps1 (&vpath)[1]
1532#define vps2 (&vps1)[1]
1533#define vps4 (&vps2)[1]
1534#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001535#ifdef CONFIG_ASH_GETOPTS
1536#define vrandom (&voptind)[1]
1537#else
1538#define vrandom (&vps4)[1]
1539#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001540#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001541
1542/*
1543 * The following macros access the values of the above variables.
1544 * They have to skip over the name. They return the null string
1545 * for unset variables.
1546 */
1547
1548#define ifsval() (vifs.text + 4)
1549#define ifsset() ((vifs.flags & VUNSET) == 0)
1550#define mailval() (vmail.text + 5)
1551#define mpathval() (vmpath.text + 9)
1552#define pathval() (vpath.text + 5)
1553#define ps1val() (vps1.text + 4)
1554#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001555#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001556#define optindval() (voptind.text + 7)
1557
1558#define mpathset() ((vmpath.flags & VUNSET) == 0)
1559
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001560static void setvar(const char *, const char *, int);
1561static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001562static void listsetvar(struct strlist *, int);
1563static char *lookupvar(const char *);
1564static char *bltinlookup(const char *);
1565static char **listvars(int, int, char ***);
1566#define environment() listvars(VEXPORT, VUNSET, 0)
1567static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001568static void poplocalvars(void);
1569static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001570#ifdef CONFIG_ASH_GETOPTS
1571static int setvarsafe(const char *, const char *, int);
1572#endif
1573static int varcmp(const char *, const char *);
1574static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001575
1576
Eric Andersenc470f442003-07-28 09:56:35 +00001577static inline int varequal(const char *a, const char *b) {
1578 return !varcmp(a, b);
1579}
Eric Andersen2870d962001-07-02 17:27:21 +00001580
1581
Eric Andersenc470f442003-07-28 09:56:35 +00001582static int loopnest; /* current loop nesting level */
1583
Eric Andersenc470f442003-07-28 09:56:35 +00001584/*
1585 * The parsefile structure pointed to by the global variable parsefile
1586 * contains information about the current file being read.
1587 */
1588
1589
1590struct redirtab {
1591 struct redirtab *next;
1592 int renamed[10];
1593 int nullredirs;
1594};
1595
1596static struct redirtab *redirlist;
1597static int nullredirs;
1598
1599extern char **environ;
1600
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001601/* output.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001602
1603
1604static void outstr(const char *, FILE *);
1605static void outcslow(int, FILE *);
1606static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001607static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001608static int out1fmt(const char *, ...)
1609 __attribute__((__format__(__printf__,1,2)));
1610static int fmtstr(char *, size_t, const char *, ...)
1611 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001612
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001613static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001614
Eric Andersenc470f442003-07-28 09:56:35 +00001615
1616static void out1str(const char *p)
1617{
1618 outstr(p, stdout);
1619}
1620
1621static void out2str(const char *p)
1622{
1623 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001624 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001625}
1626
1627/*
1628 * Initialization code.
1629 */
1630
1631/*
1632 * This routine initializes the builtin variables.
1633 */
1634
1635static inline void
1636initvar(void)
1637{
1638 struct var *vp;
1639 struct var *end;
1640 struct var **vpp;
1641
1642 /*
1643 * PS1 depends on uid
1644 */
1645#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1646 vps1.text = "PS1=\\w \\$ ";
1647#else
1648 if (!geteuid())
1649 vps1.text = "PS1=# ";
1650#endif
1651 vp = varinit;
1652 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1653 do {
1654 vpp = hashvar(vp->text);
1655 vp->next = *vpp;
1656 *vpp = vp;
1657 } while (++vp < end);
1658}
1659
1660static inline void
1661init(void)
1662{
1663
1664 /* from input.c: */
1665 {
1666 basepf.nextc = basepf.buf = basebuf;
1667 }
1668
1669 /* from trap.c: */
1670 {
1671 signal(SIGCHLD, SIG_DFL);
1672 }
1673
1674 /* from var.c: */
1675 {
1676 char **envp;
1677 char ppid[32];
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001678 const char *p;
1679 struct stat st1, st2;
Eric Andersenc470f442003-07-28 09:56:35 +00001680
1681 initvar();
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001682 for (envp = environ ; envp && *envp ; envp++) {
Eric Andersenc470f442003-07-28 09:56:35 +00001683 if (strchr(*envp, '=')) {
1684 setvareq(*envp, VEXPORT|VTEXTFIXED);
1685 }
1686 }
1687
1688 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1689 setvar("PPID", ppid, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001690
1691 p = lookupvar("PWD");
1692 if (p)
1693 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1694 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1695 p = 0;
1696 setpwd(p, 0);
Eric Andersenc470f442003-07-28 09:56:35 +00001697 }
1698}
1699
1700/* PEOF (the end of file marker) */
1701
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001702enum {
1703 INPUT_PUSH_FILE = 1,
1704 INPUT_NOFILE_OK = 2,
1705};
1706
Eric Andersenc470f442003-07-28 09:56:35 +00001707/*
1708 * The input line number. Input.c just defines this variable, and saves
1709 * and restores it when files are pushed and popped. The user of this
1710 * package must set its value.
1711 */
1712
1713static int pgetc(void);
1714static int pgetc2(void);
1715static int preadbuffer(void);
1716static void pungetc(void);
1717static void pushstring(char *, void *);
1718static void popstring(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001719static void setinputfd(int, int);
1720static void setinputstring(char *);
1721static void popfile(void);
1722static void popallfiles(void);
1723static void closescript(void);
1724
1725
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001726/* jobs.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001727
1728
1729/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1730#define FORK_FG 0
1731#define FORK_BG 1
1732#define FORK_NOJOB 2
1733
1734/* mode flags for showjob(s) */
1735#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1736#define SHOW_PID 0x04 /* include process pid */
1737#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1738
1739
1740/*
1741 * A job structure contains information about a job. A job is either a
1742 * single process or a set of processes contained in a pipeline. In the
1743 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1744 * array of pids.
1745 */
1746
1747struct procstat {
1748 pid_t pid; /* process id */
1749 int status; /* last process status from wait() */
1750 char *cmd; /* text of command being run */
1751};
1752
1753struct job {
1754 struct procstat ps0; /* status of process */
1755 struct procstat *ps; /* status or processes when more than one */
1756#if JOBS
1757 int stopstatus; /* status of a stopped job */
1758#endif
1759 uint32_t
1760 nprocs: 16, /* number of processes */
1761 state: 8,
1762#define JOBRUNNING 0 /* at least one proc running */
1763#define JOBSTOPPED 1 /* all procs are stopped */
1764#define JOBDONE 2 /* all procs are completed */
1765#if JOBS
1766 sigint: 1, /* job was killed by SIGINT */
1767 jobctl: 1, /* job running under job control */
1768#endif
1769 waited: 1, /* true if this entry has been waited for */
1770 used: 1, /* true if this entry is in used */
1771 changed: 1; /* true if status has changed */
1772 struct job *prev_job; /* previous job */
1773};
1774
1775static pid_t backgndpid; /* pid of last background process */
1776static int job_warning; /* user was warned about stopped jobs */
1777#if JOBS
1778static int jobctl; /* true if doing job control */
1779#endif
1780
1781static struct job *makejob(union node *, int);
1782static int forkshell(struct job *, union node *, int);
1783static int waitforjob(struct job *);
1784static int stoppedjobs(void);
1785
1786#if ! JOBS
1787#define setjobctl(on) /* do nothing */
1788#else
1789static void setjobctl(int);
1790static void showjobs(FILE *, int);
1791#endif
1792
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001793/* main.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001794
1795
1796/* pid of main shell */
1797static int rootpid;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001798/* shell level: 0 for the main shell, 1 for its children, and so on */
1799static int shlvl;
1800#define rootshell (!shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00001801
1802static void readcmdfile(char *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001803static int cmdloop(int);
Eric Andersenc470f442003-07-28 09:56:35 +00001804
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001805/* memalloc.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001806
1807
1808struct stackmark {
1809 struct stack_block *stackp;
1810 char *stacknxt;
1811 size_t stacknleft;
1812 struct stackmark *marknext;
1813};
1814
1815/* minimum size of a block */
1816#define MINSIZE SHELL_ALIGN(504)
1817
1818struct stack_block {
1819 struct stack_block *prev;
1820 char space[MINSIZE];
1821};
1822
1823static struct stack_block stackbase;
1824static struct stack_block *stackp = &stackbase;
1825static struct stackmark *markp;
1826static char *stacknxt = stackbase.space;
1827static size_t stacknleft = MINSIZE;
1828static char *sstrend = stackbase.space + MINSIZE;
1829static int herefd = -1;
1830
1831
1832static pointer ckmalloc(size_t);
1833static pointer ckrealloc(pointer, size_t);
1834static char *savestr(const char *);
1835static pointer stalloc(size_t);
1836static void stunalloc(pointer);
1837static void setstackmark(struct stackmark *);
1838static void popstackmark(struct stackmark *);
1839static void growstackblock(void);
1840static void *growstackstr(void);
1841static char *makestrspace(size_t, char *);
1842static char *stnputs(const char *, size_t, char *);
1843static char *stputs(const char *, char *);
1844
1845
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001846static inline char *_STPUTC(int c, char *p) {
Eric Andersenc470f442003-07-28 09:56:35 +00001847 if (p == sstrend)
1848 p = growstackstr();
1849 *p++ = c;
1850 return p;
1851}
1852
1853#define stackblock() ((void *)stacknxt)
1854#define stackblocksize() stacknleft
1855#define STARTSTACKSTR(p) ((p) = stackblock())
1856#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1857#define CHECKSTRSPACE(n, p) \
1858 ({ \
1859 char *q = (p); \
1860 size_t l = (n); \
1861 size_t m = sstrend - q; \
1862 if (l > m) \
1863 (p) = makestrspace(l, q); \
1864 0; \
1865 })
1866#define USTPUTC(c, p) (*p++ = (c))
1867#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1868#define STUNPUTC(p) (--p)
1869#define STTOPC(p) p[-1]
1870#define STADJUST(amount, p) (p += (amount))
1871
1872#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1873#define ungrabstackstr(s, p) stunalloc((s))
1874#define stackstrend() ((void *)sstrend)
1875
1876#define ckfree(p) free((pointer)(p))
1877
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001878/* mystring.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001879
1880
1881#define DOLATSTRLEN 4
1882
1883static char *prefix(const char *, const char *);
1884static int number(const char *);
1885static int is_number(const char *);
1886static char *single_quote(const char *);
1887static char *sstrdup(const char *);
1888
1889#define equal(s1, s2) (strcmp(s1, s2) == 0)
1890#define scopy(s1, s2) ((void)strcpy(s2, s1))
1891
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001892/* options.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001893
1894struct shparam {
1895 int nparam; /* # of positional parameters (without $0) */
1896 unsigned char malloc; /* if parameter list dynamically allocated */
1897 char **p; /* parameter list */
1898#ifdef CONFIG_ASH_GETOPTS
1899 int optind; /* next parameter to be processed by getopts */
1900 int optoff; /* used by getopts */
1901#endif
1902};
1903
1904
1905#define eflag optlist[0]
1906#define fflag optlist[1]
1907#define Iflag optlist[2]
1908#define iflag optlist[3]
1909#define mflag optlist[4]
1910#define nflag optlist[5]
1911#define sflag optlist[6]
1912#define xflag optlist[7]
1913#define vflag optlist[8]
1914#define Cflag optlist[9]
1915#define aflag optlist[10]
1916#define bflag optlist[11]
1917#define uflag optlist[12]
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001918#define viflag optlist[13]
Eric Andersenc470f442003-07-28 09:56:35 +00001919
1920#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001921#define nolog optlist[14]
1922#define debug optlist[15]
Paul Fox3f11b1b2005-08-04 19:04:46 +00001923#endif
1924
1925#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1926#define setvimode(on) viflag = 0 /* forcibly keep the option off */
Eric Andersenc470f442003-07-28 09:56:35 +00001927#endif
1928
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001929/* options.c */
Eric Andersenc470f442003-07-28 09:56:35 +00001930
1931
Paul Fox3f11b1b2005-08-04 19:04:46 +00001932static const char *const optletters_optnames[] = {
Eric Andersenc470f442003-07-28 09:56:35 +00001933 "e" "errexit",
1934 "f" "noglob",
1935 "I" "ignoreeof",
1936 "i" "interactive",
1937 "m" "monitor",
1938 "n" "noexec",
1939 "s" "stdin",
1940 "x" "xtrace",
1941 "v" "verbose",
1942 "C" "noclobber",
1943 "a" "allexport",
1944 "b" "notify",
1945 "u" "nounset",
Paul Fox3f11b1b2005-08-04 19:04:46 +00001946 "\0" "vi",
Eric Andersenc470f442003-07-28 09:56:35 +00001947#ifdef DEBUG
1948 "\0" "nolog",
1949 "\0" "debug",
1950#endif
1951};
1952
1953#define optletters(n) optletters_optnames[(n)][0]
1954#define optnames(n) (&optletters_optnames[(n)][1])
1955
Paul Fox3f11b1b2005-08-04 19:04:46 +00001956#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001957
1958static char optlist[NOPTS];
1959
1960
1961static char *arg0; /* value of $0 */
1962static struct shparam shellparam; /* $@ current positional parameters */
1963static char **argptr; /* argument list for builtin commands */
1964static char *optionarg; /* set by nextopt (like getopt) */
1965static char *optptr; /* used by nextopt */
1966
1967static char *minusc; /* argument to -c option */
1968
1969
1970static void procargs(int, char **);
1971static void optschanged(void);
1972static void setparam(char **);
1973static void freeparam(volatile struct shparam *);
1974static int shiftcmd(int, char **);
1975static int setcmd(int, char **);
1976static int nextopt(const char *);
1977
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001978/* redir.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001979
1980/* flags passed to redirect */
1981#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001982#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00001983
1984union node;
1985static void redirect(union node *, int);
1986static void popredir(int);
1987static void clearredir(int);
1988static int copyfd(int, int);
1989static int redirectsafe(union node *, int);
1990
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001991/* show.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001992
1993
1994#ifdef DEBUG
1995static void showtree(union node *);
1996static void trace(const char *, ...);
1997static void tracev(const char *, va_list);
1998static void trargs(char **);
1999static void trputc(int);
2000static void trputs(const char *);
2001static void opentrace(void);
2002#endif
2003
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002004/* trap.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002005
2006
2007/* trap handler commands */
2008static char *trap[NSIG];
2009/* current value of signal */
2010static char sigmode[NSIG - 1];
2011/* indicates specified signal received */
2012static char gotsig[NSIG - 1];
2013
2014static void clear_traps(void);
2015static void setsignal(int);
2016static void ignoresig(int);
2017static void onsig(int);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002018static int dotrap(void);
Eric Andersenc470f442003-07-28 09:56:35 +00002019static void setinteractive(int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002020static void exitshell(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00002021static int decode_signal(const char *, int);
2022
2023/*
2024 * This routine is called when an error or an interrupt occurs in an
2025 * interactive shell and control is returned to the main command loop.
2026 */
2027
2028static void
2029reset(void)
2030{
2031 /* from eval.c: */
2032 {
2033 evalskip = 0;
2034 loopnest = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002035 }
2036
2037 /* from input.c: */
2038 {
2039 parselleft = parsenleft = 0; /* clear input buffer */
2040 popallfiles();
2041 }
2042
2043 /* from parser.c: */
2044 {
2045 tokpushback = 0;
2046 checkkwd = 0;
2047 }
2048
2049 /* from redir.c: */
2050 {
2051 clearredir(0);
2052 }
2053
2054}
2055
2056#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002057static struct alias *atab[ATABSIZE];
2058
Eric Andersenc470f442003-07-28 09:56:35 +00002059static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002060static struct alias *freealias(struct alias *);
2061static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002062
Eric Andersenc470f442003-07-28 09:56:35 +00002063static void
2064setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002065{
2066 struct alias *ap, **app;
2067
2068 app = __lookupalias(name);
2069 ap = *app;
2070 INTOFF;
2071 if (ap) {
2072 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002073 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002074 }
Eric Andersenc470f442003-07-28 09:56:35 +00002075 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002076 ap->flag &= ~ALIASDEAD;
2077 } else {
2078 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002079 ap = ckmalloc(sizeof (struct alias));
2080 ap->name = savestr(name);
2081 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002082 ap->flag = 0;
2083 ap->next = 0;
2084 *app = ap;
2085 }
2086 INTON;
2087}
2088
Eric Andersenc470f442003-07-28 09:56:35 +00002089static int
2090unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002091{
Eric Andersencb57d552001-06-28 07:25:16 +00002092 struct alias **app;
2093
2094 app = __lookupalias(name);
2095
2096 if (*app) {
2097 INTOFF;
2098 *app = freealias(*app);
2099 INTON;
2100 return (0);
2101 }
2102
2103 return (1);
2104}
2105
Eric Andersenc470f442003-07-28 09:56:35 +00002106static void
2107rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002108{
Eric Andersencb57d552001-06-28 07:25:16 +00002109 struct alias *ap, **app;
2110 int i;
2111
2112 INTOFF;
2113 for (i = 0; i < ATABSIZE; i++) {
2114 app = &atab[i];
2115 for (ap = *app; ap; ap = *app) {
2116 *app = freealias(*app);
2117 if (ap == *app) {
2118 app = &ap->next;
2119 }
2120 }
2121 }
2122 INTON;
2123}
2124
Eric Andersenc470f442003-07-28 09:56:35 +00002125static struct alias *
2126lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002127{
Eric Andersenc470f442003-07-28 09:56:35 +00002128 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002129
Eric Andersenc470f442003-07-28 09:56:35 +00002130 if (check && ap && (ap->flag & ALIASINUSE))
2131 return (NULL);
2132 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002133}
2134
Eric Andersencb57d552001-06-28 07:25:16 +00002135/*
2136 * TODO - sort output
2137 */
Eric Andersenc470f442003-07-28 09:56:35 +00002138static int
2139aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002140{
2141 char *n, *v;
2142 int ret = 0;
2143 struct alias *ap;
2144
2145 if (argc == 1) {
2146 int i;
2147
2148 for (i = 0; i < ATABSIZE; i++)
2149 for (ap = atab[i]; ap; ap = ap->next) {
2150 printalias(ap);
2151 }
2152 return (0);
2153 }
2154 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002155 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002156 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002157 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002158 ret = 1;
2159 } else
2160 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002161 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002162 *v++ = '\0';
2163 setalias(n, v);
2164 }
2165 }
2166
2167 return (ret);
2168}
2169
Eric Andersenc470f442003-07-28 09:56:35 +00002170static int
2171unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002172{
2173 int i;
2174
2175 while ((i = nextopt("a")) != '\0') {
2176 if (i == 'a') {
2177 rmaliases();
2178 return (0);
2179 }
2180 }
2181 for (i = 0; *argptr; argptr++) {
2182 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002183 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002184 i = 1;
2185 }
2186 }
2187
2188 return (i);
2189}
2190
Eric Andersenc470f442003-07-28 09:56:35 +00002191static struct alias *
2192freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002193 struct alias *next;
2194
2195 if (ap->flag & ALIASINUSE) {
2196 ap->flag |= ALIASDEAD;
2197 return ap;
2198 }
2199
2200 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002201 ckfree(ap->name);
2202 ckfree(ap->val);
2203 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002204 return next;
2205}
2206
Eric Andersenc470f442003-07-28 09:56:35 +00002207static void
2208printalias(const struct alias *ap) {
2209 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2210}
Eric Andersencb57d552001-06-28 07:25:16 +00002211
Eric Andersenc470f442003-07-28 09:56:35 +00002212static struct alias **
2213__lookupalias(const char *name) {
2214 unsigned int hashval;
2215 struct alias **app;
2216 const char *p;
2217 unsigned int ch;
2218
2219 p = name;
2220
2221 ch = (unsigned char)*p;
2222 hashval = ch << 4;
2223 while (ch) {
2224 hashval += ch;
2225 ch = (unsigned char)*++p;
2226 }
2227 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002228
2229 for (; *app; app = &(*app)->next) {
2230 if (equal(name, (*app)->name)) {
2231 break;
2232 }
2233 }
2234
2235 return app;
2236}
Eric Andersenc470f442003-07-28 09:56:35 +00002237#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002238
Eric Andersencb57d552001-06-28 07:25:16 +00002239
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002240/* cd.c */
Eric Andersen2870d962001-07-02 17:27:21 +00002241
Eric Andersencb57d552001-06-28 07:25:16 +00002242/*
Eric Andersenc470f442003-07-28 09:56:35 +00002243 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002244 */
2245
Eric Andersenc470f442003-07-28 09:56:35 +00002246#define CD_PHYSICAL 1
2247#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002248
Eric Andersenc470f442003-07-28 09:56:35 +00002249static int docd(const char *, int);
2250static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002251
Eric Andersenc470f442003-07-28 09:56:35 +00002252static char *curdir = nullstr; /* current working directory */
2253static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002254
Eric Andersenc470f442003-07-28 09:56:35 +00002255static int
2256cdopt(void)
2257{
2258 int flags = 0;
2259 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002260
Eric Andersenc470f442003-07-28 09:56:35 +00002261 j = 'L';
2262 while ((i = nextopt("LP"))) {
2263 if (i != j) {
2264 flags ^= CD_PHYSICAL;
2265 j = i;
2266 }
2267 }
Eric Andersencb57d552001-06-28 07:25:16 +00002268
Eric Andersenc470f442003-07-28 09:56:35 +00002269 return flags;
2270}
Eric Andersen2870d962001-07-02 17:27:21 +00002271
Eric Andersenc470f442003-07-28 09:56:35 +00002272static int
2273cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002274{
2275 const char *dest;
2276 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002277 const char *p;
2278 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002279 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002280 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002281
Eric Andersenc470f442003-07-28 09:56:35 +00002282 flags = cdopt();
2283 dest = *argptr;
2284 if (!dest)
2285 dest = bltinlookup(homestr);
2286 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002287 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002288 flags |= CD_PRINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002289 }
Eric Andersenc470f442003-07-28 09:56:35 +00002290 if (!dest)
2291 dest = nullstr;
2292 if (*dest == '/')
2293 goto step7;
2294 if (*dest == '.') {
2295 c = dest[1];
2296dotdot:
2297 switch (c) {
2298 case '\0':
2299 case '/':
2300 goto step6;
2301 case '.':
2302 c = dest[2];
2303 if (c != '.')
2304 goto dotdot;
2305 }
2306 }
2307 if (!*dest)
2308 dest = ".";
2309 if (!(path = bltinlookup("CDPATH"))) {
2310step6:
2311step7:
2312 p = dest;
2313 goto docd;
2314 }
2315 do {
2316 c = *path;
2317 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002318 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002319 if (c && c != ':')
2320 flags |= CD_PRINT;
2321docd:
2322 if (!docd(p, flags))
2323 goto out;
2324 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002325 }
Eric Andersenc470f442003-07-28 09:56:35 +00002326 } while (path);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002327 sh_error("can't cd to %s", dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002328 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002329out:
2330 if (flags & CD_PRINT)
2331 out1fmt(snlfmt, curdir);
2332 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002333}
2334
2335
2336/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002337 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002338 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002339 */
2340
Eric Andersenc470f442003-07-28 09:56:35 +00002341static inline const char *
2342updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002343{
Eric Andersenc470f442003-07-28 09:56:35 +00002344 char *new;
2345 char *p;
2346 char *cdcomppath;
2347 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002348
Eric Andersenc470f442003-07-28 09:56:35 +00002349 cdcomppath = sstrdup(dir);
2350 STARTSTACKSTR(new);
2351 if (*dir != '/') {
2352 if (curdir == nullstr)
2353 return 0;
2354 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002355 }
Eric Andersenc470f442003-07-28 09:56:35 +00002356 new = makestrspace(strlen(dir) + 2, new);
2357 lim = stackblock() + 1;
2358 if (*dir != '/') {
2359 if (new[-1] != '/')
2360 USTPUTC('/', new);
2361 if (new > lim && *lim == '/')
2362 lim++;
2363 } else {
2364 USTPUTC('/', new);
2365 cdcomppath++;
2366 if (dir[1] == '/' && dir[2] != '/') {
2367 USTPUTC('/', new);
2368 cdcomppath++;
2369 lim++;
2370 }
2371 }
2372 p = strtok(cdcomppath, "/");
2373 while (p) {
2374 switch(*p) {
2375 case '.':
2376 if (p[1] == '.' && p[2] == '\0') {
2377 while (new > lim) {
2378 STUNPUTC(new);
2379 if (new[-1] == '/')
2380 break;
2381 }
2382 break;
2383 } else if (p[1] == '\0')
2384 break;
2385 /* fall through */
2386 default:
2387 new = stputs(p, new);
2388 USTPUTC('/', new);
2389 }
2390 p = strtok(0, "/");
2391 }
2392 if (new > lim)
2393 STUNPUTC(new);
2394 *new = 0;
2395 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002396}
2397
2398/*
Eric Andersenc470f442003-07-28 09:56:35 +00002399 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2400 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002401 */
2402
Eric Andersenc470f442003-07-28 09:56:35 +00002403static int
2404docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002405{
Eric Andersenc470f442003-07-28 09:56:35 +00002406 const char *dir = 0;
2407 int err;
2408
2409 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2410
Eric Andersencb57d552001-06-28 07:25:16 +00002411 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002412 if (!(flags & CD_PHYSICAL)) {
2413 dir = updatepwd(dest);
2414 if (dir)
2415 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002416 }
Eric Andersenc470f442003-07-28 09:56:35 +00002417 err = chdir(dest);
2418 if (err)
2419 goto out;
2420 setpwd(dir, 1);
2421 hashcd();
2422out:
Eric Andersencb57d552001-06-28 07:25:16 +00002423 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002424 return err;
2425}
2426
2427/*
2428 * Find out what the current directory is. If we already know the current
2429 * directory, this routine returns immediately.
2430 */
2431static inline char *
2432getpwd(void)
2433{
2434 char *dir = getcwd(0, 0);
2435 return dir ? dir : nullstr;
2436}
2437
2438static int
2439pwdcmd(int argc, char **argv)
2440{
2441 int flags;
2442 const char *dir = curdir;
2443
2444 flags = cdopt();
2445 if (flags) {
2446 if (physdir == nullstr)
2447 setpwd(dir, 0);
2448 dir = physdir;
2449 }
2450 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002451 return 0;
2452}
2453
Eric Andersenc470f442003-07-28 09:56:35 +00002454static void
2455setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002456{
Eric Andersenc470f442003-07-28 09:56:35 +00002457 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002458
Eric Andersenc470f442003-07-28 09:56:35 +00002459 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002460
Eric Andersencb57d552001-06-28 07:25:16 +00002461 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002462 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002463 }
2464 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002465 if (physdir != nullstr) {
2466 if (physdir != oldcur)
2467 free(physdir);
2468 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002469 }
Eric Andersenc470f442003-07-28 09:56:35 +00002470 if (oldcur == val || !val) {
2471 char *s = getpwd();
2472 physdir = s;
2473 if (!val)
2474 dir = s;
2475 } else
2476 dir = savestr(val);
2477 if (oldcur != dir && oldcur != nullstr) {
2478 free(oldcur);
2479 }
2480 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002481 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002482 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002483}
2484
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002485/* error.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002486
Eric Andersencb57d552001-06-28 07:25:16 +00002487/*
2488 * Errors and exceptions.
2489 */
2490
2491/*
2492 * Code to handle exceptions in C.
2493 */
2494
Eric Andersen2870d962001-07-02 17:27:21 +00002495
Eric Andersencb57d552001-06-28 07:25:16 +00002496
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002497static void exverror(int, const char *, va_list)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002498 ATTRIBUTE_NORETURN;
Eric Andersencb57d552001-06-28 07:25:16 +00002499
2500/*
2501 * Called to raise an exception. Since C doesn't include exceptions, we
2502 * just do a longjmp to the exception handler. The type of exception is
2503 * stored in the global variable "exception".
2504 */
2505
Eric Andersenc470f442003-07-28 09:56:35 +00002506static void
2507exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002508{
2509#ifdef DEBUG
2510 if (handler == NULL)
2511 abort();
2512#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002513 INTOFF;
2514
Eric Andersencb57d552001-06-28 07:25:16 +00002515 exception = e;
2516 longjmp(handler->loc, 1);
2517}
2518
2519
2520/*
2521 * Called from trap.c when a SIGINT is received. (If the user specifies
2522 * that SIGINT is to be trapped or ignored using the trap builtin, then
2523 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002524 * are held using the INTOFF macro. (The test for iflag is just
2525 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002526 */
2527
Eric Andersenc470f442003-07-28 09:56:35 +00002528static void
2529onint(void) {
2530 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002531
Eric Andersencb57d552001-06-28 07:25:16 +00002532 intpending = 0;
"Vladimir N. Oleynik"e6d88ea2005-12-13 13:24:23 +00002533#if 0
2534 /* comment by vodz: its strange for me, this programm don`t use other
2535 signal block */
Eric Andersenc470f442003-07-28 09:56:35 +00002536 sigsetmask(0);
"Vladimir N. Oleynik"e6d88ea2005-12-13 13:24:23 +00002537#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002538 i = EXSIG;
2539 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2540 if (!(rootshell && iflag)) {
2541 signal(SIGINT, SIG_DFL);
2542 raise(SIGINT);
2543 }
2544 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002545 }
Eric Andersenc470f442003-07-28 09:56:35 +00002546 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002547 /* NOTREACHED */
2548}
2549
Eric Andersenc470f442003-07-28 09:56:35 +00002550static void
2551exvwarning(const char *msg, va_list ap)
2552{
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002553 FILE *errs;
Eric Andersencb57d552001-06-28 07:25:16 +00002554
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002555 errs = stderr;
2556 fprintf(errs, "%s: ", arg0);
2557 if (commandname) {
2558 const char *fmt = (!iflag || parsefile->fd) ?
2559 "%s: %d: " : "%s: ";
2560 fprintf(errs, fmt, commandname, startlinno);
2561 }
2562 vfprintf(errs, msg, ap);
2563 outcslow('\n', errs);
Eric Andersenc470f442003-07-28 09:56:35 +00002564}
Eric Andersen2870d962001-07-02 17:27:21 +00002565
Eric Andersencb57d552001-06-28 07:25:16 +00002566/*
Eric Andersenc470f442003-07-28 09:56:35 +00002567 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002568 * is not NULL then error prints an error message using printf style
2569 * formatting. It then raises the error exception.
2570 */
Eric Andersenc470f442003-07-28 09:56:35 +00002571static void
2572exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002573{
Eric Andersencb57d552001-06-28 07:25:16 +00002574#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002575 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002576 TRACE(("exverror(%d, \"", cond));
2577 TRACEV((msg, ap));
2578 TRACE(("\") pid=%d\n", getpid()));
2579 } else
2580 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2581 if (msg)
2582#endif
2583 exvwarning(msg, ap);
2584
2585 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002586 exraise(cond);
2587 /* NOTREACHED */
2588}
2589
2590
Eric Andersenc470f442003-07-28 09:56:35 +00002591static void
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002592sh_error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002593{
Eric Andersencb57d552001-06-28 07:25:16 +00002594 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002595
Eric Andersencb57d552001-06-28 07:25:16 +00002596 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002597 exverror(EXERROR, msg, ap);
2598 /* NOTREACHED */
2599 va_end(ap);
2600}
2601
2602
Eric Andersenc470f442003-07-28 09:56:35 +00002603static void
2604exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002605{
Eric Andersencb57d552001-06-28 07:25:16 +00002606 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002607
Eric Andersencb57d552001-06-28 07:25:16 +00002608 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002609 exverror(cond, msg, ap);
2610 /* NOTREACHED */
2611 va_end(ap);
2612}
2613
Eric Andersencb57d552001-06-28 07:25:16 +00002614/*
Eric Andersenc470f442003-07-28 09:56:35 +00002615 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002616 */
2617
Eric Andersenc470f442003-07-28 09:56:35 +00002618static void
2619sh_warnx(const char *fmt, ...)
2620{
2621 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002622
Eric Andersenc470f442003-07-28 09:56:35 +00002623 va_start(ap, fmt);
2624 exvwarning(fmt, ap);
2625 va_end(ap);
2626}
Eric Andersen2870d962001-07-02 17:27:21 +00002627
Eric Andersencb57d552001-06-28 07:25:16 +00002628
2629/*
2630 * Return a string describing an error. The returned string may be a
2631 * pointer to a static buffer that will be overwritten on the next call.
2632 * Action describes the operation that got the error.
2633 */
2634
Eric Andersenc470f442003-07-28 09:56:35 +00002635static const char *
2636errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002637{
Eric Andersenc470f442003-07-28 09:56:35 +00002638 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002639
Eric Andersenc470f442003-07-28 09:56:35 +00002640 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002641 }
Eric Andersenc470f442003-07-28 09:56:35 +00002642 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002643}
2644
2645
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002646/* eval.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002647
2648/*
2649 * Evaluate a command.
2650 */
Eric Andersencb57d552001-06-28 07:25:16 +00002651
2652/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002653#define EV_EXIT 01 /* exit after evaluating tree */
2654#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2655#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002656
2657
Eric Andersenc470f442003-07-28 09:56:35 +00002658static void evalloop(union node *, int);
2659static void evalfor(union node *, int);
2660static void evalcase(union node *, int);
2661static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002662static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002663static void evalpipe(union node *, int);
2664static void evalcommand(union node *, int);
2665static int evalbltin(const struct builtincmd *, int, char **);
2666static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002667static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002668static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002669
Eric Andersenc470f442003-07-28 09:56:35 +00002670
2671static const struct builtincmd bltin = {
2672 "\0\0", bltincmd
2673};
2674
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002675
Eric Andersencb57d552001-06-28 07:25:16 +00002676/*
2677 * Called to reset things after an exception.
2678 */
2679
Eric Andersencb57d552001-06-28 07:25:16 +00002680/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002681 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002682 */
2683
Eric Andersenc470f442003-07-28 09:56:35 +00002684static int
2685evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002686{
Eric Andersen2870d962001-07-02 17:27:21 +00002687 char *p;
2688 char *concat;
2689 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002690
Eric Andersen2870d962001-07-02 17:27:21 +00002691 if (argc > 1) {
2692 p = argv[1];
2693 if (argc > 2) {
2694 STARTSTACKSTR(concat);
2695 ap = argv + 2;
2696 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002697 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002698 if ((p = *ap++) == NULL)
2699 break;
2700 STPUTC(' ', concat);
2701 }
2702 STPUTC('\0', concat);
2703 p = grabstackstr(concat);
2704 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002705 evalstring(p, ~SKIPEVAL);
2706
Eric Andersen2870d962001-07-02 17:27:21 +00002707 }
2708 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002709}
2710
Eric Andersenc470f442003-07-28 09:56:35 +00002711
Eric Andersencb57d552001-06-28 07:25:16 +00002712/*
2713 * Execute a command or commands contained in a string.
2714 */
2715
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002716static int
2717evalstring(char *s, int mask)
Eric Andersen2870d962001-07-02 17:27:21 +00002718{
Eric Andersencb57d552001-06-28 07:25:16 +00002719 union node *n;
2720 struct stackmark smark;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002721 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002722
Eric Andersencb57d552001-06-28 07:25:16 +00002723 setinputstring(s);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002724 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002725
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002726 skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002727 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002728 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002729 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002730 skip = evalskip;
2731 if (skip)
Eric Andersenc470f442003-07-28 09:56:35 +00002732 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002733 }
2734 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002735
2736 skip &= mask;
2737 evalskip = skip;
2738 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002739}
2740
Eric Andersenc470f442003-07-28 09:56:35 +00002741
Eric Andersen62483552001-07-10 06:09:16 +00002742
2743/*
Eric Andersenc470f442003-07-28 09:56:35 +00002744 * Evaluate a parse tree. The value is left in the global variable
2745 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002746 */
2747
Eric Andersenc470f442003-07-28 09:56:35 +00002748static void
2749evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002750{
Eric Andersenc470f442003-07-28 09:56:35 +00002751 int checkexit = 0;
2752 void (*evalfn)(union node *, int);
2753 unsigned isor;
2754 int status;
2755 if (n == NULL) {
2756 TRACE(("evaltree(NULL) called\n"));
2757 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002758 }
Eric Andersenc470f442003-07-28 09:56:35 +00002759 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2760 getpid(), n, n->type, flags));
2761 switch (n->type) {
2762 default:
2763#ifdef DEBUG
2764 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002765 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002766 break;
2767#endif
2768 case NNOT:
2769 evaltree(n->nnot.com, EV_TESTED);
2770 status = !exitstatus;
2771 goto setstatus;
2772 case NREDIR:
2773 expredir(n->nredir.redirect);
2774 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2775 if (!status) {
2776 evaltree(n->nredir.n, flags & EV_TESTED);
2777 status = exitstatus;
2778 }
2779 popredir(0);
2780 goto setstatus;
2781 case NCMD:
2782 evalfn = evalcommand;
2783checkexit:
2784 if (eflag && !(flags & EV_TESTED))
2785 checkexit = ~0;
2786 goto calleval;
2787 case NFOR:
2788 evalfn = evalfor;
2789 goto calleval;
2790 case NWHILE:
2791 case NUNTIL:
2792 evalfn = evalloop;
2793 goto calleval;
2794 case NSUBSHELL:
2795 case NBACKGND:
2796 evalfn = evalsubshell;
2797 goto calleval;
2798 case NPIPE:
2799 evalfn = evalpipe;
2800 goto checkexit;
2801 case NCASE:
2802 evalfn = evalcase;
2803 goto calleval;
2804 case NAND:
2805 case NOR:
2806 case NSEMI:
2807#if NAND + 1 != NOR
2808#error NAND + 1 != NOR
2809#endif
2810#if NOR + 1 != NSEMI
2811#error NOR + 1 != NSEMI
2812#endif
2813 isor = n->type - NAND;
2814 evaltree(
2815 n->nbinary.ch1,
2816 (flags | ((isor >> 1) - 1)) & EV_TESTED
2817 );
2818 if (!exitstatus == isor)
2819 break;
2820 if (!evalskip) {
2821 n = n->nbinary.ch2;
2822evaln:
2823 evalfn = evaltree;
2824calleval:
2825 evalfn(n, flags);
2826 break;
2827 }
2828 break;
2829 case NIF:
2830 evaltree(n->nif.test, EV_TESTED);
2831 if (evalskip)
2832 break;
2833 if (exitstatus == 0) {
2834 n = n->nif.ifpart;
2835 goto evaln;
2836 } else if (n->nif.elsepart) {
2837 n = n->nif.elsepart;
2838 goto evaln;
2839 }
2840 goto success;
2841 case NDEFUN:
2842 defun(n->narg.text, n->narg.next);
2843success:
2844 status = 0;
2845setstatus:
2846 exitstatus = status;
2847 break;
2848 }
2849out:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002850 if ((checkexit & exitstatus))
2851 evalskip |= SKIPEVAL;
2852 else if (pendingsigs && dotrap())
2853 goto exexit;
2854
2855 if (flags & EV_EXIT) {
2856exexit:
Eric Andersenc470f442003-07-28 09:56:35 +00002857 exraise(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002858 }
Eric Andersen62483552001-07-10 06:09:16 +00002859}
2860
Eric Andersenc470f442003-07-28 09:56:35 +00002861
2862#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2863static
2864#endif
2865void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2866
2867
2868static void
2869evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002870{
2871 int status;
2872
2873 loopnest++;
2874 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002875 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002876 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002877 int i;
2878
Eric Andersencb57d552001-06-28 07:25:16 +00002879 evaltree(n->nbinary.ch1, EV_TESTED);
2880 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002881skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002882 evalskip = 0;
2883 continue;
2884 }
2885 if (evalskip == SKIPBREAK && --skipcount <= 0)
2886 evalskip = 0;
2887 break;
2888 }
Eric Andersenc470f442003-07-28 09:56:35 +00002889 i = exitstatus;
2890 if (n->type != NWHILE)
2891 i = !i;
2892 if (i != 0)
2893 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002894 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002895 status = exitstatus;
2896 if (evalskip)
2897 goto skipping;
2898 }
2899 loopnest--;
2900 exitstatus = status;
2901}
2902
Eric Andersenc470f442003-07-28 09:56:35 +00002903
2904
2905static void
2906evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002907{
2908 struct arglist arglist;
2909 union node *argp;
2910 struct strlist *sp;
2911 struct stackmark smark;
2912
2913 setstackmark(&smark);
2914 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002915 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002916 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002917 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002918 if (evalskip)
2919 goto out;
2920 }
2921 *arglist.lastp = NULL;
2922
2923 exitstatus = 0;
2924 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002925 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002926 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002927 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002928 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002929 if (evalskip) {
2930 if (evalskip == SKIPCONT && --skipcount <= 0) {
2931 evalskip = 0;
2932 continue;
2933 }
2934 if (evalskip == SKIPBREAK && --skipcount <= 0)
2935 evalskip = 0;
2936 break;
2937 }
2938 }
2939 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002940out:
Eric Andersencb57d552001-06-28 07:25:16 +00002941 popstackmark(&smark);
2942}
2943
Eric Andersenc470f442003-07-28 09:56:35 +00002944
2945
2946static void
2947evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002948{
2949 union node *cp;
2950 union node *patp;
2951 struct arglist arglist;
2952 struct stackmark smark;
2953
2954 setstackmark(&smark);
2955 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002956 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002957 exitstatus = 0;
2958 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2959 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002960 if (casematch(patp, arglist.list->text)) {
2961 if (evalskip == 0) {
2962 evaltree(cp->nclist.body, flags);
2963 }
2964 goto out;
2965 }
2966 }
2967 }
Eric Andersenc470f442003-07-28 09:56:35 +00002968out:
Eric Andersencb57d552001-06-28 07:25:16 +00002969 popstackmark(&smark);
2970}
2971
Eric Andersenc470f442003-07-28 09:56:35 +00002972
2973
2974/*
2975 * Kick off a subshell to evaluate a tree.
2976 */
2977
2978static void
2979evalsubshell(union node *n, int flags)
2980{
2981 struct job *jp;
2982 int backgnd = (n->type == NBACKGND);
2983 int status;
2984
2985 expredir(n->nredir.redirect);
2986 if (!backgnd && flags & EV_EXIT && !trap[0])
2987 goto nofork;
2988 INTOFF;
2989 jp = makejob(n, 1);
2990 if (forkshell(jp, n, backgnd) == 0) {
2991 INTON;
2992 flags |= EV_EXIT;
2993 if (backgnd)
2994 flags &=~ EV_TESTED;
2995nofork:
2996 redirect(n->nredir.redirect, 0);
2997 evaltreenr(n->nredir.n, flags);
2998 /* never returns */
2999 }
3000 status = 0;
3001 if (! backgnd)
3002 status = waitforjob(jp);
3003 exitstatus = status;
3004 INTON;
3005}
3006
3007
3008
3009/*
3010 * Compute the names of the files in a redirection list.
3011 */
3012
3013static void
3014expredir(union node *n)
3015{
3016 union node *redir;
3017
3018 for (redir = n ; redir ; redir = redir->nfile.next) {
3019 struct arglist fn;
3020 fn.lastp = &fn.list;
3021 switch (redir->type) {
3022 case NFROMTO:
3023 case NFROM:
3024 case NTO:
3025 case NCLOBBER:
3026 case NAPPEND:
3027 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3028 redir->nfile.expfname = fn.list->text;
3029 break;
3030 case NFROMFD:
3031 case NTOFD:
3032 if (redir->ndup.vname) {
3033 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3034 fixredir(redir, fn.list->text, 1);
3035 }
3036 break;
3037 }
3038 }
3039}
3040
3041
3042
Eric Andersencb57d552001-06-28 07:25:16 +00003043/*
Eric Andersencb57d552001-06-28 07:25:16 +00003044 * Evaluate a pipeline. All the processes in the pipeline are children
3045 * of the process creating the pipeline. (This differs from some versions
3046 * of the shell, which make the last process in a pipeline the parent
3047 * of all the rest.)
3048 */
3049
Eric Andersenc470f442003-07-28 09:56:35 +00003050static void
3051evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003052{
3053 struct job *jp;
3054 struct nodelist *lp;
3055 int pipelen;
3056 int prevfd;
3057 int pip[2];
3058
Eric Andersenc470f442003-07-28 09:56:35 +00003059 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003060 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003061 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003062 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003063 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003064 INTOFF;
3065 jp = makejob(n, pipelen);
3066 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003067 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003068 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003069 pip[1] = -1;
3070 if (lp->next) {
3071 if (pipe(pip) < 0) {
3072 close(prevfd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003073 sh_error("Pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00003074 }
3075 }
3076 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3077 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003078 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003079 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003080 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003081 if (prevfd > 0) {
3082 dup2(prevfd, 0);
3083 close(prevfd);
3084 }
3085 if (pip[1] > 1) {
3086 dup2(pip[1], 1);
3087 close(pip[1]);
3088 }
Eric Andersenc470f442003-07-28 09:56:35 +00003089 evaltreenr(lp->n, flags);
3090 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003091 }
3092 if (prevfd >= 0)
3093 close(prevfd);
3094 prevfd = pip[0];
3095 close(pip[1]);
3096 }
Eric Andersencb57d552001-06-28 07:25:16 +00003097 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003098 exitstatus = waitforjob(jp);
3099 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003100 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003101 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003102}
3103
Eric Andersen62483552001-07-10 06:09:16 +00003104
3105
3106/*
3107 * Execute a command inside back quotes. If it's a builtin command, we
3108 * want to save its output in a block obtained from malloc. Otherwise
3109 * we fork off a subprocess and get the output of the command via a pipe.
3110 * Should be called with interrupts off.
3111 */
3112
Eric Andersenc470f442003-07-28 09:56:35 +00003113static void
3114evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003115{
Eric Andersenc470f442003-07-28 09:56:35 +00003116 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003117
Eric Andersen62483552001-07-10 06:09:16 +00003118 result->fd = -1;
3119 result->buf = NULL;
3120 result->nleft = 0;
3121 result->jp = NULL;
3122 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003123 goto out;
3124 }
Eric Andersenc470f442003-07-28 09:56:35 +00003125
3126 saveherefd = herefd;
3127 herefd = -1;
3128
3129 {
3130 int pip[2];
3131 struct job *jp;
3132
3133 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003134 sh_error("Pipe call failed");
Eric Andersenc470f442003-07-28 09:56:35 +00003135 jp = makejob(n, 1);
3136 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3137 FORCEINTON;
3138 close(pip[0]);
3139 if (pip[1] != 1) {
3140 close(1);
3141 copyfd(pip[1], 1);
3142 close(pip[1]);
3143 }
3144 eflag = 0;
3145 evaltreenr(n, EV_EXIT);
3146 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003147 }
Eric Andersenc470f442003-07-28 09:56:35 +00003148 close(pip[1]);
3149 result->fd = pip[0];
3150 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003151 }
Eric Andersenc470f442003-07-28 09:56:35 +00003152 herefd = saveherefd;
3153out:
Eric Andersen62483552001-07-10 06:09:16 +00003154 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003155 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003156}
3157
Eric Andersenc470f442003-07-28 09:56:35 +00003158#ifdef CONFIG_ASH_CMDCMD
3159static inline char **
3160parse_command_args(char **argv, const char **path)
3161{
3162 char *cp, c;
3163
3164 for (;;) {
3165 cp = *++argv;
3166 if (!cp)
3167 return 0;
3168 if (*cp++ != '-')
3169 break;
3170 if (!(c = *cp++))
3171 break;
3172 if (c == '-' && !*cp) {
3173 argv++;
3174 break;
3175 }
3176 do {
3177 switch (c) {
3178 case 'p':
3179 *path = defpath;
3180 break;
3181 default:
3182 /* run 'typecmd' for other options */
3183 return 0;
3184 }
3185 } while ((c = *cp++));
3186 }
3187 return argv;
3188}
3189#endif
3190
Paul Foxc3850c82005-07-20 18:23:39 +00003191static inline int
3192isassignment(const char *p)
3193{
3194 const char *q = endofname(p);
3195 if (p == q)
3196 return 0;
3197 return *q == '=';
3198}
Eric Andersen62483552001-07-10 06:09:16 +00003199
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003200#ifdef CONFIG_ASH_EXPAND_PRMT
3201static const char *expandstr(const char *ps);
3202#else
3203#define expandstr(s) s
3204#endif
3205
Eric Andersen62483552001-07-10 06:09:16 +00003206/*
3207 * Execute a simple command.
3208 */
Eric Andersencb57d552001-06-28 07:25:16 +00003209
Eric Andersenc470f442003-07-28 09:56:35 +00003210static void
3211evalcommand(union node *cmd, int flags)
3212{
3213 struct stackmark smark;
3214 union node *argp;
3215 struct arglist arglist;
3216 struct arglist varlist;
3217 char **argv;
3218 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003219 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003220 struct cmdentry cmdentry;
3221 struct job *jp;
3222 char *lastarg;
3223 const char *path;
3224 int spclbltin;
3225 int cmd_is_exec;
3226 int status;
3227 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003228 struct builtincmd *bcmd;
3229 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003230
3231 /* First expand the arguments. */
3232 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3233 setstackmark(&smark);
3234 back_exitstatus = 0;
3235
3236 cmdentry.cmdtype = CMDBUILTIN;
3237 cmdentry.u.cmd = &bltin;
3238 varlist.lastp = &varlist.list;
3239 *varlist.lastp = NULL;
3240 arglist.lastp = &arglist.list;
3241 *arglist.lastp = NULL;
3242
3243 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003244 if (cmd->ncmd.args)
3245 {
3246 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3247 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3248 }
3249
Eric Andersenc470f442003-07-28 09:56:35 +00003250 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3251 struct strlist **spp;
3252
3253 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003254 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00003255 expandarg(argp, &arglist, EXP_VARTILDE);
3256 else
3257 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3258
Eric Andersenc470f442003-07-28 09:56:35 +00003259 for (sp = *spp; sp; sp = sp->next)
3260 argc++;
3261 }
3262
3263 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3264 for (sp = arglist.list ; sp ; sp = sp->next) {
3265 TRACE(("evalcommand arg: %s\n", sp->text));
3266 *nargv++ = sp->text;
3267 }
3268 *nargv = NULL;
3269
3270 lastarg = NULL;
3271 if (iflag && funcnest == 0 && argc > 0)
3272 lastarg = nargv[-1];
3273
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003274 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003275 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003276 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003277
3278 path = vpath.text;
3279 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3280 struct strlist **spp;
3281 char *p;
3282
3283 spp = varlist.lastp;
3284 expandarg(argp, &varlist, EXP_VARTILDE);
3285
3286 /*
3287 * Modify the command lookup path, if a PATH= assignment
3288 * is present
3289 */
3290 p = (*spp)->text;
3291 if (varequal(p, path))
3292 path = p;
3293 }
3294
3295 /* Print the command if xflag is set. */
3296 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003297 int n;
3298 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003299
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003300 p++;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003301 dprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003302
3303 sp = varlist.list;
3304 for(n = 0; n < 2; n++) {
3305 while (sp) {
3306 dprintf(preverrout_fd, p, sp->text);
3307 sp = sp->next;
3308 if(*p == '%') {
3309 p--;
3310 }
3311 }
3312 sp = arglist.list;
3313 }
Eric Andersen16767e22004-03-16 05:14:10 +00003314 bb_full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003315 }
3316
3317 cmd_is_exec = 0;
3318 spclbltin = -1;
3319
3320 /* Now locate the command. */
3321 if (argc) {
3322 const char *oldpath;
3323 int cmd_flag = DO_ERR;
3324
3325 path += 5;
3326 oldpath = path;
3327 for (;;) {
3328 find_command(argv[0], &cmdentry, cmd_flag, path);
3329 if (cmdentry.cmdtype == CMDUNKNOWN) {
3330 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003331 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003332 goto bail;
3333 }
3334
3335 /* implement bltin and command here */
3336 if (cmdentry.cmdtype != CMDBUILTIN)
3337 break;
3338 if (spclbltin < 0)
3339 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3340 if (cmdentry.u.cmd == EXECCMD)
3341 cmd_is_exec++;
3342#ifdef CONFIG_ASH_CMDCMD
3343 if (cmdentry.u.cmd == COMMANDCMD) {
3344
3345 path = oldpath;
3346 nargv = parse_command_args(argv, &path);
3347 if (!nargv)
3348 break;
3349 argc -= nargv - argv;
3350 argv = nargv;
3351 cmd_flag |= DO_NOFUNC;
3352 } else
3353#endif
3354 break;
3355 }
3356 }
3357
3358 if (status) {
3359 /* We have a redirection error. */
3360 if (spclbltin > 0)
3361 exraise(EXERROR);
3362bail:
3363 exitstatus = status;
3364 goto out;
3365 }
3366
3367 /* Execute the command. */
3368 switch (cmdentry.cmdtype) {
3369 default:
3370 /* Fork off a child process if necessary. */
3371 if (!(flags & EV_EXIT) || trap[0]) {
3372 INTOFF;
3373 jp = makejob(cmd, 1);
3374 if (forkshell(jp, cmd, FORK_FG) != 0) {
3375 exitstatus = waitforjob(jp);
3376 INTON;
3377 break;
3378 }
3379 FORCEINTON;
3380 }
3381 listsetvar(varlist.list, VEXPORT|VSTACK);
3382 shellexec(argv, path, cmdentry.u.index);
3383 /* NOTREACHED */
3384
3385 case CMDBUILTIN:
3386 cmdenviron = varlist.list;
3387 if (cmdenviron) {
3388 struct strlist *list = cmdenviron;
3389 int i = VNOSET;
3390 if (spclbltin > 0 || argc == 0) {
3391 i = 0;
3392 if (cmd_is_exec && argc > 1)
3393 i = VEXPORT;
3394 }
3395 listsetvar(list, i);
3396 }
3397 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3398 int exit_status;
3399 int i, j;
3400
3401 i = exception;
3402 if (i == EXEXIT)
3403 goto raise;
3404
3405 exit_status = 2;
3406 j = 0;
3407 if (i == EXINT)
3408 j = SIGINT;
3409 if (i == EXSIG)
3410 j = pendingsigs;
3411 if (j)
3412 exit_status = j + 128;
3413 exitstatus = exit_status;
3414
3415 if (i == EXINT || spclbltin > 0) {
3416raise:
3417 longjmp(handler->loc, 1);
3418 }
3419 FORCEINTON;
3420 }
3421 break;
3422
3423 case CMDFUNCTION:
3424 listsetvar(varlist.list, 0);
3425 if (evalfun(cmdentry.u.func, argc, argv, flags))
3426 goto raise;
3427 break;
3428 }
3429
3430out:
3431 popredir(cmd_is_exec);
3432 if (lastarg)
3433 /* dsl: I think this is intended to be used to support
3434 * '_' in 'vi' command mode during line editing...
3435 * However I implemented that within libedit itself.
3436 */
3437 setvar("_", lastarg, 0);
3438 popstackmark(&smark);
3439}
3440
3441static int
3442evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3443 char *volatile savecmdname;
3444 struct jmploc *volatile savehandler;
3445 struct jmploc jmploc;
3446 int i;
3447
3448 savecmdname = commandname;
3449 if ((i = setjmp(jmploc.loc)))
3450 goto cmddone;
3451 savehandler = handler;
3452 handler = &jmploc;
3453 commandname = argv[0];
3454 argptr = argv + 1;
3455 optptr = NULL; /* initialize nextopt */
3456 exitstatus = (*cmd->builtin)(argc, argv);
3457 flushall();
3458cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003459 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003460 commandname = savecmdname;
3461 exsig = 0;
3462 handler = savehandler;
3463
3464 return i;
3465}
3466
3467static int
3468evalfun(struct funcnode *func, int argc, char **argv, int flags)
3469{
3470 volatile struct shparam saveparam;
3471 struct localvar *volatile savelocalvars;
3472 struct jmploc *volatile savehandler;
3473 struct jmploc jmploc;
3474 int e;
3475
3476 saveparam = shellparam;
3477 savelocalvars = localvars;
3478 if ((e = setjmp(jmploc.loc))) {
3479 goto funcdone;
3480 }
3481 INTOFF;
3482 savehandler = handler;
3483 handler = &jmploc;
3484 localvars = NULL;
3485 shellparam.malloc = 0;
3486 func->count++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003487 funcnest++;
Eric Andersenc470f442003-07-28 09:56:35 +00003488 INTON;
3489 shellparam.nparam = argc - 1;
3490 shellparam.p = argv + 1;
3491#ifdef CONFIG_ASH_GETOPTS
3492 shellparam.optind = 1;
3493 shellparam.optoff = -1;
3494#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003495 evaltree(&func->n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00003496funcdone:
3497 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003498 funcnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00003499 freefunc(func);
3500 poplocalvars();
3501 localvars = savelocalvars;
3502 freeparam(&shellparam);
3503 shellparam = saveparam;
3504 handler = savehandler;
3505 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003506 evalskip &= ~SKIPFUNC;
Eric Andersenc470f442003-07-28 09:56:35 +00003507 return e;
3508}
3509
3510
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003511static inline int
3512goodname(const char *p)
3513{
3514 return !*endofname(p);
3515}
3516
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003517/*
3518 * Search for a command. This is called before we fork so that the
3519 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003520 * the child. The check for "goodname" is an overly conservative
3521 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003522 */
3523
Eric Andersenc470f442003-07-28 09:56:35 +00003524static void
3525prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003526{
3527 struct cmdentry entry;
3528
3529 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003530 if (goodname(n->ncmd.args->narg.text))
3531 find_command(n->ncmd.args->narg.text, &entry, 0,
3532 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003533}
3534
Eric Andersencb57d552001-06-28 07:25:16 +00003535
Eric Andersenc470f442003-07-28 09:56:35 +00003536
Eric Andersencb57d552001-06-28 07:25:16 +00003537/*
3538 * Builtin commands. Builtin commands whose functions are closely
3539 * tied to evaluation are implemented here.
3540 */
3541
3542/*
Eric Andersenc470f442003-07-28 09:56:35 +00003543 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003544 */
3545
Eric Andersenc470f442003-07-28 09:56:35 +00003546static int
3547bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003548{
3549 /*
3550 * Preserve exitstatus of a previous possible redirection
3551 * as POSIX mandates
3552 */
Eric Andersenc470f442003-07-28 09:56:35 +00003553 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003554}
3555
3556
3557/*
3558 * Handle break and continue commands. Break, continue, and return are
3559 * all handled by setting the evalskip flag. The evaluation routines
3560 * above all check this flag, and if it is set they start skipping
3561 * commands rather than executing them. The variable skipcount is
3562 * the number of loops to break/continue, or the number of function
3563 * levels to return. (The latter is always 1.) It should probably
3564 * be an error to break out of more loops than exist, but it isn't
3565 * in the standard shell so we don't make it one here.
3566 */
3567
Eric Andersenc470f442003-07-28 09:56:35 +00003568static int
3569breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003570{
3571 int n = argc > 1 ? number(argv[1]) : 1;
3572
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003573 if (n <= 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003574 sh_error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003575 if (n > loopnest)
3576 n = loopnest;
3577 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003578 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003579 skipcount = n;
3580 }
3581 return 0;
3582}
3583
3584
3585/*
3586 * The return command.
3587 */
3588
Eric Andersenc470f442003-07-28 09:56:35 +00003589static int
3590returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003591{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003592 /*
3593 * If called outside a function, do what ksh does;
3594 * skip the rest of the file.
3595 */
3596 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
3597 return argv[1] ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003598}
3599
3600
Eric Andersenc470f442003-07-28 09:56:35 +00003601static int
3602falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003603{
3604 return 1;
3605}
3606
Eric Andersenc470f442003-07-28 09:56:35 +00003607
3608static int
3609truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003610{
3611 return 0;
3612}
Eric Andersen2870d962001-07-02 17:27:21 +00003613
Eric Andersencb57d552001-06-28 07:25:16 +00003614
Eric Andersenc470f442003-07-28 09:56:35 +00003615static int
3616execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003617{
3618 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003619 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003620 mflag = 0;
3621 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003622 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003623 }
3624 return 0;
3625}
3626
Eric Andersenc470f442003-07-28 09:56:35 +00003627
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003628/* exec.c */
Eric Andersenc470f442003-07-28 09:56:35 +00003629
3630/*
3631 * When commands are first encountered, they are entered in a hash table.
3632 * This ensures that a full path search will not have to be done for them
3633 * on each invocation.
3634 *
3635 * We should investigate converting to a linear search, even though that
3636 * would make the command name "hash" a misnomer.
3637 */
3638
3639#define CMDTABLESIZE 31 /* should be prime */
3640#define ARB 1 /* actual size determined at run time */
3641
3642
3643
3644struct tblentry {
3645 struct tblentry *next; /* next entry in hash chain */
3646 union param param; /* definition of builtin function */
3647 short cmdtype; /* index identifying command */
3648 char rehash; /* if set, cd done since entry created */
3649 char cmdname[ARB]; /* name of command */
3650};
3651
3652
3653static struct tblentry *cmdtable[CMDTABLESIZE];
3654static int builtinloc = -1; /* index in path of %builtin, or -1 */
3655
3656
3657static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003658static void clearcmdentry(int);
3659static struct tblentry *cmdlookup(const char *, int);
3660static void delete_cmd_entry(void);
3661
Eric Andersencb57d552001-06-28 07:25:16 +00003662
3663/*
3664 * Exec a program. Never returns. If you change this routine, you may
3665 * have to change the find_command routine as well.
3666 */
3667
Eric Andersenc470f442003-07-28 09:56:35 +00003668static void
3669shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003670{
3671 char *cmdname;
3672 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003673 char **envp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003674 int exerrno;
Eric Andersencb57d552001-06-28 07:25:16 +00003675
Eric Andersenc470f442003-07-28 09:56:35 +00003676 clearredir(1);
3677 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003678 if (strchr(argv[0], '/') != NULL
3679#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3680 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003681#endif
3682 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003683 tryexec(argv[0], argv, envp);
3684 e = errno;
3685 } else {
3686 e = ENOENT;
3687 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3688 if (--idx < 0 && pathopt == NULL) {
3689 tryexec(cmdname, argv, envp);
3690 if (errno != ENOENT && errno != ENOTDIR)
3691 e = errno;
3692 }
3693 stunalloc(cmdname);
3694 }
3695 }
3696
3697 /* Map to POSIX errors */
3698 switch (e) {
3699 case EACCES:
3700 exerrno = 126;
3701 break;
3702 case ENOENT:
3703 exerrno = 127;
3704 break;
3705 default:
3706 exerrno = 2;
3707 break;
3708 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003709 exitstatus = exerrno;
Eric Andersenc470f442003-07-28 09:56:35 +00003710 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3711 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003712 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3713 /* NOTREACHED */
3714}
3715
Eric Andersen2870d962001-07-02 17:27:21 +00003716
Eric Andersenc470f442003-07-28 09:56:35 +00003717static void
3718tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003719{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003720 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003721#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003722 if(find_applet_by_name(cmd) != NULL) {
3723 /* re-exec ourselves with the new arguments */
3724 execve("/proc/self/exe",argv,envp);
3725 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3726 execve("/bin/busybox",argv,envp);
3727 /* If they called chroot or otherwise made the binary no longer
3728 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003729 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003730#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003731
3732repeat:
3733#ifdef SYSV
3734 do {
3735 execve(cmd, argv, envp);
3736 } while (errno == EINTR);
3737#else
Eric Andersencb57d552001-06-28 07:25:16 +00003738 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003739#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003740 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003741 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003742 } else if (errno == ENOEXEC) {
3743 char **ap;
3744 char **new;
3745
Eric Andersenc470f442003-07-28 09:56:35 +00003746 for (ap = argv; *ap; ap++)
3747 ;
3748 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003749 ap[1] = cmd;
3750 *ap = cmd = (char *)DEFAULT_SHELL;
3751 ap += 2;
3752 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003753 while ((*ap++ = *argv++))
3754 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003755 argv = new;
3756 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003757 }
Eric Andersencb57d552001-06-28 07:25:16 +00003758}
3759
Eric Andersenc470f442003-07-28 09:56:35 +00003760
Eric Andersencb57d552001-06-28 07:25:16 +00003761
3762/*
3763 * Do a path search. The variable path (passed by reference) should be
3764 * set to the start of the path before the first call; padvance will update
3765 * this value as it proceeds. Successive calls to padvance will return
3766 * the possible path expansions in sequence. If an option (indicated by
3767 * a percent sign) appears in the path entry then the global variable
3768 * pathopt will be set to point to it; otherwise pathopt will be set to
3769 * NULL.
3770 */
3771
Eric Andersenc470f442003-07-28 09:56:35 +00003772static char *
3773padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003774{
Eric Andersencb57d552001-06-28 07:25:16 +00003775 const char *p;
3776 char *q;
3777 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003778 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003779
3780 if (*path == NULL)
3781 return NULL;
3782 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003783 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3784 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003785 while (stackblocksize() < len)
3786 growstackblock();
3787 q = stackblock();
3788 if (p != start) {
3789 memcpy(q, start, p - start);
3790 q += p - start;
3791 *q++ = '/';
3792 }
3793 strcpy(q, name);
3794 pathopt = NULL;
3795 if (*p == '%') {
3796 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003797 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003798 }
3799 if (*p == ':')
3800 *path = p + 1;
3801 else
3802 *path = NULL;
3803 return stalloc(len);
3804}
3805
3806
Eric Andersencb57d552001-06-28 07:25:16 +00003807/*** Command hashing code ***/
3808
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003809static void
3810printentry(struct tblentry *cmdp)
3811{
3812 int idx;
3813 const char *path;
3814 char *name;
3815
3816 idx = cmdp->param.index;
3817 path = pathval();
3818 do {
3819 name = padvance(&path, cmdp->cmdname);
3820 stunalloc(name);
3821 } while (--idx >= 0);
3822 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3823}
3824
Eric Andersenc470f442003-07-28 09:56:35 +00003825
3826static int
3827hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003828{
3829 struct tblentry **pp;
3830 struct tblentry *cmdp;
3831 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003832 struct cmdentry entry;
3833 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003834
Eric Andersenc470f442003-07-28 09:56:35 +00003835 while ((c = nextopt("r")) != '\0') {
3836 clearcmdentry(0);
3837 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003838 }
3839 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003840 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3841 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3842 if (cmdp->cmdtype == CMDNORMAL)
3843 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003844 }
3845 }
3846 return 0;
3847 }
3848 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003849 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003850 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003851 && (cmdp->cmdtype == CMDNORMAL
3852 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003853 delete_cmd_entry();
3854 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003855 if (entry.cmdtype == CMDUNKNOWN)
3856 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003857 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003858 }
3859 return c;
3860}
3861
Eric Andersenc470f442003-07-28 09:56:35 +00003862
Eric Andersencb57d552001-06-28 07:25:16 +00003863/*
3864 * Resolve a command name. If you change this routine, you may have to
3865 * change the shellexec routine as well.
3866 */
3867
3868static void
Eric Andersenc470f442003-07-28 09:56:35 +00003869find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003870{
3871 struct tblentry *cmdp;
3872 int idx;
3873 int prev;
3874 char *fullname;
3875 struct stat statb;
3876 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003877 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003878 struct builtincmd *bcmd;
3879
Eric Andersenc470f442003-07-28 09:56:35 +00003880 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003881 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003882 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003883 if (act & DO_ABS) {
3884 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003885#ifdef SYSV
3886 if (errno == EINTR)
3887 continue;
3888#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003889 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003890 return;
3891 }
Eric Andersencb57d552001-06-28 07:25:16 +00003892 }
3893 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003894 return;
3895 }
3896
Eric Andersenbf8bf102002-09-17 08:41:08 +00003897#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3898 if (find_applet_by_name(name)) {
3899 entry->cmdtype = CMDNORMAL;
3900 entry->u.index = -1;
3901 return;
3902 }
3903#endif
3904
Eric Andersenc470f442003-07-28 09:56:35 +00003905 updatetbl = (path == pathval());
3906 if (!updatetbl) {
3907 act |= DO_ALTPATH;
3908 if (strstr(path, "%builtin") != NULL)
3909 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003910 }
3911
Eric Andersenc470f442003-07-28 09:56:35 +00003912 /* If name is in the table, check answer will be ok */
3913 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3914 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003915
Eric Andersenc470f442003-07-28 09:56:35 +00003916 switch (cmdp->cmdtype) {
3917 default:
3918#if DEBUG
3919 abort();
3920#endif
3921 case CMDNORMAL:
3922 bit = DO_ALTPATH;
3923 break;
3924 case CMDFUNCTION:
3925 bit = DO_NOFUNC;
3926 break;
3927 case CMDBUILTIN:
3928 bit = DO_ALTBLTIN;
3929 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003930 }
Eric Andersenc470f442003-07-28 09:56:35 +00003931 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003932 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003933 cmdp = NULL;
3934 } else if (cmdp->rehash == 0)
3935 /* if not invalidated by cd, we're done */
3936 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003937 }
3938
3939 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003940 bcmd = find_builtin(name);
3941 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3942 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3943 )))
3944 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003945
3946 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003947 prev = -1; /* where to start */
3948 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003949 if (cmdp->cmdtype == CMDBUILTIN)
3950 prev = builtinloc;
3951 else
3952 prev = cmdp->param.index;
3953 }
3954
3955 e = ENOENT;
3956 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003957loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003958 while ((fullname = padvance(&path, name)) != NULL) {
3959 stunalloc(fullname);
3960 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003961 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003962 if (prefix(pathopt, "builtin")) {
3963 if (bcmd)
3964 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003965 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003966 } else if (!(act & DO_NOFUNC) &&
3967 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003968 /* handled below */
3969 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003970 /* ignore unimplemented options */
3971 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003972 }
3973 }
3974 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003975 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003976 if (idx < prev)
3977 continue;
3978 TRACE(("searchexec \"%s\": no change\n", name));
3979 goto success;
3980 }
3981 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003982#ifdef SYSV
3983 if (errno == EINTR)
3984 continue;
3985#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003986 if (errno != ENOENT && errno != ENOTDIR)
3987 e = errno;
3988 goto loop;
3989 }
Eric Andersenc470f442003-07-28 09:56:35 +00003990 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003991 if (!S_ISREG(statb.st_mode))
3992 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003993 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003994 stalloc(strlen(fullname) + 1);
3995 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00003996 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3997 cmdp->cmdtype != CMDFUNCTION)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003998 sh_error("%s not defined in %s", name, fullname);
Eric Andersencb57d552001-06-28 07:25:16 +00003999 stunalloc(fullname);
4000 goto success;
4001 }
Eric Andersencb57d552001-06-28 07:25:16 +00004002 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004003 if (!updatetbl) {
4004 entry->cmdtype = CMDNORMAL;
4005 entry->u.index = idx;
4006 return;
4007 }
4008 INTOFF;
4009 cmdp = cmdlookup(name, 1);
4010 cmdp->cmdtype = CMDNORMAL;
4011 cmdp->param.index = idx;
4012 INTON;
4013 goto success;
4014 }
4015
4016 /* We failed. If there was an entry for this command, delete it */
4017 if (cmdp && updatetbl)
4018 delete_cmd_entry();
4019 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004020 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004021 entry->cmdtype = CMDUNKNOWN;
4022 return;
4023
Eric Andersenc470f442003-07-28 09:56:35 +00004024builtin_success:
4025 if (!updatetbl) {
4026 entry->cmdtype = CMDBUILTIN;
4027 entry->u.cmd = bcmd;
4028 return;
4029 }
4030 INTOFF;
4031 cmdp = cmdlookup(name, 1);
4032 cmdp->cmdtype = CMDBUILTIN;
4033 cmdp->param.cmd = bcmd;
4034 INTON;
4035success:
Eric Andersencb57d552001-06-28 07:25:16 +00004036 cmdp->rehash = 0;
4037 entry->cmdtype = cmdp->cmdtype;
4038 entry->u = cmdp->param;
4039}
4040
4041
Eric Andersenc470f442003-07-28 09:56:35 +00004042/*
4043 * Wrapper around strcmp for qsort/bsearch/...
4044 */
4045static int pstrcmp(const void *a, const void *b)
4046{
4047 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4048}
Eric Andersencb57d552001-06-28 07:25:16 +00004049
4050/*
4051 * Search the table of builtin commands.
4052 */
4053
Eric Andersenc470f442003-07-28 09:56:35 +00004054static struct builtincmd *
4055find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004056{
4057 struct builtincmd *bp;
4058
Eric Andersenc470f442003-07-28 09:56:35 +00004059 bp = bsearch(
4060 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4061 pstrcmp
4062 );
Eric Andersencb57d552001-06-28 07:25:16 +00004063 return bp;
4064}
4065
4066
Eric Andersenc470f442003-07-28 09:56:35 +00004067
Eric Andersencb57d552001-06-28 07:25:16 +00004068/*
4069 * Called when a cd is done. Marks all commands so the next time they
4070 * are executed they will be rehashed.
4071 */
4072
Eric Andersenc470f442003-07-28 09:56:35 +00004073static void
4074hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004075{
Eric Andersencb57d552001-06-28 07:25:16 +00004076 struct tblentry **pp;
4077 struct tblentry *cmdp;
4078
Eric Andersenc470f442003-07-28 09:56:35 +00004079 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4080 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4081 if (cmdp->cmdtype == CMDNORMAL || (
4082 cmdp->cmdtype == CMDBUILTIN &&
4083 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4084 builtinloc > 0
4085 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004086 cmdp->rehash = 1;
4087 }
4088 }
4089}
4090
4091
4092
4093/*
Eric Andersenc470f442003-07-28 09:56:35 +00004094 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004095 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004096 * pathval() still returns the old value at this point.
4097 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004098 */
4099
Eric Andersenc470f442003-07-28 09:56:35 +00004100static void
4101changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004102{
Eric Andersenc470f442003-07-28 09:56:35 +00004103 const char *old, *new;
4104 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004105 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004106 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004107
Eric Andersenc470f442003-07-28 09:56:35 +00004108 old = pathval();
4109 new = newval;
4110 firstchange = 9999; /* assume no change */
4111 idx = 0;
4112 idx_bltin = -1;
4113 for (;;) {
4114 if (*old != *new) {
4115 firstchange = idx;
4116 if ((*old == '\0' && *new == ':')
4117 || (*old == ':' && *new == '\0'))
4118 firstchange++;
4119 old = new; /* ignore subsequent differences */
4120 }
4121 if (*new == '\0')
4122 break;
4123 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4124 idx_bltin = idx;
4125 if (*new == ':') {
4126 idx++;
4127 }
4128 new++, old++;
4129 }
4130 if (builtinloc < 0 && idx_bltin >= 0)
4131 builtinloc = idx_bltin; /* zap builtins */
4132 if (builtinloc >= 0 && idx_bltin < 0)
4133 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004134 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004135 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004136}
4137
4138
4139/*
4140 * Clear out command entries. The argument specifies the first entry in
4141 * PATH which has changed.
4142 */
4143
Eric Andersenc470f442003-07-28 09:56:35 +00004144static void
4145clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004146{
4147 struct tblentry **tblp;
4148 struct tblentry **pp;
4149 struct tblentry *cmdp;
4150
4151 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004152 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004153 pp = tblp;
4154 while ((cmdp = *pp) != NULL) {
4155 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004156 cmdp->param.index >= firstchange)
4157 || (cmdp->cmdtype == CMDBUILTIN &&
4158 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004159 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004160 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004161 } else {
4162 pp = &cmdp->next;
4163 }
4164 }
4165 }
4166 INTON;
4167}
4168
4169
Eric Andersenc470f442003-07-28 09:56:35 +00004170
Eric Andersencb57d552001-06-28 07:25:16 +00004171/*
Eric Andersencb57d552001-06-28 07:25:16 +00004172 * Locate a command in the command hash table. If "add" is nonzero,
4173 * add the command to the table if it is not already present. The
4174 * variable "lastcmdentry" is set to point to the address of the link
4175 * pointing to the entry, so that delete_cmd_entry can delete the
4176 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004177 *
4178 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004179 */
4180
Eric Andersen2870d962001-07-02 17:27:21 +00004181static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004182
Eric Andersenc470f442003-07-28 09:56:35 +00004183
4184static struct tblentry *
4185cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004186{
Eric Andersenc470f442003-07-28 09:56:35 +00004187 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004188 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004189 struct tblentry *cmdp;
4190 struct tblentry **pp;
4191
4192 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004193 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004194 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004195 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004196 hashval &= 0x7FFF;
4197 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004198 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004199 if (equal(cmdp->cmdname, name))
4200 break;
4201 pp = &cmdp->next;
4202 }
4203 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004204 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4205 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004206 cmdp->next = NULL;
4207 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004208 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004209 }
4210 lastcmdentry = pp;
4211 return cmdp;
4212}
4213
4214/*
4215 * Delete the command entry returned on the last lookup.
4216 */
4217
Eric Andersenc470f442003-07-28 09:56:35 +00004218static void
4219delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004220{
Eric Andersencb57d552001-06-28 07:25:16 +00004221 struct tblentry *cmdp;
4222
4223 INTOFF;
4224 cmdp = *lastcmdentry;
4225 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004226 if (cmdp->cmdtype == CMDFUNCTION)
4227 freefunc(cmdp->param.func);
4228 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004229 INTON;
4230}
4231
4232
Eric Andersenc470f442003-07-28 09:56:35 +00004233/*
4234 * Add a new command entry, replacing any existing command entry for
4235 * the same name - except special builtins.
4236 */
Eric Andersencb57d552001-06-28 07:25:16 +00004237
Eric Andersenc470f442003-07-28 09:56:35 +00004238static inline void
4239addcmdentry(char *name, struct cmdentry *entry)
4240{
4241 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004242
Eric Andersenc470f442003-07-28 09:56:35 +00004243 cmdp = cmdlookup(name, 1);
4244 if (cmdp->cmdtype == CMDFUNCTION) {
4245 freefunc(cmdp->param.func);
4246 }
4247 cmdp->cmdtype = entry->cmdtype;
4248 cmdp->param = entry->u;
4249 cmdp->rehash = 0;
4250}
Eric Andersencb57d552001-06-28 07:25:16 +00004251
Eric Andersenc470f442003-07-28 09:56:35 +00004252/*
4253 * Make a copy of a parse tree.
4254 */
Eric Andersencb57d552001-06-28 07:25:16 +00004255
Eric Andersenc470f442003-07-28 09:56:35 +00004256static inline struct funcnode *
4257copyfunc(union node *n)
4258{
4259 struct funcnode *f;
4260 size_t blocksize;
4261
4262 funcblocksize = offsetof(struct funcnode, n);
4263 funcstringsize = 0;
4264 calcsize(n);
4265 blocksize = funcblocksize;
4266 f = ckmalloc(blocksize + funcstringsize);
4267 funcblock = (char *) f + offsetof(struct funcnode, n);
4268 funcstring = (char *) f + blocksize;
4269 copynode(n);
4270 f->count = 0;
4271 return f;
4272}
4273
4274/*
4275 * Define a shell function.
4276 */
4277
4278static void
4279defun(char *name, union node *func)
4280{
4281 struct cmdentry entry;
4282
4283 INTOFF;
4284 entry.cmdtype = CMDFUNCTION;
4285 entry.u.func = copyfunc(func);
4286 addcmdentry(name, &entry);
4287 INTON;
4288}
Eric Andersencb57d552001-06-28 07:25:16 +00004289
4290
4291/*
4292 * Delete a function if it exists.
4293 */
4294
Eric Andersenc470f442003-07-28 09:56:35 +00004295static void
4296unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004297{
Eric Andersencb57d552001-06-28 07:25:16 +00004298 struct tblentry *cmdp;
4299
Eric Andersenc470f442003-07-28 09:56:35 +00004300 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4301 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004302 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004303}
4304
Eric Andersen2870d962001-07-02 17:27:21 +00004305/*
Eric Andersencb57d552001-06-28 07:25:16 +00004306 * Locate and print what a word is...
4307 */
4308
Eric Andersenc470f442003-07-28 09:56:35 +00004309
4310#ifdef CONFIG_ASH_CMDCMD
4311static int
4312describe_command(char *command, int describe_command_verbose)
4313#else
4314#define describe_command_verbose 1
4315static int
4316describe_command(char *command)
4317#endif
4318{
4319 struct cmdentry entry;
4320 struct tblentry *cmdp;
4321#ifdef CONFIG_ASH_ALIAS
4322 const struct alias *ap;
4323#endif
4324 const char *path = pathval();
4325
4326 if (describe_command_verbose) {
4327 out1str(command);
4328 }
4329
4330 /* First look at the keywords */
4331 if (findkwd(command)) {
4332 out1str(describe_command_verbose ? " is a shell keyword" : command);
4333 goto out;
4334 }
4335
4336#ifdef CONFIG_ASH_ALIAS
4337 /* Then look at the aliases */
4338 if ((ap = lookupalias(command, 0)) != NULL) {
4339 if (describe_command_verbose) {
4340 out1fmt(" is an alias for %s", ap->val);
4341 } else {
4342 out1str("alias ");
4343 printalias(ap);
4344 return 0;
4345 }
4346 goto out;
4347 }
4348#endif
4349 /* Then check if it is a tracked alias */
4350 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4351 entry.cmdtype = cmdp->cmdtype;
4352 entry.u = cmdp->param;
4353 } else {
4354 /* Finally use brute force */
4355 find_command(command, &entry, DO_ABS, path);
4356 }
4357
4358 switch (entry.cmdtype) {
4359 case CMDNORMAL: {
4360 int j = entry.u.index;
4361 char *p;
4362 if (j == -1) {
4363 p = command;
4364 } else {
4365 do {
4366 p = padvance(&path, command);
4367 stunalloc(p);
4368 } while (--j >= 0);
4369 }
4370 if (describe_command_verbose) {
4371 out1fmt(" is%s %s",
4372 (cmdp ? " a tracked alias for" : nullstr), p
4373 );
4374 } else {
4375 out1str(p);
4376 }
4377 break;
4378 }
4379
4380 case CMDFUNCTION:
4381 if (describe_command_verbose) {
4382 out1str(" is a shell function");
4383 } else {
4384 out1str(command);
4385 }
4386 break;
4387
4388 case CMDBUILTIN:
4389 if (describe_command_verbose) {
4390 out1fmt(" is a %sshell builtin",
4391 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4392 "special " : nullstr
4393 );
4394 } else {
4395 out1str(command);
4396 }
4397 break;
4398
4399 default:
4400 if (describe_command_verbose) {
4401 out1str(": not found\n");
4402 }
4403 return 127;
4404 }
4405
4406out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004407 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004408 return 0;
4409}
4410
4411static int
4412typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004413{
4414 int i;
4415 int err = 0;
4416
4417 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004418#ifdef CONFIG_ASH_CMDCMD
4419 err |= describe_command(argv[i], 1);
4420#else
4421 err |= describe_command(argv[i]);
4422#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004423 }
4424 return err;
4425}
4426
Eric Andersend35c5df2002-01-09 15:37:36 +00004427#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004428static int
4429commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004430{
4431 int c;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004432 enum {
4433 VERIFY_BRIEF = 1,
4434 VERIFY_VERBOSE = 2,
4435 } verify = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004436
4437 while ((c = nextopt("pvV")) != '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004438 if (c == 'V')
4439 verify |= VERIFY_VERBOSE;
4440 else if (c == 'v')
4441 verify |= VERIFY_BRIEF;
Eric Andersenc470f442003-07-28 09:56:35 +00004442#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004443 else if (c != 'p')
4444 abort();
Eric Andersenc470f442003-07-28 09:56:35 +00004445#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004446 if (verify)
4447 return describe_command(*argptr, verify - VERIFY_BRIEF);
Eric Andersencb57d552001-06-28 07:25:16 +00004448
4449 return 0;
4450}
Eric Andersen2870d962001-07-02 17:27:21 +00004451#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004452
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004453/* expand.c */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004454
Eric Andersencb57d552001-06-28 07:25:16 +00004455/*
4456 * Routines to expand arguments to commands. We have to deal with
4457 * backquotes, shell variables, and file metacharacters.
4458 */
Eric Andersenc470f442003-07-28 09:56:35 +00004459
Eric Andersencb57d552001-06-28 07:25:16 +00004460/*
4461 * _rmescape() flags
4462 */
Eric Andersenc470f442003-07-28 09:56:35 +00004463#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4464#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4465#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4466#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4467#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004468
4469/*
4470 * Structure specifying which parts of the string should be searched
4471 * for IFS characters.
4472 */
4473
4474struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004475 struct ifsregion *next; /* next region in list */
4476 int begoff; /* offset of start of region */
4477 int endoff; /* offset of end of region */
4478 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004479};
4480
Eric Andersenc470f442003-07-28 09:56:35 +00004481/* output of current string */
4482static char *expdest;
4483/* list of back quote expressions */
4484static struct nodelist *argbackq;
4485/* first struct in list of ifs regions */
4486static struct ifsregion ifsfirst;
4487/* last struct in list */
4488static struct ifsregion *ifslastp;
4489/* holds expanded arg list */
4490static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004491
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004492static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004493static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004494static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004495static const char *subevalvar(char *, char *, int, int, int, int, int);
4496static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004497static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004498static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004499static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004500static void recordregion(int, int, int);
4501static void removerecordregions(int);
4502static void ifsbreakup(char *, struct arglist *);
4503static void ifsfree(void);
4504static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004505static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004506
Eric Andersened9ecf72004-06-22 08:29:45 +00004507static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004508static size_t esclen(const char *, const char *);
4509static char *scanleft(char *, char *, char *, char *, int, int);
4510static char *scanright(char *, char *, char *, char *, int, int);
4511static void varunset(const char *, const char *, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00004512 ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004513
Eric Andersenc470f442003-07-28 09:56:35 +00004514
4515#define pmatch(a, b) !fnmatch((a), (b), 0)
4516/*
Eric Andersen90898442003-08-06 11:20:52 +00004517 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004518 *
4519 * Returns an stalloced string.
4520 */
4521
4522static inline char *
4523preglob(const char *pattern, int quoted, int flag) {
4524 flag |= RMESCAPE_GLOB;
4525 if (quoted) {
4526 flag |= RMESCAPE_QUOTED;
4527 }
4528 return _rmescapes((char *)pattern, flag);
4529}
4530
4531
4532static size_t
4533esclen(const char *start, const char *p) {
4534 size_t esc = 0;
4535
4536 while (p > start && *--p == CTLESC) {
4537 esc++;
4538 }
4539 return esc;
4540}
4541
Eric Andersencb57d552001-06-28 07:25:16 +00004542
4543/*
4544 * Expand shell variables and backquotes inside a here document.
4545 */
4546
Eric Andersenc470f442003-07-28 09:56:35 +00004547static inline void
4548expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004549{
Eric Andersencb57d552001-06-28 07:25:16 +00004550 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004551 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004552 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004553}
4554
4555
4556/*
4557 * Perform variable substitution and command substitution on an argument,
4558 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4559 * perform splitting and file name expansion. When arglist is NULL, perform
4560 * here document expansion.
4561 */
4562
Eric Andersenc470f442003-07-28 09:56:35 +00004563void
4564expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004565{
4566 struct strlist *sp;
4567 char *p;
4568
4569 argbackq = arg->narg.backquote;
4570 STARTSTACKSTR(expdest);
4571 ifsfirst.next = NULL;
4572 ifslastp = NULL;
4573 argstr(arg->narg.text, flag);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004574 p = _STPUTC('\0', expdest);
4575 expdest = p - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004576 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004577 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004578 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004579 p = grabstackstr(p);
Eric Andersencb57d552001-06-28 07:25:16 +00004580 exparg.lastp = &exparg.list;
4581 /*
4582 * TODO - EXP_REDIR
4583 */
4584 if (flag & EXP_FULL) {
4585 ifsbreakup(p, &exparg);
4586 *exparg.lastp = NULL;
4587 exparg.lastp = &exparg.list;
4588 expandmeta(exparg.list, flag);
4589 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004590 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004591 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004592 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004593 sp->text = p;
4594 *exparg.lastp = sp;
4595 exparg.lastp = &sp->next;
4596 }
Eric Andersenc470f442003-07-28 09:56:35 +00004597 if (ifsfirst.next)
4598 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004599 *exparg.lastp = NULL;
4600 if (exparg.list) {
4601 *arglist->lastp = exparg.list;
4602 arglist->lastp = exparg.lastp;
4603 }
4604}
4605
4606
Eric Andersenc470f442003-07-28 09:56:35 +00004607/*
4608 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4609 * characters to allow for further processing. Otherwise treat
4610 * $@ like $* since no splitting will be performed.
4611 */
4612
4613static void
4614argstr(char *p, int flag)
4615{
4616 static const char spclchars[] = {
4617 '=',
4618 ':',
4619 CTLQUOTEMARK,
4620 CTLENDVAR,
4621 CTLESC,
4622 CTLVAR,
4623 CTLBACKQ,
4624 CTLBACKQ | CTLQUOTE,
4625#ifdef CONFIG_ASH_MATH_SUPPORT
4626 CTLENDARI,
4627#endif
4628 0
4629 };
4630 const char *reject = spclchars;
4631 int c;
4632 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4633 int breakall = flag & EXP_WORD;
4634 int inquotes;
4635 size_t length;
4636 int startloc;
4637
4638 if (!(flag & EXP_VARTILDE)) {
4639 reject += 2;
4640 } else if (flag & EXP_VARTILDE2) {
4641 reject++;
4642 }
4643 inquotes = 0;
4644 length = 0;
4645 if (flag & EXP_TILDE) {
4646 char *q;
4647
4648 flag &= ~EXP_TILDE;
4649tilde:
4650 q = p;
4651 if (*q == CTLESC && (flag & EXP_QWORD))
4652 q++;
4653 if (*q == '~')
4654 p = exptilde(p, q, flag);
4655 }
4656start:
4657 startloc = expdest - (char *)stackblock();
4658 for (;;) {
4659 length += strcspn(p + length, reject);
4660 c = p[length];
4661 if (c && (!(c & 0x80)
4662#ifdef CONFIG_ASH_MATH_SUPPORT
4663 || c == CTLENDARI
4664#endif
4665 )) {
4666 /* c == '=' || c == ':' || c == CTLENDARI */
4667 length++;
4668 }
4669 if (length > 0) {
4670 int newloc;
4671 expdest = stnputs(p, length, expdest);
4672 newloc = expdest - (char *)stackblock();
4673 if (breakall && !inquotes && newloc > startloc) {
4674 recordregion(startloc, newloc, 0);
4675 }
4676 startloc = newloc;
4677 }
4678 p += length + 1;
4679 length = 0;
4680
4681 switch (c) {
4682 case '\0':
4683 goto breakloop;
4684 case '=':
4685 if (flag & EXP_VARTILDE2) {
4686 p--;
4687 continue;
4688 }
4689 flag |= EXP_VARTILDE2;
4690 reject++;
4691 /* fall through */
4692 case ':':
4693 /*
4694 * sort of a hack - expand tildes in variable
4695 * assignments (after the first '=' and after ':'s).
4696 */
4697 if (*--p == '~') {
4698 goto tilde;
4699 }
4700 continue;
4701 }
4702
4703 switch (c) {
4704 case CTLENDVAR: /* ??? */
4705 goto breakloop;
4706 case CTLQUOTEMARK:
4707 /* "$@" syntax adherence hack */
4708 if (
4709 !inquotes &&
4710 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4711 (p[4] == CTLQUOTEMARK || (
4712 p[4] == CTLENDVAR &&
4713 p[5] == CTLQUOTEMARK
4714 ))
4715 ) {
4716 p = evalvar(p + 1, flag) + 1;
4717 goto start;
4718 }
4719 inquotes = !inquotes;
4720addquote:
4721 if (quotes) {
4722 p--;
4723 length++;
4724 startloc++;
4725 }
4726 break;
4727 case CTLESC:
4728 startloc++;
4729 length++;
4730 goto addquote;
4731 case CTLVAR:
4732 p = evalvar(p, flag);
4733 goto start;
4734 case CTLBACKQ:
4735 c = 0;
4736 case CTLBACKQ|CTLQUOTE:
4737 expbackq(argbackq->n, c, quotes);
4738 argbackq = argbackq->next;
4739 goto start;
4740#ifdef CONFIG_ASH_MATH_SUPPORT
4741 case CTLENDARI:
4742 p--;
4743 expari(quotes);
4744 goto start;
4745#endif
4746 }
4747 }
4748breakloop:
4749 ;
4750}
4751
4752static char *
4753exptilde(char *startp, char *p, int flag)
4754{
4755 char c;
4756 char *name;
4757 struct passwd *pw;
4758 const char *home;
4759 int quotes = flag & (EXP_FULL | EXP_CASE);
4760 int startloc;
4761
4762 name = p + 1;
4763
4764 while ((c = *++p) != '\0') {
4765 switch(c) {
4766 case CTLESC:
4767 return (startp);
4768 case CTLQUOTEMARK:
4769 return (startp);
4770 case ':':
4771 if (flag & EXP_VARTILDE)
4772 goto done;
4773 break;
4774 case '/':
4775 case CTLENDVAR:
4776 goto done;
4777 }
4778 }
4779done:
4780 *p = '\0';
4781 if (*name == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004782 home = lookupvar(homestr);
Eric Andersenc470f442003-07-28 09:56:35 +00004783 } else {
4784 if ((pw = getpwnam(name)) == NULL)
4785 goto lose;
4786 home = pw->pw_dir;
4787 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004788 if (!home || !*home)
Eric Andersenc470f442003-07-28 09:56:35 +00004789 goto lose;
4790 *p = c;
4791 startloc = expdest - (char *)stackblock();
4792 strtodest(home, SQSYNTAX, quotes);
4793 recordregion(startloc, expdest - (char *)stackblock(), 0);
4794 return (p);
4795lose:
4796 *p = c;
4797 return (startp);
4798}
4799
4800
4801static void
4802removerecordregions(int endoff)
4803{
4804 if (ifslastp == NULL)
4805 return;
4806
4807 if (ifsfirst.endoff > endoff) {
4808 while (ifsfirst.next != NULL) {
4809 struct ifsregion *ifsp;
4810 INTOFF;
4811 ifsp = ifsfirst.next->next;
4812 ckfree(ifsfirst.next);
4813 ifsfirst.next = ifsp;
4814 INTON;
4815 }
4816 if (ifsfirst.begoff > endoff)
4817 ifslastp = NULL;
4818 else {
4819 ifslastp = &ifsfirst;
4820 ifsfirst.endoff = endoff;
4821 }
4822 return;
4823 }
4824
4825 ifslastp = &ifsfirst;
4826 while (ifslastp->next && ifslastp->next->begoff < endoff)
4827 ifslastp=ifslastp->next;
4828 while (ifslastp->next != NULL) {
4829 struct ifsregion *ifsp;
4830 INTOFF;
4831 ifsp = ifslastp->next->next;
4832 ckfree(ifslastp->next);
4833 ifslastp->next = ifsp;
4834 INTON;
4835 }
4836 if (ifslastp->endoff > endoff)
4837 ifslastp->endoff = endoff;
4838}
4839
4840
4841#ifdef CONFIG_ASH_MATH_SUPPORT
4842/*
4843 * Expand arithmetic expression. Backup to start of expression,
4844 * evaluate, place result in (backed up) result, adjust string position.
4845 */
4846void
4847expari(int quotes)
4848{
4849 char *p, *start;
4850 int begoff;
4851 int flag;
4852 int len;
4853
4854 /* ifsfree(); */
4855
4856 /*
4857 * This routine is slightly over-complicated for
4858 * efficiency. Next we scan backwards looking for the
4859 * start of arithmetic.
4860 */
4861 start = stackblock();
4862 p = expdest - 1;
4863 *p = '\0';
4864 p--;
4865 do {
4866 int esc;
4867
4868 while (*p != CTLARI) {
4869 p--;
4870#ifdef DEBUG
4871 if (p < start) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004872 sh_error("missing CTLARI (shouldn't happen)");
Eric Andersenc470f442003-07-28 09:56:35 +00004873 }
4874#endif
4875 }
4876
4877 esc = esclen(start, p);
4878 if (!(esc % 2)) {
4879 break;
4880 }
4881
4882 p -= esc + 1;
4883 } while (1);
4884
4885 begoff = p - start;
4886
4887 removerecordregions(begoff);
4888
4889 flag = p[1];
4890
4891 expdest = p;
4892
4893 if (quotes)
4894 rmescapes(p + 2);
4895
4896 len = cvtnum(dash_arith(p + 2));
4897
4898 if (flag != '"')
4899 recordregion(begoff, begoff + len, 0);
4900}
4901#endif
4902
4903/*
4904 * Expand stuff in backwards quotes.
4905 */
4906
4907static void
4908expbackq(union node *cmd, int quoted, int quotes)
4909{
4910 struct backcmd in;
4911 int i;
4912 char buf[128];
4913 char *p;
4914 char *dest;
4915 int startloc;
4916 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4917 struct stackmark smark;
4918
4919 INTOFF;
4920 setstackmark(&smark);
4921 dest = expdest;
4922 startloc = dest - (char *)stackblock();
4923 grabstackstr(dest);
4924 evalbackcmd(cmd, (struct backcmd *) &in);
4925 popstackmark(&smark);
4926
4927 p = in.buf;
4928 i = in.nleft;
4929 if (i == 0)
4930 goto read;
4931 for (;;) {
4932 memtodest(p, i, syntax, quotes);
4933read:
4934 if (in.fd < 0)
4935 break;
4936 i = safe_read(in.fd, buf, sizeof buf);
4937 TRACE(("expbackq: read returns %d\n", i));
4938 if (i <= 0)
4939 break;
4940 p = buf;
4941 }
4942
4943 if (in.buf)
4944 ckfree(in.buf);
4945 if (in.fd >= 0) {
4946 close(in.fd);
4947 back_exitstatus = waitforjob(in.jp);
4948 }
4949 INTON;
4950
4951 /* Eat all trailing newlines */
4952 dest = expdest;
4953 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4954 STUNPUTC(dest);
4955 expdest = dest;
4956
4957 if (quoted == 0)
4958 recordregion(startloc, dest - (char *)stackblock(), 0);
4959 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4960 (dest - (char *)stackblock()) - startloc,
4961 (dest - (char *)stackblock()) - startloc,
4962 stackblock() + startloc));
4963}
4964
4965
4966static char *
Eric Andersen90898442003-08-06 11:20:52 +00004967scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4968 int zero)
4969{
Eric Andersenc470f442003-07-28 09:56:35 +00004970 char *loc;
4971 char *loc2;
4972 char c;
4973
4974 loc = startp;
4975 loc2 = rmesc;
4976 do {
4977 int match;
4978 const char *s = loc2;
4979 c = *loc2;
4980 if (zero) {
4981 *loc2 = '\0';
4982 s = rmesc;
4983 }
4984 match = pmatch(str, s);
4985 *loc2 = c;
4986 if (match)
4987 return loc;
4988 if (quotes && *loc == CTLESC)
4989 loc++;
4990 loc++;
4991 loc2++;
4992 } while (c);
4993 return 0;
4994}
4995
4996
4997static char *
Eric Andersen90898442003-08-06 11:20:52 +00004998scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4999 int zero)
5000{
Eric Andersenc470f442003-07-28 09:56:35 +00005001 int esc = 0;
5002 char *loc;
5003 char *loc2;
5004
5005 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5006 int match;
5007 char c = *loc2;
5008 const char *s = loc2;
5009 if (zero) {
5010 *loc2 = '\0';
5011 s = rmesc;
5012 }
5013 match = pmatch(str, s);
5014 *loc2 = c;
5015 if (match)
5016 return loc;
5017 loc--;
5018 if (quotes) {
5019 if (--esc < 0) {
5020 esc = esclen(startp, loc);
5021 }
5022 if (esc % 2) {
5023 esc--;
5024 loc--;
5025 }
5026 }
5027 }
5028 return 0;
5029}
5030
5031static const char *
5032subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5033{
5034 char *startp;
5035 char *loc;
5036 int saveherefd = herefd;
5037 struct nodelist *saveargbackq = argbackq;
5038 int amount;
5039 char *rmesc, *rmescend;
5040 int zero;
5041 char *(*scan)(char *, char *, char *, char *, int , int);
5042
5043 herefd = -1;
5044 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5045 STPUTC('\0', expdest);
5046 herefd = saveherefd;
5047 argbackq = saveargbackq;
5048 startp = stackblock() + startloc;
5049
5050 switch (subtype) {
5051 case VSASSIGN:
5052 setvar(str, startp, 0);
5053 amount = startp - expdest;
5054 STADJUST(amount, expdest);
5055 return startp;
5056
5057 case VSQUESTION:
5058 varunset(p, str, startp, varflags);
5059 /* NOTREACHED */
5060 }
5061
5062 subtype -= VSTRIMRIGHT;
5063#ifdef DEBUG
5064 if (subtype < 0 || subtype > 3)
5065 abort();
5066#endif
5067
5068 rmesc = startp;
5069 rmescend = stackblock() + strloc;
5070 if (quotes) {
5071 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5072 if (rmesc != startp) {
5073 rmescend = expdest;
5074 startp = stackblock() + startloc;
5075 }
5076 }
5077 rmescend--;
5078 str = stackblock() + strloc;
5079 preglob(str, varflags & VSQUOTE, 0);
5080
5081 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5082 zero = subtype >> 1;
5083 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5084 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5085
5086 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5087 if (loc) {
5088 if (zero) {
5089 memmove(startp, loc, str - loc);
5090 loc = startp + (str - loc) - 1;
5091 }
5092 *loc = '\0';
5093 amount = loc - expdest;
5094 STADJUST(amount, expdest);
5095 }
5096 return loc;
5097}
5098
5099
Eric Andersen62483552001-07-10 06:09:16 +00005100/*
5101 * Expand a variable, and return a pointer to the next character in the
5102 * input string.
5103 */
Eric Andersenc470f442003-07-28 09:56:35 +00005104static char *
5105evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005106{
5107 int subtype;
5108 int varflags;
5109 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005110 int patloc;
5111 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005112 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005113 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005114 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005115 int quotes;
5116 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005117
Eric Andersenc470f442003-07-28 09:56:35 +00005118 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005119 varflags = *p++;
5120 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005121 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005122 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005123 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005124 startloc = expdest - (char *)stackblock();
5125 p = strchr(p, '=') + 1;
5126
Eric Andersenc470f442003-07-28 09:56:35 +00005127again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005128 varlen = varvalue(var, varflags, flag);
5129 if (varflags & VSNUL)
5130 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005131
Glenn L McGrath76620622004-01-13 10:19:37 +00005132 if (subtype == VSPLUS) {
5133 varlen = -1 - varlen;
5134 goto vsplus;
5135 }
Eric Andersen62483552001-07-10 06:09:16 +00005136
Eric Andersenc470f442003-07-28 09:56:35 +00005137 if (subtype == VSMINUS) {
5138vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005139 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005140 argstr(
5141 p, flag | EXP_TILDE |
5142 (quoted ? EXP_QWORD : EXP_WORD)
5143 );
5144 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005145 }
5146 if (easy)
5147 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005148 goto end;
5149 }
Eric Andersen62483552001-07-10 06:09:16 +00005150
Eric Andersenc470f442003-07-28 09:56:35 +00005151 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005152 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005153 if (subevalvar(p, var, 0, subtype, startloc,
5154 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005155 varflags &= ~VSNUL;
5156 /*
5157 * Remove any recorded regions beyond
5158 * start of variable
5159 */
5160 removerecordregions(startloc);
5161 goto again;
5162 }
Eric Andersenc470f442003-07-28 09:56:35 +00005163 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005164 }
5165 if (easy)
5166 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005167 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005168 }
5169
Glenn L McGrath76620622004-01-13 10:19:37 +00005170 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005171 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005172
Eric Andersenc470f442003-07-28 09:56:35 +00005173 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005174 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005175 goto record;
5176 }
5177
5178 if (subtype == VSNORMAL) {
5179 if (!easy)
5180 goto end;
5181record:
5182 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5183 goto end;
5184 }
5185
5186#ifdef DEBUG
5187 switch (subtype) {
5188 case VSTRIMLEFT:
5189 case VSTRIMLEFTMAX:
5190 case VSTRIMRIGHT:
5191 case VSTRIMRIGHTMAX:
5192 break;
5193 default:
5194 abort();
5195 }
5196#endif
5197
Glenn L McGrath76620622004-01-13 10:19:37 +00005198 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005199 /*
5200 * Terminate the string and start recording the pattern
5201 * right after it
5202 */
5203 STPUTC('\0', expdest);
5204 patloc = expdest - (char *)stackblock();
5205 if (subevalvar(p, NULL, patloc, subtype,
5206 startloc, varflags, quotes) == 0) {
5207 int amount = expdest - (
5208 (char *)stackblock() + patloc - 1
5209 );
5210 STADJUST(-amount, expdest);
5211 }
5212 /* Remove any recorded regions beyond start of variable */
5213 removerecordregions(startloc);
5214 goto record;
5215 }
5216
5217end:
5218 if (subtype != VSNORMAL) { /* skip to end of alternative */
5219 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005220 for (;;) {
5221 if ((c = *p++) == CTLESC)
5222 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005223 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005224 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005225 argbackq = argbackq->next;
5226 } else if (c == CTLVAR) {
5227 if ((*p++ & VSTYPE) != VSNORMAL)
5228 nesting++;
5229 } else if (c == CTLENDVAR) {
5230 if (--nesting == 0)
5231 break;
5232 }
5233 }
5234 }
5235 return p;
5236}
5237
Eric Andersencb57d552001-06-28 07:25:16 +00005238
Eric Andersencb57d552001-06-28 07:25:16 +00005239/*
5240 * Put a string on the stack.
5241 */
5242
Eric Andersenc470f442003-07-28 09:56:35 +00005243static void
5244memtodest(const char *p, size_t len, int syntax, int quotes) {
5245 char *q = expdest;
5246
5247 q = makestrspace(len * 2, q);
5248
5249 while (len--) {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005250 int c = SC2INT(*p++);
Eric Andersenc470f442003-07-28 09:56:35 +00005251 if (!c)
5252 continue;
5253 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5254 USTPUTC(CTLESC, q);
5255 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005256 }
Eric Andersenc470f442003-07-28 09:56:35 +00005257
5258 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005259}
5260
Eric Andersenc470f442003-07-28 09:56:35 +00005261
5262static void
5263strtodest(const char *p, int syntax, int quotes)
5264{
5265 memtodest(p, strlen(p), syntax, quotes);
5266}
5267
5268
Eric Andersencb57d552001-06-28 07:25:16 +00005269/*
5270 * Add the value of a specialized variable to the stack string.
5271 */
5272
Glenn L McGrath76620622004-01-13 10:19:37 +00005273static ssize_t
5274varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005275{
5276 int num;
5277 char *p;
5278 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005279 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005280 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005281 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005282 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005283 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005284 int quoted = varflags & VSQUOTE;
5285 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005286 int quotes = flags & (EXP_FULL | EXP_CASE);
5287
Glenn L McGrath76620622004-01-13 10:19:37 +00005288 if (quoted && (flags & EXP_FULL))
5289 sep = 1 << CHAR_BIT;
5290
Eric Andersencb57d552001-06-28 07:25:16 +00005291 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5292 switch (*name) {
5293 case '$':
5294 num = rootpid;
5295 goto numvar;
5296 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005297 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005298 goto numvar;
5299 case '#':
5300 num = shellparam.nparam;
5301 goto numvar;
5302 case '!':
5303 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005304 if (num == 0)
5305 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005306numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005307 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005308 break;
5309 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005310 p = makestrspace(NOPTS, expdest);
5311 for (i = NOPTS - 1; i >= 0; i--) {
5312 if (optlist[i]) {
5313 USTPUTC(optletters(i), p);
5314 len++;
5315 }
Eric Andersencb57d552001-06-28 07:25:16 +00005316 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005317 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005318 break;
5319 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005320 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005321 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005322 /* fall through */
5323 case '*':
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005324 sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005325 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5326 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005327param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005328 if (!(ap = shellparam.p))
5329 return -1;
5330 while ((p = *ap++)) {
5331 size_t partlen;
5332
5333 partlen = strlen(p);
Glenn L McGrath76620622004-01-13 10:19:37 +00005334 len += partlen;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00005335
5336 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5337 memtodest(p, partlen, syntax, quotes);
5338
5339 if (*ap && sep) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005340 char *q;
5341
5342 len++;
5343 if (subtype == VSPLUS || subtype == VSLENGTH) {
5344 continue;
5345 }
5346 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005347 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005348 STPUTC(CTLESC, q);
5349 STPUTC(sep, q);
5350 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005351 }
5352 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005353 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005354 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005355 case '1':
5356 case '2':
5357 case '3':
5358 case '4':
5359 case '5':
5360 case '6':
5361 case '7':
5362 case '8':
5363 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005364 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005365 if (num < 0 || num > shellparam.nparam)
5366 return -1;
5367 p = num ? shellparam.p[num - 1] : arg0;
5368 goto value;
5369 default:
5370 p = lookupvar(name);
5371value:
5372 if (!p)
5373 return -1;
5374
5375 len = strlen(p);
5376 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5377 memtodest(p, len, syntax, quotes);
5378 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005379 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005380
5381 if (subtype == VSPLUS || subtype == VSLENGTH)
5382 STADJUST(-len, expdest);
5383 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005384}
5385
5386
Eric Andersencb57d552001-06-28 07:25:16 +00005387/*
5388 * Record the fact that we have to scan this region of the
5389 * string for IFS characters.
5390 */
5391
Eric Andersenc470f442003-07-28 09:56:35 +00005392static void
5393recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005394{
5395 struct ifsregion *ifsp;
5396
5397 if (ifslastp == NULL) {
5398 ifsp = &ifsfirst;
5399 } else {
5400 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005401 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005402 ifsp->next = NULL;
5403 ifslastp->next = ifsp;
5404 INTON;
5405 }
5406 ifslastp = ifsp;
5407 ifslastp->begoff = start;
5408 ifslastp->endoff = end;
5409 ifslastp->nulonly = nulonly;
5410}
5411
5412
Eric Andersencb57d552001-06-28 07:25:16 +00005413/*
5414 * Break the argument string into pieces based upon IFS and add the
5415 * strings to the argument list. The regions of the string to be
5416 * searched for IFS characters have been stored by recordregion.
5417 */
Eric Andersenc470f442003-07-28 09:56:35 +00005418static void
5419ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005420{
Eric Andersencb57d552001-06-28 07:25:16 +00005421 struct ifsregion *ifsp;
5422 struct strlist *sp;
5423 char *start;
5424 char *p;
5425 char *q;
5426 const char *ifs, *realifs;
5427 int ifsspc;
5428 int nulonly;
5429
5430
5431 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005432 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005433 ifsspc = 0;
5434 nulonly = 0;
5435 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005436 ifsp = &ifsfirst;
5437 do {
5438 p = string + ifsp->begoff;
5439 nulonly = ifsp->nulonly;
5440 ifs = nulonly ? nullstr : realifs;
5441 ifsspc = 0;
5442 while (p < string + ifsp->endoff) {
5443 q = p;
5444 if (*p == CTLESC)
5445 p++;
5446 if (strchr(ifs, *p)) {
5447 if (!nulonly)
5448 ifsspc = (strchr(defifs, *p) != NULL);
5449 /* Ignore IFS whitespace at start */
5450 if (q == start && ifsspc) {
5451 p++;
5452 start = p;
5453 continue;
5454 }
5455 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005456 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005457 sp->text = start;
5458 *arglist->lastp = sp;
5459 arglist->lastp = &sp->next;
5460 p++;
5461 if (!nulonly) {
5462 for (;;) {
5463 if (p >= string + ifsp->endoff) {
5464 break;
5465 }
5466 q = p;
5467 if (*p == CTLESC)
5468 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005469 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005470 p = q;
5471 break;
5472 } else if (strchr(defifs, *p) == NULL) {
5473 if (ifsspc) {
5474 p++;
5475 ifsspc = 0;
5476 } else {
5477 p = q;
5478 break;
5479 }
5480 } else
5481 p++;
5482 }
5483 }
5484 start = p;
5485 } else
5486 p++;
5487 }
5488 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005489 if (nulonly)
5490 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005491 }
5492
Eric Andersenc470f442003-07-28 09:56:35 +00005493 if (!*start)
5494 return;
5495
5496add:
5497 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005498 sp->text = start;
5499 *arglist->lastp = sp;
5500 arglist->lastp = &sp->next;
5501}
5502
Eric Andersenc470f442003-07-28 09:56:35 +00005503static void
5504ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005505{
Eric Andersenc470f442003-07-28 09:56:35 +00005506 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005507
Eric Andersenc470f442003-07-28 09:56:35 +00005508 INTOFF;
5509 p = ifsfirst.next;
5510 do {
5511 struct ifsregion *ifsp;
5512 ifsp = p->next;
5513 ckfree(p);
5514 p = ifsp;
5515 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005516 ifslastp = NULL;
5517 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005518 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005519}
5520
Eric Andersen90898442003-08-06 11:20:52 +00005521static void expmeta(char *, char *);
5522static struct strlist *expsort(struct strlist *);
5523static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005524
Eric Andersen90898442003-08-06 11:20:52 +00005525static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005526
Eric Andersencb57d552001-06-28 07:25:16 +00005527
Eric Andersenc470f442003-07-28 09:56:35 +00005528static void
Eric Andersen90898442003-08-06 11:20:52 +00005529expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005530{
Eric Andersen90898442003-08-06 11:20:52 +00005531 static const char metachars[] = {
5532 '*', '?', '[', 0
5533 };
Eric Andersencb57d552001-06-28 07:25:16 +00005534 /* TODO - EXP_REDIR */
5535
5536 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005537 struct strlist **savelastp;
5538 struct strlist *sp;
5539 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005540
Eric Andersencb57d552001-06-28 07:25:16 +00005541 if (fflag)
5542 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005543 if (!strpbrk(str->text, metachars))
5544 goto nometa;
5545 savelastp = exparg.lastp;
5546
Eric Andersencb57d552001-06-28 07:25:16 +00005547 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005548 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005549 {
5550 int i = strlen(str->text);
5551 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5552 }
5553
5554 expmeta(expdir, p);
5555 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005556 if (p != str->text)
5557 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005558 INTON;
5559 if (exparg.lastp == savelastp) {
5560 /*
5561 * no matches
5562 */
Eric Andersenc470f442003-07-28 09:56:35 +00005563nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005564 *exparg.lastp = str;
5565 rmescapes(str->text);
5566 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005567 } else {
5568 *exparg.lastp = NULL;
5569 *savelastp = sp = expsort(*savelastp);
5570 while (sp->next != NULL)
5571 sp = sp->next;
5572 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005573 }
5574 str = str->next;
5575 }
5576}
5577
Eric Andersencb57d552001-06-28 07:25:16 +00005578/*
Eric Andersenc470f442003-07-28 09:56:35 +00005579 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005580 */
5581
Eric Andersenc470f442003-07-28 09:56:35 +00005582static void
Eric Andersen90898442003-08-06 11:20:52 +00005583addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005584{
Eric Andersencb57d552001-06-28 07:25:16 +00005585 struct strlist *sp;
5586
Eric Andersenc470f442003-07-28 09:56:35 +00005587 sp = (struct strlist *)stalloc(sizeof *sp);
5588 sp->text = sstrdup(name);
5589 *exparg.lastp = sp;
5590 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005591}
5592
5593
Eric Andersencb57d552001-06-28 07:25:16 +00005594/*
Eric Andersen90898442003-08-06 11:20:52 +00005595 * Do metacharacter (i.e. *, ?, [...]) expansion.
5596 */
5597
5598static void
5599expmeta(char *enddir, char *name)
5600{
5601 char *p;
5602 const char *cp;
5603 char *start;
5604 char *endname;
5605 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005606 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005607 DIR *dirp;
5608 struct dirent *dp;
5609 int atend;
5610 int matchdot;
5611
5612 metaflag = 0;
5613 start = name;
5614 for (p = name; *p; p++) {
5615 if (*p == '*' || *p == '?')
5616 metaflag = 1;
5617 else if (*p == '[') {
5618 char *q = p + 1;
5619 if (*q == '!')
5620 q++;
5621 for (;;) {
5622 if (*q == '\\')
5623 q++;
5624 if (*q == '/' || *q == '\0')
5625 break;
5626 if (*++q == ']') {
5627 metaflag = 1;
5628 break;
5629 }
5630 }
5631 } else if (*p == '\\')
5632 p++;
5633 else if (*p == '/') {
5634 if (metaflag)
5635 goto out;
5636 start = p + 1;
5637 }
5638 }
5639out:
5640 if (metaflag == 0) { /* we've reached the end of the file name */
5641 if (enddir != expdir)
5642 metaflag++;
5643 p = name;
5644 do {
5645 if (*p == '\\')
5646 p++;
5647 *enddir++ = *p;
5648 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005649 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005650 addfname(expdir);
5651 return;
5652 }
5653 endname = p;
5654 if (name < start) {
5655 p = name;
5656 do {
5657 if (*p == '\\')
5658 p++;
5659 *enddir++ = *p++;
5660 } while (p < start);
5661 }
5662 if (enddir == expdir) {
5663 cp = ".";
5664 } else if (enddir == expdir + 1 && *expdir == '/') {
5665 cp = "/";
5666 } else {
5667 cp = expdir;
5668 enddir[-1] = '\0';
5669 }
5670 if ((dirp = opendir(cp)) == NULL)
5671 return;
5672 if (enddir != expdir)
5673 enddir[-1] = '/';
5674 if (*endname == 0) {
5675 atend = 1;
5676 } else {
5677 atend = 0;
5678 *endname++ = '\0';
5679 }
5680 matchdot = 0;
5681 p = start;
5682 if (*p == '\\')
5683 p++;
5684 if (*p == '.')
5685 matchdot++;
5686 while (! intpending && (dp = readdir(dirp)) != NULL) {
5687 if (dp->d_name[0] == '.' && ! matchdot)
5688 continue;
5689 if (pmatch(start, dp->d_name)) {
5690 if (atend) {
5691 scopy(dp->d_name, enddir);
5692 addfname(expdir);
5693 } else {
5694 for (p = enddir, cp = dp->d_name;
5695 (*p++ = *cp++) != '\0';)
5696 continue;
5697 p[-1] = '/';
5698 expmeta(p, endname);
5699 }
5700 }
5701 }
5702 closedir(dirp);
5703 if (! atend)
5704 endname[-1] = '/';
5705}
5706
5707/*
5708 * Sort the results of file name expansion. It calculates the number of
5709 * strings to sort and then calls msort (short for merge sort) to do the
5710 * work.
5711 */
5712
5713static struct strlist *
5714expsort(struct strlist *str)
5715{
5716 int len;
5717 struct strlist *sp;
5718
5719 len = 0;
5720 for (sp = str ; sp ; sp = sp->next)
5721 len++;
5722 return msort(str, len);
5723}
5724
5725
5726static struct strlist *
5727msort(struct strlist *list, int len)
5728{
5729 struct strlist *p, *q = NULL;
5730 struct strlist **lpp;
5731 int half;
5732 int n;
5733
5734 if (len <= 1)
5735 return list;
5736 half = len >> 1;
5737 p = list;
5738 for (n = half ; --n >= 0 ; ) {
5739 q = p;
5740 p = p->next;
5741 }
5742 q->next = NULL; /* terminate first half of list */
5743 q = msort(list, half); /* sort first half of list */
5744 p = msort(p, len - half); /* sort second half */
5745 lpp = &list;
5746 for (;;) {
5747#ifdef CONFIG_LOCALE_SUPPORT
5748 if (strcoll(p->text, q->text) < 0)
5749#else
5750 if (strcmp(p->text, q->text) < 0)
5751#endif
5752 {
5753 *lpp = p;
5754 lpp = &p->next;
5755 if ((p = *lpp) == NULL) {
5756 *lpp = q;
5757 break;
5758 }
5759 } else {
5760 *lpp = q;
5761 lpp = &q->next;
5762 if ((q = *lpp) == NULL) {
5763 *lpp = p;
5764 break;
5765 }
5766 }
5767 }
5768 return list;
5769}
5770
5771
5772/*
Eric Andersencb57d552001-06-28 07:25:16 +00005773 * Returns true if the pattern matches the string.
5774 */
5775
Eric Andersenc470f442003-07-28 09:56:35 +00005776static inline int
5777patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005778{
Eric Andersenc470f442003-07-28 09:56:35 +00005779 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005780}
5781
5782
Eric Andersencb57d552001-06-28 07:25:16 +00005783/*
5784 * Remove any CTLESC characters from a string.
5785 */
5786
Eric Andersenc470f442003-07-28 09:56:35 +00005787static char *
5788_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005789{
5790 char *p, *q, *r;
5791 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005792 unsigned inquotes;
5793 int notescaped;
5794 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005795
5796 p = strpbrk(str, qchars);
5797 if (!p) {
5798 return str;
5799 }
5800 q = p;
5801 r = str;
5802 if (flag & RMESCAPE_ALLOC) {
5803 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005804 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005805
Eric Andersenc470f442003-07-28 09:56:35 +00005806 if (flag & RMESCAPE_GROW) {
5807 r = makestrspace(fulllen, expdest);
5808 } else if (flag & RMESCAPE_HEAP) {
5809 r = ckmalloc(fulllen);
5810 } else {
5811 r = stalloc(fulllen);
5812 }
5813 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005814 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005815 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005816 }
5817 }
Eric Andersenc470f442003-07-28 09:56:35 +00005818 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5819 globbing = flag & RMESCAPE_GLOB;
5820 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005821 while (*p) {
5822 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005823 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005824 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005825 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005826 continue;
5827 }
Eric Andersenc470f442003-07-28 09:56:35 +00005828 if (*p == '\\') {
5829 /* naked back slash */
5830 notescaped = 0;
5831 goto copy;
5832 }
Eric Andersencb57d552001-06-28 07:25:16 +00005833 if (*p == CTLESC) {
5834 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005835 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005836 *q++ = '\\';
5837 }
5838 }
Eric Andersenc470f442003-07-28 09:56:35 +00005839 notescaped = globbing;
5840copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005841 *q++ = *p++;
5842 }
5843 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005844 if (flag & RMESCAPE_GROW) {
5845 expdest = r;
5846 STADJUST(q - r + 1, expdest);
5847 }
Eric Andersencb57d552001-06-28 07:25:16 +00005848 return r;
5849}
Eric Andersencb57d552001-06-28 07:25:16 +00005850
5851
Eric Andersencb57d552001-06-28 07:25:16 +00005852/*
5853 * See if a pattern matches in a case statement.
5854 */
5855
Eric Andersenc470f442003-07-28 09:56:35 +00005856int
5857casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005858{
Eric Andersencb57d552001-06-28 07:25:16 +00005859 struct stackmark smark;
5860 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005861
5862 setstackmark(&smark);
5863 argbackq = pattern->narg.backquote;
5864 STARTSTACKSTR(expdest);
5865 ifslastp = NULL;
5866 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005867 STACKSTRNUL(expdest);
5868 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005869 popstackmark(&smark);
5870 return result;
5871}
5872
5873/*
5874 * Our own itoa().
5875 */
5876
Eric Andersenc470f442003-07-28 09:56:35 +00005877static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005878cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005879{
Eric Andersencb57d552001-06-28 07:25:16 +00005880 int len;
5881
Eric Andersenc470f442003-07-28 09:56:35 +00005882 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005883#ifdef CONFIG_ASH_MATH_SUPPORT_64
5884 len = fmtstr(expdest, 32, "%lld", (long long) num);
5885#else
Eric Andersenc470f442003-07-28 09:56:35 +00005886 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005887#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005888 STADJUST(len, expdest);
5889 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005890}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005891
Eric Andersenc470f442003-07-28 09:56:35 +00005892static void
5893varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005894{
Eric Andersenc470f442003-07-28 09:56:35 +00005895 const char *msg;
5896 const char *tail;
5897
5898 tail = nullstr;
5899 msg = "parameter not set";
5900 if (umsg) {
5901 if (*end == CTLENDVAR) {
5902 if (varflags & VSNUL)
5903 tail = " or null";
5904 } else
5905 msg = umsg;
5906 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005907 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005908}
Eric Andersen90898442003-08-06 11:20:52 +00005909
5910
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005911/* input.c */
Eric Andersencb57d552001-06-28 07:25:16 +00005912
Eric Andersencb57d552001-06-28 07:25:16 +00005913/*
Eric Andersen90898442003-08-06 11:20:52 +00005914 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005915 */
5916
Eric Andersenc470f442003-07-28 09:56:35 +00005917#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005918
Eric Andersenc470f442003-07-28 09:56:35 +00005919static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005920
Eric Andersencb57d552001-06-28 07:25:16 +00005921/*
Eric Andersenc470f442003-07-28 09:56:35 +00005922 * Read a character from the script, returning PEOF on end of file.
5923 * Nul characters in the input are silently discarded.
5924 */
5925
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005926
5927#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
Eric Andersenc470f442003-07-28 09:56:35 +00005928
5929#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5930#define pgetc_macro() pgetc()
5931static int
5932pgetc(void)
5933{
5934 return pgetc_as_macro();
5935}
5936#else
5937#define pgetc_macro() pgetc_as_macro()
5938static int
5939pgetc(void)
5940{
5941 return pgetc_macro();
5942}
5943#endif
5944
5945
5946/*
5947 * Same as pgetc(), but ignores PEOA.
5948 */
5949#ifdef CONFIG_ASH_ALIAS
5950static int pgetc2(void)
5951{
5952 int c;
5953
5954 do {
5955 c = pgetc_macro();
5956 } while (c == PEOA);
5957 return c;
5958}
5959#else
5960static inline int pgetc2(void)
5961{
5962 return pgetc_macro();
5963}
5964#endif
5965
Glenn L McGrath28939ad2004-07-21 10:20:19 +00005966/*
5967 * Read a line from the script.
5968 */
5969
5970static inline char *
5971pfgets(char *line, int len)
5972{
5973 char *p = line;
5974 int nleft = len;
5975 int c;
5976
5977 while (--nleft > 0) {
5978 c = pgetc2();
5979 if (c == PEOF) {
5980 if (p == line)
5981 return NULL;
5982 break;
5983 }
5984 *p++ = c;
5985 if (c == '\n')
5986 break;
5987 }
5988 *p = '\0';
5989 return line;
5990}
5991
5992
Eric Andersenc470f442003-07-28 09:56:35 +00005993
5994#ifdef CONFIG_FEATURE_COMMAND_EDITING
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00005995#ifdef CONFIG_ASH_EXPAND_PRMT
5996static char *cmdedit_prompt;
5997#else
Eric Andersenc470f442003-07-28 09:56:35 +00005998static const char *cmdedit_prompt;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00005999#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006000static inline void putprompt(const char *s)
6001{
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006002#ifdef CONFIG_ASH_EXPAND_PRMT
6003 free(cmdedit_prompt);
6004 cmdedit_prompt = bb_xstrdup(s);
6005#else
Eric Andersenc470f442003-07-28 09:56:35 +00006006 cmdedit_prompt = s;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006007#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006008}
6009#else
6010static inline void putprompt(const char *s)
6011{
6012 out2str(s);
6013}
6014#endif
6015
6016static inline int
6017preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006018{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006019 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006020 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006021 parsenextc = buf;
6022
Eric Andersenc470f442003-07-28 09:56:35 +00006023retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006024#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006025 if (!iflag || parsefile->fd)
6026 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6027 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006028#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006029 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006030#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006031 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6032 if(nr == 0) {
6033 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006034 if(trap[SIGINT]) {
6035 buf[0] = '\n';
6036 buf[1] = 0;
6037 raise(SIGINT);
6038 return 1;
6039 }
Eric Andersenc470f442003-07-28 09:56:35 +00006040 goto retry;
6041 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006042 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006043 /* Ctrl+D presend */
6044 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006045 }
Eric Andersencb57d552001-06-28 07:25:16 +00006046 }
6047#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006048 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006049#endif
6050
6051 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006052 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6053 int flags = fcntl(0, F_GETFL, 0);
6054 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006055 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006056 if (fcntl(0, F_SETFL, flags) >= 0) {
6057 out2str("sh: turning off NDELAY mode\n");
6058 goto retry;
6059 }
6060 }
6061 }
6062 }
6063 return nr;
6064}
6065
6066/*
6067 * Refill the input buffer and return the next input character:
6068 *
6069 * 1) If a string was pushed back on the input, pop it;
6070 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6071 * from a string so we can't refill the buffer, return EOF.
6072 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6073 * 4) Process input up to the next newline, deleting nul characters.
6074 */
6075
Eric Andersenc470f442003-07-28 09:56:35 +00006076int
6077preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006078{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006079 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00006080 int more;
6081 char savec;
6082
6083 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006084#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006085 if (parsenleft == -1 && parsefile->strpush->ap &&
6086 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006087 return PEOA;
6088 }
Eric Andersen2870d962001-07-02 17:27:21 +00006089#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006090 popstring();
6091 if (--parsenleft >= 0)
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006092 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006093 }
6094 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6095 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006096 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006097
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006098 more = parselleft;
6099 if (more <= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006100again:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006101 if ((more = preadfd()) <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006102 parselleft = parsenleft = EOF_NLEFT;
6103 return PEOF;
6104 }
6105 }
6106
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006107 q = parsenextc;
Eric Andersencb57d552001-06-28 07:25:16 +00006108
6109 /* delete nul characters */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006110 for (;;) {
6111 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00006112
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006113 more--;
6114 c = *q;
Eric Andersenc470f442003-07-28 09:56:35 +00006115
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006116 if (!c)
6117 memmove(q, q + 1, more);
6118 else {
6119 q++;
6120 if (c == '\n') {
6121 parsenleft = q - parsenextc - 1;
6122 break;
6123 }
Eric Andersencb57d552001-06-28 07:25:16 +00006124 }
6125
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006126 if (more <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006127 parsenleft = q - parsenextc - 1;
6128 if (parsenleft < 0)
6129 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006130 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006131 }
6132 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006133 parselleft = more;
Eric Andersencb57d552001-06-28 07:25:16 +00006134
6135 savec = *q;
6136 *q = '\0';
6137
6138 if (vflag) {
6139 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006140 }
6141
6142 *q = savec;
6143
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006144 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006145}
6146
Eric Andersenc470f442003-07-28 09:56:35 +00006147/*
6148 * Undo the last call to pgetc. Only one character may be pushed back.
6149 * PEOF may be pushed back.
6150 */
6151
6152void
6153pungetc(void)
6154{
6155 parsenleft++;
6156 parsenextc--;
6157}
Eric Andersencb57d552001-06-28 07:25:16 +00006158
6159/*
6160 * Push a string back onto the input at this current parsefile level.
6161 * We handle aliases this way.
6162 */
Eric Andersenc470f442003-07-28 09:56:35 +00006163void
6164pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006165{
Eric Andersencb57d552001-06-28 07:25:16 +00006166 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006167 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006168
Eric Andersenc470f442003-07-28 09:56:35 +00006169 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006170 INTOFF;
6171/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6172 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006173 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006174 sp->prev = parsefile->strpush;
6175 parsefile->strpush = sp;
6176 } else
6177 sp = parsefile->strpush = &(parsefile->basestrpush);
6178 sp->prevstring = parsenextc;
6179 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006180#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006181 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006182 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006183 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006184 sp->string = s;
6185 }
Eric Andersen2870d962001-07-02 17:27:21 +00006186#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006187 parsenextc = s;
6188 parsenleft = len;
6189 INTON;
6190}
6191
Eric Andersenc470f442003-07-28 09:56:35 +00006192void
6193popstring(void)
6194{
6195 struct strpush *sp = parsefile->strpush;
6196
6197 INTOFF;
6198#ifdef CONFIG_ASH_ALIAS
6199 if (sp->ap) {
6200 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6201 checkkwd |= CHKALIAS;
6202 }
6203 if (sp->string != sp->ap->val) {
6204 ckfree(sp->string);
6205 }
6206 sp->ap->flag &= ~ALIASINUSE;
6207 if (sp->ap->flag & ALIASDEAD) {
6208 unalias(sp->ap->name);
6209 }
6210 }
6211#endif
6212 parsenextc = sp->prevstring;
6213 parsenleft = sp->prevnleft;
6214/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6215 parsefile->strpush = sp->prev;
6216 if (sp != &(parsefile->basestrpush))
6217 ckfree(sp);
6218 INTON;
6219}
6220
6221/*
6222 * Set the input to take input from a file. If push is set, push the
6223 * old input onto the stack first.
6224 */
6225
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006226static int
6227setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00006228{
6229 int fd;
6230 int fd2;
6231
6232 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006233 if ((fd = open(fname, O_RDONLY)) < 0) {
6234 if (flags & INPUT_NOFILE_OK)
6235 goto out;
6236 sh_error("Can't open %s", fname);
6237 }
Eric Andersenc470f442003-07-28 09:56:35 +00006238 if (fd < 10) {
6239 fd2 = copyfd(fd, 10);
6240 close(fd);
6241 if (fd2 < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006242 sh_error("Out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +00006243 fd = fd2;
6244 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006245 setinputfd(fd, flags & INPUT_PUSH_FILE);
6246out:
Eric Andersenc470f442003-07-28 09:56:35 +00006247 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006248 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +00006249}
6250
6251
6252/*
6253 * Like setinputfile, but takes an open file descriptor. Call this with
6254 * interrupts off.
6255 */
6256
6257static void
6258setinputfd(int fd, int push)
6259{
6260 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6261 if (push) {
6262 pushfile();
6263 parsefile->buf = 0;
6264 }
6265 parsefile->fd = fd;
6266 if (parsefile->buf == NULL)
6267 parsefile->buf = ckmalloc(IBUFSIZ);
6268 parselleft = parsenleft = 0;
6269 plinno = 1;
6270}
6271
Eric Andersencb57d552001-06-28 07:25:16 +00006272
Eric Andersencb57d552001-06-28 07:25:16 +00006273/*
6274 * Like setinputfile, but takes input from a string.
6275 */
6276
Eric Andersenc470f442003-07-28 09:56:35 +00006277static void
6278setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006279{
Eric Andersencb57d552001-06-28 07:25:16 +00006280 INTOFF;
6281 pushfile();
6282 parsenextc = string;
6283 parsenleft = strlen(string);
6284 parsefile->buf = NULL;
6285 plinno = 1;
6286 INTON;
6287}
6288
6289
Eric Andersencb57d552001-06-28 07:25:16 +00006290/*
6291 * To handle the "." command, a stack of input files is used. Pushfile
6292 * adds a new entry to the stack and popfile restores the previous level.
6293 */
6294
Eric Andersenc470f442003-07-28 09:56:35 +00006295static void
6296pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006297{
Eric Andersencb57d552001-06-28 07:25:16 +00006298 struct parsefile *pf;
6299
6300 parsefile->nleft = parsenleft;
6301 parsefile->lleft = parselleft;
6302 parsefile->nextc = parsenextc;
6303 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006304 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006305 pf->prev = parsefile;
6306 pf->fd = -1;
6307 pf->strpush = NULL;
6308 pf->basestrpush.prev = NULL;
6309 parsefile = pf;
6310}
6311
Eric Andersenc470f442003-07-28 09:56:35 +00006312
6313static void
6314popfile(void)
6315{
6316 struct parsefile *pf = parsefile;
6317
6318 INTOFF;
6319 if (pf->fd >= 0)
6320 close(pf->fd);
6321 if (pf->buf)
6322 ckfree(pf->buf);
6323 while (pf->strpush)
6324 popstring();
6325 parsefile = pf->prev;
6326 ckfree(pf);
6327 parsenleft = parsefile->nleft;
6328 parselleft = parsefile->lleft;
6329 parsenextc = parsefile->nextc;
6330 plinno = parsefile->linno;
6331 INTON;
6332}
Eric Andersencb57d552001-06-28 07:25:16 +00006333
6334
Eric Andersen2870d962001-07-02 17:27:21 +00006335/*
Eric Andersenc470f442003-07-28 09:56:35 +00006336 * Return to top level.
6337 */
Eric Andersen2870d962001-07-02 17:27:21 +00006338
Eric Andersenc470f442003-07-28 09:56:35 +00006339static void
6340popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006341{
Eric Andersenc470f442003-07-28 09:56:35 +00006342 while (parsefile != &basepf)
6343 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006344}
6345
Eric Andersen2870d962001-07-02 17:27:21 +00006346
Eric Andersenc470f442003-07-28 09:56:35 +00006347/*
6348 * Close the file(s) that the shell is reading commands from. Called
6349 * after a fork is done.
6350 */
6351
6352static void
6353closescript(void)
6354{
6355 popallfiles();
6356 if (parsefile->fd > 0) {
6357 close(parsefile->fd);
6358 parsefile->fd = 0;
6359 }
6360}
Eric Andersenc470f442003-07-28 09:56:35 +00006361
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006362/* jobs.c */
Eric Andersenc470f442003-07-28 09:56:35 +00006363
6364/* mode flags for set_curjob */
6365#define CUR_DELETE 2
6366#define CUR_RUNNING 1
6367#define CUR_STOPPED 0
6368
6369/* mode flags for dowait */
6370#define DOWAIT_NORMAL 0
6371#define DOWAIT_BLOCK 1
6372
6373/* array of jobs */
6374static struct job *jobtab;
6375/* size of array */
6376static unsigned njobs;
6377#if JOBS
6378/* pgrp of shell on invocation */
6379static int initialpgrp;
6380static int ttyfd = -1;
6381#endif
6382/* current job */
6383static struct job *curjob;
6384/* number of presumed living untracked jobs */
6385static int jobless;
6386
6387static void set_curjob(struct job *, unsigned);
6388#if JOBS
6389static int restartjob(struct job *, int);
6390static void xtcsetpgrp(int, pid_t);
6391static char *commandtext(union node *);
6392static void cmdlist(union node *, int);
6393static void cmdtxt(union node *);
6394static void cmdputs(const char *);
6395static void showpipe(struct job *, FILE *);
6396#endif
6397static int sprint_status(char *, int, int);
6398static void freejob(struct job *);
6399static struct job *getjob(const char *, int);
6400static struct job *growjobtab(void);
6401static void forkchild(struct job *, union node *, int);
6402static void forkparent(struct job *, union node *, int, pid_t);
6403static int dowait(int, struct job *);
6404static int getstatus(struct job *);
6405
6406static void
6407set_curjob(struct job *jp, unsigned mode)
6408{
6409 struct job *jp1;
6410 struct job **jpp, **curp;
6411
6412 /* first remove from list */
6413 jpp = curp = &curjob;
6414 do {
6415 jp1 = *jpp;
6416 if (jp1 == jp)
6417 break;
6418 jpp = &jp1->prev_job;
6419 } while (1);
6420 *jpp = jp1->prev_job;
6421
6422 /* Then re-insert in correct position */
6423 jpp = curp;
6424 switch (mode) {
6425 default:
6426#ifdef DEBUG
6427 abort();
6428#endif
6429 case CUR_DELETE:
6430 /* job being deleted */
6431 break;
6432 case CUR_RUNNING:
6433 /* newly created job or backgrounded job,
6434 put after all stopped jobs. */
6435 do {
6436 jp1 = *jpp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006437#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006438 if (!jp1 || jp1->state != JOBSTOPPED)
6439#endif
6440 break;
6441 jpp = &jp1->prev_job;
6442 } while (1);
6443 /* FALLTHROUGH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006444#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006445 case CUR_STOPPED:
6446#endif
6447 /* newly stopped job - becomes curjob */
6448 jp->prev_job = *jpp;
6449 *jpp = jp;
6450 break;
6451 }
6452}
6453
6454#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006455/*
6456 * Turn job control on and off.
6457 *
6458 * Note: This code assumes that the third arg to ioctl is a character
6459 * pointer, which is true on Berkeley systems but not System V. Since
6460 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006461 *
6462 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006463 */
6464
Eric Andersenc470f442003-07-28 09:56:35 +00006465void
6466setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006467{
Eric Andersenc470f442003-07-28 09:56:35 +00006468 int fd;
6469 int pgrp;
6470
6471 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006472 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006473 if (on) {
6474 int ofd;
6475 ofd = fd = open(_PATH_TTY, O_RDWR);
6476 if (fd < 0) {
6477 fd += 3;
6478 while (!isatty(fd) && --fd >= 0)
6479 ;
6480 }
6481 fd = fcntl(fd, F_DUPFD, 10);
6482 close(ofd);
6483 if (fd < 0)
6484 goto out;
6485 fcntl(fd, F_SETFD, FD_CLOEXEC);
6486 do { /* while we are in the background */
6487 if ((pgrp = tcgetpgrp(fd)) < 0) {
6488out:
6489 sh_warnx("can't access tty; job control turned off");
6490 mflag = on = 0;
6491 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006492 }
Eric Andersenc470f442003-07-28 09:56:35 +00006493 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006494 break;
6495 killpg(0, SIGTTIN);
6496 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006497 initialpgrp = pgrp;
6498
Eric Andersencb57d552001-06-28 07:25:16 +00006499 setsignal(SIGTSTP);
6500 setsignal(SIGTTOU);
6501 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006502 pgrp = rootpid;
6503 setpgid(0, pgrp);
6504 xtcsetpgrp(fd, pgrp);
6505 } else {
6506 /* turning job control off */
6507 fd = ttyfd;
6508 pgrp = initialpgrp;
6509 xtcsetpgrp(fd, pgrp);
6510 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006511 setsignal(SIGTSTP);
6512 setsignal(SIGTTOU);
6513 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006514close:
6515 close(fd);
6516 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006517 }
Eric Andersenc470f442003-07-28 09:56:35 +00006518 ttyfd = fd;
6519 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006520}
Eric Andersencb57d552001-06-28 07:25:16 +00006521
Eric Andersenc470f442003-07-28 09:56:35 +00006522static int
Eric Andersen90898442003-08-06 11:20:52 +00006523killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006524{
6525 int signo = -1;
6526 int list = 0;
6527 int i;
6528 pid_t pid;
6529 struct job *jp;
6530
6531 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006532usage:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006533 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006534"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6535"kill -l [exitstatus]"
6536 );
Eric Andersencb57d552001-06-28 07:25:16 +00006537 }
6538
Eric Andersenc470f442003-07-28 09:56:35 +00006539 if (**++argv == '-') {
6540 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006541 if (signo < 0) {
6542 int c;
6543
6544 while ((c = nextopt("ls:")) != '\0')
6545 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006546 default:
6547#ifdef DEBUG
6548 abort();
6549#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006550 case 'l':
6551 list = 1;
6552 break;
6553 case 's':
6554 signo = decode_signal(optionarg, 1);
6555 if (signo < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006556 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006557 "invalid signal number or name: %s",
6558 optionarg
6559 );
Eric Andersencb57d552001-06-28 07:25:16 +00006560 }
Eric Andersen2870d962001-07-02 17:27:21 +00006561 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006562 }
Eric Andersenc470f442003-07-28 09:56:35 +00006563 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006564 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006565 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006566 }
6567
6568 if (!list && signo < 0)
6569 signo = SIGTERM;
6570
Eric Andersenc470f442003-07-28 09:56:35 +00006571 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006572 goto usage;
6573 }
6574
6575 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006576 const char *name;
6577
Eric Andersenc470f442003-07-28 09:56:35 +00006578 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006579 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006580 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006581 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006582 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006583 }
6584 return 0;
6585 }
Eric Andersen34506362001-08-02 05:02:46 +00006586 name = u_signal_names(*argptr, &signo, -1);
6587 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006588 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006589 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006590 sh_error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006591 return 0;
6592 }
6593
Eric Andersenc470f442003-07-28 09:56:35 +00006594 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006595 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006596 if (**argv == '%') {
6597 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006598 pid = -jp->ps[0].pid;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006599 } else {
6600 pid = **argv == '-' ?
6601 -number(*argv + 1) : number(*argv);
6602 }
Eric Andersenc470f442003-07-28 09:56:35 +00006603 if (kill(pid, signo) != 0) {
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006604 sh_warnx("(%d) - %m", pid);
Eric Andersenc470f442003-07-28 09:56:35 +00006605 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006606 }
Eric Andersenc470f442003-07-28 09:56:35 +00006607 } while (*++argv);
6608
6609 return i;
6610}
6611#endif /* JOBS */
6612
6613#if defined(JOBS) || defined(DEBUG)
6614static int
6615jobno(const struct job *jp)
6616{
6617 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006618}
6619#endif
6620
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006621#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006622static int
6623fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006624{
Eric Andersenc470f442003-07-28 09:56:35 +00006625 struct job *jp;
6626 FILE *out;
6627 int mode;
6628 int retval;
6629
6630 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6631 nextopt(nullstr);
6632 argv = argptr;
6633 out = stdout;
6634 do {
6635 jp = getjob(*argv, 1);
6636 if (mode == FORK_BG) {
6637 set_curjob(jp, CUR_RUNNING);
6638 fprintf(out, "[%d] ", jobno(jp));
6639 }
6640 outstr(jp->ps->cmd, out);
6641 showpipe(jp, out);
6642 retval = restartjob(jp, mode);
6643 } while (*argv && *++argv);
6644 return retval;
6645}
6646
6647static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6648
6649
6650static int
6651restartjob(struct job *jp, int mode)
6652{
6653 struct procstat *ps;
6654 int i;
6655 int status;
6656 pid_t pgid;
6657
6658 INTOFF;
6659 if (jp->state == JOBDONE)
6660 goto out;
6661 jp->state = JOBRUNNING;
6662 pgid = jp->ps->pid;
6663 if (mode == FORK_FG)
6664 xtcsetpgrp(ttyfd, pgid);
6665 killpg(pgid, SIGCONT);
6666 ps = jp->ps;
6667 i = jp->nprocs;
6668 do {
6669 if (WIFSTOPPED(ps->status)) {
6670 ps->status = -1;
6671 }
6672 } while (ps++, --i);
6673out:
6674 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6675 INTON;
6676 return status;
6677}
6678#endif
6679
6680static int
6681sprint_status(char *s, int status, int sigonly)
6682{
6683 int col;
6684 int st;
6685
6686 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006687 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006688#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006689 if (WIFSTOPPED(status))
6690 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006691 else
Eric Andersenc470f442003-07-28 09:56:35 +00006692#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006693 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006694 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006695 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006696 goto out;
6697#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006698 if (WIFSTOPPED(status))
6699 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006700#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006701 }
6702 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006703 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006704 if (WCOREDUMP(status)) {
6705 col += fmtstr(s + col, 16, " (core dumped)");
6706 }
6707 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006708 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006709 if (st)
6710 col = fmtstr(s, 16, "Done(%d)", st);
6711 else
6712 col = fmtstr(s, 16, "Done");
6713 }
6714
6715out:
6716 return col;
6717}
6718
6719#if JOBS
6720static void
6721showjob(FILE *out, struct job *jp, int mode)
6722{
6723 struct procstat *ps;
6724 struct procstat *psend;
6725 int col;
6726 int indent;
6727 char s[80];
6728
6729 ps = jp->ps;
6730
6731 if (mode & SHOW_PGID) {
6732 /* just output process (group) id of pipeline */
6733 fprintf(out, "%d\n", ps->pid);
6734 return;
6735 }
6736
6737 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6738 indent = col;
6739
6740 if (jp == curjob)
6741 s[col - 2] = '+';
6742 else if (curjob && jp == curjob->prev_job)
6743 s[col - 2] = '-';
6744
6745 if (mode & SHOW_PID)
6746 col += fmtstr(s + col, 16, "%d ", ps->pid);
6747
6748 psend = ps + jp->nprocs;
6749
6750 if (jp->state == JOBRUNNING) {
6751 scopy("Running", s + col);
6752 col += strlen("Running");
6753 } else {
6754 int status = psend[-1].status;
6755#if JOBS
6756 if (jp->state == JOBSTOPPED)
6757 status = jp->stopstatus;
6758#endif
6759 col += sprint_status(s + col, status, 0);
6760 }
6761
6762 goto start;
6763
6764 do {
6765 /* for each process */
6766 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6767
6768start:
Eric Andersen90898442003-08-06 11:20:52 +00006769 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006770 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6771 );
6772 if (!(mode & SHOW_PID)) {
6773 showpipe(jp, out);
6774 break;
6775 }
6776 if (++ps == psend) {
6777 outcslow('\n', out);
6778 break;
6779 }
6780 } while (1);
6781
6782 jp->changed = 0;
6783
6784 if (jp->state == JOBDONE) {
6785 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6786 freejob(jp);
6787 }
6788}
6789
6790
6791static int
6792jobscmd(int argc, char **argv)
6793{
6794 int mode, m;
6795 FILE *out;
6796
6797 mode = 0;
6798 while ((m = nextopt("lp")))
6799 if (m == 'l')
6800 mode = SHOW_PID;
6801 else
6802 mode = SHOW_PGID;
6803
6804 out = stdout;
6805 argv = argptr;
6806 if (*argv)
6807 do
6808 showjob(out, getjob(*argv,0), mode);
6809 while (*++argv);
6810 else
6811 showjobs(out, mode);
6812
Eric Andersencb57d552001-06-28 07:25:16 +00006813 return 0;
6814}
6815
6816
6817/*
6818 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6819 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006820 */
6821
Eric Andersenc470f442003-07-28 09:56:35 +00006822static void
6823showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006824{
Eric Andersencb57d552001-06-28 07:25:16 +00006825 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006826
Eric Andersenc470f442003-07-28 09:56:35 +00006827 TRACE(("showjobs(%x) called\n", mode));
6828
6829 /* If not even one one job changed, there is nothing to do */
6830 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6831 continue;
6832
6833 for (jp = curjob; jp; jp = jp->prev_job) {
6834 if (!(mode & SHOW_CHANGED) || jp->changed)
6835 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006836 }
6837}
Eric Andersenc470f442003-07-28 09:56:35 +00006838#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006839
6840/*
6841 * Mark a job structure as unused.
6842 */
6843
Eric Andersenc470f442003-07-28 09:56:35 +00006844static void
6845freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006846{
Eric Andersenc470f442003-07-28 09:56:35 +00006847 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006848 int i;
6849
6850 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006851 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006852 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006853 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006854 }
6855 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006856 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006857 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006858 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006859 INTON;
6860}
6861
6862
Eric Andersenc470f442003-07-28 09:56:35 +00006863static int
6864waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006865{
6866 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006867 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006868 struct job *jp;
6869
Eric Andersenc470f442003-07-28 09:56:35 +00006870 EXSIGON();
6871
6872 nextopt(nullstr);
6873 retval = 0;
6874
6875 argv = argptr;
6876 if (!*argv) {
6877 /* wait for all jobs */
6878 for (;;) {
6879 jp = curjob;
6880 while (1) {
6881 if (!jp) {
6882 /* no running procs */
6883 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006884 }
Eric Andersenc470f442003-07-28 09:56:35 +00006885 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006886 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006887 jp->waited = 1;
6888 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006889 }
Eric Andersenc470f442003-07-28 09:56:35 +00006890 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006891 }
6892 }
Eric Andersenc470f442003-07-28 09:56:35 +00006893
6894 retval = 127;
6895 do {
6896 if (**argv != '%') {
6897 pid_t pid = number(*argv);
6898 job = curjob;
6899 goto start;
6900 do {
6901 if (job->ps[job->nprocs - 1].pid == pid)
6902 break;
6903 job = job->prev_job;
6904start:
6905 if (!job)
6906 goto repeat;
6907 } while (1);
6908 } else
6909 job = getjob(*argv, 0);
6910 /* loop until process terminated or stopped */
6911 while (job->state == JOBRUNNING)
6912 dowait(DOWAIT_BLOCK, 0);
6913 job->waited = 1;
6914 retval = getstatus(job);
6915repeat:
6916 ;
6917 } while (*++argv);
6918
6919out:
6920 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006921}
6922
6923
Eric Andersencb57d552001-06-28 07:25:16 +00006924/*
6925 * Convert a job name to a job structure.
6926 */
6927
Eric Andersenc470f442003-07-28 09:56:35 +00006928static struct job *
6929getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006930{
Eric Andersencb57d552001-06-28 07:25:16 +00006931 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006932 struct job *found;
6933 const char *err_msg = "No such job: %s";
6934 unsigned num;
6935 int c;
6936 const char *p;
6937 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006938
Eric Andersenc470f442003-07-28 09:56:35 +00006939 jp = curjob;
6940 p = name;
6941 if (!p)
6942 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006943
Eric Andersenc470f442003-07-28 09:56:35 +00006944 if (*p != '%')
6945 goto err;
6946
6947 c = *++p;
6948 if (!c)
6949 goto currentjob;
6950
6951 if (!p[1]) {
6952 if (c == '+' || c == '%') {
6953currentjob:
6954 err_msg = "No current job";
6955 goto check;
6956 } else if (c == '-') {
6957 if (jp)
6958 jp = jp->prev_job;
6959 err_msg = "No previous job";
6960check:
6961 if (!jp)
6962 goto err;
6963 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006964 }
6965 }
Eric Andersenc470f442003-07-28 09:56:35 +00006966
6967 if (is_number(p)) {
6968 num = atoi(p);
6969 if (num < njobs) {
6970 jp = jobtab + num - 1;
6971 if (jp->used)
6972 goto gotit;
6973 goto err;
6974 }
6975 }
6976
6977 match = prefix;
6978 if (*p == '?') {
6979 match = strstr;
6980 p++;
6981 }
6982
6983 found = 0;
6984 while (1) {
6985 if (!jp)
6986 goto err;
6987 if (match(jp->ps[0].cmd, p)) {
6988 if (found)
6989 goto err;
6990 found = jp;
6991 err_msg = "%s: ambiguous";
6992 }
6993 jp = jp->prev_job;
6994 }
6995
6996gotit:
6997#if JOBS
6998 err_msg = "job %s not created under job control";
6999 if (getctl && jp->jobctl == 0)
7000 goto err;
7001#endif
7002 return jp;
7003err:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007004 sh_error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007005}
7006
7007
Eric Andersencb57d552001-06-28 07:25:16 +00007008/*
Eric Andersenc470f442003-07-28 09:56:35 +00007009 * Return a new job structure.
7010 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007011 */
7012
Eric Andersenc470f442003-07-28 09:56:35 +00007013static struct job *
7014makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007015{
7016 int i;
7017 struct job *jp;
7018
Eric Andersenc470f442003-07-28 09:56:35 +00007019 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007020 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007021 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007022 break;
7023 }
7024 if (jp->used == 0)
7025 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007026 if (jp->state != JOBDONE || !jp->waited)
7027 continue;
7028#if JOBS
7029 if (jobctl)
7030 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007031#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007032 freejob(jp);
7033 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007034 }
Eric Andersenc470f442003-07-28 09:56:35 +00007035 memset(jp, 0, sizeof(*jp));
7036#if JOBS
7037 if (jobctl)
7038 jp->jobctl = 1;
7039#endif
7040 jp->prev_job = curjob;
7041 curjob = jp;
7042 jp->used = 1;
7043 jp->ps = &jp->ps0;
7044 if (nprocs > 1) {
7045 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7046 }
7047 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7048 jobno(jp)));
7049 return jp;
7050}
7051
7052static struct job *
7053growjobtab(void)
7054{
7055 size_t len;
7056 ptrdiff_t offset;
7057 struct job *jp, *jq;
7058
7059 len = njobs * sizeof(*jp);
7060 jq = jobtab;
7061 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7062
7063 offset = (char *)jp - (char *)jq;
7064 if (offset) {
7065 /* Relocate pointers */
7066 size_t l = len;
7067
7068 jq = (struct job *)((char *)jq + l);
7069 while (l) {
7070 l -= sizeof(*jp);
7071 jq--;
7072#define joff(p) ((struct job *)((char *)(p) + l))
7073#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007074 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007075 jmove(joff(jp)->ps);
7076 if (joff(jp)->prev_job)
7077 jmove(joff(jp)->prev_job);
7078 }
7079 if (curjob)
7080 jmove(curjob);
7081#undef joff
7082#undef jmove
7083 }
7084
7085 njobs += 4;
7086 jobtab = jp;
7087 jp = (struct job *)((char *)jp + len);
7088 jq = jp + 3;
7089 do {
7090 jq->used = 0;
7091 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007092 return jp;
7093}
7094
7095
7096/*
Eric Andersenc470f442003-07-28 09:56:35 +00007097 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007098 * own process group. Jp is a job structure that the job is to be added to.
7099 * N is the command that will be evaluated by the child. Both jp and n may
7100 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007101 * FORK_FG - Fork off a foreground process.
7102 * FORK_BG - Fork off a background process.
7103 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7104 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007105 *
7106 * When job control is turned off, background processes have their standard
7107 * input redirected to /dev/null (except for the second and later processes
7108 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007109 *
7110 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007111 */
7112
Eric Andersenc470f442003-07-28 09:56:35 +00007113static inline void
7114forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007115{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007116 int oldlvl;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007117
Eric Andersenc470f442003-07-28 09:56:35 +00007118 TRACE(("Child shell %d\n", getpid()));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007119 oldlvl = shlvl;
7120 shlvl++;
Eric Andersenc470f442003-07-28 09:56:35 +00007121
7122 closescript();
7123 clear_traps();
7124#if JOBS
7125 /* do job control only in root shell */
7126 jobctl = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007127 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007128 pid_t pgrp;
7129
7130 if (jp->nprocs == 0)
7131 pgrp = getpid();
7132 else
7133 pgrp = jp->ps[0].pid;
7134 /* This can fail because we are doing it in the parent also */
7135 (void)setpgid(0, pgrp);
7136 if (mode == FORK_FG)
7137 xtcsetpgrp(ttyfd, pgrp);
7138 setsignal(SIGTSTP);
7139 setsignal(SIGTTOU);
7140 } else
Eric Andersen62483552001-07-10 06:09:16 +00007141#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007142 if (mode == FORK_BG) {
7143 ignoresig(SIGINT);
7144 ignoresig(SIGQUIT);
7145 if (jp->nprocs == 0) {
7146 close(0);
7147 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007148 sh_error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007149 }
Eric Andersencb57d552001-06-28 07:25:16 +00007150 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007151 if (!oldlvl && iflag) {
Eric Andersenc470f442003-07-28 09:56:35 +00007152 setsignal(SIGINT);
7153 setsignal(SIGQUIT);
7154 setsignal(SIGTERM);
7155 }
7156 for (jp = curjob; jp; jp = jp->prev_job)
7157 freejob(jp);
7158 jobless = 0;
7159}
7160
7161static inline void
7162forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7163{
7164 TRACE(("In parent shell: child = %d\n", pid));
7165 if (!jp) {
7166 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7167 jobless++;
7168 return;
7169 }
7170#if JOBS
7171 if (mode != FORK_NOJOB && jp->jobctl) {
7172 int pgrp;
7173
7174 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007175 pgrp = pid;
7176 else
7177 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007178 /* This can fail because we are doing it in the child also */
7179 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007180 }
Eric Andersen62483552001-07-10 06:09:16 +00007181#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007182 if (mode == FORK_BG) {
7183 backgndpid = pid; /* set $! */
7184 set_curjob(jp, CUR_RUNNING);
7185 }
Eric Andersencb57d552001-06-28 07:25:16 +00007186 if (jp) {
7187 struct procstat *ps = &jp->ps[jp->nprocs++];
7188 ps->pid = pid;
7189 ps->status = -1;
7190 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007191#if JOBS
7192 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007193 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007194#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007195 }
Eric Andersencb57d552001-06-28 07:25:16 +00007196}
7197
Eric Andersenc470f442003-07-28 09:56:35 +00007198static int
7199forkshell(struct job *jp, union node *n, int mode)
7200{
7201 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007202
Eric Andersenc470f442003-07-28 09:56:35 +00007203 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7204 pid = fork();
7205 if (pid < 0) {
7206 TRACE(("Fork failed, errno=%d", errno));
7207 if (jp)
7208 freejob(jp);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007209 sh_error("Cannot fork");
Eric Andersenc470f442003-07-28 09:56:35 +00007210 }
7211 if (pid == 0)
7212 forkchild(jp, n, mode);
7213 else
7214 forkparent(jp, n, mode, pid);
7215 return pid;
7216}
Eric Andersencb57d552001-06-28 07:25:16 +00007217
7218/*
7219 * Wait for job to finish.
7220 *
7221 * Under job control we have the problem that while a child process is
7222 * running interrupts generated by the user are sent to the child but not
7223 * to the shell. This means that an infinite loop started by an inter-
7224 * active user may be hard to kill. With job control turned off, an
7225 * interactive user may place an interactive program inside a loop. If
7226 * the interactive program catches interrupts, the user doesn't want
7227 * these interrupts to also abort the loop. The approach we take here
7228 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007229 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007230 * signal if the child process was terminated by an interrupt signal.
7231 * Unfortunately, some programs want to do a bit of cleanup and then
7232 * exit on interrupt; unless these processes terminate themselves by
7233 * sending a signal to themselves (instead of calling exit) they will
7234 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007235 *
7236 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007237 */
7238
Eric Andersenc470f442003-07-28 09:56:35 +00007239int
7240waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007241{
Eric Andersencb57d552001-06-28 07:25:16 +00007242 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007243
Eric Andersenc470f442003-07-28 09:56:35 +00007244 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7245 while (jp->state == JOBRUNNING) {
7246 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007247 }
Eric Andersenc470f442003-07-28 09:56:35 +00007248 st = getstatus(jp);
7249#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007250 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007251 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007252 /*
7253 * This is truly gross.
7254 * If we're doing job control, then we did a TIOCSPGRP which
7255 * caused us (the shell) to no longer be in the controlling
7256 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7257 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007258 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007259 */
Eric Andersenc470f442003-07-28 09:56:35 +00007260 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007261 raise(SIGINT);
7262 }
Eric Andersen2870d962001-07-02 17:27:21 +00007263 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007264#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007265 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007266 return st;
7267}
7268
7269
Eric Andersen62483552001-07-10 06:09:16 +00007270/*
7271 * Do a wait system call. If job control is compiled in, we accept
7272 * stopped processes. If block is zero, we return a value of zero
7273 * rather than blocking.
7274 *
7275 * System V doesn't have a non-blocking wait system call. It does
7276 * have a SIGCLD signal that is sent to a process when one of it's
7277 * children dies. The obvious way to use SIGCLD would be to install
7278 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7279 * was received, and have waitproc bump another counter when it got
7280 * the status of a process. Waitproc would then know that a wait
7281 * system call would not block if the two counters were different.
7282 * This approach doesn't work because if a process has children that
7283 * have not been waited for, System V will send it a SIGCLD when it
7284 * installs a signal handler for SIGCLD. What this means is that when
7285 * a child exits, the shell will be sent SIGCLD signals continuously
7286 * until is runs out of stack space, unless it does a wait call before
7287 * restoring the signal handler. The code below takes advantage of
7288 * this (mis)feature by installing a signal handler for SIGCLD and
7289 * then checking to see whether it was called. If there are any
7290 * children to be waited for, it will be.
7291 *
Eric Andersenc470f442003-07-28 09:56:35 +00007292 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7293 * waits at all. In this case, the user will not be informed when
7294 * a background process until the next time she runs a real program
7295 * (as opposed to running a builtin command or just typing return),
7296 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007297 */
7298
Eric Andersenc470f442003-07-28 09:56:35 +00007299static inline int
7300waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007301{
Eric Andersenc470f442003-07-28 09:56:35 +00007302 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007303
Eric Andersenc470f442003-07-28 09:56:35 +00007304#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007305 if (jobctl)
7306 flags |= WUNTRACED;
7307#endif
7308 if (block == 0)
7309 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007310 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007311}
7312
Eric Andersenc470f442003-07-28 09:56:35 +00007313/*
7314 * Wait for a process to terminate.
7315 */
7316
7317static int
7318dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007319{
7320 int pid;
7321 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007322 struct job *jp;
7323 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007324 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007325
7326 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007327 pid = waitproc(block, &status);
7328 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007329 if (pid <= 0)
7330 return pid;
7331 INTOFF;
7332 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007333 for (jp = curjob; jp; jp = jp->prev_job) {
7334 struct procstat *sp;
7335 struct procstat *spend;
7336 if (jp->state == JOBDONE)
7337 continue;
7338 state = JOBDONE;
7339 spend = jp->ps + jp->nprocs;
7340 sp = jp->ps;
7341 do {
7342 if (sp->pid == pid) {
7343 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7344 sp->status = status;
7345 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007346 }
Eric Andersenc470f442003-07-28 09:56:35 +00007347 if (sp->status == -1)
7348 state = JOBRUNNING;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007349#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007350 if (state == JOBRUNNING)
7351 continue;
7352 if (WIFSTOPPED(sp->status)) {
7353 jp->stopstatus = sp->status;
7354 state = JOBSTOPPED;
7355 }
Eric Andersencb57d552001-06-28 07:25:16 +00007356#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007357 } while (++sp < spend);
7358 if (thisjob)
7359 goto gotjob;
7360 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007361#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007362 if (!WIFSTOPPED(status))
7363#endif
7364
7365 jobless--;
7366 goto out;
7367
7368gotjob:
7369 if (state != JOBRUNNING) {
7370 thisjob->changed = 1;
7371
7372 if (thisjob->state != state) {
7373 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7374 thisjob->state = state;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007375#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007376 if (state == JOBSTOPPED) {
7377 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007378 }
Eric Andersenc470f442003-07-28 09:56:35 +00007379#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007380 }
7381 }
Eric Andersencb57d552001-06-28 07:25:16 +00007382
Eric Andersenc470f442003-07-28 09:56:35 +00007383out:
7384 INTON;
7385
7386 if (thisjob && thisjob == job) {
7387 char s[48 + 1];
7388 int len;
7389
7390 len = sprint_status(s, status, 1);
7391 if (len) {
7392 s[len] = '\n';
7393 s[len + 1] = 0;
7394 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007395 }
Eric Andersencb57d552001-06-28 07:25:16 +00007396 }
7397 return pid;
7398}
7399
7400
Eric Andersencb57d552001-06-28 07:25:16 +00007401/*
7402 * return 1 if there are stopped jobs, otherwise 0
7403 */
Eric Andersen90898442003-08-06 11:20:52 +00007404
Eric Andersenc470f442003-07-28 09:56:35 +00007405int
7406stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007407{
Eric Andersencb57d552001-06-28 07:25:16 +00007408 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007409 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007410
Eric Andersenc470f442003-07-28 09:56:35 +00007411 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007412 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007413 goto out;
7414 jp = curjob;
7415 if (jp && jp->state == JOBSTOPPED) {
7416 out2str("You have stopped jobs.\n");
7417 job_warning = 2;
7418 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007419 }
7420
Eric Andersenc470f442003-07-28 09:56:35 +00007421out:
7422 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007423}
7424
7425/*
7426 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007427 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007428 */
7429
Eric Andersenc470f442003-07-28 09:56:35 +00007430#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007431static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007432
Eric Andersenc470f442003-07-28 09:56:35 +00007433static char *
7434commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007435{
Eric Andersenc470f442003-07-28 09:56:35 +00007436 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007437
Eric Andersenc470f442003-07-28 09:56:35 +00007438 STARTSTACKSTR(cmdnextc);
7439 cmdtxt(n);
7440 name = stackblock();
7441 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7442 name, cmdnextc, cmdnextc));
7443 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007444}
7445
Eric Andersenc470f442003-07-28 09:56:35 +00007446static void
7447cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007448{
Eric Andersencb57d552001-06-28 07:25:16 +00007449 union node *np;
7450 struct nodelist *lp;
7451 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007452 char s[2];
7453
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007454 if (!n)
7455 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007456 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007457 default:
7458#if DEBUG
7459 abort();
7460#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007461 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007462 lp = n->npipe.cmdlist;
7463 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007464 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007465 lp = lp->next;
7466 if (!lp)
7467 break;
7468 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007469 }
7470 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007471 case NSEMI:
7472 p = "; ";
7473 goto binop;
7474 case NAND:
7475 p = " && ";
7476 goto binop;
7477 case NOR:
7478 p = " || ";
7479binop:
7480 cmdtxt(n->nbinary.ch1);
7481 cmdputs(p);
7482 n = n->nbinary.ch2;
7483 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007484 case NREDIR:
7485 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007486 n = n->nredir.n;
7487 goto donode;
7488 case NNOT:
7489 cmdputs("!");
7490 n = n->nnot.com;
7491donode:
7492 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007493 break;
7494 case NIF:
7495 cmdputs("if ");
7496 cmdtxt(n->nif.test);
7497 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007498 n = n->nif.ifpart;
7499 if (n->nif.elsepart) {
7500 cmdtxt(n);
7501 cmdputs("; else ");
7502 n = n->nif.elsepart;
7503 }
7504 p = "; fi";
7505 goto dotail;
7506 case NSUBSHELL:
7507 cmdputs("(");
7508 n = n->nredir.n;
7509 p = ")";
7510 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007511 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007512 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007513 goto until;
7514 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007515 p = "until ";
7516until:
7517 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007518 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007519 n = n->nbinary.ch2;
7520 p = "; done";
7521dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007522 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007523dotail:
7524 cmdtxt(n);
7525 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007526 case NFOR:
7527 cmdputs("for ");
7528 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007529 cmdputs(" in ");
7530 cmdlist(n->nfor.args, 1);
7531 n = n->nfor.body;
7532 p = "; done";
7533 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007534 case NDEFUN:
7535 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007536 p = "() { ... }";
7537 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007538 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007539 cmdlist(n->ncmd.args, 1);
7540 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007541 break;
7542 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007543 p = n->narg.text;
7544dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007545 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007546 break;
7547 case NHERE:
7548 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007549 p = "<<...";
7550 goto dotail2;
7551 case NCASE:
7552 cmdputs("case ");
7553 cmdputs(n->ncase.expr->narg.text);
7554 cmdputs(" in ");
7555 for (np = n->ncase.cases; np; np = np->nclist.next) {
7556 cmdtxt(np->nclist.pattern);
7557 cmdputs(") ");
7558 cmdtxt(np->nclist.body);
7559 cmdputs(";; ");
7560 }
7561 p = "esac";
7562 goto dotail2;
7563 case NTO:
7564 p = ">";
7565 goto redir;
7566 case NCLOBBER:
7567 p = ">|";
7568 goto redir;
7569 case NAPPEND:
7570 p = ">>";
7571 goto redir;
7572 case NTOFD:
7573 p = ">&";
7574 goto redir;
7575 case NFROM:
7576 p = "<";
7577 goto redir;
7578 case NFROMFD:
7579 p = "<&";
7580 goto redir;
7581 case NFROMTO:
7582 p = "<>";
7583redir:
7584 s[0] = n->nfile.fd + '0';
7585 s[1] = '\0';
7586 cmdputs(s);
7587 cmdputs(p);
7588 if (n->type == NTOFD || n->type == NFROMFD) {
7589 s[0] = n->ndup.dupfd + '0';
7590 p = s;
7591 goto dotail2;
7592 } else {
7593 n = n->nfile.fname;
7594 goto donode;
7595 }
Eric Andersencb57d552001-06-28 07:25:16 +00007596 }
7597}
Eric Andersencb57d552001-06-28 07:25:16 +00007598
Eric Andersenc470f442003-07-28 09:56:35 +00007599static void
7600cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007601{
Eric Andersenc470f442003-07-28 09:56:35 +00007602 for (; np; np = np->narg.next) {
7603 if (!sep)
7604 cmdputs(spcstr);
7605 cmdtxt(np);
7606 if (sep && np->narg.next)
7607 cmdputs(spcstr);
7608 }
Eric Andersencb57d552001-06-28 07:25:16 +00007609}
7610
Eric Andersenc470f442003-07-28 09:56:35 +00007611static void
7612cmdputs(const char *s)
7613{
7614 const char *p, *str;
7615 char c, cc[2] = " ";
7616 char *nextc;
7617 int subtype = 0;
7618 int quoted = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007619 static const char vstype[VSTYPE + 1][4] = {
7620 "", "}", "-", "+", "?", "=",
7621 "%", "%%", "#", "##"
Eric Andersenc470f442003-07-28 09:56:35 +00007622 };
Eric Andersenc470f442003-07-28 09:56:35 +00007623 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7624 p = s;
7625 while ((c = *p++) != 0) {
7626 str = 0;
7627 switch (c) {
7628 case CTLESC:
7629 c = *p++;
7630 break;
7631 case CTLVAR:
7632 subtype = *p++;
7633 if ((subtype & VSTYPE) == VSLENGTH)
7634 str = "${#";
7635 else
7636 str = "${";
7637 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7638 quoted ^= 1;
7639 c = '"';
7640 } else
7641 goto dostr;
7642 break;
7643 case CTLENDVAR:
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007644 str = "\"}" + !(quoted & 1);
Eric Andersenc470f442003-07-28 09:56:35 +00007645 quoted >>= 1;
7646 subtype = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007647 goto dostr;
Eric Andersenc470f442003-07-28 09:56:35 +00007648 case CTLBACKQ:
7649 str = "$(...)";
7650 goto dostr;
7651 case CTLBACKQ+CTLQUOTE:
7652 str = "\"$(...)\"";
7653 goto dostr;
7654#ifdef CONFIG_ASH_MATH_SUPPORT
7655 case CTLARI:
7656 str = "$((";
7657 goto dostr;
7658 case CTLENDARI:
7659 str = "))";
7660 goto dostr;
7661#endif
7662 case CTLQUOTEMARK:
7663 quoted ^= 1;
7664 c = '"';
7665 break;
7666 case '=':
7667 if (subtype == 0)
7668 break;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007669 if ((subtype & VSTYPE) != VSNORMAL)
7670 quoted <<= 1;
Eric Andersenc470f442003-07-28 09:56:35 +00007671 str = vstype[subtype & VSTYPE];
7672 if (subtype & VSNUL)
7673 c = ':';
7674 else
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007675 goto checkstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007676 break;
7677 case '\'':
7678 case '\\':
7679 case '"':
7680 case '$':
7681 /* These can only happen inside quotes */
7682 cc[0] = c;
7683 str = cc;
7684 c = '\\';
7685 break;
7686 default:
7687 break;
7688 }
7689 USTPUTC(c, nextc);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007690checkstr:
Eric Andersenc470f442003-07-28 09:56:35 +00007691 if (!str)
7692 continue;
7693dostr:
7694 while ((c = *str++)) {
7695 USTPUTC(c, nextc);
7696 }
7697 }
7698 if (quoted & 1) {
7699 USTPUTC('"', nextc);
7700 }
7701 *nextc = 0;
7702 cmdnextc = nextc;
7703}
7704
7705
7706static void
7707showpipe(struct job *jp, FILE *out)
7708{
7709 struct procstat *sp;
7710 struct procstat *spend;
7711
7712 spend = jp->ps + jp->nprocs;
7713 for (sp = jp->ps + 1; sp < spend; sp++)
7714 fprintf(out, " | %s", sp->cmd);
7715 outcslow('\n', out);
7716 flushall();
7717}
7718
7719static void
7720xtcsetpgrp(int fd, pid_t pgrp)
7721{
7722 if (tcsetpgrp(fd, pgrp))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007723 sh_error("Cannot set tty process group (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +00007724}
7725#endif /* JOBS */
7726
7727static int
7728getstatus(struct job *job) {
7729 int status;
7730 int retval;
7731
7732 status = job->ps[job->nprocs - 1].status;
7733 retval = WEXITSTATUS(status);
7734 if (!WIFEXITED(status)) {
7735#if JOBS
7736 retval = WSTOPSIG(status);
7737 if (!WIFSTOPPED(status))
7738#endif
7739 {
7740 /* XXX: limits number of signals */
7741 retval = WTERMSIG(status);
7742#if JOBS
7743 if (retval == SIGINT)
7744 job->sigint = 1;
7745#endif
7746 }
7747 retval += 128;
7748 }
7749 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7750 jobno(job), job->nprocs, status, retval));
7751 return retval;
7752}
7753
Eric Andersend35c5df2002-01-09 15:37:36 +00007754#ifdef CONFIG_ASH_MAIL
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007755/* mail.c */
Eric Andersenec074692001-10-31 11:05:49 +00007756
Eric Andersencb57d552001-06-28 07:25:16 +00007757/*
Eric Andersenc470f442003-07-28 09:56:35 +00007758 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007759 */
7760
Eric Andersencb57d552001-06-28 07:25:16 +00007761#define MAXMBOXES 10
7762
Eric Andersenc470f442003-07-28 09:56:35 +00007763/* times of mailboxes */
7764static time_t mailtime[MAXMBOXES];
7765/* Set if MAIL or MAILPATH is changed. */
7766static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007767
7768
7769
7770/*
Eric Andersenc470f442003-07-28 09:56:35 +00007771 * Print appropriate message(s) if mail has arrived.
7772 * If mail_var_path_changed is set,
7773 * then the value of MAIL has mail_var_path_changed,
7774 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007775 */
7776
Eric Andersenc470f442003-07-28 09:56:35 +00007777static void
7778chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007779{
Eric Andersencb57d552001-06-28 07:25:16 +00007780 const char *mpath;
7781 char *p;
7782 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007783 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007784 struct stackmark smark;
7785 struct stat statb;
7786
Eric Andersencb57d552001-06-28 07:25:16 +00007787 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007788 mpath = mpathset() ? mpathval() : mailval();
7789 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007790 p = padvance(&mpath, nullstr);
7791 if (p == NULL)
7792 break;
7793 if (*p == '\0')
7794 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007795 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007796#ifdef DEBUG
7797 if (q[-1] != '/')
7798 abort();
7799#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007800 q[-1] = '\0'; /* delete trailing '/' */
7801 if (stat(p, &statb) < 0) {
7802 *mtp = 0;
7803 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007804 }
Eric Andersenc470f442003-07-28 09:56:35 +00007805 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7806 fprintf(
7807 stderr, snlfmt,
7808 pathopt ? pathopt : "you have mail"
7809 );
7810 }
7811 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007812 }
Eric Andersenc470f442003-07-28 09:56:35 +00007813 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007814 popstackmark(&smark);
7815}
Eric Andersencb57d552001-06-28 07:25:16 +00007816
Eric Andersenec074692001-10-31 11:05:49 +00007817
Eric Andersenc470f442003-07-28 09:56:35 +00007818static void
7819changemail(const char *val)
7820{
7821 mail_var_path_changed++;
7822}
7823
7824#endif /* CONFIG_ASH_MAIL */
7825
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007826/* main.c */
Eric Andersenc470f442003-07-28 09:56:35 +00007827
Eric Andersencb57d552001-06-28 07:25:16 +00007828
Eric Andersencb57d552001-06-28 07:25:16 +00007829#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007830static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007831extern int etext();
7832#endif
7833
Eric Andersenc470f442003-07-28 09:56:35 +00007834static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007835
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007836static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007837
Eric Andersencb57d552001-06-28 07:25:16 +00007838/*
7839 * Main routine. We initialize things, parse the arguments, execute
7840 * profiles if we're a login shell, and then call cmdloop to execute
7841 * commands. The setjmp call sets up the location to jump to when an
7842 * exception occurs. When an exception occurs the variable "state"
7843 * is used to figure out how far we had gotten.
7844 */
7845
Eric Andersenc470f442003-07-28 09:56:35 +00007846int
7847ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007848{
Eric Andersenc470f442003-07-28 09:56:35 +00007849 char *shinit;
7850 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007851 struct jmploc jmploc;
7852 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007853
Eric Andersenc470f442003-07-28 09:56:35 +00007854#ifdef __GLIBC__
7855 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007856#endif
7857
Eric Andersencb57d552001-06-28 07:25:16 +00007858#if PROFILE
7859 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7860#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007861 state = 0;
7862 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007863 int e;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007864 int s;
Eric Andersenc470f442003-07-28 09:56:35 +00007865
Eric Andersencb57d552001-06-28 07:25:16 +00007866 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007867
7868 e = exception;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007869 if (e == EXERROR)
7870 exitstatus = 2;
7871 s = state;
7872 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00007873 exitshell();
7874
Eric Andersen90898442003-08-06 11:20:52 +00007875 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007876 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007877 }
7878 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007879 FORCEINTON; /* enable interrupts */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007880 if (s == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00007881 goto state1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007882 else if (s == 2)
Eric Andersencb57d552001-06-28 07:25:16 +00007883 goto state2;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007884 else if (s == 3)
Eric Andersencb57d552001-06-28 07:25:16 +00007885 goto state3;
7886 else
7887 goto state4;
7888 }
7889 handler = &jmploc;
7890#ifdef DEBUG
7891 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007892 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007893#endif
7894 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007895
7896#ifdef CONFIG_ASH_RANDOM_SUPPORT
7897 rseed = rootpid + ((time_t)time((time_t *)0));
7898#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007899 init();
7900 setstackmark(&smark);
7901 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007902#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7903 if ( iflag ) {
7904 const char *hp = lookupvar("HISTFILE");
7905
7906 if(hp == NULL ) {
7907 hp = lookupvar("HOME");
7908 if(hp != NULL) {
7909 char *defhp = concat_path_file(hp, ".ash_history");
7910 setvar("HISTFILE", defhp, 0);
7911 free(defhp);
7912 }
7913 }
7914 }
7915#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007916 if (argv[0] && argv[0][0] == '-')
7917 isloginsh = 1;
7918 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007919 state = 1;
7920 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007921state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007922 state = 2;
7923 read_profile(".profile");
7924 }
Eric Andersenc470f442003-07-28 09:56:35 +00007925state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007926 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007927 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007928#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007929 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007930#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007931 iflag
7932 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007933 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007934 read_profile(shinit);
7935 }
Eric Andersencb57d552001-06-28 07:25:16 +00007936 }
Eric Andersenc470f442003-07-28 09:56:35 +00007937state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007938 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007939 if (minusc)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007940 evalstring(minusc, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007941
7942 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007943#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007944 if ( iflag ) {
7945 const char *hp = lookupvar("HISTFILE");
7946
7947 if(hp != NULL )
7948 load_history ( hp );
7949 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007950#endif
Eric Andersen90898442003-08-06 11:20:52 +00007951state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007952 cmdloop(1);
7953 }
7954#if PROFILE
7955 monitor(0);
7956#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007957#if GPROF
7958 {
7959 extern void _mcleanup(void);
7960 _mcleanup();
7961 }
7962#endif
7963 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007964 /* NOTREACHED */
7965}
7966
7967
7968/*
7969 * Read and execute commands. "Top" is nonzero for the top level command
7970 * loop; it turns on prompting if the shell is interactive.
7971 */
7972
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007973static int
Eric Andersenc470f442003-07-28 09:56:35 +00007974cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007975{
7976 union node *n;
7977 struct stackmark smark;
7978 int inter;
7979 int numeof = 0;
7980
7981 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00007982 for (;;) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007983 int skip;
7984
Glenn L McGrath76620622004-01-13 10:19:37 +00007985 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007986#if JOBS
7987 if (jobctl)
7988 showjobs(stderr, SHOW_CHANGED);
7989#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007990 inter = 0;
7991 if (iflag && top) {
7992 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00007993#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007994 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00007995#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007996 }
7997 n = parsecmd(inter);
7998 /* showtree(n); DEBUG */
7999 if (n == NEOF) {
8000 if (!top || numeof >= 50)
8001 break;
8002 if (!stoppedjobs()) {
8003 if (!Iflag)
8004 break;
8005 out2str("\nUse \"exit\" to leave shell.\n");
8006 }
8007 numeof++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008008 } else if (nflag == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008009 job_warning = (job_warning == 2) ? 1 : 0;
8010 numeof = 0;
8011 evaltree(n, 0);
8012 }
8013 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008014 skip = evalskip;
8015
8016 if (skip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008017 evalskip = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008018 return skip & SKIPEVAL;
Eric Andersencb57d552001-06-28 07:25:16 +00008019 }
8020 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008021
8022 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008023}
8024
8025
Eric Andersencb57d552001-06-28 07:25:16 +00008026/*
8027 * Read /etc/profile or .profile. Return on error.
8028 */
8029
Eric Andersenc470f442003-07-28 09:56:35 +00008030static void
8031read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008032{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008033 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008034
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008035 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008036 return;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008037
8038 skip = cmdloop(0);
Eric Andersencb57d552001-06-28 07:25:16 +00008039 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008040
8041 if (skip)
8042 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00008043}
8044
8045
Eric Andersencb57d552001-06-28 07:25:16 +00008046/*
8047 * Read a file containing shell functions.
8048 */
8049
Eric Andersenc470f442003-07-28 09:56:35 +00008050static void
8051readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008052{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008053 setinputfile(name, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008054 cmdloop(0);
8055 popfile();
8056}
8057
8058
Eric Andersencb57d552001-06-28 07:25:16 +00008059/*
Eric Andersenc470f442003-07-28 09:56:35 +00008060 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008061 * search for the file, which is necessary to find sub-commands.
8062 */
8063
Eric Andersenc470f442003-07-28 09:56:35 +00008064static inline char *
8065find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008066{
8067 char *fullname;
8068 const char *path = pathval();
8069 struct stat statb;
8070
8071 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008072 if (strchr(name, '/'))
8073 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008074
Eric Andersenc470f442003-07-28 09:56:35 +00008075 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008076 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8077 /*
8078 * Don't bother freeing here, since it will
8079 * be freed by the caller.
8080 */
8081 return fullname;
8082 }
8083 stunalloc(fullname);
8084 }
8085
8086 /* not found in the PATH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008087 sh_error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008088 /* NOTREACHED */
8089}
8090
Eric Andersen1e6aba92004-04-12 19:12:13 +00008091static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008092{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008093 struct strlist *sp;
8094 volatile struct shparam saveparam;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008095 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008096
Eric Andersen1e6aba92004-04-12 19:12:13 +00008097 for (sp = cmdenviron; sp; sp = sp->next)
8098 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8099
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00008100 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008101 char *fullname;
Eric Andersencb57d552001-06-28 07:25:16 +00008102
Eric Andersencb57d552001-06-28 07:25:16 +00008103 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008104
8105 if (argc > 2) {
8106 saveparam = shellparam;
8107 shellparam.malloc = 0;
8108 shellparam.nparam = argc - 2;
8109 shellparam.p = argv + 2;
8110 };
8111
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008112 setinputfile(fullname, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008113 commandname = fullname;
8114 cmdloop(0);
8115 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008116
8117 if (argc > 2) {
8118 freeparam(&shellparam);
8119 shellparam = saveparam;
8120 };
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008121 status = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00008122 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008123 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008124}
8125
8126
Eric Andersenc470f442003-07-28 09:56:35 +00008127static int
8128exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008129{
8130 if (stoppedjobs())
8131 return 0;
8132 if (argc > 1)
8133 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008134 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008135 /* NOTREACHED */
8136}
Eric Andersen62483552001-07-10 06:09:16 +00008137
Paul Fox0b621582005-08-09 19:38:05 +00008138#ifdef CONFIG_ASH_BUILTIN_ECHO
8139static int
8140echocmd(int argc, char **argv)
8141{
8142 return bb_echo(argc, argv);
8143}
8144#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008145/* memalloc.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008146
8147/*
Eric Andersen90898442003-08-06 11:20:52 +00008148 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008149 */
8150
8151static pointer
8152ckrealloc(pointer p, size_t nbytes)
8153{
8154 p = realloc(p, nbytes);
8155 if (p == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008156 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008157 return p;
8158}
8159
Eric Andersen90898442003-08-06 11:20:52 +00008160static pointer
8161ckmalloc(size_t nbytes)
8162{
8163 return ckrealloc(NULL, nbytes);
8164}
Eric Andersenc470f442003-07-28 09:56:35 +00008165
8166/*
8167 * Make a copy of a string in safe storage.
8168 */
8169
8170static char *
8171savestr(const char *s)
8172{
8173 char *p = strdup(s);
8174 if (!p)
"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
8179
8180/*
8181 * Parse trees for commands are allocated in lifo order, so we use a stack
8182 * to make this more efficient, and also to avoid all sorts of exception
8183 * handling code to handle interrupts in the middle of a parse.
8184 *
8185 * The size 504 was chosen because the Ultrix malloc handles that size
8186 * well.
8187 */
8188
8189
8190static pointer
8191stalloc(size_t nbytes)
8192{
8193 char *p;
8194 size_t aligned;
8195
8196 aligned = SHELL_ALIGN(nbytes);
8197 if (aligned > stacknleft) {
8198 size_t len;
8199 size_t blocksize;
8200 struct stack_block *sp;
8201
8202 blocksize = aligned;
8203 if (blocksize < MINSIZE)
8204 blocksize = MINSIZE;
8205 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8206 if (len < blocksize)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008207 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008208 INTOFF;
8209 sp = ckmalloc(len);
8210 sp->prev = stackp;
8211 stacknxt = sp->space;
8212 stacknleft = blocksize;
8213 sstrend = stacknxt + blocksize;
8214 stackp = sp;
8215 INTON;
8216 }
8217 p = stacknxt;
8218 stacknxt += aligned;
8219 stacknleft -= aligned;
8220 return p;
8221}
8222
8223
8224void
8225stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008226{
Eric Andersencb57d552001-06-28 07:25:16 +00008227#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008228 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008229 write(2, "stunalloc\n", 10);
8230 abort();
8231 }
8232#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008233 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008234 stacknxt = p;
8235}
8236
8237
Eric Andersenc470f442003-07-28 09:56:35 +00008238void
8239setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008240{
Eric Andersencb57d552001-06-28 07:25:16 +00008241 mark->stackp = stackp;
8242 mark->stacknxt = stacknxt;
8243 mark->stacknleft = stacknleft;
8244 mark->marknext = markp;
8245 markp = mark;
8246}
8247
8248
Eric Andersenc470f442003-07-28 09:56:35 +00008249void
8250popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008251{
Eric Andersencb57d552001-06-28 07:25:16 +00008252 struct stack_block *sp;
8253
8254 INTOFF;
8255 markp = mark->marknext;
8256 while (stackp != mark->stackp) {
8257 sp = stackp;
8258 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008259 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008260 }
8261 stacknxt = mark->stacknxt;
8262 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008263 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008264 INTON;
8265}
8266
8267
8268/*
8269 * When the parser reads in a string, it wants to stick the string on the
8270 * stack and only adjust the stack pointer when it knows how big the
8271 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8272 * of space on top of the stack and stackblocklen returns the length of
8273 * this block. Growstackblock will grow this space by at least one byte,
8274 * possibly moving it (like realloc). Grabstackblock actually allocates the
8275 * part of the block that has been used.
8276 */
8277
Eric Andersenc470f442003-07-28 09:56:35 +00008278void
8279growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008280{
Eric Andersenc470f442003-07-28 09:56:35 +00008281 size_t newlen;
8282
8283 newlen = stacknleft * 2;
8284 if (newlen < stacknleft)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008285 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008286 if (newlen < 128)
8287 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008288
8289 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008290 struct stack_block *oldstackp;
8291 struct stackmark *xmark;
8292 struct stack_block *sp;
8293 struct stack_block *prevstackp;
8294 size_t grosslen;
8295
Eric Andersencb57d552001-06-28 07:25:16 +00008296 INTOFF;
8297 oldstackp = stackp;
8298 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008299 prevstackp = sp->prev;
8300 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8301 sp = ckrealloc((pointer)sp, grosslen);
8302 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008303 stackp = sp;
8304 stacknxt = sp->space;
8305 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008306 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008307
Eric Andersenc470f442003-07-28 09:56:35 +00008308 /*
8309 * Stack marks pointing to the start of the old block
8310 * must be relocated to point to the new block
8311 */
8312 xmark = markp;
8313 while (xmark != NULL && xmark->stackp == oldstackp) {
8314 xmark->stackp = stackp;
8315 xmark->stacknxt = stacknxt;
8316 xmark->stacknleft = stacknleft;
8317 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008318 }
8319 INTON;
8320 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008321 char *oldspace = stacknxt;
8322 int oldlen = stacknleft;
8323 char *p = stalloc(newlen);
8324
8325 /* free the space we just allocated */
8326 stacknxt = memcpy(p, oldspace, oldlen);
8327 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008328 }
8329}
8330
Eric Andersenc470f442003-07-28 09:56:35 +00008331static inline void
8332grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008333{
Eric Andersenc470f442003-07-28 09:56:35 +00008334 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008335 stacknxt += len;
8336 stacknleft -= len;
8337}
8338
Eric Andersencb57d552001-06-28 07:25:16 +00008339/*
Eric Andersenc470f442003-07-28 09:56:35 +00008340 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008341 * The user declares a variable of type STACKSTR, which may be declared
8342 * to be a register. The macro STARTSTACKSTR initializes things. Then
8343 * the user uses the macro STPUTC to add characters to the string. In
8344 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8345 * grown as necessary. When the user is done, she can just leave the
8346 * string there and refer to it using stackblock(). Or she can allocate
8347 * the space for it using grabstackstr(). If it is necessary to allow
8348 * someone else to use the stack temporarily and then continue to grow
8349 * the string, the user should use grabstack to allocate the space, and
8350 * then call ungrabstr(p) to return to the previous mode of operation.
8351 *
8352 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8353 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8354 * is space for at least one character.
8355 */
8356
Eric Andersenc470f442003-07-28 09:56:35 +00008357void *
8358growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008359{
Eric Andersenc470f442003-07-28 09:56:35 +00008360 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008361 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008362 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008363 return stackblock();
8364 }
8365 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008366 return stackblock() + len;
8367}
8368
Eric Andersencb57d552001-06-28 07:25:16 +00008369/*
8370 * Called from CHECKSTRSPACE.
8371 */
8372
Eric Andersenc470f442003-07-28 09:56:35 +00008373char *
8374makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008375{
Eric Andersenc470f442003-07-28 09:56:35 +00008376 size_t len = p - stacknxt;
8377 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008378
Eric Andersenc470f442003-07-28 09:56:35 +00008379 for (;;) {
8380 size_t nleft;
8381
8382 size = stackblocksize();
8383 nleft = size - len;
8384 if (nleft >= newlen)
8385 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008386 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008387 }
Eric Andersencb57d552001-06-28 07:25:16 +00008388 return stackblock() + len;
8389}
8390
Eric Andersenc470f442003-07-28 09:56:35 +00008391char *
8392stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008393{
Eric Andersenc470f442003-07-28 09:56:35 +00008394 p = makestrspace(n, p);
8395 p = mempcpy(p, s, n);
8396 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008397}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008398
Eric Andersenc470f442003-07-28 09:56:35 +00008399char *
8400stputs(const char *s, char *p)
8401{
8402 return stnputs(s, strlen(s), p);
8403}
8404
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008405/* mystring.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008406
Eric Andersencb57d552001-06-28 07:25:16 +00008407/*
Eric Andersenc470f442003-07-28 09:56:35 +00008408 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008409 *
Eric Andersenc470f442003-07-28 09:56:35 +00008410 * number(s) Convert a string of digits to an integer.
8411 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008412 */
8413
Eric Andersencb57d552001-06-28 07:25:16 +00008414/*
8415 * prefix -- see if pfx is a prefix of string.
8416 */
8417
Eric Andersenc470f442003-07-28 09:56:35 +00008418char *
8419prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008420{
Eric Andersencb57d552001-06-28 07:25:16 +00008421 while (*pfx) {
8422 if (*pfx++ != *string++)
8423 return 0;
8424 }
Eric Andersenc470f442003-07-28 09:56:35 +00008425 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008426}
8427
8428
8429/*
8430 * Convert a string of digits to an integer, printing an error message on
8431 * failure.
8432 */
8433
Eric Andersenc470f442003-07-28 09:56:35 +00008434int
8435number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008436{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008437
Eric Andersenc470f442003-07-28 09:56:35 +00008438 if (! is_number(s))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008439 sh_error(illnum, s);
Eric Andersenc470f442003-07-28 09:56:35 +00008440 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008441}
8442
Eric Andersenc470f442003-07-28 09:56:35 +00008443
Eric Andersenc470f442003-07-28 09:56:35 +00008444/*
8445 * Check for a valid number. This should be elsewhere.
8446 */
8447
8448int
8449is_number(const char *p)
8450{
8451 do {
8452 if (! is_digit(*p))
8453 return 0;
8454 } while (*++p != '\0');
8455 return 1;
8456}
8457
8458
Eric Andersencb57d552001-06-28 07:25:16 +00008459/*
8460 * Produce a possibly single quoted string suitable as input to the shell.
8461 * The return string is allocated on the stack.
8462 */
8463
Eric Andersenc470f442003-07-28 09:56:35 +00008464char *
8465single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008466 char *p;
8467
8468 STARTSTACKSTR(p);
8469
8470 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008471 char *q;
8472 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008473
Eric Andersenc470f442003-07-28 09:56:35 +00008474 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008475
Eric Andersenc470f442003-07-28 09:56:35 +00008476 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008477
Eric Andersenc470f442003-07-28 09:56:35 +00008478 *q++ = '\'';
8479 q = mempcpy(q, s, len);
8480 *q++ = '\'';
8481 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008482
Eric Andersenc470f442003-07-28 09:56:35 +00008483 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008484
Eric Andersenc470f442003-07-28 09:56:35 +00008485 len = strspn(s, "'");
8486 if (!len)
8487 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008488
Eric Andersenc470f442003-07-28 09:56:35 +00008489 q = p = makestrspace(len + 3, p);
8490
8491 *q++ = '"';
8492 q = mempcpy(q, s, len);
8493 *q++ = '"';
8494 s += len;
8495
8496 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008497 } while (*s);
8498
8499 USTPUTC(0, p);
8500
Eric Andersenc470f442003-07-28 09:56:35 +00008501 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008502}
8503
8504/*
Eric Andersenc470f442003-07-28 09:56:35 +00008505 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008506 */
8507
Eric Andersenc470f442003-07-28 09:56:35 +00008508char *
8509sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008510{
Eric Andersenc470f442003-07-28 09:56:35 +00008511 size_t len = strlen(p) + 1;
8512 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008513}
Eric Andersenc470f442003-07-28 09:56:35 +00008514
8515
8516static void
8517calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008518{
Eric Andersenc470f442003-07-28 09:56:35 +00008519 if (n == NULL)
8520 return;
8521 funcblocksize += nodesize[n->type];
8522 switch (n->type) {
8523 case NCMD:
8524 calcsize(n->ncmd.redirect);
8525 calcsize(n->ncmd.args);
8526 calcsize(n->ncmd.assign);
8527 break;
8528 case NPIPE:
8529 sizenodelist(n->npipe.cmdlist);
8530 break;
8531 case NREDIR:
8532 case NBACKGND:
8533 case NSUBSHELL:
8534 calcsize(n->nredir.redirect);
8535 calcsize(n->nredir.n);
8536 break;
8537 case NAND:
8538 case NOR:
8539 case NSEMI:
8540 case NWHILE:
8541 case NUNTIL:
8542 calcsize(n->nbinary.ch2);
8543 calcsize(n->nbinary.ch1);
8544 break;
8545 case NIF:
8546 calcsize(n->nif.elsepart);
8547 calcsize(n->nif.ifpart);
8548 calcsize(n->nif.test);
8549 break;
8550 case NFOR:
8551 funcstringsize += strlen(n->nfor.var) + 1;
8552 calcsize(n->nfor.body);
8553 calcsize(n->nfor.args);
8554 break;
8555 case NCASE:
8556 calcsize(n->ncase.cases);
8557 calcsize(n->ncase.expr);
8558 break;
8559 case NCLIST:
8560 calcsize(n->nclist.body);
8561 calcsize(n->nclist.pattern);
8562 calcsize(n->nclist.next);
8563 break;
8564 case NDEFUN:
8565 case NARG:
8566 sizenodelist(n->narg.backquote);
8567 funcstringsize += strlen(n->narg.text) + 1;
8568 calcsize(n->narg.next);
8569 break;
8570 case NTO:
8571 case NCLOBBER:
8572 case NFROM:
8573 case NFROMTO:
8574 case NAPPEND:
8575 calcsize(n->nfile.fname);
8576 calcsize(n->nfile.next);
8577 break;
8578 case NTOFD:
8579 case NFROMFD:
8580 calcsize(n->ndup.vname);
8581 calcsize(n->ndup.next);
8582 break;
8583 case NHERE:
8584 case NXHERE:
8585 calcsize(n->nhere.doc);
8586 calcsize(n->nhere.next);
8587 break;
8588 case NNOT:
8589 calcsize(n->nnot.com);
8590 break;
8591 };
Eric Andersencb57d552001-06-28 07:25:16 +00008592}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008593
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008594
Eric Andersenc470f442003-07-28 09:56:35 +00008595static void
8596sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008597{
8598 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008599 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008600 calcsize(lp->n);
8601 lp = lp->next;
8602 }
8603}
Eric Andersencb57d552001-06-28 07:25:16 +00008604
8605
Eric Andersenc470f442003-07-28 09:56:35 +00008606static union node *
8607copynode(union node *n)
8608{
8609 union node *new;
8610
8611 if (n == NULL)
8612 return NULL;
8613 new = funcblock;
8614 funcblock = (char *) funcblock + nodesize[n->type];
8615 switch (n->type) {
8616 case NCMD:
8617 new->ncmd.redirect = copynode(n->ncmd.redirect);
8618 new->ncmd.args = copynode(n->ncmd.args);
8619 new->ncmd.assign = copynode(n->ncmd.assign);
8620 break;
8621 case NPIPE:
8622 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8623 new->npipe.backgnd = n->npipe.backgnd;
8624 break;
8625 case NREDIR:
8626 case NBACKGND:
8627 case NSUBSHELL:
8628 new->nredir.redirect = copynode(n->nredir.redirect);
8629 new->nredir.n = copynode(n->nredir.n);
8630 break;
8631 case NAND:
8632 case NOR:
8633 case NSEMI:
8634 case NWHILE:
8635 case NUNTIL:
8636 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8637 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8638 break;
8639 case NIF:
8640 new->nif.elsepart = copynode(n->nif.elsepart);
8641 new->nif.ifpart = copynode(n->nif.ifpart);
8642 new->nif.test = copynode(n->nif.test);
8643 break;
8644 case NFOR:
8645 new->nfor.var = nodesavestr(n->nfor.var);
8646 new->nfor.body = copynode(n->nfor.body);
8647 new->nfor.args = copynode(n->nfor.args);
8648 break;
8649 case NCASE:
8650 new->ncase.cases = copynode(n->ncase.cases);
8651 new->ncase.expr = copynode(n->ncase.expr);
8652 break;
8653 case NCLIST:
8654 new->nclist.body = copynode(n->nclist.body);
8655 new->nclist.pattern = copynode(n->nclist.pattern);
8656 new->nclist.next = copynode(n->nclist.next);
8657 break;
8658 case NDEFUN:
8659 case NARG:
8660 new->narg.backquote = copynodelist(n->narg.backquote);
8661 new->narg.text = nodesavestr(n->narg.text);
8662 new->narg.next = copynode(n->narg.next);
8663 break;
8664 case NTO:
8665 case NCLOBBER:
8666 case NFROM:
8667 case NFROMTO:
8668 case NAPPEND:
8669 new->nfile.fname = copynode(n->nfile.fname);
8670 new->nfile.fd = n->nfile.fd;
8671 new->nfile.next = copynode(n->nfile.next);
8672 break;
8673 case NTOFD:
8674 case NFROMFD:
8675 new->ndup.vname = copynode(n->ndup.vname);
8676 new->ndup.dupfd = n->ndup.dupfd;
8677 new->ndup.fd = n->ndup.fd;
8678 new->ndup.next = copynode(n->ndup.next);
8679 break;
8680 case NHERE:
8681 case NXHERE:
8682 new->nhere.doc = copynode(n->nhere.doc);
8683 new->nhere.fd = n->nhere.fd;
8684 new->nhere.next = copynode(n->nhere.next);
8685 break;
8686 case NNOT:
8687 new->nnot.com = copynode(n->nnot.com);
8688 break;
8689 };
8690 new->type = n->type;
8691 return new;
8692}
8693
8694
8695static struct nodelist *
8696copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008697{
8698 struct nodelist *start;
8699 struct nodelist **lpp;
8700
8701 lpp = &start;
8702 while (lp) {
8703 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008704 funcblock = (char *) funcblock +
8705 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008706 (*lpp)->n = copynode(lp->n);
8707 lp = lp->next;
8708 lpp = &(*lpp)->next;
8709 }
8710 *lpp = NULL;
8711 return start;
8712}
8713
8714
Eric Andersenc470f442003-07-28 09:56:35 +00008715static char *
8716nodesavestr(char *s)
8717{
8718 char *rtn = funcstring;
8719
8720 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008721 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008722}
8723
Eric Andersenc470f442003-07-28 09:56:35 +00008724
Eric Andersenc470f442003-07-28 09:56:35 +00008725/*
8726 * Free a parse tree.
8727 */
8728
8729static void
8730freefunc(struct funcnode *f)
8731{
8732 if (f && --f->count < 0)
8733 ckfree(f);
8734}
8735
8736
8737static void options(int);
8738static void setoption(int, int);
8739
Eric Andersencb57d552001-06-28 07:25:16 +00008740
Eric Andersencb57d552001-06-28 07:25:16 +00008741/*
8742 * Process the shell command line arguments.
8743 */
8744
Eric Andersenc470f442003-07-28 09:56:35 +00008745void
8746procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008747{
8748 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008749 const char *xminusc;
8750 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008751
Eric Andersenc470f442003-07-28 09:56:35 +00008752 xargv = argv;
8753 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008754 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008755 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008756 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008757 optlist[i] = 2;
8758 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008759 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008760 xargv = argptr;
8761 xminusc = minusc;
8762 if (*xargv == NULL) {
8763 if (xminusc)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008764 sh_error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008765 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008766 }
Eric Andersencb57d552001-06-28 07:25:16 +00008767 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8768 iflag = 1;
8769 if (mflag == 2)
8770 mflag = iflag;
8771 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008772 if (optlist[i] == 2)
8773 optlist[i] = 0;
8774#if DEBUG == 2
8775 debug = 1;
8776#endif
8777 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8778 if (xminusc) {
8779 minusc = *xargv++;
8780 if (*xargv)
8781 goto setarg0;
8782 } else if (!sflag) {
8783 setinputfile(*xargv, 0);
8784setarg0:
8785 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008786 commandname = arg0;
8787 }
Eric Andersencb57d552001-06-28 07:25:16 +00008788
Eric Andersenc470f442003-07-28 09:56:35 +00008789 shellparam.p = xargv;
8790#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008791 shellparam.optind = 1;
8792 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008793#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008794 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008795 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008796 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008797 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008798 }
8799 optschanged();
8800}
8801
8802
Eric Andersenc470f442003-07-28 09:56:35 +00008803void
8804optschanged(void)
8805{
8806#ifdef DEBUG
8807 opentrace();
8808#endif
8809 setinteractive(iflag);
8810 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008811 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008812}
Eric Andersencb57d552001-06-28 07:25:16 +00008813
Eric Andersenc470f442003-07-28 09:56:35 +00008814static inline void
8815minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008816{
8817 int i;
8818
8819 if (name == NULL) {
8820 out1str("Current option settings\n");
8821 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008822 out1fmt("%-16s%s\n", optnames(i),
8823 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008824 } else {
8825 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008826 if (equal(name, optnames(i))) {
8827 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008828 return;
8829 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008830 sh_error("Illegal option -o %s", name);
Eric Andersen62483552001-07-10 06:09:16 +00008831 }
8832}
8833
Eric Andersenc470f442003-07-28 09:56:35 +00008834/*
8835 * Process shell options. The global variable argptr contains a pointer
8836 * to the argument list; we advance it past the options.
8837 */
Eric Andersen62483552001-07-10 06:09:16 +00008838
Eric Andersenc470f442003-07-28 09:56:35 +00008839static void
8840options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008841{
8842 char *p;
8843 int val;
8844 int c;
8845
8846 if (cmdline)
8847 minusc = NULL;
8848 while ((p = *argptr) != NULL) {
8849 argptr++;
8850 if ((c = *p++) == '-') {
8851 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008852 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8853 if (!cmdline) {
8854 /* "-" means turn off -x and -v */
8855 if (p[0] == '\0')
8856 xflag = vflag = 0;
8857 /* "--" means reset params */
8858 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008859 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008860 }
Eric Andersenc470f442003-07-28 09:56:35 +00008861 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008862 }
8863 } else if (c == '+') {
8864 val = 0;
8865 } else {
8866 argptr--;
8867 break;
8868 }
8869 while ((c = *p++) != '\0') {
8870 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008871 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008872 } else if (c == 'o') {
8873 minus_o(*argptr, val);
8874 if (*argptr)
8875 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008876 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008877 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008878 isloginsh = 1;
8879 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008880 } else {
8881 setoption(c, val);
8882 }
8883 }
8884 }
8885}
8886
Eric Andersencb57d552001-06-28 07:25:16 +00008887
Eric Andersenc470f442003-07-28 09:56:35 +00008888static void
8889setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008890{
Eric Andersencb57d552001-06-28 07:25:16 +00008891 int i;
8892
8893 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008894 if (optletters(i) == flag) {
8895 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008896 return;
8897 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008898 sh_error("Illegal option -%c", flag);
Eric Andersencb57d552001-06-28 07:25:16 +00008899 /* NOTREACHED */
8900}
8901
8902
8903
Eric Andersencb57d552001-06-28 07:25:16 +00008904/*
8905 * Set the shell parameters.
8906 */
8907
Eric Andersenc470f442003-07-28 09:56:35 +00008908void
8909setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008910{
Eric Andersencb57d552001-06-28 07:25:16 +00008911 char **newparam;
8912 char **ap;
8913 int nparam;
8914
Eric Andersenc470f442003-07-28 09:56:35 +00008915 for (nparam = 0 ; argv[nparam] ; nparam++);
8916 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008917 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008918 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008919 }
8920 *ap = NULL;
8921 freeparam(&shellparam);
8922 shellparam.malloc = 1;
8923 shellparam.nparam = nparam;
8924 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008925#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008926 shellparam.optind = 1;
8927 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008928#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008929}
8930
8931
8932/*
8933 * Free the list of positional parameters.
8934 */
8935
Eric Andersenc470f442003-07-28 09:56:35 +00008936void
8937freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008938{
Eric Andersencb57d552001-06-28 07:25:16 +00008939 char **ap;
8940
8941 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008942 for (ap = param->p ; *ap ; ap++)
8943 ckfree(*ap);
8944 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008945 }
8946}
8947
8948
8949
8950/*
8951 * The shift builtin command.
8952 */
8953
Eric Andersenc470f442003-07-28 09:56:35 +00008954int
8955shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008956{
8957 int n;
8958 char **ap1, **ap2;
8959
8960 n = 1;
8961 if (argc > 1)
8962 n = number(argv[1]);
8963 if (n > shellparam.nparam)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008964 sh_error("can't shift that many");
Eric Andersencb57d552001-06-28 07:25:16 +00008965 INTOFF;
8966 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008967 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008968 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008969 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008970 }
8971 ap2 = shellparam.p;
8972 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008973#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008974 shellparam.optind = 1;
8975 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008976#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008977 INTON;
8978 return 0;
8979}
8980
8981
8982
8983/*
8984 * The set command builtin.
8985 */
8986
Eric Andersenc470f442003-07-28 09:56:35 +00008987int
8988setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008989{
8990 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00008991 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00008992 INTOFF;
8993 options(0);
8994 optschanged();
8995 if (*argptr != NULL) {
8996 setparam(argptr);
8997 }
8998 INTON;
8999 return 0;
9000}
9001
9002
Eric Andersenc470f442003-07-28 09:56:35 +00009003#ifdef CONFIG_ASH_GETOPTS
9004static void
9005getoptsreset(value)
9006 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009007{
9008 shellparam.optind = number(value);
9009 shellparam.optoff = -1;
9010}
Eric Andersenc470f442003-07-28 09:56:35 +00009011#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009012
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009013#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009014static void change_lc_all(const char *value)
9015{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009016 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009017 setlocale(LC_ALL, value);
9018}
9019
9020static void change_lc_ctype(const char *value)
9021{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009022 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009023 setlocale(LC_CTYPE, value);
9024}
9025
9026#endif
9027
Eric Andersen16767e22004-03-16 05:14:10 +00009028#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009029/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009030static void change_random(const char *value)
9031{
Eric Andersen16767e22004-03-16 05:14:10 +00009032 if(value == NULL) {
9033 /* "get", generate */
9034 char buf[16];
9035
9036 rseed = rseed * 1103515245 + 12345;
9037 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9038 /* set without recursion */
9039 setvar(vrandom.text, buf, VNOFUNC);
9040 vrandom.flags &= ~VNOFUNC;
9041 } else {
9042 /* set/reset */
9043 rseed = strtoul(value, (char **)NULL, 10);
9044 }
Eric Andersenef02f822004-03-11 13:34:24 +00009045}
Eric Andersen16767e22004-03-16 05:14:10 +00009046#endif
9047
Eric Andersenef02f822004-03-11 13:34:24 +00009048
Eric Andersend35c5df2002-01-09 15:37:36 +00009049#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009050static int
Eric Andersenc470f442003-07-28 09:56:35 +00009051getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009052{
9053 char *p, *q;
9054 char c = '?';
9055 int done = 0;
9056 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009057 char s[12];
9058 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009059
Eric Andersena48b0a32003-10-22 10:56:47 +00009060 if(*param_optind < 1)
9061 return 1;
9062 optnext = optfirst + *param_optind - 1;
9063
9064 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009065 p = NULL;
9066 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009067 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009068 if (p == NULL || *p == '\0') {
9069 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009070 p = *optnext;
9071 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009072atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009073 p = NULL;
9074 done = 1;
9075 goto out;
9076 }
9077 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009078 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009079 goto atend;
9080 }
9081
9082 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009083 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009084 if (*q == '\0') {
9085 if (optstr[0] == ':') {
9086 s[0] = c;
9087 s[1] = '\0';
9088 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009089 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009090 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009091 (void) unsetvar("OPTARG");
9092 }
9093 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009094 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009095 }
9096 if (*++q == ':')
9097 q++;
9098 }
9099
9100 if (*++q == ':') {
9101 if (*p == '\0' && (p = *optnext) == NULL) {
9102 if (optstr[0] == ':') {
9103 s[0] = c;
9104 s[1] = '\0';
9105 err |= setvarsafe("OPTARG", s, 0);
9106 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009107 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009108 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009109 (void) unsetvar("OPTARG");
9110 c = '?';
9111 }
Eric Andersenc470f442003-07-28 09:56:35 +00009112 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009113 }
9114
9115 if (p == *optnext)
9116 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009117 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009118 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009119 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009120 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009121
Eric Andersenc470f442003-07-28 09:56:35 +00009122out:
Eric Andersencb57d552001-06-28 07:25:16 +00009123 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009124 *param_optind = optnext - optfirst + 1;
9125 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009126 err |= setvarsafe("OPTIND", s, VNOFUNC);
9127 s[0] = c;
9128 s[1] = '\0';
9129 err |= setvarsafe(optvar, s, 0);
9130 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009131 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009132 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009133 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009134 exraise(EXERROR);
9135 }
9136 return done;
9137}
Eric Andersenc470f442003-07-28 09:56:35 +00009138
9139/*
9140 * The getopts builtin. Shellparam.optnext points to the next argument
9141 * to be processed. Shellparam.optptr points to the next character to
9142 * be processed in the current argument. If shellparam.optnext is NULL,
9143 * then it's the first time getopts has been called.
9144 */
9145
9146int
9147getoptscmd(int argc, char **argv)
9148{
9149 char **optbase;
9150
9151 if (argc < 3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009152 sh_error("Usage: getopts optstring var [arg]");
Eric Andersenc470f442003-07-28 09:56:35 +00009153 else if (argc == 3) {
9154 optbase = shellparam.p;
9155 if (shellparam.optind > shellparam.nparam + 1) {
9156 shellparam.optind = 1;
9157 shellparam.optoff = -1;
9158 }
9159 }
9160 else {
9161 optbase = &argv[3];
9162 if (shellparam.optind > argc - 2) {
9163 shellparam.optind = 1;
9164 shellparam.optoff = -1;
9165 }
9166 }
9167
9168 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9169 &shellparam.optoff);
9170}
9171#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009172
9173/*
9174 * XXX - should get rid of. have all builtins use getopt(3). the
9175 * library getopt must have the BSD extension static variable "optreset"
9176 * otherwise it can't be used within the shell safely.
9177 *
9178 * Standard option processing (a la getopt) for builtin routines. The
9179 * only argument that is passed to nextopt is the option string; the
9180 * other arguments are unnecessary. It return the character, or '\0' on
9181 * end of input.
9182 */
9183
Eric Andersenc470f442003-07-28 09:56:35 +00009184static int
9185nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009186{
Eric Andersencb57d552001-06-28 07:25:16 +00009187 char *p;
9188 const char *q;
9189 char c;
9190
9191 if ((p = optptr) == NULL || *p == '\0') {
9192 p = *argptr;
9193 if (p == NULL || *p != '-' || *++p == '\0')
9194 return '\0';
9195 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009196 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009197 return '\0';
9198 }
9199 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009200 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009201 if (*q == '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009202 sh_error("Illegal option -%c", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009203 if (*++q == ':')
9204 q++;
9205 }
9206 if (*++q == ':') {
9207 if (*p == '\0' && (p = *argptr++) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009208 sh_error("No arg for -%c option", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009209 optionarg = p;
9210 p = NULL;
9211 }
9212 optptr = p;
9213 return c;
9214}
9215
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009216
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009217/* output.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009218
Eric Andersenc470f442003-07-28 09:56:35 +00009219void
9220outstr(const char *p, FILE *file)
9221{
9222 INTOFF;
9223 fputs(p, file);
9224 INTON;
9225}
9226
9227void
9228flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009229{
Eric Andersencb57d552001-06-28 07:25:16 +00009230 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009231 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009232 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009233 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009234}
9235
Eric Andersenc470f442003-07-28 09:56:35 +00009236void
Eric Andersen16767e22004-03-16 05:14:10 +00009237flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009238{
9239 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009240 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009241 INTON;
9242}
9243
9244static void
9245outcslow(int c, FILE *dest)
9246{
9247 INTOFF;
9248 putc(c, dest);
9249 fflush(dest);
9250 INTON;
9251}
9252
9253
9254static int
9255out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009256{
9257 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009258 int r;
9259
9260 INTOFF;
9261 va_start(ap, fmt);
9262 r = vprintf(fmt, ap);
9263 va_end(ap);
9264 INTON;
9265 return r;
9266}
9267
9268
9269int
9270fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9271{
9272 va_list ap;
9273 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009274
Eric Andersencb57d552001-06-28 07:25:16 +00009275 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009276 INTOFF;
9277 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009278 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009279 INTON;
9280 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009281}
9282
Eric Andersenc470f442003-07-28 09:56:35 +00009283
Eric Andersencb57d552001-06-28 07:25:16 +00009284
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009285/* parser.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009286
9287
Eric Andersencb57d552001-06-28 07:25:16 +00009288/*
9289 * Shell command parser.
9290 */
9291
9292#define EOFMARKLEN 79
9293
9294
Eric Andersencb57d552001-06-28 07:25:16 +00009295struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009296 struct heredoc *next; /* next here document in list */
9297 union node *here; /* redirection node */
9298 char *eofmark; /* string indicating end of input */
9299 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009300};
9301
9302
9303
Eric Andersenc470f442003-07-28 09:56:35 +00009304static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009305
9306
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009307static union node *list(int);
9308static union node *andor(void);
9309static union node *pipeline(void);
9310static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009311static union node *simplecmd(void);
9312static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009313static void parsefname(void);
9314static void parseheredoc(void);
9315static char peektoken(void);
9316static int readtoken(void);
9317static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009318static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009319static int noexpand(char *);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00009320static void synexpect(int) ATTRIBUTE_NORETURN;
9321static void synerror(const char *) ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009322static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009323
9324
Eric Andersenc470f442003-07-28 09:56:35 +00009325
Eric Andersenc470f442003-07-28 09:56:35 +00009326
Eric Andersencb57d552001-06-28 07:25:16 +00009327/*
9328 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9329 * valid parse tree indicating a blank line.)
9330 */
9331
Eric Andersenc470f442003-07-28 09:56:35 +00009332union node *
9333parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009334{
9335 int t;
9336
9337 tokpushback = 0;
9338 doprompt = interact;
9339 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009340 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009341 needprompt = 0;
9342 t = readtoken();
9343 if (t == TEOF)
9344 return NEOF;
9345 if (t == TNL)
9346 return NULL;
9347 tokpushback++;
9348 return list(1);
9349}
9350
9351
Eric Andersenc470f442003-07-28 09:56:35 +00009352static union node *
9353list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009354{
9355 union node *n1, *n2, *n3;
9356 int tok;
9357
Eric Andersenc470f442003-07-28 09:56:35 +00009358 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9359 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009360 return NULL;
9361 n1 = NULL;
9362 for (;;) {
9363 n2 = andor();
9364 tok = readtoken();
9365 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009366 if (n2->type == NPIPE) {
9367 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009368 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009369 if (n2->type != NREDIR) {
9370 n3 = stalloc(sizeof(struct nredir));
9371 n3->nredir.n = n2;
9372 n3->nredir.redirect = NULL;
9373 n2 = n3;
9374 }
9375 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009376 }
9377 }
9378 if (n1 == NULL) {
9379 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009380 }
9381 else {
9382 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009383 n3->type = NSEMI;
9384 n3->nbinary.ch1 = n1;
9385 n3->nbinary.ch2 = n2;
9386 n1 = n3;
9387 }
9388 switch (tok) {
9389 case TBACKGND:
9390 case TSEMI:
9391 tok = readtoken();
9392 /* fall through */
9393 case TNL:
9394 if (tok == TNL) {
9395 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009396 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009397 return n1;
9398 } else {
9399 tokpushback++;
9400 }
Eric Andersenc470f442003-07-28 09:56:35 +00009401 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009402 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009403 return n1;
9404 break;
9405 case TEOF:
9406 if (heredoclist)
9407 parseheredoc();
9408 else
Eric Andersenc470f442003-07-28 09:56:35 +00009409 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009410 return n1;
9411 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009412 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009413 synexpect(-1);
9414 tokpushback++;
9415 return n1;
9416 }
9417 }
9418}
9419
9420
9421
Eric Andersenc470f442003-07-28 09:56:35 +00009422static union node *
9423andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009424{
Eric Andersencb57d552001-06-28 07:25:16 +00009425 union node *n1, *n2, *n3;
9426 int t;
9427
Eric Andersencb57d552001-06-28 07:25:16 +00009428 n1 = pipeline();
9429 for (;;) {
9430 if ((t = readtoken()) == TAND) {
9431 t = NAND;
9432 } else if (t == TOR) {
9433 t = NOR;
9434 } else {
9435 tokpushback++;
9436 return n1;
9437 }
Eric Andersenc470f442003-07-28 09:56:35 +00009438 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009439 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009440 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009441 n3->type = t;
9442 n3->nbinary.ch1 = n1;
9443 n3->nbinary.ch2 = n2;
9444 n1 = n3;
9445 }
9446}
9447
9448
9449
Eric Andersenc470f442003-07-28 09:56:35 +00009450static union node *
9451pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009452{
Eric Andersencb57d552001-06-28 07:25:16 +00009453 union node *n1, *n2, *pipenode;
9454 struct nodelist *lp, *prev;
9455 int negate;
9456
9457 negate = 0;
9458 TRACE(("pipeline: entered\n"));
9459 if (readtoken() == TNOT) {
9460 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009461 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009462 } else
9463 tokpushback++;
9464 n1 = command();
9465 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009466 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009467 pipenode->type = NPIPE;
9468 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009469 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009470 pipenode->npipe.cmdlist = lp;
9471 lp->n = n1;
9472 do {
9473 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009474 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9475 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009476 lp->n = command();
9477 prev->next = lp;
9478 } while (readtoken() == TPIPE);
9479 lp->next = NULL;
9480 n1 = pipenode;
9481 }
9482 tokpushback++;
9483 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009484 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009485 n2->type = NNOT;
9486 n2->nnot.com = n1;
9487 return n2;
9488 } else
9489 return n1;
9490}
9491
9492
9493
Eric Andersenc470f442003-07-28 09:56:35 +00009494static union node *
9495command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009496{
Eric Andersencb57d552001-06-28 07:25:16 +00009497 union node *n1, *n2;
9498 union node *ap, **app;
9499 union node *cp, **cpp;
9500 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009501 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009502 int t;
9503
9504 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009505 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009506
Eric Andersencb57d552001-06-28 07:25:16 +00009507 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009508 default:
9509 synexpect(-1);
9510 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009511 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009512 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009513 n1->type = NIF;
9514 n1->nif.test = list(0);
9515 if (readtoken() != TTHEN)
9516 synexpect(TTHEN);
9517 n1->nif.ifpart = list(0);
9518 n2 = n1;
9519 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009520 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009521 n2 = n2->nif.elsepart;
9522 n2->type = NIF;
9523 n2->nif.test = list(0);
9524 if (readtoken() != TTHEN)
9525 synexpect(TTHEN);
9526 n2->nif.ifpart = list(0);
9527 }
9528 if (lasttoken == TELSE)
9529 n2->nif.elsepart = list(0);
9530 else {
9531 n2->nif.elsepart = NULL;
9532 tokpushback++;
9533 }
Eric Andersenc470f442003-07-28 09:56:35 +00009534 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009535 break;
9536 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009537 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009538 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009539 n1 = (union node *)stalloc(sizeof (struct nbinary));
9540 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009541 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009542 if ((got=readtoken()) != TDO) {
9543TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009544 synexpect(TDO);
9545 }
9546 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009547 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009548 break;
9549 }
9550 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009551 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009552 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009553 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009554 n1->type = NFOR;
9555 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009556 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009557 if (readtoken() == TIN) {
9558 app = &ap;
9559 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009560 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009561 n2->type = NARG;
9562 n2->narg.text = wordtext;
9563 n2->narg.backquote = backquotelist;
9564 *app = n2;
9565 app = &n2->narg.next;
9566 }
9567 *app = NULL;
9568 n1->nfor.args = ap;
9569 if (lasttoken != TNL && lasttoken != TSEMI)
9570 synexpect(-1);
9571 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009572 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009573 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009574 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009575 n2->narg.backquote = NULL;
9576 n2->narg.next = NULL;
9577 n1->nfor.args = n2;
9578 /*
9579 * Newline or semicolon here is optional (but note
9580 * that the original Bourne shell only allowed NL).
9581 */
9582 if (lasttoken != TNL && lasttoken != TSEMI)
9583 tokpushback++;
9584 }
Eric Andersenc470f442003-07-28 09:56:35 +00009585 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009586 if (readtoken() != TDO)
9587 synexpect(TDO);
9588 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009589 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009590 break;
9591 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009592 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009593 n1->type = NCASE;
9594 if (readtoken() != TWORD)
9595 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009596 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009597 n2->type = NARG;
9598 n2->narg.text = wordtext;
9599 n2->narg.backquote = backquotelist;
9600 n2->narg.next = NULL;
9601 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009602 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009603 } while (readtoken() == TNL);
9604 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009605 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009606 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009607next_case:
9608 checkkwd = CHKNL | CHKKWD;
9609 t = readtoken();
9610 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009611 if (lasttoken == TLP)
9612 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009613 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009614 cp->type = NCLIST;
9615 app = &cp->nclist.pattern;
9616 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009617 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009618 ap->type = NARG;
9619 ap->narg.text = wordtext;
9620 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009621 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009622 break;
9623 app = &ap->narg.next;
9624 readtoken();
9625 }
9626 ap->narg.next = NULL;
9627 if (lasttoken != TRP)
9628 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009629 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009630
Eric Andersenc470f442003-07-28 09:56:35 +00009631 cpp = &cp->nclist.next;
9632
9633 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009634 if ((t = readtoken()) != TESAC) {
9635 if (t != TENDCASE)
9636 synexpect(TENDCASE);
9637 else
Eric Andersenc470f442003-07-28 09:56:35 +00009638 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009639 }
Eric Andersenc470f442003-07-28 09:56:35 +00009640 }
Eric Andersencb57d552001-06-28 07:25:16 +00009641 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009642 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009643 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009644 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009645 n1->type = NSUBSHELL;
9646 n1->nredir.n = list(0);
9647 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009648 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009649 break;
9650 case TBEGIN:
9651 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009652 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009653 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009654 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009655 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009656 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009657 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009658 }
9659
Eric Andersenc470f442003-07-28 09:56:35 +00009660 if (readtoken() != t)
9661 synexpect(t);
9662
9663redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009664 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009665 checkkwd = CHKKWD | CHKALIAS;
9666 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009667 while (readtoken() == TREDIR) {
9668 *rpp = n2 = redirnode;
9669 rpp = &n2->nfile.next;
9670 parsefname();
9671 }
9672 tokpushback++;
9673 *rpp = NULL;
9674 if (redir) {
9675 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009676 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009677 n2->type = NREDIR;
9678 n2->nredir.n = n1;
9679 n1 = n2;
9680 }
9681 n1->nredir.redirect = redir;
9682 }
9683
9684 return n1;
9685}
9686
9687
Eric Andersenc470f442003-07-28 09:56:35 +00009688static union node *
9689simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009690 union node *args, **app;
9691 union node *n = NULL;
9692 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009693 union node **rpp, *redir;
9694 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009695
9696 args = NULL;
9697 app = &args;
9698 vars = NULL;
9699 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009700 redir = NULL;
9701 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009702
Eric Andersenc470f442003-07-28 09:56:35 +00009703 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009704 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009705 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009706 switch (readtoken()) {
9707 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009708 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009709 n->type = NARG;
9710 n->narg.text = wordtext;
9711 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009712 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009713 *vpp = n;
9714 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009715 } else {
9716 *app = n;
9717 app = &n->narg.next;
9718 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009719 }
9720 break;
9721 case TREDIR:
9722 *rpp = n = redirnode;
9723 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009724 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009725 break;
9726 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009727 if (
9728 args && app == &args->narg.next &&
9729 !vars && !redir
9730 ) {
9731 struct builtincmd *bcmd;
9732 const char *name;
9733
Eric Andersencb57d552001-06-28 07:25:16 +00009734 /* We have a function */
9735 if (readtoken() != TRP)
9736 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009737 name = n->narg.text;
9738 if (
9739 !goodname(name) || (
9740 (bcmd = find_builtin(name)) &&
9741 IS_BUILTIN_SPECIAL(bcmd)
9742 )
9743 )
9744 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009745 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009746 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009747 n->narg.next = command();
9748 return n;
9749 }
9750 /* fall through */
9751 default:
9752 tokpushback++;
9753 goto out;
9754 }
9755 }
Eric Andersenc470f442003-07-28 09:56:35 +00009756out:
Eric Andersencb57d552001-06-28 07:25:16 +00009757 *app = NULL;
9758 *vpp = NULL;
9759 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009760 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009761 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009762 n->ncmd.args = args;
9763 n->ncmd.assign = vars;
9764 n->ncmd.redirect = redir;
9765 return n;
9766}
9767
Eric Andersenc470f442003-07-28 09:56:35 +00009768static union node *
9769makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009770{
Eric Andersencb57d552001-06-28 07:25:16 +00009771 union node *n;
9772
Eric Andersenc470f442003-07-28 09:56:35 +00009773 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009774 n->type = NARG;
9775 n->narg.next = NULL;
9776 n->narg.text = wordtext;
9777 n->narg.backquote = backquotelist;
9778 return n;
9779}
9780
Eric Andersenc470f442003-07-28 09:56:35 +00009781void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009782{
Eric Andersencb57d552001-06-28 07:25:16 +00009783 TRACE(("Fix redir %s %d\n", text, err));
9784 if (!err)
9785 n->ndup.vname = NULL;
9786
9787 if (is_digit(text[0]) && text[1] == '\0')
9788 n->ndup.dupfd = digit_val(text[0]);
9789 else if (text[0] == '-' && text[1] == '\0')
9790 n->ndup.dupfd = -1;
9791 else {
9792
9793 if (err)
9794 synerror("Bad fd number");
9795 else
9796 n->ndup.vname = makename();
9797 }
9798}
9799
9800
Eric Andersenc470f442003-07-28 09:56:35 +00009801static void
9802parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009803{
Eric Andersencb57d552001-06-28 07:25:16 +00009804 union node *n = redirnode;
9805
9806 if (readtoken() != TWORD)
9807 synexpect(-1);
9808 if (n->type == NHERE) {
9809 struct heredoc *here = heredoc;
9810 struct heredoc *p;
9811 int i;
9812
9813 if (quoteflag == 0)
9814 n->type = NXHERE;
9815 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009816 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009817 synerror("Illegal eof marker for << redirection");
9818 rmescapes(wordtext);
9819 here->eofmark = wordtext;
9820 here->next = NULL;
9821 if (heredoclist == NULL)
9822 heredoclist = here;
9823 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009824 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009825 p->next = here;
9826 }
9827 } else if (n->type == NTOFD || n->type == NFROMFD) {
9828 fixredir(n, wordtext, 0);
9829 } else {
9830 n->nfile.fname = makename();
9831 }
9832}
9833
9834
9835/*
9836 * Input any here documents.
9837 */
9838
Eric Andersenc470f442003-07-28 09:56:35 +00009839static void
9840parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009841{
Eric Andersencb57d552001-06-28 07:25:16 +00009842 struct heredoc *here;
9843 union node *n;
9844
Eric Andersenc470f442003-07-28 09:56:35 +00009845 here = heredoclist;
9846 heredoclist = 0;
9847
9848 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009849 if (needprompt) {
9850 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009851 }
Eric Andersenc470f442003-07-28 09:56:35 +00009852 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9853 here->eofmark, here->striptabs);
9854 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009855 n->narg.type = NARG;
9856 n->narg.next = NULL;
9857 n->narg.text = wordtext;
9858 n->narg.backquote = backquotelist;
9859 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009860 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009861 }
9862}
9863
Eric Andersenc470f442003-07-28 09:56:35 +00009864static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009865{
Eric Andersencb57d552001-06-28 07:25:16 +00009866 int t;
9867
9868 t = readtoken();
9869 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009870 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009871}
9872
Eric Andersenc470f442003-07-28 09:56:35 +00009873static int
9874readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009875{
Eric Andersencb57d552001-06-28 07:25:16 +00009876 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009877#ifdef DEBUG
9878 int alreadyseen = tokpushback;
9879#endif
9880
Eric Andersend35c5df2002-01-09 15:37:36 +00009881#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009882top:
Eric Andersen2870d962001-07-02 17:27:21 +00009883#endif
9884
Eric Andersencb57d552001-06-28 07:25:16 +00009885 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009886
Eric Andersenc470f442003-07-28 09:56:35 +00009887 /*
9888 * eat newlines
9889 */
9890 if (checkkwd & CHKNL) {
9891 while (t == TNL) {
9892 parseheredoc();
9893 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009894 }
9895 }
9896
Eric Andersenc470f442003-07-28 09:56:35 +00009897 if (t != TWORD || quoteflag) {
9898 goto out;
9899 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009900
Eric Andersenc470f442003-07-28 09:56:35 +00009901 /*
9902 * check for keywords
9903 */
9904 if (checkkwd & CHKKWD) {
9905 const char *const *pp;
9906
9907 if ((pp = findkwd(wordtext))) {
9908 lasttoken = t = pp - tokname_array;
9909 TRACE(("keyword %s recognized\n", tokname(t)));
9910 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009911 }
Eric Andersenc470f442003-07-28 09:56:35 +00009912 }
9913
9914 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009915#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009916 struct alias *ap;
9917 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009918 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009919 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009920 }
Eric Andersencb57d552001-06-28 07:25:16 +00009921 goto top;
9922 }
Eric Andersen2870d962001-07-02 17:27:21 +00009923#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009924 }
Eric Andersenc470f442003-07-28 09:56:35 +00009925out:
9926 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009927#ifdef DEBUG
9928 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009929 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009930 else
Eric Andersenc470f442003-07-28 09:56:35 +00009931 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009932#endif
9933 return (t);
9934}
9935
9936
9937/*
9938 * Read the next input token.
9939 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009940 * backquotes. We set quoteflag to true if any part of the word was
9941 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009942 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009943 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009944 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009945 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009946 *
9947 * [Change comment: here documents and internal procedures]
9948 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9949 * word parsing code into a separate routine. In this case, readtoken
9950 * doesn't need to have any internal procedures, but parseword does.
9951 * We could also make parseoperator in essence the main routine, and
9952 * have parseword (readtoken1?) handle both words and redirection.]
9953 */
9954
Eric Andersen81fe1232003-07-29 06:38:40 +00009955#define NEW_xxreadtoken
9956#ifdef NEW_xxreadtoken
9957
9958/* singles must be first! */
9959static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9960
9961static const char xxreadtoken_tokens[] = {
9962 TNL, TLP, TRP, /* only single occurrence allowed */
9963 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9964 TEOF, /* corresponds to trailing nul */
9965 TAND, TOR, TENDCASE, /* if double occurrence */
9966};
9967
9968#define xxreadtoken_doubles \
9969 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9970#define xxreadtoken_singles \
9971 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9972
9973static int xxreadtoken()
9974{
9975 int c;
9976
9977 if (tokpushback) {
9978 tokpushback = 0;
9979 return lasttoken;
9980 }
9981 if (needprompt) {
9982 setprompt(2);
Eric Andersen81fe1232003-07-29 06:38:40 +00009983 }
9984 startlinno = plinno;
9985 for (;;) { /* until token or start of word found */
9986 c = pgetc_macro();
9987
9988 if ((c != ' ') && (c != '\t')
9989#ifdef CONFIG_ASH_ALIAS
9990 && (c != PEOA)
9991#endif
9992 ) {
9993 if (c == '#') {
9994 while ((c = pgetc()) != '\n' && c != PEOF);
9995 pungetc();
9996 } else if (c == '\\') {
9997 if (pgetc() != '\n') {
9998 pungetc();
9999 goto READTOKEN1;
10000 }
10001 startlinno = ++plinno;
10002 if (doprompt)
10003 setprompt(2);
10004 } else {
10005 const char *p
10006 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10007
10008 if (c != PEOF) {
10009 if (c == '\n') {
10010 plinno++;
10011 needprompt = doprompt;
10012 }
10013
10014 p = strchr(xxreadtoken_chars, c);
10015 if (p == NULL) {
10016 READTOKEN1:
10017 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10018 }
10019
10020 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10021 if (pgetc() == *p) { /* double occurrence? */
10022 p += xxreadtoken_doubles + 1;
10023 } else {
10024 pungetc();
10025 }
10026 }
10027 }
10028
10029 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10030 }
10031 }
10032 }
10033}
10034
10035
10036#else
Eric Andersen2870d962001-07-02 17:27:21 +000010037#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010038
Eric Andersenc470f442003-07-28 09:56:35 +000010039static int
10040xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010041{
Eric Andersencb57d552001-06-28 07:25:16 +000010042 int c;
10043
10044 if (tokpushback) {
10045 tokpushback = 0;
10046 return lasttoken;
10047 }
10048 if (needprompt) {
10049 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010050 }
10051 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010052 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010053 c = pgetc_macro();
10054 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010055 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010056#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010057 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010058#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010059 continue;
10060 case '#':
10061 while ((c = pgetc()) != '\n' && c != PEOF);
10062 pungetc();
10063 continue;
10064 case '\\':
10065 if (pgetc() == '\n') {
10066 startlinno = ++plinno;
10067 if (doprompt)
10068 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010069 continue;
10070 }
10071 pungetc();
10072 goto breakloop;
10073 case '\n':
10074 plinno++;
10075 needprompt = doprompt;
10076 RETURN(TNL);
10077 case PEOF:
10078 RETURN(TEOF);
10079 case '&':
10080 if (pgetc() == '&')
10081 RETURN(TAND);
10082 pungetc();
10083 RETURN(TBACKGND);
10084 case '|':
10085 if (pgetc() == '|')
10086 RETURN(TOR);
10087 pungetc();
10088 RETURN(TPIPE);
10089 case ';':
10090 if (pgetc() == ';')
10091 RETURN(TENDCASE);
10092 pungetc();
10093 RETURN(TSEMI);
10094 case '(':
10095 RETURN(TLP);
10096 case ')':
10097 RETURN(TRP);
10098 default:
10099 goto breakloop;
10100 }
10101 }
Eric Andersenc470f442003-07-28 09:56:35 +000010102breakloop:
10103 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010104#undef RETURN
10105}
Eric Andersen81fe1232003-07-29 06:38:40 +000010106#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010107
Eric Andersencb57d552001-06-28 07:25:16 +000010108
Eric Andersencb57d552001-06-28 07:25:16 +000010109/*
10110 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10111 * is not NULL, read a here document. In the latter case, eofmark is the
10112 * word which marks the end of the document and striptabs is true if
10113 * leading tabs should be stripped from the document. The argument firstc
10114 * is the first character of the input token or document.
10115 *
10116 * Because C does not have internal subroutines, I have simulated them
10117 * using goto's to implement the subroutine linkage. The following macros
10118 * will run code that appears at the end of readtoken1.
10119 */
10120
Eric Andersen2870d962001-07-02 17:27:21 +000010121#define CHECKEND() {goto checkend; checkend_return:;}
10122#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10123#define PARSESUB() {goto parsesub; parsesub_return:;}
10124#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10125#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10126#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010127
10128static int
Eric Andersenc470f442003-07-28 09:56:35 +000010129readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010130{
Eric Andersencb57d552001-06-28 07:25:16 +000010131 int c = firstc;
10132 char *out;
10133 int len;
10134 char line[EOFMARKLEN + 1];
10135 struct nodelist *bqlist;
10136 int quotef;
10137 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010138 int varnest; /* levels of variables expansion */
10139 int arinest; /* levels of arithmetic expansion */
10140 int parenlevel; /* levels of parens in arithmetic */
10141 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010142 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010143 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010144#if __GNUC__
10145 /* Avoid longjmp clobbering */
10146 (void) &out;
10147 (void) &quotef;
10148 (void) &dblquote;
10149 (void) &varnest;
10150 (void) &arinest;
10151 (void) &parenlevel;
10152 (void) &dqvarnest;
10153 (void) &oldstyle;
10154 (void) &prevsyntax;
10155 (void) &syntax;
10156#endif
10157
10158 startlinno = plinno;
10159 dblquote = 0;
10160 if (syntax == DQSYNTAX)
10161 dblquote = 1;
10162 quotef = 0;
10163 bqlist = NULL;
10164 varnest = 0;
10165 arinest = 0;
10166 parenlevel = 0;
10167 dqvarnest = 0;
10168
10169 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010170 loop: { /* for each line, until end of word */
10171 CHECKEND(); /* set c to PEOF if at end of here document */
10172 for (;;) { /* until end of line or end of word */
10173 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10174 switch(SIT(c, syntax)) {
10175 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010176 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010177 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010178 USTPUTC(c, out);
10179 plinno++;
10180 if (doprompt)
10181 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010182 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010183 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010184 case CWORD:
10185 USTPUTC(c, out);
10186 break;
10187 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010188 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010189 USTPUTC(CTLESC, out);
10190 USTPUTC(c, out);
10191 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010192 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010193 c = pgetc2();
10194 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010195 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010196 USTPUTC('\\', out);
10197 pungetc();
10198 } else if (c == '\n') {
10199 if (doprompt)
10200 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010201 } else {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010202 if (dblquote &&
Eric Andersenc470f442003-07-28 09:56:35 +000010203 c != '\\' && c != '`' &&
10204 c != '$' && (
10205 c != '"' ||
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010206 eofmark != NULL)
Eric Andersenc470f442003-07-28 09:56:35 +000010207 ) {
10208 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010209 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010210 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010211 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010212 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010213 USTPUTC(c, out);
10214 quotef++;
10215 }
10216 break;
10217 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010218 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010219quotemark:
10220 if (eofmark == NULL) {
10221 USTPUTC(CTLQUOTEMARK, out);
10222 }
Eric Andersencb57d552001-06-28 07:25:16 +000010223 break;
10224 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010225 syntax = DQSYNTAX;
10226 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010227 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010228 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010229 if (eofmark != NULL && arinest == 0 &&
10230 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010231 USTPUTC(c, out);
10232 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010233 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010234 syntax = BASESYNTAX;
10235 dblquote = 0;
10236 }
10237 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010238 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010239 }
10240 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010241 case CVAR: /* '$' */
10242 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010243 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010244 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010245 if (varnest > 0) {
10246 varnest--;
10247 if (dqvarnest > 0) {
10248 dqvarnest--;
10249 }
10250 USTPUTC(CTLENDVAR, out);
10251 } else {
10252 USTPUTC(c, out);
10253 }
10254 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010255#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010256 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010257 parenlevel++;
10258 USTPUTC(c, out);
10259 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010260 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010261 if (parenlevel > 0) {
10262 USTPUTC(c, out);
10263 --parenlevel;
10264 } else {
10265 if (pgetc() == ')') {
10266 if (--arinest == 0) {
10267 USTPUTC(CTLENDARI, out);
10268 syntax = prevsyntax;
10269 if (syntax == DQSYNTAX)
10270 dblquote = 1;
10271 else
10272 dblquote = 0;
10273 } else
10274 USTPUTC(')', out);
10275 } else {
10276 /*
10277 * unbalanced parens
10278 * (don't 2nd guess - no error)
10279 */
10280 pungetc();
10281 USTPUTC(')', out);
10282 }
10283 }
10284 break;
10285#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010286 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010287 PARSEBACKQOLD();
10288 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010289 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010290 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010291 case CIGN:
10292 break;
10293 default:
10294 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010295 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010296#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010297 if (c != PEOA)
10298#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010299 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010300
Eric Andersencb57d552001-06-28 07:25:16 +000010301 }
10302 c = pgetc_macro();
10303 }
10304 }
Eric Andersenc470f442003-07-28 09:56:35 +000010305endword:
10306#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010307 if (syntax == ARISYNTAX)
10308 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010309#endif
10310 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010311 synerror("Unterminated quoted string");
10312 if (varnest != 0) {
10313 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010314 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010315 synerror("Missing '}'");
10316 }
10317 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010318 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010319 out = stackblock();
10320 if (eofmark == NULL) {
10321 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010322 && quotef == 0
10323 && len <= 2
10324 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010325 PARSEREDIR();
10326 return lasttoken = TREDIR;
10327 } else {
10328 pungetc();
10329 }
10330 }
10331 quoteflag = quotef;
10332 backquotelist = bqlist;
10333 grabstackblock(len);
10334 wordtext = out;
10335 return lasttoken = TWORD;
10336/* end of readtoken routine */
10337
10338
10339
10340/*
10341 * Check to see whether we are at the end of the here document. When this
10342 * is called, c is set to the first character of the next input line. If
10343 * we are at the end of the here document, this routine sets the c to PEOF.
10344 */
10345
Eric Andersenc470f442003-07-28 09:56:35 +000010346checkend: {
10347 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010348#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010349 if (c == PEOA) {
10350 c = pgetc2();
10351 }
10352#endif
10353 if (striptabs) {
10354 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010355 c = pgetc2();
10356 }
Eric Andersenc470f442003-07-28 09:56:35 +000010357 }
10358 if (c == *eofmark) {
10359 if (pfgets(line, sizeof line) != NULL) {
10360 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010361
Eric Andersenc470f442003-07-28 09:56:35 +000010362 p = line;
10363 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10364 if (*p == '\n' && *q == '\0') {
10365 c = PEOF;
10366 plinno++;
10367 needprompt = doprompt;
10368 } else {
10369 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010370 }
10371 }
10372 }
10373 }
Eric Andersenc470f442003-07-28 09:56:35 +000010374 goto checkend_return;
10375}
Eric Andersencb57d552001-06-28 07:25:16 +000010376
10377
10378/*
10379 * Parse a redirection operator. The variable "out" points to a string
10380 * specifying the fd to be redirected. The variable "c" contains the
10381 * first character of the redirection operator.
10382 */
10383
Eric Andersenc470f442003-07-28 09:56:35 +000010384parseredir: {
10385 char fd = *out;
10386 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010387
Eric Andersenc470f442003-07-28 09:56:35 +000010388 np = (union node *)stalloc(sizeof (struct nfile));
10389 if (c == '>') {
10390 np->nfile.fd = 1;
10391 c = pgetc();
10392 if (c == '>')
10393 np->type = NAPPEND;
10394 else if (c == '|')
10395 np->type = NCLOBBER;
10396 else if (c == '&')
10397 np->type = NTOFD;
10398 else {
10399 np->type = NTO;
10400 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010401 }
Eric Andersenc470f442003-07-28 09:56:35 +000010402 } else { /* c == '<' */
10403 np->nfile.fd = 0;
10404 switch (c = pgetc()) {
10405 case '<':
10406 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10407 np = (union node *)stalloc(sizeof (struct nhere));
10408 np->nfile.fd = 0;
10409 }
10410 np->type = NHERE;
10411 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10412 heredoc->here = np;
10413 if ((c = pgetc()) == '-') {
10414 heredoc->striptabs = 1;
10415 } else {
10416 heredoc->striptabs = 0;
10417 pungetc();
10418 }
10419 break;
10420
10421 case '&':
10422 np->type = NFROMFD;
10423 break;
10424
10425 case '>':
10426 np->type = NFROMTO;
10427 break;
10428
10429 default:
10430 np->type = NFROM;
10431 pungetc();
10432 break;
10433 }
Eric Andersencb57d552001-06-28 07:25:16 +000010434 }
Eric Andersenc470f442003-07-28 09:56:35 +000010435 if (fd != '\0')
10436 np->nfile.fd = digit_val(fd);
10437 redirnode = np;
10438 goto parseredir_return;
10439}
Eric Andersencb57d552001-06-28 07:25:16 +000010440
10441
10442/*
10443 * Parse a substitution. At this point, we have read the dollar sign
10444 * and nothing else.
10445 */
10446
Eric Andersenc470f442003-07-28 09:56:35 +000010447parsesub: {
10448 int subtype;
10449 int typeloc;
10450 int flags;
10451 char *p;
10452 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010453
Eric Andersenc470f442003-07-28 09:56:35 +000010454 c = pgetc();
10455 if (
10456 c <= PEOA_OR_PEOF ||
10457 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10458 ) {
10459 USTPUTC('$', out);
10460 pungetc();
10461 } else if (c == '(') { /* $(command) or $((arith)) */
10462 if (pgetc() == '(') {
10463#ifdef CONFIG_ASH_MATH_SUPPORT
10464 PARSEARITH();
10465#else
10466 synerror("We unsupport $((arith))");
10467#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010468 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010469 pungetc();
10470 PARSEBACKQNEW();
10471 }
10472 } else {
10473 USTPUTC(CTLVAR, out);
10474 typeloc = out - (char *)stackblock();
10475 USTPUTC(VSNORMAL, out);
10476 subtype = VSNORMAL;
10477 if (c == '{') {
10478 c = pgetc();
10479 if (c == '#') {
10480 if ((c = pgetc()) == '}')
10481 c = '#';
10482 else
10483 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010484 }
Eric Andersenc470f442003-07-28 09:56:35 +000010485 else
10486 subtype = 0;
10487 }
10488 if (c > PEOA_OR_PEOF && is_name(c)) {
10489 do {
10490 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010491 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010492 } while (c > PEOA_OR_PEOF && is_in_name(c));
10493 } else if (is_digit(c)) {
10494 do {
10495 STPUTC(c, out);
10496 c = pgetc();
10497 } while (is_digit(c));
10498 }
10499 else if (is_special(c)) {
10500 USTPUTC(c, out);
10501 c = pgetc();
10502 }
10503 else
10504badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010505
Eric Andersenc470f442003-07-28 09:56:35 +000010506 STPUTC('=', out);
10507 flags = 0;
10508 if (subtype == 0) {
10509 switch (c) {
10510 case ':':
10511 flags = VSNUL;
10512 c = pgetc();
10513 /*FALLTHROUGH*/
10514 default:
10515 p = strchr(types, c);
10516 if (p == NULL)
10517 goto badsub;
10518 subtype = p - types + VSNORMAL;
10519 break;
10520 case '%':
10521 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010522 {
10523 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010524 subtype = c == '#' ? VSTRIMLEFT :
10525 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010526 c = pgetc();
10527 if (c == cc)
10528 subtype++;
10529 else
10530 pungetc();
10531 break;
10532 }
10533 }
Eric Andersenc470f442003-07-28 09:56:35 +000010534 } else {
10535 pungetc();
10536 }
10537 if (dblquote || arinest)
10538 flags |= VSQUOTE;
10539 *((char *)stackblock() + typeloc) = subtype | flags;
10540 if (subtype != VSNORMAL) {
10541 varnest++;
10542 if (dblquote || arinest) {
10543 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010544 }
10545 }
10546 }
Eric Andersenc470f442003-07-28 09:56:35 +000010547 goto parsesub_return;
10548}
Eric Andersencb57d552001-06-28 07:25:16 +000010549
10550
10551/*
10552 * Called to parse command substitutions. Newstyle is set if the command
10553 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10554 * list of commands (passed by reference), and savelen is the number of
10555 * characters on the top of the stack which must be preserved.
10556 */
10557
Eric Andersenc470f442003-07-28 09:56:35 +000010558parsebackq: {
10559 struct nodelist **nlpp;
10560 int savepbq;
10561 union node *n;
10562 char *volatile str;
10563 struct jmploc jmploc;
10564 struct jmploc *volatile savehandler;
10565 size_t savelen;
10566 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010567#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010568 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010569#endif
10570
Eric Andersenc470f442003-07-28 09:56:35 +000010571 savepbq = parsebackquote;
10572 if (setjmp(jmploc.loc)) {
10573 if (str)
10574 ckfree(str);
10575 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010576 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010577 longjmp(handler->loc, 1);
10578 }
10579 INTOFF;
10580 str = NULL;
10581 savelen = out - (char *)stackblock();
10582 if (savelen > 0) {
10583 str = ckmalloc(savelen);
10584 memcpy(str, stackblock(), savelen);
10585 }
10586 savehandler = handler;
10587 handler = &jmploc;
10588 INTON;
10589 if (oldstyle) {
10590 /* We must read until the closing backquote, giving special
10591 treatment to some slashes, and then push the string and
10592 reread it as input, interpreting it normally. */
10593 char *pout;
10594 int pc;
10595 size_t psavelen;
10596 char *pstr;
10597
10598
10599 STARTSTACKSTR(pout);
10600 for (;;) {
10601 if (needprompt) {
10602 setprompt(2);
Eric Andersenc470f442003-07-28 09:56:35 +000010603 }
10604 switch (pc = pgetc()) {
10605 case '`':
10606 goto done;
10607
10608 case '\\':
10609 if ((pc = pgetc()) == '\n') {
10610 plinno++;
10611 if (doprompt)
10612 setprompt(2);
10613 /*
10614 * If eating a newline, avoid putting
10615 * the newline into the new character
10616 * stream (via the STPUTC after the
10617 * switch).
10618 */
10619 continue;
10620 }
10621 if (pc != '\\' && pc != '`' && pc != '$'
10622 && (!dblquote || pc != '"'))
10623 STPUTC('\\', pout);
10624 if (pc > PEOA_OR_PEOF) {
10625 break;
10626 }
10627 /* fall through */
10628
10629 case PEOF:
10630#ifdef CONFIG_ASH_ALIAS
10631 case PEOA:
10632#endif
10633 startlinno = plinno;
10634 synerror("EOF in backquote substitution");
10635
10636 case '\n':
10637 plinno++;
10638 needprompt = doprompt;
10639 break;
10640
10641 default:
10642 break;
10643 }
10644 STPUTC(pc, pout);
10645 }
10646done:
10647 STPUTC('\0', pout);
10648 psavelen = pout - (char *)stackblock();
10649 if (psavelen > 0) {
10650 pstr = grabstackstr(pout);
10651 setinputstring(pstr);
10652 }
10653 }
10654 nlpp = &bqlist;
10655 while (*nlpp)
10656 nlpp = &(*nlpp)->next;
10657 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10658 (*nlpp)->next = NULL;
10659 parsebackquote = oldstyle;
10660
10661 if (oldstyle) {
10662 saveprompt = doprompt;
10663 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010664 }
10665
Eric Andersenc470f442003-07-28 09:56:35 +000010666 n = list(2);
10667
10668 if (oldstyle)
10669 doprompt = saveprompt;
10670 else {
10671 if (readtoken() != TRP)
10672 synexpect(TRP);
10673 }
10674
10675 (*nlpp)->n = n;
10676 if (oldstyle) {
10677 /*
10678 * Start reading from old file again, ignoring any pushed back
10679 * tokens left from the backquote parsing
10680 */
10681 popfile();
10682 tokpushback = 0;
10683 }
10684 while (stackblocksize() <= savelen)
10685 growstackblock();
10686 STARTSTACKSTR(out);
10687 if (str) {
10688 memcpy(out, str, savelen);
10689 STADJUST(savelen, out);
10690 INTOFF;
10691 ckfree(str);
10692 str = NULL;
10693 INTON;
10694 }
10695 parsebackquote = savepbq;
10696 handler = savehandler;
10697 if (arinest || dblquote)
10698 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10699 else
10700 USTPUTC(CTLBACKQ, out);
10701 if (oldstyle)
10702 goto parsebackq_oldreturn;
10703 else
10704 goto parsebackq_newreturn;
10705}
10706
10707#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010708/*
10709 * Parse an arithmetic expansion (indicate start of one and set state)
10710 */
Eric Andersenc470f442003-07-28 09:56:35 +000010711parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010712
Eric Andersenc470f442003-07-28 09:56:35 +000010713 if (++arinest == 1) {
10714 prevsyntax = syntax;
10715 syntax = ARISYNTAX;
10716 USTPUTC(CTLARI, out);
10717 if (dblquote)
10718 USTPUTC('"',out);
10719 else
10720 USTPUTC(' ',out);
10721 } else {
10722 /*
10723 * we collapse embedded arithmetic expansion to
10724 * parenthesis, which should be equivalent
10725 */
10726 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010727 }
Eric Andersenc470f442003-07-28 09:56:35 +000010728 goto parsearith_return;
10729}
10730#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010731
Eric Andersenc470f442003-07-28 09:56:35 +000010732} /* end of readtoken */
10733
Eric Andersencb57d552001-06-28 07:25:16 +000010734
10735
Eric Andersencb57d552001-06-28 07:25:16 +000010736/*
10737 * Returns true if the text contains nothing to expand (no dollar signs
10738 * or backquotes).
10739 */
10740
Eric Andersenc470f442003-07-28 09:56:35 +000010741static int
10742noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010743{
Eric Andersencb57d552001-06-28 07:25:16 +000010744 char *p;
10745 char c;
10746
10747 p = text;
10748 while ((c = *p++) != '\0') {
10749 if (c == CTLQUOTEMARK)
10750 continue;
10751 if (c == CTLESC)
10752 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010753 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010754 return 0;
10755 }
10756 return 1;
10757}
10758
10759
10760/*
Eric Andersenc470f442003-07-28 09:56:35 +000010761 * Return of a legal variable name (a letter or underscore followed by zero or
10762 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010763 */
10764
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010765static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010766endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010767{
Eric Andersenc470f442003-07-28 09:56:35 +000010768 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010769
Eric Andersenc470f442003-07-28 09:56:35 +000010770 p = (char *) name;
10771 if (! is_name(*p))
10772 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010773 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010774 if (! is_in_name(*p))
10775 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010776 }
Eric Andersenc470f442003-07-28 09:56:35 +000010777 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010778}
10779
10780
10781/*
10782 * Called when an unexpected token is read during the parse. The argument
10783 * is the token that is expected, or -1 if more than one type of token can
10784 * occur at this point.
10785 */
10786
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010787static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010788{
10789 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010790 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010791
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010792 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10793 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010794 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010795 synerror(msg);
10796 /* NOTREACHED */
10797}
10798
Eric Andersenc470f442003-07-28 09:56:35 +000010799static void
10800synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010801{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010802 sh_error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010803 /* NOTREACHED */
10804}
10805
Eric Andersencb57d552001-06-28 07:25:16 +000010806
10807/*
10808 * called by editline -- any expansions to the prompt
10809 * should be added here.
10810 */
Eric Andersenc470f442003-07-28 09:56:35 +000010811
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010812#ifdef CONFIG_ASH_EXPAND_PRMT
10813static const char *
10814expandstr(const char *ps)
10815{
10816 union node n;
10817
10818 /* XXX Fix (char *) cast. */
10819 setinputstring((char *)ps);
10820 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10821 popfile();
10822
10823 n.narg.type = NARG;
10824 n.narg.next = NULL;
10825 n.narg.text = wordtext;
10826 n.narg.backquote = backquotelist;
10827
10828 expandarg(&n, NULL, 0);
10829 return stackblock();
10830}
10831#endif
10832
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010833static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010834{
Eric Andersenc470f442003-07-28 09:56:35 +000010835 const char *prompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010836#ifdef CONFIG_ASH_EXPAND_PRMT
10837 struct stackmark smark;
10838#endif
10839
10840 needprompt = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010841
10842 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010843 case 1:
10844 prompt = ps1val();
10845 break;
10846 case 2:
10847 prompt = ps2val();
10848 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010849 default: /* 0 */
10850 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010851 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010852#ifdef CONFIG_ASH_EXPAND_PRMT
10853 setstackmark(&smark);
10854 stalloc(stackblocksize());
10855#endif
10856 putprompt(expandstr(prompt));
10857#ifdef CONFIG_ASH_EXPAND_PRMT
10858 popstackmark(&smark);
10859#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010860}
10861
Eric Andersencb57d552001-06-28 07:25:16 +000010862
Eric Andersenc470f442003-07-28 09:56:35 +000010863static const char *const *findkwd(const char *s)
10864{
10865 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010866 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010867 sizeof(const char *), pstrcmp);
10868}
10869
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010870/* redir.c */
Eric Andersenc470f442003-07-28 09:56:35 +000010871
Eric Andersencb57d552001-06-28 07:25:16 +000010872/*
10873 * Code for dealing with input/output redirection.
10874 */
10875
Eric Andersenc470f442003-07-28 09:56:35 +000010876#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010877#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010878# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010879#else
10880# define PIPESIZE PIPE_BUF
10881#endif
10882
Eric Andersen62483552001-07-10 06:09:16 +000010883/*
10884 * Open a file in noclobber mode.
10885 * The code was copied from bash.
10886 */
Eric Andersenc470f442003-07-28 09:56:35 +000010887static inline int
10888noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010889{
10890 int r, fd;
10891 struct stat finfo, finfo2;
10892
10893 /*
10894 * If the file exists and is a regular file, return an error
10895 * immediately.
10896 */
10897 r = stat(fname, &finfo);
10898 if (r == 0 && S_ISREG(finfo.st_mode)) {
10899 errno = EEXIST;
10900 return -1;
10901 }
10902
10903 /*
10904 * If the file was not present (r != 0), make sure we open it
10905 * exclusively so that if it is created before we open it, our open
10906 * will fail. Make sure that we do not truncate an existing file.
10907 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10908 * file was not a regular file, we leave O_EXCL off.
10909 */
10910 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010911 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10912 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010913
10914 /* If the open failed, return the file descriptor right away. */
10915 if (fd < 0)
10916 return fd;
10917
10918 /*
10919 * OK, the open succeeded, but the file may have been changed from a
10920 * non-regular file to a regular file between the stat and the open.
10921 * We are assuming that the O_EXCL open handles the case where FILENAME
10922 * did not exist and is symlinked to an existing file between the stat
10923 * and open.
10924 */
10925
10926 /*
10927 * If we can open it and fstat the file descriptor, and neither check
10928 * revealed that it was a regular file, and the file has not been
10929 * replaced, return the file descriptor.
10930 */
Eric Andersenc470f442003-07-28 09:56:35 +000010931 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10932 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010933 return fd;
10934
10935 /* The file has been replaced. badness. */
10936 close(fd);
10937 errno = EEXIST;
10938 return -1;
10939}
Eric Andersencb57d552001-06-28 07:25:16 +000010940
10941/*
Eric Andersen62483552001-07-10 06:09:16 +000010942 * Handle here documents. Normally we fork off a process to write the
10943 * data to a pipe. If the document is short, we can stuff the data in
10944 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010945 */
10946
Eric Andersenc470f442003-07-28 09:56:35 +000010947static inline int
10948openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010949{
10950 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010951 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010952
Eric Andersen62483552001-07-10 06:09:16 +000010953 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010954 sh_error("Pipe call failed");
Eric Andersen62483552001-07-10 06:09:16 +000010955 if (redir->type == NHERE) {
10956 len = strlen(redir->nhere.doc->narg.text);
10957 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010958 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010959 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010960 }
Eric Andersencb57d552001-06-28 07:25:16 +000010961 }
Eric Andersenc470f442003-07-28 09:56:35 +000010962 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010963 close(pip[0]);
10964 signal(SIGINT, SIG_IGN);
10965 signal(SIGQUIT, SIG_IGN);
10966 signal(SIGHUP, SIG_IGN);
10967#ifdef SIGTSTP
10968 signal(SIGTSTP, SIG_IGN);
10969#endif
10970 signal(SIGPIPE, SIG_DFL);
10971 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000010972 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010973 else
10974 expandhere(redir->nhere.doc, pip[1]);
10975 _exit(0);
10976 }
Eric Andersenc470f442003-07-28 09:56:35 +000010977out:
Eric Andersen62483552001-07-10 06:09:16 +000010978 close(pip[1]);
10979 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010980}
10981
Eric Andersenc470f442003-07-28 09:56:35 +000010982static int
10983openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010984{
Eric Andersencb57d552001-06-28 07:25:16 +000010985 char *fname;
10986 int f;
10987
10988 switch (redir->nfile.type) {
10989 case NFROM:
10990 fname = redir->nfile.expfname;
10991 if ((f = open(fname, O_RDONLY)) < 0)
10992 goto eopen;
10993 break;
10994 case NFROMTO:
10995 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010996 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010997 goto ecreate;
10998 break;
10999 case NTO:
11000 /* Take care of noclobber mode. */
11001 if (Cflag) {
11002 fname = redir->nfile.expfname;
11003 if ((f = noclobberopen(fname)) < 0)
11004 goto ecreate;
11005 break;
11006 }
Eric Andersenc470f442003-07-28 09:56:35 +000011007 /* FALLTHROUGH */
11008 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011009 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011010 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011011 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011012 break;
11013 case NAPPEND:
11014 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011015 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011016 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011017 break;
11018 default:
11019#ifdef DEBUG
11020 abort();
11021#endif
11022 /* Fall through to eliminate warning. */
11023 case NTOFD:
11024 case NFROMFD:
11025 f = -1;
11026 break;
11027 case NHERE:
11028 case NXHERE:
11029 f = openhere(redir);
11030 break;
11031 }
11032
11033 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011034ecreate:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011035 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011036eopen:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011037 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
Eric Andersencb57d552001-06-28 07:25:16 +000011038}
11039
Eric Andersenc470f442003-07-28 09:56:35 +000011040static inline void
11041dupredirect(union node *redir, int f)
11042{
11043 int fd = redir->nfile.fd;
11044
11045 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11046 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11047 copyfd(redir->ndup.dupfd, fd);
11048 }
11049 return;
11050 }
11051
11052 if (f != fd) {
11053 copyfd(f, fd);
11054 close(f);
11055 }
11056 return;
11057}
Eric Andersencb57d552001-06-28 07:25:16 +000011058
Eric Andersen62483552001-07-10 06:09:16 +000011059/*
11060 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11061 * old file descriptors are stashed away so that the redirection can be
11062 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11063 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011064 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011065 */
11066
Eric Andersenc470f442003-07-28 09:56:35 +000011067static void
11068redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011069{
11070 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011071 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011072 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011073 int fd;
11074 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011075 int *p;
11076 nullredirs++;
11077 if (!redir) {
11078 return;
Eric Andersen62483552001-07-10 06:09:16 +000011079 }
Eric Andersenc470f442003-07-28 09:56:35 +000011080 sv = NULL;
11081 INTOFF;
11082 if (flags & REDIR_PUSH) {
11083 struct redirtab *q;
11084 q = ckmalloc(sizeof (struct redirtab));
11085 q->next = redirlist;
11086 redirlist = q;
11087 q->nullredirs = nullredirs - 1;
11088 for (i = 0 ; i < 10 ; i++)
11089 q->renamed[i] = EMPTY;
11090 nullredirs = 0;
11091 sv = q;
11092 }
11093 n = redir;
11094 do {
Eric Andersen62483552001-07-10 06:09:16 +000011095 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011096 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011097 n->ndup.dupfd == fd)
11098 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011099
Eric Andersen62483552001-07-10 06:09:16 +000011100 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011101 if (fd == newfd)
11102 continue;
11103 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11104 i = fcntl(fd, F_DUPFD, 10);
11105
11106 if (i == -1) {
11107 i = errno;
11108 if (i != EBADF) {
11109 close(newfd);
11110 errno = i;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011111 sh_error("%d: %m", fd);
Eric Andersen62483552001-07-10 06:09:16 +000011112 /* NOTREACHED */
11113 }
Eric Andersenc470f442003-07-28 09:56:35 +000011114 } else {
11115 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011116 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011117 }
Eric Andersenc470f442003-07-28 09:56:35 +000011118 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011119 close(fd);
11120 }
Eric Andersenc470f442003-07-28 09:56:35 +000011121 dupredirect(n, newfd);
11122 } while ((n = n->nfile.next));
11123 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011124 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11125 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011126}
11127
11128
Eric Andersencb57d552001-06-28 07:25:16 +000011129/*
11130 * Undo the effects of the last redirection.
11131 */
11132
Eric Andersenc470f442003-07-28 09:56:35 +000011133void
11134popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011135{
Eric Andersenc470f442003-07-28 09:56:35 +000011136 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011137 int i;
11138
Eric Andersenc470f442003-07-28 09:56:35 +000011139 if (--nullredirs >= 0)
11140 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011141 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011142 rp = redirlist;
11143 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011144 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011145 if (!drop) {
11146 close(i);
11147 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011148 }
Eric Andersenc470f442003-07-28 09:56:35 +000011149 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011150 }
11151 }
11152 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011153 nullredirs = rp->nullredirs;
11154 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011155 INTON;
11156}
11157
11158/*
Eric Andersenc470f442003-07-28 09:56:35 +000011159 * Undo all redirections. Called on error or interrupt.
11160 */
11161
11162/*
Eric Andersencb57d552001-06-28 07:25:16 +000011163 * Discard all saved file descriptors.
11164 */
11165
Eric Andersenc470f442003-07-28 09:56:35 +000011166void
11167clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011168{
Eric Andersenc470f442003-07-28 09:56:35 +000011169 for (;;) {
11170 nullredirs = 0;
11171 if (!redirlist)
11172 break;
11173 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011174 }
Eric Andersencb57d552001-06-28 07:25:16 +000011175}
11176
11177
Eric Andersencb57d552001-06-28 07:25:16 +000011178/*
11179 * Copy a file descriptor to be >= to. Returns -1
11180 * if the source file descriptor is closed, EMPTY if there are no unused
11181 * file descriptors left.
11182 */
11183
Eric Andersenc470f442003-07-28 09:56:35 +000011184int
11185copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011186{
11187 int newfd;
11188
11189 newfd = fcntl(from, F_DUPFD, to);
11190 if (newfd < 0) {
11191 if (errno == EMFILE)
11192 return EMPTY;
11193 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011194 sh_error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011195 }
11196 return newfd;
11197}
11198
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011199
Eric Andersenc470f442003-07-28 09:56:35 +000011200int
11201redirectsafe(union node *redir, int flags)
11202{
11203 int err;
11204 volatile int saveint;
11205 struct jmploc *volatile savehandler = handler;
11206 struct jmploc jmploc;
11207
11208 SAVEINT(saveint);
11209 if (!(err = setjmp(jmploc.loc) * 2)) {
11210 handler = &jmploc;
11211 redirect(redir, flags);
11212 }
11213 handler = savehandler;
11214 if (err && exception != EXERROR)
11215 longjmp(handler->loc, 1);
11216 RESTOREINT(saveint);
11217 return err;
11218}
11219
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011220/* show.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011221
11222#ifdef DEBUG
11223static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011224static void shcmd(union node *, FILE *);
11225static void sharg(union node *, FILE *);
11226static void indent(int, char *, FILE *);
11227static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011228
11229
Eric Andersenc470f442003-07-28 09:56:35 +000011230void
11231showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011232{
11233 trputs("showtree called\n");
11234 shtree(n, 1, NULL, stdout);
11235}
Eric Andersencb57d552001-06-28 07:25:16 +000011236
Eric Andersenc470f442003-07-28 09:56:35 +000011237
11238static void
11239shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011240{
11241 struct nodelist *lp;
11242 const char *s;
11243
11244 if (n == NULL)
11245 return;
11246
11247 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011248 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011249 case NSEMI:
11250 s = "; ";
11251 goto binop;
11252 case NAND:
11253 s = " && ";
11254 goto binop;
11255 case NOR:
11256 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011257binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011258 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011259 /* if (ind < 0) */
11260 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011261 shtree(n->nbinary.ch2, ind, NULL, fp);
11262 break;
11263 case NCMD:
11264 shcmd(n, fp);
11265 if (ind >= 0)
11266 putc('\n', fp);
11267 break;
11268 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011269 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011270 shcmd(lp->n, fp);
11271 if (lp->next)
11272 fputs(" | ", fp);
11273 }
11274 if (n->npipe.backgnd)
11275 fputs(" &", fp);
11276 if (ind >= 0)
11277 putc('\n', fp);
11278 break;
11279 default:
11280 fprintf(fp, "<node type %d>", n->type);
11281 if (ind >= 0)
11282 putc('\n', fp);
11283 break;
11284 }
11285}
11286
11287
Eric Andersenc470f442003-07-28 09:56:35 +000011288static void
11289shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011290{
11291 union node *np;
11292 int first;
11293 const char *s;
11294 int dftfd;
11295
11296 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011297 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11298 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011299 putchar(' ');
11300 sharg(np, fp);
11301 first = 0;
11302 }
Eric Andersenc470f442003-07-28 09:56:35 +000011303 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11304 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011305 putchar(' ');
11306 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011307 case NTO: s = ">"; dftfd = 1; break;
11308 case NCLOBBER: s = ">|"; dftfd = 1; break;
11309 case NAPPEND: s = ">>"; dftfd = 1; break;
11310 case NTOFD: s = ">&"; dftfd = 1; break;
11311 case NFROM: s = "<"; dftfd = 0; break;
11312 case NFROMFD: s = "<&"; dftfd = 0; break;
11313 case NFROMTO: s = "<>"; dftfd = 0; break;
11314 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011315 }
11316 if (np->nfile.fd != dftfd)
11317 fprintf(fp, "%d", np->nfile.fd);
11318 fputs(s, fp);
11319 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11320 fprintf(fp, "%d", np->ndup.dupfd);
11321 } else {
11322 sharg(np->nfile.fname, fp);
11323 }
11324 first = 0;
11325 }
11326}
11327
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011328
Eric Andersenc470f442003-07-28 09:56:35 +000011329
11330static void
11331sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011332{
Eric Andersencb57d552001-06-28 07:25:16 +000011333 char *p;
11334 struct nodelist *bqlist;
11335 int subtype;
11336
11337 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011338 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011339 abort();
11340 }
11341 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011342 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011343 switch (*p) {
11344 case CTLESC:
11345 putc(*++p, fp);
11346 break;
11347 case CTLVAR:
11348 putc('$', fp);
11349 putc('{', fp);
11350 subtype = *++p;
11351 if (subtype == VSLENGTH)
11352 putc('#', fp);
11353
11354 while (*p != '=')
11355 putc(*p++, fp);
11356
11357 if (subtype & VSNUL)
11358 putc(':', fp);
11359
11360 switch (subtype & VSTYPE) {
11361 case VSNORMAL:
11362 putc('}', fp);
11363 break;
11364 case VSMINUS:
11365 putc('-', fp);
11366 break;
11367 case VSPLUS:
11368 putc('+', fp);
11369 break;
11370 case VSQUESTION:
11371 putc('?', fp);
11372 break;
11373 case VSASSIGN:
11374 putc('=', fp);
11375 break;
11376 case VSTRIMLEFT:
11377 putc('#', fp);
11378 break;
11379 case VSTRIMLEFTMAX:
11380 putc('#', fp);
11381 putc('#', fp);
11382 break;
11383 case VSTRIMRIGHT:
11384 putc('%', fp);
11385 break;
11386 case VSTRIMRIGHTMAX:
11387 putc('%', fp);
11388 putc('%', fp);
11389 break;
11390 case VSLENGTH:
11391 break;
11392 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011393 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011394 }
11395 break;
11396 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011397 putc('}', fp);
11398 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011399 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011400 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011401 putc('$', fp);
11402 putc('(', fp);
11403 shtree(bqlist->n, -1, NULL, fp);
11404 putc(')', fp);
11405 break;
11406 default:
11407 putc(*p, fp);
11408 break;
11409 }
11410 }
11411}
11412
11413
Eric Andersenc470f442003-07-28 09:56:35 +000011414static void
11415indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011416{
11417 int i;
11418
Eric Andersenc470f442003-07-28 09:56:35 +000011419 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011420 if (pfx && i == amount - 1)
11421 fputs(pfx, fp);
11422 putc('\t', fp);
11423 }
11424}
Eric Andersencb57d552001-06-28 07:25:16 +000011425
Eric Andersenc470f442003-07-28 09:56:35 +000011426
11427
11428/*
11429 * Debugging stuff.
11430 */
11431
11432
Eric Andersencb57d552001-06-28 07:25:16 +000011433FILE *tracefile;
11434
Eric Andersencb57d552001-06-28 07:25:16 +000011435
Eric Andersenc470f442003-07-28 09:56:35 +000011436void
11437trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011438{
Eric Andersenc470f442003-07-28 09:56:35 +000011439 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011440 return;
11441 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011442}
11443
Eric Andersenc470f442003-07-28 09:56:35 +000011444void
11445trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011446{
11447 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011448
Eric Andersenc470f442003-07-28 09:56:35 +000011449 if (debug != 1)
11450 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011451 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011452 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011453 va_end(va);
11454}
11455
Eric Andersenc470f442003-07-28 09:56:35 +000011456void
11457tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011458{
Eric Andersenc470f442003-07-28 09:56:35 +000011459 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011460 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011461 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011462}
11463
11464
Eric Andersenc470f442003-07-28 09:56:35 +000011465void
11466trputs(const char *s)
11467{
11468 if (debug != 1)
11469 return;
11470 fputs(s, tracefile);
11471}
11472
11473
11474static void
11475trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011476{
11477 char *p;
11478 char c;
11479
Eric Andersenc470f442003-07-28 09:56:35 +000011480 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011481 return;
11482 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011483 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011484 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011485 case '\n': c = 'n'; goto backslash;
11486 case '\t': c = 't'; goto backslash;
11487 case '\r': c = 'r'; goto backslash;
11488 case '"': c = '"'; goto backslash;
11489 case '\\': c = '\\'; goto backslash;
11490 case CTLESC: c = 'e'; goto backslash;
11491 case CTLVAR: c = 'v'; goto backslash;
11492 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11493 case CTLBACKQ: c = 'q'; goto backslash;
11494 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11495backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011496 putc(c, tracefile);
11497 break;
11498 default:
11499 if (*p >= ' ' && *p <= '~')
11500 putc(*p, tracefile);
11501 else {
11502 putc('\\', tracefile);
11503 putc(*p >> 6 & 03, tracefile);
11504 putc(*p >> 3 & 07, tracefile);
11505 putc(*p & 07, tracefile);
11506 }
11507 break;
11508 }
11509 }
11510 putc('"', tracefile);
11511}
11512
11513
Eric Andersenc470f442003-07-28 09:56:35 +000011514void
11515trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011516{
Eric Andersenc470f442003-07-28 09:56:35 +000011517 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011518 return;
11519 while (*ap) {
11520 trstring(*ap++);
11521 if (*ap)
11522 putc(' ', tracefile);
11523 else
11524 putc('\n', tracefile);
11525 }
Eric Andersencb57d552001-06-28 07:25:16 +000011526}
11527
11528
Eric Andersenc470f442003-07-28 09:56:35 +000011529void
11530opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011531{
Eric Andersencb57d552001-06-28 07:25:16 +000011532 char s[100];
11533#ifdef O_APPEND
11534 int flags;
11535#endif
11536
Eric Andersenc470f442003-07-28 09:56:35 +000011537 if (debug != 1) {
11538 if (tracefile)
11539 fflush(tracefile);
11540 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011541 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011542 }
Eric Andersenc470f442003-07-28 09:56:35 +000011543 scopy("./trace", s);
11544 if (tracefile) {
11545 if (!freopen(s, "a", tracefile)) {
11546 fprintf(stderr, "Can't re-open %s\n", s);
11547 debug = 0;
11548 return;
11549 }
11550 } else {
11551 if ((tracefile = fopen(s, "a")) == NULL) {
11552 fprintf(stderr, "Can't open %s\n", s);
11553 debug = 0;
11554 return;
11555 }
11556 }
Eric Andersencb57d552001-06-28 07:25:16 +000011557#ifdef O_APPEND
11558 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11559 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11560#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011561 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011562 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011563}
Eric Andersenc470f442003-07-28 09:56:35 +000011564#endif /* DEBUG */
11565
11566
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011567/* trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011568
11569/*
11570 * Sigmode records the current value of the signal handlers for the various
11571 * modes. A value of zero means that the current handler is not known.
11572 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11573 */
11574
11575#define S_DFL 1 /* default signal handling (SIG_DFL) */
11576#define S_CATCH 2 /* signal is caught */
11577#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11578#define S_HARD_IGN 4 /* signal is ignored permenantly */
11579#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11580
Eric Andersencb57d552001-06-28 07:25:16 +000011581
11582
11583/*
Eric Andersencb57d552001-06-28 07:25:16 +000011584 * The trap builtin.
11585 */
11586
Eric Andersenc470f442003-07-28 09:56:35 +000011587int
11588trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011589{
11590 char *action;
11591 char **ap;
11592 int signo;
11593
Eric Andersenc470f442003-07-28 09:56:35 +000011594 nextopt(nullstr);
11595 ap = argptr;
11596 if (!*ap) {
11597 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011598 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011599 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011600
Eric Andersenc470f442003-07-28 09:56:35 +000011601 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011602 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011603 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011604 out1fmt("trap -- %s %s\n",
11605 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011606 }
11607 }
11608 return 0;
11609 }
Eric Andersenc470f442003-07-28 09:56:35 +000011610 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011611 action = NULL;
11612 else
11613 action = *ap++;
11614 while (*ap) {
11615 if ((signo = decode_signal(*ap, 0)) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011616 sh_error("%s: bad trap", *ap);
Eric Andersencb57d552001-06-28 07:25:16 +000011617 INTOFF;
11618 if (action) {
11619 if (action[0] == '-' && action[1] == '\0')
11620 action = NULL;
11621 else
Eric Andersenc470f442003-07-28 09:56:35 +000011622 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011623 }
Eric Andersenc470f442003-07-28 09:56:35 +000011624 if (trap[signo])
11625 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011626 trap[signo] = action;
11627 if (signo != 0)
11628 setsignal(signo);
11629 INTON;
11630 ap++;
11631 }
11632 return 0;
11633}
11634
11635
Eric Andersenc470f442003-07-28 09:56:35 +000011636/*
11637 * Clear traps on a fork.
11638 */
11639
11640void
11641clear_traps(void)
11642{
11643 char **tp;
11644
11645 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11646 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11647 INTOFF;
11648 ckfree(*tp);
11649 *tp = NULL;
11650 if (tp != &trap[0])
11651 setsignal(tp - trap);
11652 INTON;
11653 }
11654 }
11655}
11656
11657
Eric Andersencb57d552001-06-28 07:25:16 +000011658/*
11659 * Set the signal handler for the specified signal. The routine figures
11660 * out what it should be set to.
11661 */
11662
Eric Andersenc470f442003-07-28 09:56:35 +000011663void
11664setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011665{
11666 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011667 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011668 struct sigaction act;
11669
11670 if ((t = trap[signo]) == NULL)
11671 action = S_DFL;
11672 else if (*t != '\0')
11673 action = S_CATCH;
11674 else
11675 action = S_IGN;
11676 if (rootshell && action == S_DFL) {
11677 switch (signo) {
11678 case SIGINT:
11679 if (iflag || minusc || sflag == 0)
11680 action = S_CATCH;
11681 break;
11682 case SIGQUIT:
11683#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011684 if (debug)
11685 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011686#endif
11687 /* FALLTHROUGH */
11688 case SIGTERM:
11689 if (iflag)
11690 action = S_IGN;
11691 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011692#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011693 case SIGTSTP:
11694 case SIGTTOU:
11695 if (mflag)
11696 action = S_IGN;
11697 break;
11698#endif
11699 }
11700 }
11701
11702 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011703 tsig = *t;
11704 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011705 /*
11706 * current setting unknown
11707 */
11708 if (sigaction(signo, 0, &act) == -1) {
11709 /*
11710 * Pretend it worked; maybe we should give a warning
11711 * here, but other shells don't. We don't alter
11712 * sigmode, so that we retry every time.
11713 */
11714 return;
11715 }
11716 if (act.sa_handler == SIG_IGN) {
11717 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011718 signo == SIGTTIN || signo == SIGTTOU)) {
11719 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011720 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011721 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011722 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011723 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011724 }
11725 }
Eric Andersenc470f442003-07-28 09:56:35 +000011726 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011727 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011728 switch (action) {
11729 case S_CATCH:
11730 act.sa_handler = onsig;
11731 break;
11732 case S_IGN:
11733 act.sa_handler = SIG_IGN;
11734 break;
11735 default:
11736 act.sa_handler = SIG_DFL;
11737 }
Eric Andersencb57d552001-06-28 07:25:16 +000011738 *t = action;
11739 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011740 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011741 sigaction(signo, &act, 0);
11742}
11743
11744/*
11745 * Ignore a signal.
11746 */
11747
Eric Andersenc470f442003-07-28 09:56:35 +000011748void
11749ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011750{
11751 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11752 signal(signo, SIG_IGN);
11753 }
11754 sigmode[signo - 1] = S_HARD_IGN;
11755}
11756
11757
Eric Andersencb57d552001-06-28 07:25:16 +000011758/*
11759 * Signal handler.
11760 */
11761
Eric Andersenc470f442003-07-28 09:56:35 +000011762void
11763onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011764{
Eric Andersencb57d552001-06-28 07:25:16 +000011765 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011766 pendingsigs = signo;
11767
11768 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11769 if (!suppressint)
11770 onint();
11771 intpending = 1;
11772 }
Eric Andersencb57d552001-06-28 07:25:16 +000011773}
11774
11775
Eric Andersencb57d552001-06-28 07:25:16 +000011776/*
11777 * Called to execute a trap. Perhaps we should avoid entering new trap
11778 * handlers while we are executing a trap handler.
11779 */
11780
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011781int
Eric Andersenc470f442003-07-28 09:56:35 +000011782dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011783{
Eric Andersenc470f442003-07-28 09:56:35 +000011784 char *p;
11785 char *q;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011786 int i;
Eric Andersencb57d552001-06-28 07:25:16 +000011787 int savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011788 int skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011789
Eric Andersenc470f442003-07-28 09:56:35 +000011790 savestatus = exitstatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011791 pendingsigs = 0;
11792 xbarrier();
11793
11794 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11795 if (!*q)
11796 continue;
11797 *q = 0;
11798
11799 p = trap[i + 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011800 if (!p)
11801 continue;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011802 skip = evalstring(p, SKIPEVAL);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011803 exitstatus = savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011804 if (skip)
11805 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011806 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011807
11808 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +000011809}
11810
Eric Andersenc470f442003-07-28 09:56:35 +000011811
Eric Andersenc470f442003-07-28 09:56:35 +000011812/*
11813 * Controls whether the shell is interactive or not.
11814 */
11815
Eric Andersenc470f442003-07-28 09:56:35 +000011816void
11817setinteractive(int on)
11818{
11819 static int is_interactive;
11820
11821 if (++on == is_interactive)
11822 return;
11823 is_interactive = on;
11824 setsignal(SIGINT);
11825 setsignal(SIGQUIT);
11826 setsignal(SIGTERM);
11827#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11828 if(is_interactive > 1) {
11829 /* Looks like they want an interactive shell */
11830 static int do_banner;
11831
11832 if(!do_banner) {
11833 out1fmt(
11834 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11835 "Enter 'help' for a list of built-in commands.\n\n");
11836 do_banner++;
11837 }
11838 }
11839#endif
11840}
11841
11842
11843#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11844/*** List the available builtins ***/
11845
11846static int helpcmd(int argc, char **argv)
11847{
11848 int col, i;
11849
11850 out1fmt("\nBuilt-in commands:\n-------------------\n");
11851 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11852 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11853 builtincmd[i].name + 1);
11854 if (col > 60) {
11855 out1fmt("\n");
11856 col = 0;
11857 }
11858 }
11859#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11860 {
11861 extern const struct BB_applet applets[];
11862 extern const size_t NUM_APPLETS;
11863
11864 for (i = 0; i < NUM_APPLETS; i++) {
11865
11866 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11867 if (col > 60) {
11868 out1fmt("\n");
11869 col = 0;
11870 }
11871 }
11872 }
11873#endif
11874 out1fmt("\n\n");
11875 return EXIT_SUCCESS;
11876}
11877#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11878
Eric Andersencb57d552001-06-28 07:25:16 +000011879/*
11880 * Called to exit the shell.
11881 */
11882
Eric Andersenc470f442003-07-28 09:56:35 +000011883void
11884exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011885{
Eric Andersenc470f442003-07-28 09:56:35 +000011886 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011887 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011888 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011889
Eric Andersenc470f442003-07-28 09:56:35 +000011890 status = exitstatus;
11891 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011892 if (setjmp(loc.loc)) {
11893 if (exception == EXEXIT)
11894 _exit(exitstatus);
Eric Andersenc470f442003-07-28 09:56:35 +000011895 goto out;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011896 }
Eric Andersenc470f442003-07-28 09:56:35 +000011897 handler = &loc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011898 if ((p = trap[0])) {
Eric Andersencb57d552001-06-28 07:25:16 +000011899 trap[0] = NULL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011900 evalstring(p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011901 }
Eric Andersencb57d552001-06-28 07:25:16 +000011902 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011903 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011904#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11905 if (iflag && rootshell) {
11906 const char *hp = lookupvar("HISTFILE");
11907
11908 if(hp != NULL )
11909 save_history ( hp );
11910 }
11911#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011912out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011913 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011914 /* NOTREACHED */
11915}
11916
11917static int decode_signal(const char *string, int minsig)
11918{
11919 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011920 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011921
Eric Andersen34506362001-08-02 05:02:46 +000011922 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011923}
Eric Andersen34506362001-08-02 05:02:46 +000011924
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011925/* var.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011926
11927static struct var *vartab[VTABSIZE];
11928
11929static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011930static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011931
11932/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011933 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011934 */
11935
Eric Andersenc470f442003-07-28 09:56:35 +000011936
11937#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011938/*
Eric Andersenc470f442003-07-28 09:56:35 +000011939 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011940 */
11941
Eric Andersenc470f442003-07-28 09:56:35 +000011942int
11943setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011944{
Eric Andersenc470f442003-07-28 09:56:35 +000011945 int err;
11946 volatile int saveint;
11947 struct jmploc *volatile savehandler = handler;
11948 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011949
Eric Andersenc470f442003-07-28 09:56:35 +000011950 SAVEINT(saveint);
11951 if (setjmp(jmploc.loc))
11952 err = 1;
11953 else {
11954 handler = &jmploc;
11955 setvar(name, val, flags);
11956 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011957 }
Eric Andersenc470f442003-07-28 09:56:35 +000011958 handler = savehandler;
11959 RESTOREINT(saveint);
11960 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011961}
Eric Andersenc470f442003-07-28 09:56:35 +000011962#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011963
11964/*
11965 * Set the value of a variable. The flags argument is ored with the
11966 * flags of the variable. If val is NULL, the variable is unset.
11967 */
11968
Eric Andersenc470f442003-07-28 09:56:35 +000011969static void
11970setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011971{
Eric Andersenc470f442003-07-28 09:56:35 +000011972 char *p, *q;
11973 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011974 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011975 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011976
Eric Andersenc470f442003-07-28 09:56:35 +000011977 q = endofname(name);
11978 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011979 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011980 if (!namelen || p != q)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011981 sh_error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011982 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011983 if (val == NULL) {
11984 flags |= VUNSET;
11985 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011986 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011987 }
11988 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011989 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
Paul Fox8de331d2005-07-21 12:03:05 +000011990 if (val) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011991 *p++ = '=';
Eric Andersenc470f442003-07-28 09:56:35 +000011992 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011993 }
Eric Andersenc470f442003-07-28 09:56:35 +000011994 *p = '\0';
11995 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011996 INTON;
11997}
11998
11999
Eric Andersencb57d552001-06-28 07:25:16 +000012000/*
12001 * Same as setvar except that the variable and value are passed in
12002 * the first argument as name=value. Since the first argument will
12003 * be actually stored in the table, it should not be a string that
12004 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012005 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012006 */
12007
Eric Andersenc470f442003-07-28 09:56:35 +000012008void
12009setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012010{
12011 struct var *vp, **vpp;
12012
12013 vpp = hashvar(s);
12014 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012015 vp = *findvar(vpp, s);
12016 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012017 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12018 const char *n;
12019
Eric Andersenc470f442003-07-28 09:56:35 +000012020 if (flags & VNOSAVE)
12021 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012022 n = vp->text;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012023 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012024 }
Eric Andersenc470f442003-07-28 09:56:35 +000012025
12026 if (flags & VNOSET)
12027 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012028
12029 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012030 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012031
Eric Andersenc470f442003-07-28 09:56:35 +000012032 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12033 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012034
Eric Andersenc470f442003-07-28 09:56:35 +000012035 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12036 } else {
12037 if (flags & VNOSET)
12038 return;
12039 /* not found */
12040 vp = ckmalloc(sizeof (*vp));
12041 vp->next = *vpp;
12042 vp->func = NULL;
12043 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012044 }
Eric Andersenc470f442003-07-28 09:56:35 +000012045 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12046 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012047 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012048 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012049}
12050
12051
Eric Andersencb57d552001-06-28 07:25:16 +000012052/*
12053 * Process a linked list of variable assignments.
12054 */
12055
Eric Andersenc470f442003-07-28 09:56:35 +000012056static void
12057listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012058{
Eric Andersenc470f442003-07-28 09:56:35 +000012059 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012060
Eric Andersenc470f442003-07-28 09:56:35 +000012061 if (!lp)
12062 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012063 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012064 do {
12065 setvareq(lp->text, flags);
12066 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012067 INTON;
12068}
12069
12070
Eric Andersencb57d552001-06-28 07:25:16 +000012071/*
12072 * Find the value of a variable. Returns NULL if not set.
12073 */
12074
Eric Andersenc470f442003-07-28 09:56:35 +000012075static char *
12076lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012077{
Eric Andersencb57d552001-06-28 07:25:16 +000012078 struct var *v;
12079
Eric Andersen16767e22004-03-16 05:14:10 +000012080 if ((v = *findvar(hashvar(name), name))) {
12081#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012082 /*
12083 * Dynamic variables are implemented roughly the same way they are
12084 * in bash. Namely, they're "special" so long as they aren't unset.
12085 * As soon as they're unset, they're no longer dynamic, and dynamic
12086 * lookup will no longer happen at that point. -- PFM.
12087 */
Eric Andersen16767e22004-03-16 05:14:10 +000012088 if((v->flags & VDYNAMIC))
12089 (*v->func)(NULL);
12090#endif
12091 if(!(v->flags & VUNSET))
12092 return strchrnul(v->text, '=') + 1;
12093 }
Eric Andersenef02f822004-03-11 13:34:24 +000012094
Eric Andersencb57d552001-06-28 07:25:16 +000012095 return NULL;
12096}
12097
12098
Eric Andersencb57d552001-06-28 07:25:16 +000012099/*
12100 * Search the environment of a builtin command.
12101 */
12102
Eric Andersenc470f442003-07-28 09:56:35 +000012103static char *
12104bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012105{
Eric Andersenc470f442003-07-28 09:56:35 +000012106 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012107
Eric Andersenc470f442003-07-28 09:56:35 +000012108 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012109 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012110 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012111 }
12112 return lookupvar(name);
12113}
12114
12115
Eric Andersencb57d552001-06-28 07:25:16 +000012116/*
Eric Andersenc470f442003-07-28 09:56:35 +000012117 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012118 */
12119
Eric Andersenc470f442003-07-28 09:56:35 +000012120static char **
12121listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012122{
Eric Andersencb57d552001-06-28 07:25:16 +000012123 struct var **vpp;
12124 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012125 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012126 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012127
Eric Andersenc470f442003-07-28 09:56:35 +000012128 STARTSTACKSTR(ep);
12129 vpp = vartab;
12130 mask = on | off;
12131 do {
12132 for (vp = *vpp ; vp ; vp = vp->next)
12133 if ((vp->flags & mask) == on) {
12134 if (ep == stackstrend())
12135 ep = growstackstr();
12136 *ep++ = (char *) vp->text;
12137 }
12138 } while (++vpp < vartab + VTABSIZE);
12139 if (ep == stackstrend())
12140 ep = growstackstr();
12141 if (end)
12142 *end = ep;
12143 *ep++ = NULL;
12144 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012145}
12146
12147
12148/*
Eric Andersenc470f442003-07-28 09:56:35 +000012149 * POSIX requires that 'set' (but not export or readonly) output the
12150 * variables in lexicographic order - by the locale's collating order (sigh).
12151 * Maybe we could keep them in an ordered balanced binary tree
12152 * instead of hashed lists.
12153 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012154 */
12155
Eric Andersenc470f442003-07-28 09:56:35 +000012156static int
12157showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012158{
Eric Andersenc470f442003-07-28 09:56:35 +000012159 const char *sep;
12160 char **ep, **epend;
12161
12162 ep = listvars(on, off, &epend);
12163 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12164
12165 sep = *sep_prefix ? spcstr : sep_prefix;
12166
12167 for (; ep < epend; ep++) {
12168 const char *p;
12169 const char *q;
12170
12171 p = strchrnul(*ep, '=');
12172 q = nullstr;
12173 if (*p)
12174 q = single_quote(++p);
12175
12176 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12177 }
12178
Eric Andersencb57d552001-06-28 07:25:16 +000012179 return 0;
12180}
12181
12182
12183
12184/*
12185 * The export and readonly commands.
12186 */
12187
Eric Andersenc470f442003-07-28 09:56:35 +000012188static int
12189exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012190{
12191 struct var *vp;
12192 char *name;
12193 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012194 char **aptr;
12195 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12196 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012197
Eric Andersenc470f442003-07-28 09:56:35 +000012198 notp = nextopt("p") - 'p';
12199 if (notp && ((name = *(aptr = argptr)))) {
12200 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012201 if ((p = strchr(name, '=')) != NULL) {
12202 p++;
12203 } else {
12204 if ((vp = *findvar(hashvar(name), name))) {
12205 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012206 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012207 }
12208 }
12209 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012210 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012211 } else {
12212 showvars(argv[0], flag, 0);
12213 }
12214 return 0;
12215}
12216
Eric Andersen34506362001-08-02 05:02:46 +000012217
Eric Andersencb57d552001-06-28 07:25:16 +000012218/*
Eric Andersencb57d552001-06-28 07:25:16 +000012219 * Make a variable a local variable. When a variable is made local, it's
12220 * value and flags are saved in a localvar structure. The saved values
12221 * will be restored when the shell function returns. We handle the name
12222 * "-" as a special case.
12223 */
12224
Eric Andersenc470f442003-07-28 09:56:35 +000012225static inline void
12226mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012227{
Eric Andersencb57d552001-06-28 07:25:16 +000012228 struct localvar *lvp;
12229 struct var **vpp;
12230 struct var *vp;
12231
12232 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012233 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012234 if (name[0] == '-' && name[1] == '\0') {
12235 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012236 p = ckmalloc(sizeof(optlist));
12237 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012238 vp = NULL;
12239 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012240 char *eq;
12241
Eric Andersencb57d552001-06-28 07:25:16 +000012242 vpp = hashvar(name);
12243 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012244 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012245 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012246 if (eq)
12247 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012248 else
12249 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012250 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012251 lvp->flags = VUNSET;
12252 } else {
12253 lvp->text = vp->text;
12254 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012255 vp->flags |= VSTRFIXED|VTEXTFIXED;
12256 if (eq)
12257 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012258 }
12259 }
12260 lvp->vp = vp;
12261 lvp->next = localvars;
12262 localvars = lvp;
12263 INTON;
12264}
12265
Eric Andersenc470f442003-07-28 09:56:35 +000012266/*
12267 * The "local" command.
12268 */
12269
12270static int
12271localcmd(int argc, char **argv)
12272{
12273 char *name;
12274
12275 argv = argptr;
12276 while ((name = *argv++) != NULL) {
12277 mklocal(name);
12278 }
12279 return 0;
12280}
12281
12282
Eric Andersencb57d552001-06-28 07:25:16 +000012283/*
12284 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012285 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012286 */
12287
Eric Andersenc470f442003-07-28 09:56:35 +000012288static void
12289poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012290{
Eric Andersencb57d552001-06-28 07:25:16 +000012291 struct localvar *lvp;
12292 struct var *vp;
12293
12294 while ((lvp = localvars) != NULL) {
12295 localvars = lvp->next;
12296 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012297 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12298 if (vp == NULL) { /* $- saved */
12299 memcpy(optlist, lvp->text, sizeof(optlist));
12300 ckfree(lvp->text);
12301 optschanged();
12302 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12303 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012304 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012305 if (vp->func)
12306 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12307 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12308 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012309 vp->flags = lvp->flags;
12310 vp->text = lvp->text;
12311 }
Eric Andersenc470f442003-07-28 09:56:35 +000012312 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012313 }
12314}
12315
12316
Eric Andersencb57d552001-06-28 07:25:16 +000012317/*
12318 * The unset builtin command. We unset the function before we unset the
12319 * variable to allow a function to be unset when there is a readonly variable
12320 * with the same name.
12321 */
12322
Eric Andersenc470f442003-07-28 09:56:35 +000012323int
12324unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012325{
12326 char **ap;
12327 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012328 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012329 int ret = 0;
12330
12331 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012332 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012333 }
Eric Andersencb57d552001-06-28 07:25:16 +000012334
Eric Andersenc470f442003-07-28 09:56:35 +000012335 for (ap = argptr; *ap ; ap++) {
12336 if (flag != 'f') {
12337 i = unsetvar(*ap);
12338 ret |= i;
12339 if (!(i & 2))
12340 continue;
12341 }
12342 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012343 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012344 }
Eric Andersenc470f442003-07-28 09:56:35 +000012345 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012346}
12347
12348
12349/*
12350 * Unset the specified variable.
12351 */
12352
Eric Andersenc470f442003-07-28 09:56:35 +000012353int
12354unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012355{
Eric Andersencb57d552001-06-28 07:25:16 +000012356 struct var **vpp;
12357 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012358 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012359
12360 vpp = findvar(hashvar(s), s);
12361 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012362 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012363 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012364 int flags = vp->flags;
12365
12366 retval = 1;
12367 if (flags & VREADONLY)
12368 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012369#ifdef DYNAMIC_VAR
12370 vp->flags &= ~VDYNAMIC;
12371#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012372 if (flags & VUNSET)
12373 goto ok;
12374 if ((flags & VSTRFIXED) == 0) {
12375 INTOFF;
12376 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12377 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012378 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012379 ckfree(vp);
12380 INTON;
12381 } else {
12382 setvar(s, 0, 0);
12383 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012384 }
Eric Andersenc470f442003-07-28 09:56:35 +000012385ok:
12386 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012387 }
12388
Eric Andersenc470f442003-07-28 09:56:35 +000012389out:
12390 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012391}
12392
12393
12394
12395/*
12396 * Find the appropriate entry in the hash table from the name.
12397 */
12398
Eric Andersenc470f442003-07-28 09:56:35 +000012399static struct var **
12400hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012401{
Eric Andersencb57d552001-06-28 07:25:16 +000012402 unsigned int hashval;
12403
12404 hashval = ((unsigned char) *p) << 4;
12405 while (*p && *p != '=')
12406 hashval += (unsigned char) *p++;
12407 return &vartab[hashval % VTABSIZE];
12408}
12409
12410
12411
12412/*
Eric Andersenc470f442003-07-28 09:56:35 +000012413 * Compares two strings up to the first = or '\0'. The first
12414 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012415 * either '=' or '\0'.
12416 */
12417
Eric Andersenc470f442003-07-28 09:56:35 +000012418int
12419varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012420{
Eric Andersenc470f442003-07-28 09:56:35 +000012421 int c, d;
12422
12423 while ((c = *p) == (d = *q)) {
12424 if (!c || c == '=')
12425 goto out;
12426 p++;
12427 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012428 }
Eric Andersenc470f442003-07-28 09:56:35 +000012429 if (c == '=')
12430 c = 0;
12431 if (d == '=')
12432 d = 0;
12433out:
12434 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012435}
12436
Eric Andersenc470f442003-07-28 09:56:35 +000012437static int
12438vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012439{
Eric Andersenc470f442003-07-28 09:56:35 +000012440 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012441}
12442
Eric Andersenc470f442003-07-28 09:56:35 +000012443static struct var **
12444findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012445{
12446 for (; *vpp; vpp = &(*vpp)->next) {
12447 if (varequal((*vpp)->text, name)) {
12448 break;
12449 }
12450 }
12451 return vpp;
12452}
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012453/* setmode.c */
Eric Andersencb57d552001-06-28 07:25:16 +000012454
Eric Andersenc470f442003-07-28 09:56:35 +000012455#include <sys/times.h>
12456
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012457static const unsigned char timescmd_str[] = {
12458 ' ', offsetof(struct tms, tms_utime),
12459 '\n', offsetof(struct tms, tms_stime),
12460 ' ', offsetof(struct tms, tms_cutime),
12461 '\n', offsetof(struct tms, tms_cstime),
12462 0
12463};
Eric Andersencb57d552001-06-28 07:25:16 +000012464
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012465static int timescmd(int ac, char **av)
12466{
12467 long int clk_tck, s, t;
12468 const unsigned char *p;
12469 struct tms buf;
12470
12471 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012472 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012473
12474 p = timescmd_str;
12475 do {
12476 t = *(clock_t *)(((char *) &buf) + p[1]);
12477 s = t / clk_tck;
12478 out1fmt("%ldm%ld.%.3lds%c",
12479 s/60, s%60,
12480 ((t - s * clk_tck) * 1000) / clk_tck,
12481 p[0]);
12482 } while (*(p += 2));
12483
Eric Andersencb57d552001-06-28 07:25:16 +000012484 return 0;
12485}
12486
Eric Andersend35c5df2002-01-09 15:37:36 +000012487#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012488static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012489dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012490{
Eric Andersened9ecf72004-06-22 08:29:45 +000012491 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012492 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012493
Eric Andersenc470f442003-07-28 09:56:35 +000012494 INTOFF;
12495 result = arith(s, &errcode);
12496 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012497 if (errcode == -3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012498 sh_error("exponent less than 0");
Eric Andersen90898442003-08-06 11:20:52 +000012499 else if (errcode == -2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012500 sh_error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012501 else if (errcode == -5)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012502 sh_error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012503 else
12504 synerror(s);
12505 }
12506 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012507
Eric Andersenc470f442003-07-28 09:56:35 +000012508 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012509}
Eric Andersenc470f442003-07-28 09:56:35 +000012510
12511
12512/*
Eric Andersen90898442003-08-06 11:20:52 +000012513 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12514 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12515 *
12516 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012517 */
Eric Andersen90898442003-08-06 11:20:52 +000012518
Eric Andersenc470f442003-07-28 09:56:35 +000012519static int
Eric Andersen90898442003-08-06 11:20:52 +000012520letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012521{
Eric Andersenc470f442003-07-28 09:56:35 +000012522 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012523 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012524
Eric Andersen90898442003-08-06 11:20:52 +000012525 ap = argv + 1;
12526 if(!*ap)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012527 sh_error("expression expected");
Eric Andersen90898442003-08-06 11:20:52 +000012528 for (ap = argv + 1; *ap; ap++) {
12529 i = dash_arith(*ap);
12530 }
Eric Andersenc470f442003-07-28 09:56:35 +000012531
Eric Andersen90898442003-08-06 11:20:52 +000012532 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012533}
12534#endif /* CONFIG_ASH_MATH_SUPPORT */
12535
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012536/* miscbltin.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012537
12538/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012539 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012540 */
12541
12542#undef rflag
12543
12544#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012545#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012546typedef enum __rlimit_resource rlim_t;
12547#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012548#endif
12549
12550
Eric Andersenc470f442003-07-28 09:56:35 +000012551/*
12552 * The read builtin. The -e option causes backslashes to escape the
12553 * following character.
12554 *
12555 * This uses unbuffered input, which may be avoidable in some cases.
12556 */
12557
12558static int
12559readcmd(int argc, char **argv)
12560{
12561 char **ap;
12562 int backslash;
12563 char c;
12564 int rflag;
12565 char *prompt;
12566 const char *ifs;
12567 char *p;
12568 int startword;
12569 int status;
12570 int i;
Paul Fox02eb9342005-09-07 16:56:02 +000012571#if defined(CONFIG_ASH_READ_NCHARS)
12572 int nch_flag = 0;
12573 int nchars = 0;
12574 int silent = 0;
12575 struct termios tty, old_tty;
12576#endif
12577#if defined(CONFIG_ASH_READ_TIMEOUT)
12578 fd_set set;
12579 struct timeval ts;
12580
12581 ts.tv_sec = ts.tv_usec = 0;
12582#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012583
12584 rflag = 0;
12585 prompt = NULL;
Paul Fox02eb9342005-09-07 16:56:02 +000012586#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12587 while ((i = nextopt("p:rt:n:s")) != '\0')
12588#elif defined(CONFIG_ASH_READ_NCHARS)
12589 while ((i = nextopt("p:rn:s")) != '\0')
12590#elif defined(CONFIG_ASH_READ_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012591 while ((i = nextopt("p:rt:")) != '\0')
12592#else
12593 while ((i = nextopt("p:r")) != '\0')
12594#endif
12595 {
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012596 switch(i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012597 case 'p':
Eric Andersenc470f442003-07-28 09:56:35 +000012598 prompt = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012599 break;
12600#if defined(CONFIG_ASH_READ_NCHARS)
12601 case 'n':
12602 nchars = strtol(optionarg, &p, 10);
12603 if (*p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012604 sh_error("invalid count");
Paul Fox02eb9342005-09-07 16:56:02 +000012605 nch_flag = (nchars > 0);
12606 break;
12607 case 's':
12608 silent = 1;
12609 break;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012610#endif
Paul Fox02eb9342005-09-07 16:56:02 +000012611#if defined(CONFIG_ASH_READ_TIMEOUT)
12612 case 't':
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012613 ts.tv_sec = strtol(optionarg, &p, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012614 ts.tv_usec = 0;
12615 if (*p == '.') {
12616 char *p2;
12617 if (*++p) {
12618 int scale;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012619 ts.tv_usec = strtol(p, &p2, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012620 if (*p2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012621 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012622 scale = p2 - p;
12623 /* normalize to usec */
12624 if (scale > 6)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012625 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012626 while (scale++ < 6)
12627 ts.tv_usec *= 10;
12628 }
12629 } else if (*p) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012630 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012631 }
12632 if ( ! ts.tv_sec && ! ts.tv_usec)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012633 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012634 break;
12635#endif
12636 case 'r':
12637 rflag = 1;
12638 break;
12639 default:
12640 break;
12641 }
Eric Andersenc470f442003-07-28 09:56:35 +000012642 }
12643 if (prompt && isatty(0)) {
12644 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012645 }
12646 if (*(ap = argptr) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012647 sh_error("arg count");
Eric Andersenc470f442003-07-28 09:56:35 +000012648 if ((ifs = bltinlookup("IFS")) == NULL)
12649 ifs = defifs;
Paul Fox02eb9342005-09-07 16:56:02 +000012650#if defined(CONFIG_ASH_READ_NCHARS)
12651 if (nch_flag || silent) {
12652 tcgetattr(0, &tty);
12653 old_tty = tty;
12654 if (nch_flag) {
12655 tty.c_lflag &= ~ICANON;
12656 tty.c_cc[VMIN] = nchars;
12657 }
12658 if (silent) {
12659 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12660
12661 }
12662 tcsetattr(0, TCSANOW, &tty);
12663 }
12664#endif
12665#if defined(CONFIG_ASH_READ_TIMEOUT)
12666 if (ts.tv_sec || ts.tv_usec) {
12667 FD_ZERO (&set);
12668 FD_SET (0, &set);
12669
12670 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12671 if (!i) {
12672#if defined(CONFIG_ASH_READ_NCHARS)
12673 if (nch_flag)
12674 tcsetattr(0, TCSANOW, &old_tty);
12675#endif
12676 return 1;
12677 }
12678 }
Ned Ludd2123b7c2005-02-09 21:07:23 +000012679#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012680 status = 0;
12681 startword = 1;
12682 backslash = 0;
12683 STARTSTACKSTR(p);
Paul Fox02eb9342005-09-07 16:56:02 +000012684#if defined(CONFIG_ASH_READ_NCHARS)
12685 while (!nch_flag || nchars--)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012686#else
12687 for (;;)
12688#endif
12689 {
Eric Andersenc470f442003-07-28 09:56:35 +000012690 if (read(0, &c, 1) != 1) {
12691 status = 1;
12692 break;
12693 }
12694 if (c == '\0')
12695 continue;
12696 if (backslash) {
12697 backslash = 0;
12698 if (c != '\n')
12699 goto put;
12700 continue;
12701 }
12702 if (!rflag && c == '\\') {
12703 backslash++;
12704 continue;
12705 }
12706 if (c == '\n')
12707 break;
12708 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12709 continue;
12710 }
12711 startword = 0;
12712 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12713 STACKSTRNUL(p);
12714 setvar(*ap, stackblock(), 0);
12715 ap++;
12716 startword = 1;
12717 STARTSTACKSTR(p);
12718 } else {
12719put:
12720 STPUTC(c, p);
12721 }
12722 }
Paul Fox02eb9342005-09-07 16:56:02 +000012723#if defined(CONFIG_ASH_READ_NCHARS)
12724 if (nch_flag || silent)
12725 tcsetattr(0, TCSANOW, &old_tty);
12726#endif
12727
Eric Andersenc470f442003-07-28 09:56:35 +000012728 STACKSTRNUL(p);
12729 /* Remove trailing blanks */
12730 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12731 *p = '\0';
12732 setvar(*ap, stackblock(), 0);
12733 while (*++ap != NULL)
12734 setvar(*ap, nullstr, 0);
12735 return status;
12736}
12737
12738
12739static int umaskcmd(int argc, char **argv)
12740{
12741 static const char permuser[3] = "ugo";
12742 static const char permmode[3] = "rwx";
12743 static const short int permmask[] = {
12744 S_IRUSR, S_IWUSR, S_IXUSR,
12745 S_IRGRP, S_IWGRP, S_IXGRP,
12746 S_IROTH, S_IWOTH, S_IXOTH
12747 };
12748
12749 char *ap;
12750 mode_t mask;
12751 int i;
12752 int symbolic_mode = 0;
12753
12754 while (nextopt("S") != '\0') {
12755 symbolic_mode = 1;
12756 }
12757
12758 INTOFF;
12759 mask = umask(0);
12760 umask(mask);
12761 INTON;
12762
12763 if ((ap = *argptr) == NULL) {
12764 if (symbolic_mode) {
12765 char buf[18];
12766 char *p = buf;
12767
12768 for (i = 0; i < 3; i++) {
12769 int j;
12770
12771 *p++ = permuser[i];
12772 *p++ = '=';
12773 for (j = 0; j < 3; j++) {
12774 if ((mask & permmask[3 * i + j]) == 0) {
12775 *p++ = permmode[j];
12776 }
12777 }
12778 *p++ = ',';
12779 }
12780 *--p = 0;
12781 puts(buf);
12782 } else {
12783 out1fmt("%.4o\n", mask);
12784 }
12785 } else {
12786 if (is_digit((unsigned char) *ap)) {
12787 mask = 0;
12788 do {
12789 if (*ap >= '8' || *ap < '0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012790 sh_error(illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012791 mask = (mask << 3) + (*ap - '0');
12792 } while (*++ap != '\0');
12793 umask(mask);
12794 } else {
12795 mask = ~mask & 0777;
12796 if (!bb_parse_mode(ap, &mask)) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012797 sh_error("Illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012798 }
12799 umask(~mask & 0777);
12800 }
12801 }
12802 return 0;
12803}
12804
12805/*
12806 * ulimit builtin
12807 *
12808 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12809 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12810 * ash by J.T. Conklin.
12811 *
12812 * Public domain.
12813 */
12814
12815struct limits {
12816 const char *name;
12817 int cmd;
12818 int factor; /* multiply by to get rlim_{cur,max} values */
12819 char option;
12820};
12821
12822static const struct limits limits[] = {
12823#ifdef RLIMIT_CPU
12824 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12825#endif
12826#ifdef RLIMIT_FSIZE
12827 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12828#endif
12829#ifdef RLIMIT_DATA
12830 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12831#endif
12832#ifdef RLIMIT_STACK
12833 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12834#endif
12835#ifdef RLIMIT_CORE
12836 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12837#endif
12838#ifdef RLIMIT_RSS
12839 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12840#endif
12841#ifdef RLIMIT_MEMLOCK
12842 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12843#endif
12844#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012845 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012846#endif
12847#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012848 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012849#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012850#ifdef RLIMIT_AS
12851 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012852#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012853#ifdef RLIMIT_LOCKS
12854 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012855#endif
12856 { (char *) 0, 0, 0, '\0' }
12857};
12858
Glenn L McGrath76620622004-01-13 10:19:37 +000012859enum limtype { SOFT = 0x1, HARD = 0x2 };
12860
12861static void printlim(enum limtype how, const struct rlimit *limit,
12862 const struct limits *l)
12863{
12864 rlim_t val;
12865
12866 val = limit->rlim_max;
12867 if (how & SOFT)
12868 val = limit->rlim_cur;
12869
12870 if (val == RLIM_INFINITY)
12871 out1fmt("unlimited\n");
12872 else {
12873 val /= l->factor;
12874 out1fmt("%lld\n", (long long) val);
12875 }
12876}
12877
Eric Andersenc470f442003-07-28 09:56:35 +000012878int
12879ulimitcmd(int argc, char **argv)
12880{
12881 int c;
12882 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012883 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012884 const struct limits *l;
12885 int set, all = 0;
12886 int optc, what;
12887 struct rlimit limit;
12888
12889 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012890 while ((optc = nextopt("HSa"
12891#ifdef RLIMIT_CPU
12892 "t"
12893#endif
12894#ifdef RLIMIT_FSIZE
12895 "f"
12896#endif
12897#ifdef RLIMIT_DATA
12898 "d"
12899#endif
12900#ifdef RLIMIT_STACK
12901 "s"
12902#endif
12903#ifdef RLIMIT_CORE
12904 "c"
12905#endif
12906#ifdef RLIMIT_RSS
12907 "m"
12908#endif
12909#ifdef RLIMIT_MEMLOCK
12910 "l"
12911#endif
12912#ifdef RLIMIT_NPROC
12913 "p"
12914#endif
12915#ifdef RLIMIT_NOFILE
12916 "n"
12917#endif
12918#ifdef RLIMIT_AS
12919 "v"
12920#endif
12921#ifdef RLIMIT_LOCKS
12922 "w"
12923#endif
12924 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012925 switch (optc) {
12926 case 'H':
12927 how = HARD;
12928 break;
12929 case 'S':
12930 how = SOFT;
12931 break;
12932 case 'a':
12933 all = 1;
12934 break;
12935 default:
12936 what = optc;
12937 }
12938
Glenn L McGrath76620622004-01-13 10:19:37 +000012939 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012940 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012941
12942 set = *argptr ? 1 : 0;
12943 if (set) {
12944 char *p = *argptr;
12945
12946 if (all || argptr[1])
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012947 sh_error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012948 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012949 val = RLIM_INFINITY;
12950 else {
12951 val = (rlim_t) 0;
12952
12953 while ((c = *p++) >= '0' && c <= '9')
12954 {
12955 val = (val * 10) + (long)(c - '0');
12956 if (val < (rlim_t) 0)
12957 break;
12958 }
12959 if (c)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012960 sh_error("bad number");
Eric Andersenc470f442003-07-28 09:56:35 +000012961 val *= l->factor;
12962 }
12963 }
12964 if (all) {
12965 for (l = limits; l->name; l++) {
12966 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012967 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012968 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012969 }
12970 return 0;
12971 }
12972
12973 getrlimit(l->cmd, &limit);
12974 if (set) {
12975 if (how & HARD)
12976 limit.rlim_max = val;
12977 if (how & SOFT)
12978 limit.rlim_cur = val;
12979 if (setrlimit(l->cmd, &limit) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012980 sh_error("error setting limit (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +000012981 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012982 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012983 }
12984 return 0;
12985}
12986
Eric Andersen90898442003-08-06 11:20:52 +000012987
12988#ifdef CONFIG_ASH_MATH_SUPPORT
12989
12990/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12991
12992 Permission is hereby granted, free of charge, to any person obtaining
12993 a copy of this software and associated documentation files (the
12994 "Software"), to deal in the Software without restriction, including
12995 without limitation the rights to use, copy, modify, merge, publish,
12996 distribute, sublicense, and/or sell copies of the Software, and to
12997 permit persons to whom the Software is furnished to do so, subject to
12998 the following conditions:
12999
13000 The above copyright notice and this permission notice shall be
13001 included in all copies or substantial portions of the Software.
13002
13003 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13004 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13005 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13006 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13007 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13008 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13009 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13010*/
13011
13012/* This is my infix parser/evaluator. It is optimized for size, intended
13013 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000013014 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000013015 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000013016 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000013017 * be that which POSIX specifies for shells. */
13018
13019/* The code uses a simple two-stack algorithm. See
13020 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000013021 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000013022 * this is based (this code differs in that it applies operators immediately
13023 * to the stack instead of adding them to a queue to end up with an
13024 * expression). */
13025
13026/* To use the routine, call it with an expression string and error return
13027 * pointer */
13028
13029/*
13030 * Aug 24, 2001 Manuel Novoa III
13031 *
13032 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13033 *
13034 * 1) In arith_apply():
13035 * a) Cached values of *numptr and &(numptr[-1]).
13036 * b) Removed redundant test for zero denominator.
13037 *
13038 * 2) In arith():
13039 * a) Eliminated redundant code for processing operator tokens by moving
13040 * to a table-based implementation. Also folded handling of parens
13041 * into the table.
13042 * b) Combined all 3 loops which called arith_apply to reduce generated
13043 * code size at the cost of speed.
13044 *
13045 * 3) The following expressions were treated as valid by the original code:
13046 * 1() , 0! , 1 ( *3 ) .
13047 * These bugs have been fixed by internally enclosing the expression in
13048 * parens and then checking that all binary ops and right parens are
13049 * preceded by a valid expression (NUM_TOKEN).
13050 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013051 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013052 * ctype's isspace() if it is used by another busybox applet or if additional
13053 * whitespace chars should be considered. Look below the "#include"s for a
13054 * precompiler test.
13055 */
13056
13057/*
13058 * Aug 26, 2001 Manuel Novoa III
13059 *
13060 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13061 *
13062 * Merge in Aaron's comments previously posted to the busybox list,
13063 * modified slightly to take account of my changes to the code.
13064 *
13065 */
13066
13067/*
13068 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13069 *
13070 * - allow access to variable,
13071 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13072 * - realize assign syntax (VAR=expr, +=, *= etc)
13073 * - realize exponentiation (** operator)
13074 * - realize comma separated - expr, expr
13075 * - realise ++expr --expr expr++ expr--
13076 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013077 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013078 * - was restored loses XOR operator
13079 * - remove one goto label, added three ;-)
13080 * - protect $((num num)) as true zero expr (Manuel`s error)
13081 * - always use special isspace(), see comment from bash ;-)
13082 */
13083
13084
13085#define arith_isspace(arithval) \
13086 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13087
13088
13089typedef unsigned char operator;
13090
13091/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013092 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013093 * precedence. The ID portion is so that multiple operators can have the
13094 * same precedence, ensuring that the leftmost one is evaluated first.
13095 * Consider * and /. */
13096
13097#define tok_decl(prec,id) (((id)<<5)|(prec))
13098#define PREC(op) ((op) & 0x1F)
13099
13100#define TOK_LPAREN tok_decl(0,0)
13101
13102#define TOK_COMMA tok_decl(1,0)
13103
13104#define TOK_ASSIGN tok_decl(2,0)
13105#define TOK_AND_ASSIGN tok_decl(2,1)
13106#define TOK_OR_ASSIGN tok_decl(2,2)
13107#define TOK_XOR_ASSIGN tok_decl(2,3)
13108#define TOK_PLUS_ASSIGN tok_decl(2,4)
13109#define TOK_MINUS_ASSIGN tok_decl(2,5)
13110#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13111#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13112
13113#define TOK_MUL_ASSIGN tok_decl(3,0)
13114#define TOK_DIV_ASSIGN tok_decl(3,1)
13115#define TOK_REM_ASSIGN tok_decl(3,2)
13116
13117/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13118#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13119
13120/* conditional is right associativity too */
13121#define TOK_CONDITIONAL tok_decl(4,0)
13122#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13123
13124#define TOK_OR tok_decl(5,0)
13125
13126#define TOK_AND tok_decl(6,0)
13127
13128#define TOK_BOR tok_decl(7,0)
13129
13130#define TOK_BXOR tok_decl(8,0)
13131
13132#define TOK_BAND tok_decl(9,0)
13133
13134#define TOK_EQ tok_decl(10,0)
13135#define TOK_NE tok_decl(10,1)
13136
13137#define TOK_LT tok_decl(11,0)
13138#define TOK_GT tok_decl(11,1)
13139#define TOK_GE tok_decl(11,2)
13140#define TOK_LE tok_decl(11,3)
13141
13142#define TOK_LSHIFT tok_decl(12,0)
13143#define TOK_RSHIFT tok_decl(12,1)
13144
13145#define TOK_ADD tok_decl(13,0)
13146#define TOK_SUB tok_decl(13,1)
13147
13148#define TOK_MUL tok_decl(14,0)
13149#define TOK_DIV tok_decl(14,1)
13150#define TOK_REM tok_decl(14,2)
13151
13152/* exponent is right associativity */
13153#define TOK_EXPONENT tok_decl(15,1)
13154
13155/* For now unary operators. */
13156#define UNARYPREC 16
13157#define TOK_BNOT tok_decl(UNARYPREC,0)
13158#define TOK_NOT tok_decl(UNARYPREC,1)
13159
13160#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13161#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13162
13163#define PREC_PRE (UNARYPREC+2)
13164
13165#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13166#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13167
13168#define PREC_POST (UNARYPREC+3)
13169
13170#define TOK_POST_INC tok_decl(PREC_POST, 0)
13171#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13172
13173#define SPEC_PREC (UNARYPREC+4)
13174
13175#define TOK_NUM tok_decl(SPEC_PREC, 0)
13176#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13177
13178#define NUMPTR (*numstackptr)
13179
13180static inline int tok_have_assign(operator op)
13181{
13182 operator prec = PREC(op);
13183
13184 convert_prec_is_assing(prec);
13185 return (prec == PREC(TOK_ASSIGN) ||
13186 prec == PREC_PRE || prec == PREC_POST);
13187}
13188
13189static inline int is_right_associativity(operator prec)
13190{
13191 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13192 prec == PREC(TOK_CONDITIONAL));
13193}
13194
13195
13196typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013197 arith_t val;
13198 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013199 char contidional_second_val_initialized;
13200 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013201 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013202} v_n_t;
13203
13204
13205typedef struct CHK_VAR_RECURSIVE_LOOPED {
13206 const char *var;
13207 struct CHK_VAR_RECURSIVE_LOOPED *next;
13208} chk_var_recursive_looped_t;
13209
13210static chk_var_recursive_looped_t *prev_chk_var_recursive;
13211
13212
13213static int arith_lookup_val(v_n_t *t)
13214{
13215 if(t->var) {
13216 const char * p = lookupvar(t->var);
13217
13218 if(p) {
13219 int errcode;
13220
13221 /* recursive try as expression */
13222 chk_var_recursive_looped_t *cur;
13223 chk_var_recursive_looped_t cur_save;
13224
13225 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13226 if(strcmp(cur->var, t->var) == 0) {
13227 /* expression recursion loop detected */
13228 return -5;
13229 }
13230 }
13231 /* save current lookuped var name */
13232 cur = prev_chk_var_recursive;
13233 cur_save.var = t->var;
13234 cur_save.next = cur;
13235 prev_chk_var_recursive = &cur_save;
13236
13237 t->val = arith (p, &errcode);
13238 /* restore previous ptr after recursiving */
13239 prev_chk_var_recursive = cur;
13240 return errcode;
13241 } else {
13242 /* allow undefined var as 0 */
13243 t->val = 0;
13244 }
13245 }
13246 return 0;
13247}
13248
13249/* "applying" a token means performing it on the top elements on the integer
13250 * stack. For a unary operator it will only change the top element, but a
13251 * binary operator will pop two arguments and push a result */
13252static inline int
13253arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13254{
Eric Andersen90898442003-08-06 11:20:52 +000013255 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013256 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013257 int ret_arith_lookup_val;
13258
13259 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13260 without arguments */
13261 numptr_m1 = NUMPTR - 1;
13262
13263 /* check operand is var with noninteger value */
13264 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13265 if(ret_arith_lookup_val)
13266 return ret_arith_lookup_val;
13267
13268 rez = numptr_m1->val;
13269 if (op == TOK_UMINUS)
13270 rez *= -1;
13271 else if (op == TOK_NOT)
13272 rez = !rez;
13273 else if (op == TOK_BNOT)
13274 rez = ~rez;
13275 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13276 rez++;
13277 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13278 rez--;
13279 else if (op != TOK_UPLUS) {
13280 /* Binary operators */
13281
13282 /* check and binary operators need two arguments */
13283 if (numptr_m1 == numstack) goto err;
13284
13285 /* ... and they pop one */
13286 --NUMPTR;
13287 numptr_val = rez;
13288 if (op == TOK_CONDITIONAL) {
13289 if(! numptr_m1->contidional_second_val_initialized) {
13290 /* protect $((expr1 ? expr2)) without ": expr" */
13291 goto err;
13292 }
13293 rez = numptr_m1->contidional_second_val;
13294 } else if(numptr_m1->contidional_second_val_initialized) {
13295 /* protect $((expr1 : expr2)) without "expr ? " */
13296 goto err;
13297 }
13298 numptr_m1 = NUMPTR - 1;
13299 if(op != TOK_ASSIGN) {
13300 /* check operand is var with noninteger value for not '=' */
13301 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13302 if(ret_arith_lookup_val)
13303 return ret_arith_lookup_val;
13304 }
13305 if (op == TOK_CONDITIONAL) {
13306 numptr_m1->contidional_second_val = rez;
13307 }
13308 rez = numptr_m1->val;
13309 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13310 rez |= numptr_val;
13311 else if (op == TOK_OR)
13312 rez = numptr_val || rez;
13313 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13314 rez &= numptr_val;
13315 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13316 rez ^= numptr_val;
13317 else if (op == TOK_AND)
13318 rez = rez && numptr_val;
13319 else if (op == TOK_EQ)
13320 rez = (rez == numptr_val);
13321 else if (op == TOK_NE)
13322 rez = (rez != numptr_val);
13323 else if (op == TOK_GE)
13324 rez = (rez >= numptr_val);
13325 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13326 rez >>= numptr_val;
13327 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13328 rez <<= numptr_val;
13329 else if (op == TOK_GT)
13330 rez = (rez > numptr_val);
13331 else if (op == TOK_LT)
13332 rez = (rez < numptr_val);
13333 else if (op == TOK_LE)
13334 rez = (rez <= numptr_val);
13335 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13336 rez *= numptr_val;
13337 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13338 rez += numptr_val;
13339 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13340 rez -= numptr_val;
13341 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13342 rez = numptr_val;
13343 else if (op == TOK_CONDITIONAL_SEP) {
13344 if (numptr_m1 == numstack) {
13345 /* protect $((expr : expr)) without "expr ? " */
13346 goto err;
13347 }
13348 numptr_m1->contidional_second_val_initialized = op;
13349 numptr_m1->contidional_second_val = numptr_val;
13350 }
13351 else if (op == TOK_CONDITIONAL) {
13352 rez = rez ?
13353 numptr_val : numptr_m1->contidional_second_val;
13354 }
13355 else if(op == TOK_EXPONENT) {
13356 if(numptr_val < 0)
13357 return -3; /* exponent less than 0 */
13358 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013359 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013360
13361 if(numptr_val)
13362 while(numptr_val--)
13363 c *= rez;
13364 rez = c;
13365 }
13366 }
13367 else if(numptr_val==0) /* zero divisor check */
13368 return -2;
13369 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13370 rez /= numptr_val;
13371 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13372 rez %= numptr_val;
13373 }
13374 if(tok_have_assign(op)) {
13375 char buf[32];
13376
13377 if(numptr_m1->var == NULL) {
13378 /* Hmm, 1=2 ? */
13379 goto err;
13380 }
13381 /* save to shell variable */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013382#ifdef CONFIG_ASH_MATH_SUPPORT_64
13383 snprintf(buf, sizeof(buf), "%lld", rez);
13384#else
13385 snprintf(buf, sizeof(buf), "%ld", rez);
13386#endif
Eric Andersen90898442003-08-06 11:20:52 +000013387 setvar(numptr_m1->var, buf, 0);
13388 /* after saving, make previous value for v++ or v-- */
13389 if(op == TOK_POST_INC)
13390 rez--;
13391 else if(op == TOK_POST_DEC)
13392 rez++;
13393 }
13394 numptr_m1->val = rez;
13395 /* protect geting var value, is number now */
13396 numptr_m1->var = NULL;
13397 return 0;
13398err: return(-1);
13399}
13400
13401/* longest must first */
13402static const char op_tokens[] = {
13403 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13404 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13405 '<','<', 0, TOK_LSHIFT,
13406 '>','>', 0, TOK_RSHIFT,
13407 '|','|', 0, TOK_OR,
13408 '&','&', 0, TOK_AND,
13409 '!','=', 0, TOK_NE,
13410 '<','=', 0, TOK_LE,
13411 '>','=', 0, TOK_GE,
13412 '=','=', 0, TOK_EQ,
13413 '|','=', 0, TOK_OR_ASSIGN,
13414 '&','=', 0, TOK_AND_ASSIGN,
13415 '*','=', 0, TOK_MUL_ASSIGN,
13416 '/','=', 0, TOK_DIV_ASSIGN,
13417 '%','=', 0, TOK_REM_ASSIGN,
13418 '+','=', 0, TOK_PLUS_ASSIGN,
13419 '-','=', 0, TOK_MINUS_ASSIGN,
13420 '-','-', 0, TOK_POST_DEC,
13421 '^','=', 0, TOK_XOR_ASSIGN,
13422 '+','+', 0, TOK_POST_INC,
13423 '*','*', 0, TOK_EXPONENT,
13424 '!', 0, TOK_NOT,
13425 '<', 0, TOK_LT,
13426 '>', 0, TOK_GT,
13427 '=', 0, TOK_ASSIGN,
13428 '|', 0, TOK_BOR,
13429 '&', 0, TOK_BAND,
13430 '*', 0, TOK_MUL,
13431 '/', 0, TOK_DIV,
13432 '%', 0, TOK_REM,
13433 '+', 0, TOK_ADD,
13434 '-', 0, TOK_SUB,
13435 '^', 0, TOK_BXOR,
13436 /* uniq */
13437 '~', 0, TOK_BNOT,
13438 ',', 0, TOK_COMMA,
13439 '?', 0, TOK_CONDITIONAL,
13440 ':', 0, TOK_CONDITIONAL_SEP,
13441 ')', 0, TOK_RPAREN,
13442 '(', 0, TOK_LPAREN,
13443 0
13444};
13445/* ptr to ")" */
13446#define endexpression &op_tokens[sizeof(op_tokens)-7]
13447
13448
Eric Andersened9ecf72004-06-22 08:29:45 +000013449static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013450{
13451 register char arithval; /* Current character under analysis */
13452 operator lasttok, op;
13453 operator prec;
13454
13455 const char *p = endexpression;
13456 int errcode;
13457
13458 size_t datasizes = strlen(expr) + 2;
13459
13460 /* Stack of integers */
13461 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013462 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013463 * the reader. */
13464 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13465 *numstackptr = numstack;
13466 /* Stack of operator tokens */
13467 operator *stack = alloca((datasizes) * sizeof(operator)),
13468 *stackptr = stack;
13469
13470 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13471 *perrcode = errcode = 0;
13472
13473 while(1) {
13474 if ((arithval = *expr) == 0) {
13475 if (p == endexpression) {
13476 /* Null expression. */
13477 return 0;
13478 }
13479
13480 /* This is only reached after all tokens have been extracted from the
13481 * input stream. If there are still tokens on the operator stack, they
13482 * are to be applied in order. At the end, there should be a final
13483 * result on the integer stack */
13484
13485 if (expr != endexpression + 1) {
13486 /* If we haven't done so already, */
13487 /* append a closing right paren */
13488 expr = endexpression;
13489 /* and let the loop process it. */
13490 continue;
13491 }
13492 /* At this point, we're done with the expression. */
13493 if (numstackptr != numstack+1) {
13494 /* ... but if there isn't, it's bad */
13495 err:
13496 return (*perrcode = -1);
13497 }
13498 if(numstack->var) {
13499 /* expression is $((var)) only, lookup now */
13500 errcode = arith_lookup_val(numstack);
13501 }
13502 ret:
13503 *perrcode = errcode;
13504 return numstack->val;
13505 } else {
13506 /* Continue processing the expression. */
13507 if (arith_isspace(arithval)) {
13508 /* Skip whitespace */
13509 goto prologue;
13510 }
13511 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013512 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013513
13514 numstackptr->var = alloca(var_name_size);
13515 safe_strncpy(numstackptr->var, expr, var_name_size);
13516 expr = p;
13517 num:
13518 numstackptr->contidional_second_val_initialized = 0;
13519 numstackptr++;
13520 lasttok = TOK_NUM;
13521 continue;
13522 } else if (is_digit(arithval)) {
13523 numstackptr->var = NULL;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013524#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersenad63cb22004-10-08 09:43:34 +000013525 numstackptr->val = strtoll(expr, (char **) &expr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013526#else
13527 numstackptr->val = strtol(expr, (char **) &expr, 0);
13528#endif
Eric Andersen90898442003-08-06 11:20:52 +000013529 goto num;
13530 }
13531 for(p = op_tokens; ; p++) {
13532 const char *o;
13533
13534 if(*p == 0) {
13535 /* strange operator not found */
13536 goto err;
13537 }
13538 for(o = expr; *p && *o == *p; p++)
13539 o++;
13540 if(! *p) {
13541 /* found */
13542 expr = o - 1;
13543 break;
13544 }
13545 /* skip tail uncompared token */
13546 while(*p)
13547 p++;
13548 /* skip zero delim */
13549 p++;
13550 }
13551 op = p[1];
13552
13553 /* post grammar: a++ reduce to num */
13554 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13555 lasttok = TOK_NUM;
13556
13557 /* Plus and minus are binary (not unary) _only_ if the last
13558 * token was as number, or a right paren (which pretends to be
13559 * a number, since it evaluates to one). Think about it.
13560 * It makes sense. */
13561 if (lasttok != TOK_NUM) {
13562 switch(op) {
13563 case TOK_ADD:
13564 op = TOK_UPLUS;
13565 break;
13566 case TOK_SUB:
13567 op = TOK_UMINUS;
13568 break;
13569 case TOK_POST_INC:
13570 op = TOK_PRE_INC;
13571 break;
13572 case TOK_POST_DEC:
13573 op = TOK_PRE_DEC;
13574 break;
13575 }
13576 }
13577 /* We don't want a unary operator to cause recursive descent on the
13578 * stack, because there can be many in a row and it could cause an
13579 * operator to be evaluated before its argument is pushed onto the
13580 * integer stack. */
13581 /* But for binary operators, "apply" everything on the operator
13582 * stack until we find an operator with a lesser priority than the
13583 * one we have just extracted. */
13584 /* Left paren is given the lowest priority so it will never be
13585 * "applied" in this way.
13586 * if associativity is right and priority eq, applied also skip
13587 */
13588 prec = PREC(op);
13589 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13590 /* not left paren or unary */
13591 if (lasttok != TOK_NUM) {
13592 /* binary op must be preceded by a num */
13593 goto err;
13594 }
13595 while (stackptr != stack) {
13596 if (op == TOK_RPAREN) {
13597 /* The algorithm employed here is simple: while we don't
13598 * hit an open paren nor the bottom of the stack, pop
13599 * tokens and apply them */
13600 if (stackptr[-1] == TOK_LPAREN) {
13601 --stackptr;
13602 /* Any operator directly after a */
13603 lasttok = TOK_NUM;
13604 /* close paren should consider itself binary */
13605 goto prologue;
13606 }
13607 } else {
13608 operator prev_prec = PREC(stackptr[-1]);
13609
13610 convert_prec_is_assing(prec);
13611 convert_prec_is_assing(prev_prec);
13612 if (prev_prec < prec)
13613 break;
13614 /* check right assoc */
13615 if(prev_prec == prec && is_right_associativity(prec))
13616 break;
13617 }
13618 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13619 if(errcode) goto ret;
13620 }
13621 if (op == TOK_RPAREN) {
13622 goto err;
13623 }
13624 }
13625
13626 /* Push this operator to the stack and remember it. */
13627 *stackptr++ = lasttok = op;
13628
13629 prologue:
13630 ++expr;
13631 }
13632 }
13633}
13634#endif /* CONFIG_ASH_MATH_SUPPORT */
13635
13636
Eric Andersenc470f442003-07-28 09:56:35 +000013637#ifdef DEBUG
13638const char *bb_applet_name = "debug stuff usage";
13639int main(int argc, char **argv)
13640{
13641 return ash_main(argc, argv);
13642}
13643#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013644
Eric Andersendf82f612001-06-28 07:46:40 +000013645/*-
13646 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013647 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013648 *
13649 * This code is derived from software contributed to Berkeley by
13650 * Kenneth Almquist.
13651 *
13652 * Redistribution and use in source and binary forms, with or without
13653 * modification, are permitted provided that the following conditions
13654 * are met:
13655 * 1. Redistributions of source code must retain the above copyright
13656 * notice, this list of conditions and the following disclaimer.
13657 * 2. Redistributions in binary form must reproduce the above copyright
13658 * notice, this list of conditions and the following disclaimer in the
13659 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013660 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013661 * may be used to endorse or promote products derived from this software
13662 * without specific prior written permission.
13663 *
13664 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13665 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13666 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13667 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13668 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13669 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13670 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13671 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13672 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13673 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13674 * SUCH DAMAGE.
13675 */