blob: 9eb395fd9b697d8bfc0f51dc3f7373b1cd259e47 [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;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001405#define arith_t_type (long long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001406#else
1407typedef long arith_t;
Eric Andersena68ea1c2006-01-30 22:48:39 +00001408#define arith_t_type (long)
Eric Andersened9ecf72004-06-22 08:29:45 +00001409#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001410
1411#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001412static arith_t dash_arith(const char *);
1413static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001414#endif
1415
Eric Andersen16767e22004-03-16 05:14:10 +00001416#ifdef CONFIG_ASH_RANDOM_SUPPORT
1417static unsigned long rseed;
1418static void change_random(const char *);
1419# ifndef DYNAMIC_VAR
1420# define DYNAMIC_VAR
1421# endif
1422#endif
1423
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001424/* init.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001425
1426static void reset(void);
1427
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001428/* var.h */
Eric Andersen2870d962001-07-02 17:27:21 +00001429
1430/*
1431 * Shell variables.
1432 */
1433
1434/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001435#define VEXPORT 0x01 /* variable is exported */
1436#define VREADONLY 0x02 /* variable cannot be modified */
1437#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1438#define VTEXTFIXED 0x08 /* text is statically allocated */
1439#define VSTACK 0x10 /* text is allocated on the stack */
1440#define VUNSET 0x20 /* the variable is not set */
1441#define VNOFUNC 0x40 /* don't call the callback function */
1442#define VNOSET 0x80 /* do not set variable - just readonly test */
1443#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001444#ifdef DYNAMIC_VAR
1445# define VDYNAMIC 0x200 /* dynamic variable */
1446# else
1447# define VDYNAMIC 0
1448#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001449
1450struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001451 struct var *next; /* next entry in hash list */
1452 int flags; /* flags are defined above */
1453 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001454 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001455 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001456};
1457
1458struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001459 struct localvar *next; /* next local variable in list */
1460 struct var *vp; /* the variable that was made local */
1461 int flags; /* saved flags */
1462 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001463};
1464
1465
Eric Andersen2870d962001-07-02 17:27:21 +00001466static struct localvar *localvars;
1467
Eric Andersenc470f442003-07-28 09:56:35 +00001468/*
1469 * Shell variables.
1470 */
1471
1472#ifdef CONFIG_ASH_GETOPTS
1473static void getoptsreset(const char *);
1474#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001475
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001476#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001477#include <locale.h>
1478static void change_lc_all(const char *value);
1479static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001480#endif
1481
Eric Andersenef02f822004-03-11 13:34:24 +00001482
Eric Andersen2870d962001-07-02 17:27:21 +00001483#define VTABSIZE 39
1484
Eric Andersen90898442003-08-06 11:20:52 +00001485static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001486#ifdef IFS_BROKEN
1487static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001488#define defifs (defifsvar + 4)
1489#else
Eric Andersenc470f442003-07-28 09:56:35 +00001490static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001491#endif
1492
Eric Andersenc470f442003-07-28 09:56:35 +00001493
1494static struct var varinit[] = {
1495#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001496 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001497#else
Eric Andersen16767e22004-03-16 05:14:10 +00001498 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001499#endif
1500
1501#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001502 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1503 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001504#endif
1505
Eric Andersen16767e22004-03-16 05:14:10 +00001506 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1507 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1508 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1509 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001510#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001511 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1512#endif
1513#ifdef CONFIG_ASH_RANDOM_SUPPORT
1514 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001515#endif
1516#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001517 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1518 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001519#endif
1520#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001521 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001522#endif
1523};
1524
1525#define vifs varinit[0]
1526#ifdef CONFIG_ASH_MAIL
1527#define vmail (&vifs)[1]
1528#define vmpath (&vmail)[1]
1529#else
1530#define vmpath vifs
1531#endif
1532#define vpath (&vmpath)[1]
1533#define vps1 (&vpath)[1]
1534#define vps2 (&vps1)[1]
1535#define vps4 (&vps2)[1]
1536#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001537#ifdef CONFIG_ASH_GETOPTS
1538#define vrandom (&voptind)[1]
1539#else
1540#define vrandom (&vps4)[1]
1541#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001542#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001543
1544/*
1545 * The following macros access the values of the above variables.
1546 * They have to skip over the name. They return the null string
1547 * for unset variables.
1548 */
1549
1550#define ifsval() (vifs.text + 4)
1551#define ifsset() ((vifs.flags & VUNSET) == 0)
1552#define mailval() (vmail.text + 5)
1553#define mpathval() (vmpath.text + 9)
1554#define pathval() (vpath.text + 5)
1555#define ps1val() (vps1.text + 4)
1556#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001557#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001558#define optindval() (voptind.text + 7)
1559
1560#define mpathset() ((vmpath.flags & VUNSET) == 0)
1561
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001562static void setvar(const char *, const char *, int);
1563static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001564static void listsetvar(struct strlist *, int);
1565static char *lookupvar(const char *);
1566static char *bltinlookup(const char *);
1567static char **listvars(int, int, char ***);
1568#define environment() listvars(VEXPORT, VUNSET, 0)
1569static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001570static void poplocalvars(void);
1571static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001572#ifdef CONFIG_ASH_GETOPTS
1573static int setvarsafe(const char *, const char *, int);
1574#endif
1575static int varcmp(const char *, const char *);
1576static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001577
1578
Eric Andersenc470f442003-07-28 09:56:35 +00001579static inline int varequal(const char *a, const char *b) {
1580 return !varcmp(a, b);
1581}
Eric Andersen2870d962001-07-02 17:27:21 +00001582
1583
Eric Andersenc470f442003-07-28 09:56:35 +00001584static int loopnest; /* current loop nesting level */
1585
Eric Andersenc470f442003-07-28 09:56:35 +00001586/*
1587 * The parsefile structure pointed to by the global variable parsefile
1588 * contains information about the current file being read.
1589 */
1590
1591
1592struct redirtab {
1593 struct redirtab *next;
1594 int renamed[10];
1595 int nullredirs;
1596};
1597
1598static struct redirtab *redirlist;
1599static int nullredirs;
1600
1601extern char **environ;
1602
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001603/* output.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001604
1605
1606static void outstr(const char *, FILE *);
1607static void outcslow(int, FILE *);
1608static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001609static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001610static int out1fmt(const char *, ...)
1611 __attribute__((__format__(__printf__,1,2)));
1612static int fmtstr(char *, size_t, const char *, ...)
1613 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001614
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001615static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001616
Eric Andersenc470f442003-07-28 09:56:35 +00001617
1618static void out1str(const char *p)
1619{
1620 outstr(p, stdout);
1621}
1622
1623static void out2str(const char *p)
1624{
1625 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001626 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001627}
1628
1629/*
1630 * Initialization code.
1631 */
1632
1633/*
1634 * This routine initializes the builtin variables.
1635 */
1636
1637static inline void
1638initvar(void)
1639{
1640 struct var *vp;
1641 struct var *end;
1642 struct var **vpp;
1643
1644 /*
1645 * PS1 depends on uid
1646 */
1647#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1648 vps1.text = "PS1=\\w \\$ ";
1649#else
1650 if (!geteuid())
1651 vps1.text = "PS1=# ";
1652#endif
1653 vp = varinit;
1654 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1655 do {
1656 vpp = hashvar(vp->text);
1657 vp->next = *vpp;
1658 *vpp = vp;
1659 } while (++vp < end);
1660}
1661
1662static inline void
1663init(void)
1664{
1665
1666 /* from input.c: */
1667 {
1668 basepf.nextc = basepf.buf = basebuf;
1669 }
1670
1671 /* from trap.c: */
1672 {
1673 signal(SIGCHLD, SIG_DFL);
1674 }
1675
1676 /* from var.c: */
1677 {
1678 char **envp;
1679 char ppid[32];
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001680 const char *p;
1681 struct stat st1, st2;
Eric Andersenc470f442003-07-28 09:56:35 +00001682
1683 initvar();
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001684 for (envp = environ ; envp && *envp ; envp++) {
Eric Andersenc470f442003-07-28 09:56:35 +00001685 if (strchr(*envp, '=')) {
1686 setvareq(*envp, VEXPORT|VTEXTFIXED);
1687 }
1688 }
1689
1690 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1691 setvar("PPID", ppid, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001692
1693 p = lookupvar("PWD");
1694 if (p)
1695 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1696 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1697 p = 0;
1698 setpwd(p, 0);
Eric Andersenc470f442003-07-28 09:56:35 +00001699 }
1700}
1701
1702/* PEOF (the end of file marker) */
1703
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001704enum {
1705 INPUT_PUSH_FILE = 1,
1706 INPUT_NOFILE_OK = 2,
1707};
1708
Eric Andersenc470f442003-07-28 09:56:35 +00001709/*
1710 * The input line number. Input.c just defines this variable, and saves
1711 * and restores it when files are pushed and popped. The user of this
1712 * package must set its value.
1713 */
1714
1715static int pgetc(void);
1716static int pgetc2(void);
1717static int preadbuffer(void);
1718static void pungetc(void);
1719static void pushstring(char *, void *);
1720static void popstring(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001721static void setinputfd(int, int);
1722static void setinputstring(char *);
1723static void popfile(void);
1724static void popallfiles(void);
1725static void closescript(void);
1726
1727
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001728/* jobs.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001729
1730
1731/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1732#define FORK_FG 0
1733#define FORK_BG 1
1734#define FORK_NOJOB 2
1735
1736/* mode flags for showjob(s) */
1737#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1738#define SHOW_PID 0x04 /* include process pid */
1739#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1740
1741
1742/*
1743 * A job structure contains information about a job. A job is either a
1744 * single process or a set of processes contained in a pipeline. In the
1745 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1746 * array of pids.
1747 */
1748
1749struct procstat {
1750 pid_t pid; /* process id */
1751 int status; /* last process status from wait() */
1752 char *cmd; /* text of command being run */
1753};
1754
1755struct job {
1756 struct procstat ps0; /* status of process */
1757 struct procstat *ps; /* status or processes when more than one */
1758#if JOBS
1759 int stopstatus; /* status of a stopped job */
1760#endif
1761 uint32_t
1762 nprocs: 16, /* number of processes */
1763 state: 8,
1764#define JOBRUNNING 0 /* at least one proc running */
1765#define JOBSTOPPED 1 /* all procs are stopped */
1766#define JOBDONE 2 /* all procs are completed */
1767#if JOBS
1768 sigint: 1, /* job was killed by SIGINT */
1769 jobctl: 1, /* job running under job control */
1770#endif
1771 waited: 1, /* true if this entry has been waited for */
1772 used: 1, /* true if this entry is in used */
1773 changed: 1; /* true if status has changed */
1774 struct job *prev_job; /* previous job */
1775};
1776
1777static pid_t backgndpid; /* pid of last background process */
1778static int job_warning; /* user was warned about stopped jobs */
1779#if JOBS
1780static int jobctl; /* true if doing job control */
1781#endif
1782
1783static struct job *makejob(union node *, int);
1784static int forkshell(struct job *, union node *, int);
1785static int waitforjob(struct job *);
1786static int stoppedjobs(void);
1787
1788#if ! JOBS
1789#define setjobctl(on) /* do nothing */
1790#else
1791static void setjobctl(int);
1792static void showjobs(FILE *, int);
1793#endif
1794
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001795/* main.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001796
1797
1798/* pid of main shell */
1799static int rootpid;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001800/* shell level: 0 for the main shell, 1 for its children, and so on */
1801static int shlvl;
1802#define rootshell (!shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00001803
1804static void readcmdfile(char *);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001805static int cmdloop(int);
Eric Andersenc470f442003-07-28 09:56:35 +00001806
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001807/* memalloc.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001808
1809
1810struct stackmark {
1811 struct stack_block *stackp;
1812 char *stacknxt;
1813 size_t stacknleft;
1814 struct stackmark *marknext;
1815};
1816
1817/* minimum size of a block */
1818#define MINSIZE SHELL_ALIGN(504)
1819
1820struct stack_block {
1821 struct stack_block *prev;
1822 char space[MINSIZE];
1823};
1824
1825static struct stack_block stackbase;
1826static struct stack_block *stackp = &stackbase;
1827static struct stackmark *markp;
1828static char *stacknxt = stackbase.space;
1829static size_t stacknleft = MINSIZE;
1830static char *sstrend = stackbase.space + MINSIZE;
1831static int herefd = -1;
1832
1833
1834static pointer ckmalloc(size_t);
1835static pointer ckrealloc(pointer, size_t);
1836static char *savestr(const char *);
1837static pointer stalloc(size_t);
1838static void stunalloc(pointer);
1839static void setstackmark(struct stackmark *);
1840static void popstackmark(struct stackmark *);
1841static void growstackblock(void);
1842static void *growstackstr(void);
1843static char *makestrspace(size_t, char *);
1844static char *stnputs(const char *, size_t, char *);
1845static char *stputs(const char *, char *);
1846
1847
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001848static inline char *_STPUTC(int c, char *p) {
Eric Andersenc470f442003-07-28 09:56:35 +00001849 if (p == sstrend)
1850 p = growstackstr();
1851 *p++ = c;
1852 return p;
1853}
1854
1855#define stackblock() ((void *)stacknxt)
1856#define stackblocksize() stacknleft
1857#define STARTSTACKSTR(p) ((p) = stackblock())
1858#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1859#define CHECKSTRSPACE(n, p) \
1860 ({ \
1861 char *q = (p); \
1862 size_t l = (n); \
1863 size_t m = sstrend - q; \
1864 if (l > m) \
1865 (p) = makestrspace(l, q); \
1866 0; \
1867 })
1868#define USTPUTC(c, p) (*p++ = (c))
1869#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1870#define STUNPUTC(p) (--p)
1871#define STTOPC(p) p[-1]
1872#define STADJUST(amount, p) (p += (amount))
1873
1874#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1875#define ungrabstackstr(s, p) stunalloc((s))
1876#define stackstrend() ((void *)sstrend)
1877
1878#define ckfree(p) free((pointer)(p))
1879
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001880/* mystring.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001881
1882
1883#define DOLATSTRLEN 4
1884
1885static char *prefix(const char *, const char *);
1886static int number(const char *);
1887static int is_number(const char *);
1888static char *single_quote(const char *);
1889static char *sstrdup(const char *);
1890
1891#define equal(s1, s2) (strcmp(s1, s2) == 0)
1892#define scopy(s1, s2) ((void)strcpy(s2, s1))
1893
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001894/* options.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001895
1896struct shparam {
1897 int nparam; /* # of positional parameters (without $0) */
1898 unsigned char malloc; /* if parameter list dynamically allocated */
1899 char **p; /* parameter list */
1900#ifdef CONFIG_ASH_GETOPTS
1901 int optind; /* next parameter to be processed by getopts */
1902 int optoff; /* used by getopts */
1903#endif
1904};
1905
1906
1907#define eflag optlist[0]
1908#define fflag optlist[1]
1909#define Iflag optlist[2]
1910#define iflag optlist[3]
1911#define mflag optlist[4]
1912#define nflag optlist[5]
1913#define sflag optlist[6]
1914#define xflag optlist[7]
1915#define vflag optlist[8]
1916#define Cflag optlist[9]
1917#define aflag optlist[10]
1918#define bflag optlist[11]
1919#define uflag optlist[12]
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001920#define viflag optlist[13]
Eric Andersenc470f442003-07-28 09:56:35 +00001921
1922#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001923#define nolog optlist[14]
1924#define debug optlist[15]
Paul Fox3f11b1b2005-08-04 19:04:46 +00001925#endif
1926
1927#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1928#define setvimode(on) viflag = 0 /* forcibly keep the option off */
Eric Andersenc470f442003-07-28 09:56:35 +00001929#endif
1930
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001931/* options.c */
Eric Andersenc470f442003-07-28 09:56:35 +00001932
1933
Paul Fox3f11b1b2005-08-04 19:04:46 +00001934static const char *const optletters_optnames[] = {
Eric Andersenc470f442003-07-28 09:56:35 +00001935 "e" "errexit",
1936 "f" "noglob",
1937 "I" "ignoreeof",
1938 "i" "interactive",
1939 "m" "monitor",
1940 "n" "noexec",
1941 "s" "stdin",
1942 "x" "xtrace",
1943 "v" "verbose",
1944 "C" "noclobber",
1945 "a" "allexport",
1946 "b" "notify",
1947 "u" "nounset",
Paul Fox3f11b1b2005-08-04 19:04:46 +00001948 "\0" "vi",
Eric Andersenc470f442003-07-28 09:56:35 +00001949#ifdef DEBUG
1950 "\0" "nolog",
1951 "\0" "debug",
1952#endif
1953};
1954
1955#define optletters(n) optletters_optnames[(n)][0]
1956#define optnames(n) (&optletters_optnames[(n)][1])
1957
Paul Fox3f11b1b2005-08-04 19:04:46 +00001958#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001959
1960static char optlist[NOPTS];
1961
1962
1963static char *arg0; /* value of $0 */
1964static struct shparam shellparam; /* $@ current positional parameters */
1965static char **argptr; /* argument list for builtin commands */
1966static char *optionarg; /* set by nextopt (like getopt) */
1967static char *optptr; /* used by nextopt */
1968
1969static char *minusc; /* argument to -c option */
1970
1971
1972static void procargs(int, char **);
1973static void optschanged(void);
1974static void setparam(char **);
1975static void freeparam(volatile struct shparam *);
1976static int shiftcmd(int, char **);
1977static int setcmd(int, char **);
1978static int nextopt(const char *);
1979
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001980/* redir.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001981
1982/* flags passed to redirect */
1983#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001984#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00001985
1986union node;
1987static void redirect(union node *, int);
1988static void popredir(int);
1989static void clearredir(int);
1990static int copyfd(int, int);
1991static int redirectsafe(union node *, int);
1992
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00001993/* show.h */
Eric Andersenc470f442003-07-28 09:56:35 +00001994
1995
1996#ifdef DEBUG
1997static void showtree(union node *);
1998static void trace(const char *, ...);
1999static void tracev(const char *, va_list);
2000static void trargs(char **);
2001static void trputc(int);
2002static void trputs(const char *);
2003static void opentrace(void);
2004#endif
2005
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002006/* trap.h */
Eric Andersenc470f442003-07-28 09:56:35 +00002007
2008
2009/* trap handler commands */
2010static char *trap[NSIG];
2011/* current value of signal */
2012static char sigmode[NSIG - 1];
2013/* indicates specified signal received */
2014static char gotsig[NSIG - 1];
2015
2016static void clear_traps(void);
2017static void setsignal(int);
2018static void ignoresig(int);
2019static void onsig(int);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002020static int dotrap(void);
Eric Andersenc470f442003-07-28 09:56:35 +00002021static void setinteractive(int);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002022static void exitshell(void) ATTRIBUTE_NORETURN;
Eric Andersenc470f442003-07-28 09:56:35 +00002023static int decode_signal(const char *, int);
2024
2025/*
2026 * This routine is called when an error or an interrupt occurs in an
2027 * interactive shell and control is returned to the main command loop.
2028 */
2029
2030static void
2031reset(void)
2032{
2033 /* from eval.c: */
2034 {
2035 evalskip = 0;
2036 loopnest = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002037 }
2038
2039 /* from input.c: */
2040 {
2041 parselleft = parsenleft = 0; /* clear input buffer */
2042 popallfiles();
2043 }
2044
2045 /* from parser.c: */
2046 {
2047 tokpushback = 0;
2048 checkkwd = 0;
2049 }
2050
2051 /* from redir.c: */
2052 {
2053 clearredir(0);
2054 }
2055
2056}
2057
2058#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002059static struct alias *atab[ATABSIZE];
2060
Eric Andersenc470f442003-07-28 09:56:35 +00002061static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002062static struct alias *freealias(struct alias *);
2063static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002064
Eric Andersenc470f442003-07-28 09:56:35 +00002065static void
2066setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002067{
2068 struct alias *ap, **app;
2069
2070 app = __lookupalias(name);
2071 ap = *app;
2072 INTOFF;
2073 if (ap) {
2074 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002075 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002076 }
Eric Andersenc470f442003-07-28 09:56:35 +00002077 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002078 ap->flag &= ~ALIASDEAD;
2079 } else {
2080 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002081 ap = ckmalloc(sizeof (struct alias));
2082 ap->name = savestr(name);
2083 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002084 ap->flag = 0;
2085 ap->next = 0;
2086 *app = ap;
2087 }
2088 INTON;
2089}
2090
Eric Andersenc470f442003-07-28 09:56:35 +00002091static int
2092unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002093{
Eric Andersencb57d552001-06-28 07:25:16 +00002094 struct alias **app;
2095
2096 app = __lookupalias(name);
2097
2098 if (*app) {
2099 INTOFF;
2100 *app = freealias(*app);
2101 INTON;
2102 return (0);
2103 }
2104
2105 return (1);
2106}
2107
Eric Andersenc470f442003-07-28 09:56:35 +00002108static void
2109rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002110{
Eric Andersencb57d552001-06-28 07:25:16 +00002111 struct alias *ap, **app;
2112 int i;
2113
2114 INTOFF;
2115 for (i = 0; i < ATABSIZE; i++) {
2116 app = &atab[i];
2117 for (ap = *app; ap; ap = *app) {
2118 *app = freealias(*app);
2119 if (ap == *app) {
2120 app = &ap->next;
2121 }
2122 }
2123 }
2124 INTON;
2125}
2126
Eric Andersenc470f442003-07-28 09:56:35 +00002127static struct alias *
2128lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002129{
Eric Andersenc470f442003-07-28 09:56:35 +00002130 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002131
Eric Andersenc470f442003-07-28 09:56:35 +00002132 if (check && ap && (ap->flag & ALIASINUSE))
2133 return (NULL);
2134 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002135}
2136
Eric Andersencb57d552001-06-28 07:25:16 +00002137/*
2138 * TODO - sort output
2139 */
Eric Andersenc470f442003-07-28 09:56:35 +00002140static int
2141aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002142{
2143 char *n, *v;
2144 int ret = 0;
2145 struct alias *ap;
2146
2147 if (argc == 1) {
2148 int i;
2149
2150 for (i = 0; i < ATABSIZE; i++)
2151 for (ap = atab[i]; ap; ap = ap->next) {
2152 printalias(ap);
2153 }
2154 return (0);
2155 }
2156 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002157 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002158 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002159 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002160 ret = 1;
2161 } else
2162 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002163 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002164 *v++ = '\0';
2165 setalias(n, v);
2166 }
2167 }
2168
2169 return (ret);
2170}
2171
Eric Andersenc470f442003-07-28 09:56:35 +00002172static int
2173unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002174{
2175 int i;
2176
2177 while ((i = nextopt("a")) != '\0') {
2178 if (i == 'a') {
2179 rmaliases();
2180 return (0);
2181 }
2182 }
2183 for (i = 0; *argptr; argptr++) {
2184 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002185 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002186 i = 1;
2187 }
2188 }
2189
2190 return (i);
2191}
2192
Eric Andersenc470f442003-07-28 09:56:35 +00002193static struct alias *
2194freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002195 struct alias *next;
2196
2197 if (ap->flag & ALIASINUSE) {
2198 ap->flag |= ALIASDEAD;
2199 return ap;
2200 }
2201
2202 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002203 ckfree(ap->name);
2204 ckfree(ap->val);
2205 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002206 return next;
2207}
2208
Eric Andersenc470f442003-07-28 09:56:35 +00002209static void
2210printalias(const struct alias *ap) {
2211 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2212}
Eric Andersencb57d552001-06-28 07:25:16 +00002213
Eric Andersenc470f442003-07-28 09:56:35 +00002214static struct alias **
2215__lookupalias(const char *name) {
2216 unsigned int hashval;
2217 struct alias **app;
2218 const char *p;
2219 unsigned int ch;
2220
2221 p = name;
2222
2223 ch = (unsigned char)*p;
2224 hashval = ch << 4;
2225 while (ch) {
2226 hashval += ch;
2227 ch = (unsigned char)*++p;
2228 }
2229 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002230
2231 for (; *app; app = &(*app)->next) {
2232 if (equal(name, (*app)->name)) {
2233 break;
2234 }
2235 }
2236
2237 return app;
2238}
Eric Andersenc470f442003-07-28 09:56:35 +00002239#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002240
Eric Andersencb57d552001-06-28 07:25:16 +00002241
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002242/* cd.c */
Eric Andersen2870d962001-07-02 17:27:21 +00002243
Eric Andersencb57d552001-06-28 07:25:16 +00002244/*
Eric Andersenc470f442003-07-28 09:56:35 +00002245 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002246 */
2247
Eric Andersenc470f442003-07-28 09:56:35 +00002248#define CD_PHYSICAL 1
2249#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002250
Eric Andersenc470f442003-07-28 09:56:35 +00002251static int docd(const char *, int);
2252static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002253
Eric Andersenc470f442003-07-28 09:56:35 +00002254static char *curdir = nullstr; /* current working directory */
2255static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002256
Eric Andersenc470f442003-07-28 09:56:35 +00002257static int
2258cdopt(void)
2259{
2260 int flags = 0;
2261 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002262
Eric Andersenc470f442003-07-28 09:56:35 +00002263 j = 'L';
2264 while ((i = nextopt("LP"))) {
2265 if (i != j) {
2266 flags ^= CD_PHYSICAL;
2267 j = i;
2268 }
2269 }
Eric Andersencb57d552001-06-28 07:25:16 +00002270
Eric Andersenc470f442003-07-28 09:56:35 +00002271 return flags;
2272}
Eric Andersen2870d962001-07-02 17:27:21 +00002273
Eric Andersenc470f442003-07-28 09:56:35 +00002274static int
2275cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002276{
2277 const char *dest;
2278 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002279 const char *p;
2280 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002281 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002282 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002283
Eric Andersenc470f442003-07-28 09:56:35 +00002284 flags = cdopt();
2285 dest = *argptr;
2286 if (!dest)
2287 dest = bltinlookup(homestr);
2288 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002289 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002290 flags |= CD_PRINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002291 }
Eric Andersenc470f442003-07-28 09:56:35 +00002292 if (!dest)
2293 dest = nullstr;
2294 if (*dest == '/')
2295 goto step7;
2296 if (*dest == '.') {
2297 c = dest[1];
2298dotdot:
2299 switch (c) {
2300 case '\0':
2301 case '/':
2302 goto step6;
2303 case '.':
2304 c = dest[2];
2305 if (c != '.')
2306 goto dotdot;
2307 }
2308 }
2309 if (!*dest)
2310 dest = ".";
2311 if (!(path = bltinlookup("CDPATH"))) {
2312step6:
2313step7:
2314 p = dest;
2315 goto docd;
2316 }
2317 do {
2318 c = *path;
2319 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002320 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002321 if (c && c != ':')
2322 flags |= CD_PRINT;
2323docd:
2324 if (!docd(p, flags))
2325 goto out;
2326 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002327 }
Eric Andersenc470f442003-07-28 09:56:35 +00002328 } while (path);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002329 sh_error("can't cd to %s", dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002330 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002331out:
2332 if (flags & CD_PRINT)
2333 out1fmt(snlfmt, curdir);
2334 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002335}
2336
2337
2338/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002339 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002340 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002341 */
2342
Eric Andersenc470f442003-07-28 09:56:35 +00002343static inline const char *
2344updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002345{
Eric Andersenc470f442003-07-28 09:56:35 +00002346 char *new;
2347 char *p;
2348 char *cdcomppath;
2349 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002350
Eric Andersenc470f442003-07-28 09:56:35 +00002351 cdcomppath = sstrdup(dir);
2352 STARTSTACKSTR(new);
2353 if (*dir != '/') {
2354 if (curdir == nullstr)
2355 return 0;
2356 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002357 }
Eric Andersenc470f442003-07-28 09:56:35 +00002358 new = makestrspace(strlen(dir) + 2, new);
2359 lim = stackblock() + 1;
2360 if (*dir != '/') {
2361 if (new[-1] != '/')
2362 USTPUTC('/', new);
2363 if (new > lim && *lim == '/')
2364 lim++;
2365 } else {
2366 USTPUTC('/', new);
2367 cdcomppath++;
2368 if (dir[1] == '/' && dir[2] != '/') {
2369 USTPUTC('/', new);
2370 cdcomppath++;
2371 lim++;
2372 }
2373 }
2374 p = strtok(cdcomppath, "/");
2375 while (p) {
2376 switch(*p) {
2377 case '.':
2378 if (p[1] == '.' && p[2] == '\0') {
2379 while (new > lim) {
2380 STUNPUTC(new);
2381 if (new[-1] == '/')
2382 break;
2383 }
2384 break;
2385 } else if (p[1] == '\0')
2386 break;
2387 /* fall through */
2388 default:
2389 new = stputs(p, new);
2390 USTPUTC('/', new);
2391 }
2392 p = strtok(0, "/");
2393 }
2394 if (new > lim)
2395 STUNPUTC(new);
2396 *new = 0;
2397 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002398}
2399
2400/*
Eric Andersenc470f442003-07-28 09:56:35 +00002401 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2402 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002403 */
2404
Eric Andersenc470f442003-07-28 09:56:35 +00002405static int
2406docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002407{
Eric Andersenc470f442003-07-28 09:56:35 +00002408 const char *dir = 0;
2409 int err;
2410
2411 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2412
Eric Andersencb57d552001-06-28 07:25:16 +00002413 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002414 if (!(flags & CD_PHYSICAL)) {
2415 dir = updatepwd(dest);
2416 if (dir)
2417 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002418 }
Eric Andersenc470f442003-07-28 09:56:35 +00002419 err = chdir(dest);
2420 if (err)
2421 goto out;
2422 setpwd(dir, 1);
2423 hashcd();
2424out:
Eric Andersencb57d552001-06-28 07:25:16 +00002425 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002426 return err;
2427}
2428
2429/*
2430 * Find out what the current directory is. If we already know the current
2431 * directory, this routine returns immediately.
2432 */
2433static inline char *
2434getpwd(void)
2435{
2436 char *dir = getcwd(0, 0);
2437 return dir ? dir : nullstr;
2438}
2439
2440static int
2441pwdcmd(int argc, char **argv)
2442{
2443 int flags;
2444 const char *dir = curdir;
2445
2446 flags = cdopt();
2447 if (flags) {
2448 if (physdir == nullstr)
2449 setpwd(dir, 0);
2450 dir = physdir;
2451 }
2452 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002453 return 0;
2454}
2455
Eric Andersenc470f442003-07-28 09:56:35 +00002456static void
2457setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002458{
Eric Andersenc470f442003-07-28 09:56:35 +00002459 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002460
Eric Andersenc470f442003-07-28 09:56:35 +00002461 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002462
Eric Andersencb57d552001-06-28 07:25:16 +00002463 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002464 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002465 }
2466 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002467 if (physdir != nullstr) {
2468 if (physdir != oldcur)
2469 free(physdir);
2470 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002471 }
Eric Andersenc470f442003-07-28 09:56:35 +00002472 if (oldcur == val || !val) {
2473 char *s = getpwd();
2474 physdir = s;
2475 if (!val)
2476 dir = s;
2477 } else
2478 dir = savestr(val);
2479 if (oldcur != dir && oldcur != nullstr) {
2480 free(oldcur);
2481 }
2482 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002483 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002484 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002485}
2486
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002487/* error.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002488
Eric Andersencb57d552001-06-28 07:25:16 +00002489/*
2490 * Errors and exceptions.
2491 */
2492
2493/*
2494 * Code to handle exceptions in C.
2495 */
2496
Eric Andersen2870d962001-07-02 17:27:21 +00002497
Eric Andersencb57d552001-06-28 07:25:16 +00002498
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002499static void exverror(int, const char *, va_list)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00002500 ATTRIBUTE_NORETURN;
Eric Andersencb57d552001-06-28 07:25:16 +00002501
2502/*
2503 * Called to raise an exception. Since C doesn't include exceptions, we
2504 * just do a longjmp to the exception handler. The type of exception is
2505 * stored in the global variable "exception".
2506 */
2507
Eric Andersenc470f442003-07-28 09:56:35 +00002508static void
2509exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002510{
2511#ifdef DEBUG
2512 if (handler == NULL)
2513 abort();
2514#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002515 INTOFF;
2516
Eric Andersencb57d552001-06-28 07:25:16 +00002517 exception = e;
2518 longjmp(handler->loc, 1);
2519}
2520
2521
2522/*
2523 * Called from trap.c when a SIGINT is received. (If the user specifies
2524 * that SIGINT is to be trapped or ignored using the trap builtin, then
2525 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002526 * are held using the INTOFF macro. (The test for iflag is just
2527 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002528 */
2529
Eric Andersenc470f442003-07-28 09:56:35 +00002530static void
2531onint(void) {
2532 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002533
Eric Andersencb57d552001-06-28 07:25:16 +00002534 intpending = 0;
"Vladimir N. Oleynik"e6d88ea2005-12-13 13:24:23 +00002535#if 0
2536 /* comment by vodz: its strange for me, this programm don`t use other
2537 signal block */
Eric Andersenc470f442003-07-28 09:56:35 +00002538 sigsetmask(0);
"Vladimir N. Oleynik"e6d88ea2005-12-13 13:24:23 +00002539#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002540 i = EXSIG;
2541 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2542 if (!(rootshell && iflag)) {
2543 signal(SIGINT, SIG_DFL);
2544 raise(SIGINT);
2545 }
2546 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002547 }
Eric Andersenc470f442003-07-28 09:56:35 +00002548 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002549 /* NOTREACHED */
2550}
2551
Eric Andersenc470f442003-07-28 09:56:35 +00002552static void
2553exvwarning(const char *msg, va_list ap)
2554{
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002555 FILE *errs;
Eric Andersencb57d552001-06-28 07:25:16 +00002556
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002557 errs = stderr;
2558 fprintf(errs, "%s: ", arg0);
2559 if (commandname) {
2560 const char *fmt = (!iflag || parsefile->fd) ?
2561 "%s: %d: " : "%s: ";
2562 fprintf(errs, fmt, commandname, startlinno);
2563 }
2564 vfprintf(errs, msg, ap);
2565 outcslow('\n', errs);
Eric Andersenc470f442003-07-28 09:56:35 +00002566}
Eric Andersen2870d962001-07-02 17:27:21 +00002567
Eric Andersencb57d552001-06-28 07:25:16 +00002568/*
Eric Andersenc470f442003-07-28 09:56:35 +00002569 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002570 * is not NULL then error prints an error message using printf style
2571 * formatting. It then raises the error exception.
2572 */
Eric Andersenc470f442003-07-28 09:56:35 +00002573static void
2574exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002575{
Eric Andersencb57d552001-06-28 07:25:16 +00002576#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002577 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002578 TRACE(("exverror(%d, \"", cond));
2579 TRACEV((msg, ap));
2580 TRACE(("\") pid=%d\n", getpid()));
2581 } else
2582 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2583 if (msg)
2584#endif
2585 exvwarning(msg, ap);
2586
2587 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002588 exraise(cond);
2589 /* NOTREACHED */
2590}
2591
2592
Eric Andersenc470f442003-07-28 09:56:35 +00002593static void
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002594sh_error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002595{
Eric Andersencb57d552001-06-28 07:25:16 +00002596 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002597
Eric Andersencb57d552001-06-28 07:25:16 +00002598 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002599 exverror(EXERROR, msg, ap);
2600 /* NOTREACHED */
2601 va_end(ap);
2602}
2603
2604
Eric Andersenc470f442003-07-28 09:56:35 +00002605static void
2606exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002607{
Eric Andersencb57d552001-06-28 07:25:16 +00002608 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002609
Eric Andersencb57d552001-06-28 07:25:16 +00002610 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002611 exverror(cond, msg, ap);
2612 /* NOTREACHED */
2613 va_end(ap);
2614}
2615
Eric Andersencb57d552001-06-28 07:25:16 +00002616/*
Eric Andersenc470f442003-07-28 09:56:35 +00002617 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002618 */
2619
Eric Andersenc470f442003-07-28 09:56:35 +00002620static void
2621sh_warnx(const char *fmt, ...)
2622{
2623 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002624
Eric Andersenc470f442003-07-28 09:56:35 +00002625 va_start(ap, fmt);
2626 exvwarning(fmt, ap);
2627 va_end(ap);
2628}
Eric Andersen2870d962001-07-02 17:27:21 +00002629
Eric Andersencb57d552001-06-28 07:25:16 +00002630
2631/*
2632 * Return a string describing an error. The returned string may be a
2633 * pointer to a static buffer that will be overwritten on the next call.
2634 * Action describes the operation that got the error.
2635 */
2636
Eric Andersenc470f442003-07-28 09:56:35 +00002637static const char *
2638errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002639{
Eric Andersenc470f442003-07-28 09:56:35 +00002640 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002641
Eric Andersenc470f442003-07-28 09:56:35 +00002642 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002643 }
Eric Andersenc470f442003-07-28 09:56:35 +00002644 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002645}
2646
2647
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002648/* eval.c */
Eric Andersenc470f442003-07-28 09:56:35 +00002649
2650/*
2651 * Evaluate a command.
2652 */
Eric Andersencb57d552001-06-28 07:25:16 +00002653
2654/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002655#define EV_EXIT 01 /* exit after evaluating tree */
2656#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2657#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002658
2659
Eric Andersenc470f442003-07-28 09:56:35 +00002660static void evalloop(union node *, int);
2661static void evalfor(union node *, int);
2662static void evalcase(union node *, int);
2663static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002664static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002665static void evalpipe(union node *, int);
2666static void evalcommand(union node *, int);
2667static int evalbltin(const struct builtincmd *, int, char **);
2668static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002669static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002670static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002671
Eric Andersenc470f442003-07-28 09:56:35 +00002672
2673static const struct builtincmd bltin = {
2674 "\0\0", bltincmd
2675};
2676
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002677
Eric Andersencb57d552001-06-28 07:25:16 +00002678/*
2679 * Called to reset things after an exception.
2680 */
2681
Eric Andersencb57d552001-06-28 07:25:16 +00002682/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002683 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002684 */
2685
Eric Andersenc470f442003-07-28 09:56:35 +00002686static int
2687evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002688{
Eric Andersen2870d962001-07-02 17:27:21 +00002689 char *p;
2690 char *concat;
2691 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002692
Eric Andersen2870d962001-07-02 17:27:21 +00002693 if (argc > 1) {
2694 p = argv[1];
2695 if (argc > 2) {
2696 STARTSTACKSTR(concat);
2697 ap = argv + 2;
2698 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002699 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002700 if ((p = *ap++) == NULL)
2701 break;
2702 STPUTC(' ', concat);
2703 }
2704 STPUTC('\0', concat);
2705 p = grabstackstr(concat);
2706 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002707 evalstring(p, ~SKIPEVAL);
2708
Eric Andersen2870d962001-07-02 17:27:21 +00002709 }
2710 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002711}
2712
Eric Andersenc470f442003-07-28 09:56:35 +00002713
Eric Andersencb57d552001-06-28 07:25:16 +00002714/*
2715 * Execute a command or commands contained in a string.
2716 */
2717
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002718static int
2719evalstring(char *s, int mask)
Eric Andersen2870d962001-07-02 17:27:21 +00002720{
Eric Andersencb57d552001-06-28 07:25:16 +00002721 union node *n;
2722 struct stackmark smark;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002723 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002724
Eric Andersencb57d552001-06-28 07:25:16 +00002725 setinputstring(s);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002726 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002727
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002728 skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002729 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002730 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002731 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002732 skip = evalskip;
2733 if (skip)
Eric Andersenc470f442003-07-28 09:56:35 +00002734 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002735 }
2736 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002737
2738 skip &= mask;
2739 evalskip = skip;
2740 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +00002741}
2742
Eric Andersenc470f442003-07-28 09:56:35 +00002743
Eric Andersen62483552001-07-10 06:09:16 +00002744
2745/*
Eric Andersenc470f442003-07-28 09:56:35 +00002746 * Evaluate a parse tree. The value is left in the global variable
2747 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002748 */
2749
Eric Andersenc470f442003-07-28 09:56:35 +00002750static void
2751evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002752{
Eric Andersenc470f442003-07-28 09:56:35 +00002753 int checkexit = 0;
2754 void (*evalfn)(union node *, int);
2755 unsigned isor;
2756 int status;
2757 if (n == NULL) {
2758 TRACE(("evaltree(NULL) called\n"));
2759 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002760 }
Eric Andersenc470f442003-07-28 09:56:35 +00002761 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2762 getpid(), n, n->type, flags));
2763 switch (n->type) {
2764 default:
2765#ifdef DEBUG
2766 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002767 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002768 break;
2769#endif
2770 case NNOT:
2771 evaltree(n->nnot.com, EV_TESTED);
2772 status = !exitstatus;
2773 goto setstatus;
2774 case NREDIR:
2775 expredir(n->nredir.redirect);
2776 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2777 if (!status) {
2778 evaltree(n->nredir.n, flags & EV_TESTED);
2779 status = exitstatus;
2780 }
2781 popredir(0);
2782 goto setstatus;
2783 case NCMD:
2784 evalfn = evalcommand;
2785checkexit:
2786 if (eflag && !(flags & EV_TESTED))
2787 checkexit = ~0;
2788 goto calleval;
2789 case NFOR:
2790 evalfn = evalfor;
2791 goto calleval;
2792 case NWHILE:
2793 case NUNTIL:
2794 evalfn = evalloop;
2795 goto calleval;
2796 case NSUBSHELL:
2797 case NBACKGND:
2798 evalfn = evalsubshell;
2799 goto calleval;
2800 case NPIPE:
2801 evalfn = evalpipe;
2802 goto checkexit;
2803 case NCASE:
2804 evalfn = evalcase;
2805 goto calleval;
2806 case NAND:
2807 case NOR:
2808 case NSEMI:
2809#if NAND + 1 != NOR
2810#error NAND + 1 != NOR
2811#endif
2812#if NOR + 1 != NSEMI
2813#error NOR + 1 != NSEMI
2814#endif
2815 isor = n->type - NAND;
2816 evaltree(
2817 n->nbinary.ch1,
2818 (flags | ((isor >> 1) - 1)) & EV_TESTED
2819 );
2820 if (!exitstatus == isor)
2821 break;
2822 if (!evalskip) {
2823 n = n->nbinary.ch2;
2824evaln:
2825 evalfn = evaltree;
2826calleval:
2827 evalfn(n, flags);
2828 break;
2829 }
2830 break;
2831 case NIF:
2832 evaltree(n->nif.test, EV_TESTED);
2833 if (evalskip)
2834 break;
2835 if (exitstatus == 0) {
2836 n = n->nif.ifpart;
2837 goto evaln;
2838 } else if (n->nif.elsepart) {
2839 n = n->nif.elsepart;
2840 goto evaln;
2841 }
2842 goto success;
2843 case NDEFUN:
2844 defun(n->narg.text, n->narg.next);
2845success:
2846 status = 0;
2847setstatus:
2848 exitstatus = status;
2849 break;
2850 }
2851out:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002852 if ((checkexit & exitstatus))
2853 evalskip |= SKIPEVAL;
2854 else if (pendingsigs && dotrap())
2855 goto exexit;
2856
2857 if (flags & EV_EXIT) {
2858exexit:
Eric Andersenc470f442003-07-28 09:56:35 +00002859 exraise(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00002860 }
Eric Andersen62483552001-07-10 06:09:16 +00002861}
2862
Eric Andersenc470f442003-07-28 09:56:35 +00002863
2864#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2865static
2866#endif
2867void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2868
2869
2870static void
2871evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002872{
2873 int status;
2874
2875 loopnest++;
2876 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002877 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002878 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002879 int i;
2880
Eric Andersencb57d552001-06-28 07:25:16 +00002881 evaltree(n->nbinary.ch1, EV_TESTED);
2882 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002883skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002884 evalskip = 0;
2885 continue;
2886 }
2887 if (evalskip == SKIPBREAK && --skipcount <= 0)
2888 evalskip = 0;
2889 break;
2890 }
Eric Andersenc470f442003-07-28 09:56:35 +00002891 i = exitstatus;
2892 if (n->type != NWHILE)
2893 i = !i;
2894 if (i != 0)
2895 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002896 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002897 status = exitstatus;
2898 if (evalskip)
2899 goto skipping;
2900 }
2901 loopnest--;
2902 exitstatus = status;
2903}
2904
Eric Andersenc470f442003-07-28 09:56:35 +00002905
2906
2907static void
2908evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002909{
2910 struct arglist arglist;
2911 union node *argp;
2912 struct strlist *sp;
2913 struct stackmark smark;
2914
2915 setstackmark(&smark);
2916 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002917 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002918 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002919 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002920 if (evalskip)
2921 goto out;
2922 }
2923 *arglist.lastp = NULL;
2924
2925 exitstatus = 0;
2926 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002927 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002928 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002929 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002930 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002931 if (evalskip) {
2932 if (evalskip == SKIPCONT && --skipcount <= 0) {
2933 evalskip = 0;
2934 continue;
2935 }
2936 if (evalskip == SKIPBREAK && --skipcount <= 0)
2937 evalskip = 0;
2938 break;
2939 }
2940 }
2941 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002942out:
Eric Andersencb57d552001-06-28 07:25:16 +00002943 popstackmark(&smark);
2944}
2945
Eric Andersenc470f442003-07-28 09:56:35 +00002946
2947
2948static void
2949evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002950{
2951 union node *cp;
2952 union node *patp;
2953 struct arglist arglist;
2954 struct stackmark smark;
2955
2956 setstackmark(&smark);
2957 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002958 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002959 exitstatus = 0;
2960 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2961 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002962 if (casematch(patp, arglist.list->text)) {
2963 if (evalskip == 0) {
2964 evaltree(cp->nclist.body, flags);
2965 }
2966 goto out;
2967 }
2968 }
2969 }
Eric Andersenc470f442003-07-28 09:56:35 +00002970out:
Eric Andersencb57d552001-06-28 07:25:16 +00002971 popstackmark(&smark);
2972}
2973
Eric Andersenc470f442003-07-28 09:56:35 +00002974
2975
2976/*
2977 * Kick off a subshell to evaluate a tree.
2978 */
2979
2980static void
2981evalsubshell(union node *n, int flags)
2982{
2983 struct job *jp;
2984 int backgnd = (n->type == NBACKGND);
2985 int status;
2986
2987 expredir(n->nredir.redirect);
2988 if (!backgnd && flags & EV_EXIT && !trap[0])
2989 goto nofork;
2990 INTOFF;
2991 jp = makejob(n, 1);
2992 if (forkshell(jp, n, backgnd) == 0) {
2993 INTON;
2994 flags |= EV_EXIT;
2995 if (backgnd)
2996 flags &=~ EV_TESTED;
2997nofork:
2998 redirect(n->nredir.redirect, 0);
2999 evaltreenr(n->nredir.n, flags);
3000 /* never returns */
3001 }
3002 status = 0;
3003 if (! backgnd)
3004 status = waitforjob(jp);
3005 exitstatus = status;
3006 INTON;
3007}
3008
3009
3010
3011/*
3012 * Compute the names of the files in a redirection list.
3013 */
3014
3015static void
3016expredir(union node *n)
3017{
3018 union node *redir;
3019
3020 for (redir = n ; redir ; redir = redir->nfile.next) {
3021 struct arglist fn;
3022 fn.lastp = &fn.list;
3023 switch (redir->type) {
3024 case NFROMTO:
3025 case NFROM:
3026 case NTO:
3027 case NCLOBBER:
3028 case NAPPEND:
3029 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3030 redir->nfile.expfname = fn.list->text;
3031 break;
3032 case NFROMFD:
3033 case NTOFD:
3034 if (redir->ndup.vname) {
3035 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3036 fixredir(redir, fn.list->text, 1);
3037 }
3038 break;
3039 }
3040 }
3041}
3042
3043
3044
Eric Andersencb57d552001-06-28 07:25:16 +00003045/*
Eric Andersencb57d552001-06-28 07:25:16 +00003046 * Evaluate a pipeline. All the processes in the pipeline are children
3047 * of the process creating the pipeline. (This differs from some versions
3048 * of the shell, which make the last process in a pipeline the parent
3049 * of all the rest.)
3050 */
3051
Eric Andersenc470f442003-07-28 09:56:35 +00003052static void
3053evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003054{
3055 struct job *jp;
3056 struct nodelist *lp;
3057 int pipelen;
3058 int prevfd;
3059 int pip[2];
3060
Eric Andersenc470f442003-07-28 09:56:35 +00003061 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003062 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003063 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003064 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003065 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003066 INTOFF;
3067 jp = makejob(n, pipelen);
3068 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003069 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003070 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003071 pip[1] = -1;
3072 if (lp->next) {
3073 if (pipe(pip) < 0) {
3074 close(prevfd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003075 sh_error("Pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00003076 }
3077 }
3078 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3079 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003080 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003081 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003082 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003083 if (prevfd > 0) {
3084 dup2(prevfd, 0);
3085 close(prevfd);
3086 }
3087 if (pip[1] > 1) {
3088 dup2(pip[1], 1);
3089 close(pip[1]);
3090 }
Eric Andersenc470f442003-07-28 09:56:35 +00003091 evaltreenr(lp->n, flags);
3092 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003093 }
3094 if (prevfd >= 0)
3095 close(prevfd);
3096 prevfd = pip[0];
3097 close(pip[1]);
3098 }
Eric Andersencb57d552001-06-28 07:25:16 +00003099 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003100 exitstatus = waitforjob(jp);
3101 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003102 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003103 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003104}
3105
Eric Andersen62483552001-07-10 06:09:16 +00003106
3107
3108/*
3109 * Execute a command inside back quotes. If it's a builtin command, we
3110 * want to save its output in a block obtained from malloc. Otherwise
3111 * we fork off a subprocess and get the output of the command via a pipe.
3112 * Should be called with interrupts off.
3113 */
3114
Eric Andersenc470f442003-07-28 09:56:35 +00003115static void
3116evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003117{
Eric Andersenc470f442003-07-28 09:56:35 +00003118 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003119
Eric Andersen62483552001-07-10 06:09:16 +00003120 result->fd = -1;
3121 result->buf = NULL;
3122 result->nleft = 0;
3123 result->jp = NULL;
3124 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003125 goto out;
3126 }
Eric Andersenc470f442003-07-28 09:56:35 +00003127
3128 saveherefd = herefd;
3129 herefd = -1;
3130
3131 {
3132 int pip[2];
3133 struct job *jp;
3134
3135 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003136 sh_error("Pipe call failed");
Eric Andersenc470f442003-07-28 09:56:35 +00003137 jp = makejob(n, 1);
3138 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3139 FORCEINTON;
3140 close(pip[0]);
3141 if (pip[1] != 1) {
3142 close(1);
3143 copyfd(pip[1], 1);
3144 close(pip[1]);
3145 }
3146 eflag = 0;
3147 evaltreenr(n, EV_EXIT);
3148 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003149 }
Eric Andersenc470f442003-07-28 09:56:35 +00003150 close(pip[1]);
3151 result->fd = pip[0];
3152 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003153 }
Eric Andersenc470f442003-07-28 09:56:35 +00003154 herefd = saveherefd;
3155out:
Eric Andersen62483552001-07-10 06:09:16 +00003156 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003157 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003158}
3159
Eric Andersenc470f442003-07-28 09:56:35 +00003160#ifdef CONFIG_ASH_CMDCMD
3161static inline char **
3162parse_command_args(char **argv, const char **path)
3163{
3164 char *cp, c;
3165
3166 for (;;) {
3167 cp = *++argv;
3168 if (!cp)
3169 return 0;
3170 if (*cp++ != '-')
3171 break;
3172 if (!(c = *cp++))
3173 break;
3174 if (c == '-' && !*cp) {
3175 argv++;
3176 break;
3177 }
3178 do {
3179 switch (c) {
3180 case 'p':
3181 *path = defpath;
3182 break;
3183 default:
3184 /* run 'typecmd' for other options */
3185 return 0;
3186 }
3187 } while ((c = *cp++));
3188 }
3189 return argv;
3190}
3191#endif
3192
Paul Foxc3850c82005-07-20 18:23:39 +00003193static inline int
3194isassignment(const char *p)
3195{
3196 const char *q = endofname(p);
3197 if (p == q)
3198 return 0;
3199 return *q == '=';
3200}
Eric Andersen62483552001-07-10 06:09:16 +00003201
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003202#ifdef CONFIG_ASH_EXPAND_PRMT
3203static const char *expandstr(const char *ps);
3204#else
3205#define expandstr(s) s
3206#endif
3207
Eric Andersen62483552001-07-10 06:09:16 +00003208/*
3209 * Execute a simple command.
3210 */
Eric Andersencb57d552001-06-28 07:25:16 +00003211
Eric Andersenc470f442003-07-28 09:56:35 +00003212static void
3213evalcommand(union node *cmd, int flags)
3214{
3215 struct stackmark smark;
3216 union node *argp;
3217 struct arglist arglist;
3218 struct arglist varlist;
3219 char **argv;
3220 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003221 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003222 struct cmdentry cmdentry;
3223 struct job *jp;
3224 char *lastarg;
3225 const char *path;
3226 int spclbltin;
3227 int cmd_is_exec;
3228 int status;
3229 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003230 struct builtincmd *bcmd;
3231 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003232
3233 /* First expand the arguments. */
3234 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3235 setstackmark(&smark);
3236 back_exitstatus = 0;
3237
3238 cmdentry.cmdtype = CMDBUILTIN;
3239 cmdentry.u.cmd = &bltin;
3240 varlist.lastp = &varlist.list;
3241 *varlist.lastp = NULL;
3242 arglist.lastp = &arglist.list;
3243 *arglist.lastp = NULL;
3244
3245 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003246 if (cmd->ncmd.args)
3247 {
3248 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3249 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3250 }
3251
Eric Andersenc470f442003-07-28 09:56:35 +00003252 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3253 struct strlist **spp;
3254
3255 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003256 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00003257 expandarg(argp, &arglist, EXP_VARTILDE);
3258 else
3259 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3260
Eric Andersenc470f442003-07-28 09:56:35 +00003261 for (sp = *spp; sp; sp = sp->next)
3262 argc++;
3263 }
3264
3265 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3266 for (sp = arglist.list ; sp ; sp = sp->next) {
3267 TRACE(("evalcommand arg: %s\n", sp->text));
3268 *nargv++ = sp->text;
3269 }
3270 *nargv = NULL;
3271
3272 lastarg = NULL;
3273 if (iflag && funcnest == 0 && argc > 0)
3274 lastarg = nargv[-1];
3275
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003276 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003277 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003278 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003279
3280 path = vpath.text;
3281 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3282 struct strlist **spp;
3283 char *p;
3284
3285 spp = varlist.lastp;
3286 expandarg(argp, &varlist, EXP_VARTILDE);
3287
3288 /*
3289 * Modify the command lookup path, if a PATH= assignment
3290 * is present
3291 */
3292 p = (*spp)->text;
3293 if (varequal(p, path))
3294 path = p;
3295 }
3296
3297 /* Print the command if xflag is set. */
3298 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003299 int n;
3300 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003301
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003302 p++;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003303 dprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003304
3305 sp = varlist.list;
3306 for(n = 0; n < 2; n++) {
3307 while (sp) {
3308 dprintf(preverrout_fd, p, sp->text);
3309 sp = sp->next;
3310 if(*p == '%') {
3311 p--;
3312 }
3313 }
3314 sp = arglist.list;
3315 }
Eric Andersen16767e22004-03-16 05:14:10 +00003316 bb_full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003317 }
3318
3319 cmd_is_exec = 0;
3320 spclbltin = -1;
3321
3322 /* Now locate the command. */
3323 if (argc) {
3324 const char *oldpath;
3325 int cmd_flag = DO_ERR;
3326
3327 path += 5;
3328 oldpath = path;
3329 for (;;) {
3330 find_command(argv[0], &cmdentry, cmd_flag, path);
3331 if (cmdentry.cmdtype == CMDUNKNOWN) {
3332 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003333 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003334 goto bail;
3335 }
3336
3337 /* implement bltin and command here */
3338 if (cmdentry.cmdtype != CMDBUILTIN)
3339 break;
3340 if (spclbltin < 0)
3341 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3342 if (cmdentry.u.cmd == EXECCMD)
3343 cmd_is_exec++;
3344#ifdef CONFIG_ASH_CMDCMD
3345 if (cmdentry.u.cmd == COMMANDCMD) {
3346
3347 path = oldpath;
3348 nargv = parse_command_args(argv, &path);
3349 if (!nargv)
3350 break;
3351 argc -= nargv - argv;
3352 argv = nargv;
3353 cmd_flag |= DO_NOFUNC;
3354 } else
3355#endif
3356 break;
3357 }
3358 }
3359
3360 if (status) {
3361 /* We have a redirection error. */
3362 if (spclbltin > 0)
3363 exraise(EXERROR);
3364bail:
3365 exitstatus = status;
3366 goto out;
3367 }
3368
3369 /* Execute the command. */
3370 switch (cmdentry.cmdtype) {
3371 default:
3372 /* Fork off a child process if necessary. */
3373 if (!(flags & EV_EXIT) || trap[0]) {
3374 INTOFF;
3375 jp = makejob(cmd, 1);
3376 if (forkshell(jp, cmd, FORK_FG) != 0) {
3377 exitstatus = waitforjob(jp);
3378 INTON;
3379 break;
3380 }
3381 FORCEINTON;
3382 }
3383 listsetvar(varlist.list, VEXPORT|VSTACK);
3384 shellexec(argv, path, cmdentry.u.index);
3385 /* NOTREACHED */
3386
3387 case CMDBUILTIN:
3388 cmdenviron = varlist.list;
3389 if (cmdenviron) {
3390 struct strlist *list = cmdenviron;
3391 int i = VNOSET;
3392 if (spclbltin > 0 || argc == 0) {
3393 i = 0;
3394 if (cmd_is_exec && argc > 1)
3395 i = VEXPORT;
3396 }
3397 listsetvar(list, i);
3398 }
3399 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3400 int exit_status;
3401 int i, j;
3402
3403 i = exception;
3404 if (i == EXEXIT)
3405 goto raise;
3406
3407 exit_status = 2;
3408 j = 0;
3409 if (i == EXINT)
3410 j = SIGINT;
3411 if (i == EXSIG)
3412 j = pendingsigs;
3413 if (j)
3414 exit_status = j + 128;
3415 exitstatus = exit_status;
3416
3417 if (i == EXINT || spclbltin > 0) {
3418raise:
3419 longjmp(handler->loc, 1);
3420 }
3421 FORCEINTON;
3422 }
3423 break;
3424
3425 case CMDFUNCTION:
3426 listsetvar(varlist.list, 0);
3427 if (evalfun(cmdentry.u.func, argc, argv, flags))
3428 goto raise;
3429 break;
3430 }
3431
3432out:
3433 popredir(cmd_is_exec);
3434 if (lastarg)
3435 /* dsl: I think this is intended to be used to support
3436 * '_' in 'vi' command mode during line editing...
3437 * However I implemented that within libedit itself.
3438 */
3439 setvar("_", lastarg, 0);
3440 popstackmark(&smark);
3441}
3442
3443static int
3444evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3445 char *volatile savecmdname;
3446 struct jmploc *volatile savehandler;
3447 struct jmploc jmploc;
3448 int i;
3449
3450 savecmdname = commandname;
3451 if ((i = setjmp(jmploc.loc)))
3452 goto cmddone;
3453 savehandler = handler;
3454 handler = &jmploc;
3455 commandname = argv[0];
3456 argptr = argv + 1;
3457 optptr = NULL; /* initialize nextopt */
3458 exitstatus = (*cmd->builtin)(argc, argv);
3459 flushall();
3460cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003461 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003462 commandname = savecmdname;
3463 exsig = 0;
3464 handler = savehandler;
3465
3466 return i;
3467}
3468
3469static int
3470evalfun(struct funcnode *func, int argc, char **argv, int flags)
3471{
3472 volatile struct shparam saveparam;
3473 struct localvar *volatile savelocalvars;
3474 struct jmploc *volatile savehandler;
3475 struct jmploc jmploc;
3476 int e;
3477
3478 saveparam = shellparam;
3479 savelocalvars = localvars;
3480 if ((e = setjmp(jmploc.loc))) {
3481 goto funcdone;
3482 }
3483 INTOFF;
3484 savehandler = handler;
3485 handler = &jmploc;
3486 localvars = NULL;
3487 shellparam.malloc = 0;
3488 func->count++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003489 funcnest++;
Eric Andersenc470f442003-07-28 09:56:35 +00003490 INTON;
3491 shellparam.nparam = argc - 1;
3492 shellparam.p = argv + 1;
3493#ifdef CONFIG_ASH_GETOPTS
3494 shellparam.optind = 1;
3495 shellparam.optoff = -1;
3496#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003497 evaltree(&func->n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00003498funcdone:
3499 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003500 funcnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00003501 freefunc(func);
3502 poplocalvars();
3503 localvars = savelocalvars;
3504 freeparam(&shellparam);
3505 shellparam = saveparam;
3506 handler = savehandler;
3507 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003508 evalskip &= ~SKIPFUNC;
Eric Andersenc470f442003-07-28 09:56:35 +00003509 return e;
3510}
3511
3512
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003513static inline int
3514goodname(const char *p)
3515{
3516 return !*endofname(p);
3517}
3518
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003519/*
3520 * Search for a command. This is called before we fork so that the
3521 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003522 * the child. The check for "goodname" is an overly conservative
3523 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003524 */
3525
Eric Andersenc470f442003-07-28 09:56:35 +00003526static void
3527prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003528{
3529 struct cmdentry entry;
3530
3531 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003532 if (goodname(n->ncmd.args->narg.text))
3533 find_command(n->ncmd.args->narg.text, &entry, 0,
3534 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003535}
3536
Eric Andersencb57d552001-06-28 07:25:16 +00003537
Eric Andersenc470f442003-07-28 09:56:35 +00003538
Eric Andersencb57d552001-06-28 07:25:16 +00003539/*
3540 * Builtin commands. Builtin commands whose functions are closely
3541 * tied to evaluation are implemented here.
3542 */
3543
3544/*
Eric Andersenc470f442003-07-28 09:56:35 +00003545 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003546 */
3547
Eric Andersenc470f442003-07-28 09:56:35 +00003548static int
3549bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003550{
3551 /*
3552 * Preserve exitstatus of a previous possible redirection
3553 * as POSIX mandates
3554 */
Eric Andersenc470f442003-07-28 09:56:35 +00003555 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003556}
3557
3558
3559/*
3560 * Handle break and continue commands. Break, continue, and return are
3561 * all handled by setting the evalskip flag. The evaluation routines
3562 * above all check this flag, and if it is set they start skipping
3563 * commands rather than executing them. The variable skipcount is
3564 * the number of loops to break/continue, or the number of function
3565 * levels to return. (The latter is always 1.) It should probably
3566 * be an error to break out of more loops than exist, but it isn't
3567 * in the standard shell so we don't make it one here.
3568 */
3569
Eric Andersenc470f442003-07-28 09:56:35 +00003570static int
3571breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003572{
3573 int n = argc > 1 ? number(argv[1]) : 1;
3574
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003575 if (n <= 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003576 sh_error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003577 if (n > loopnest)
3578 n = loopnest;
3579 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003580 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003581 skipcount = n;
3582 }
3583 return 0;
3584}
3585
3586
3587/*
3588 * The return command.
3589 */
3590
Eric Andersenc470f442003-07-28 09:56:35 +00003591static int
3592returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003593{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003594 /*
3595 * If called outside a function, do what ksh does;
3596 * skip the rest of the file.
3597 */
3598 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
3599 return argv[1] ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003600}
3601
3602
Eric Andersenc470f442003-07-28 09:56:35 +00003603static int
3604falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003605{
3606 return 1;
3607}
3608
Eric Andersenc470f442003-07-28 09:56:35 +00003609
3610static int
3611truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003612{
3613 return 0;
3614}
Eric Andersen2870d962001-07-02 17:27:21 +00003615
Eric Andersencb57d552001-06-28 07:25:16 +00003616
Eric Andersenc470f442003-07-28 09:56:35 +00003617static int
3618execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003619{
3620 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003621 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003622 mflag = 0;
3623 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003624 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003625 }
3626 return 0;
3627}
3628
Eric Andersenc470f442003-07-28 09:56:35 +00003629
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003630/* exec.c */
Eric Andersenc470f442003-07-28 09:56:35 +00003631
3632/*
3633 * When commands are first encountered, they are entered in a hash table.
3634 * This ensures that a full path search will not have to be done for them
3635 * on each invocation.
3636 *
3637 * We should investigate converting to a linear search, even though that
3638 * would make the command name "hash" a misnomer.
3639 */
3640
3641#define CMDTABLESIZE 31 /* should be prime */
3642#define ARB 1 /* actual size determined at run time */
3643
3644
3645
3646struct tblentry {
3647 struct tblentry *next; /* next entry in hash chain */
3648 union param param; /* definition of builtin function */
3649 short cmdtype; /* index identifying command */
3650 char rehash; /* if set, cd done since entry created */
3651 char cmdname[ARB]; /* name of command */
3652};
3653
3654
3655static struct tblentry *cmdtable[CMDTABLESIZE];
3656static int builtinloc = -1; /* index in path of %builtin, or -1 */
3657
3658
3659static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003660static void clearcmdentry(int);
3661static struct tblentry *cmdlookup(const char *, int);
3662static void delete_cmd_entry(void);
3663
Eric Andersencb57d552001-06-28 07:25:16 +00003664
3665/*
3666 * Exec a program. Never returns. If you change this routine, you may
3667 * have to change the find_command routine as well.
3668 */
3669
Eric Andersenc470f442003-07-28 09:56:35 +00003670static void
3671shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003672{
3673 char *cmdname;
3674 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003675 char **envp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003676 int exerrno;
Eric Andersencb57d552001-06-28 07:25:16 +00003677
Eric Andersenc470f442003-07-28 09:56:35 +00003678 clearredir(1);
3679 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003680 if (strchr(argv[0], '/') != NULL
3681#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3682 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003683#endif
3684 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003685 tryexec(argv[0], argv, envp);
3686 e = errno;
3687 } else {
3688 e = ENOENT;
3689 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3690 if (--idx < 0 && pathopt == NULL) {
3691 tryexec(cmdname, argv, envp);
3692 if (errno != ENOENT && errno != ENOTDIR)
3693 e = errno;
3694 }
3695 stunalloc(cmdname);
3696 }
3697 }
3698
3699 /* Map to POSIX errors */
3700 switch (e) {
3701 case EACCES:
3702 exerrno = 126;
3703 break;
3704 case ENOENT:
3705 exerrno = 127;
3706 break;
3707 default:
3708 exerrno = 2;
3709 break;
3710 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00003711 exitstatus = exerrno;
Eric Andersenc470f442003-07-28 09:56:35 +00003712 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3713 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003714 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3715 /* NOTREACHED */
3716}
3717
Eric Andersen2870d962001-07-02 17:27:21 +00003718
Eric Andersenc470f442003-07-28 09:56:35 +00003719static void
3720tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003721{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003722 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003723#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003724 if(find_applet_by_name(cmd) != NULL) {
3725 /* re-exec ourselves with the new arguments */
3726 execve("/proc/self/exe",argv,envp);
3727 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3728 execve("/bin/busybox",argv,envp);
3729 /* If they called chroot or otherwise made the binary no longer
3730 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003731 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003732#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003733
3734repeat:
3735#ifdef SYSV
3736 do {
3737 execve(cmd, argv, envp);
3738 } while (errno == EINTR);
3739#else
Eric Andersencb57d552001-06-28 07:25:16 +00003740 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003741#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003742 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003743 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003744 } else if (errno == ENOEXEC) {
3745 char **ap;
3746 char **new;
3747
Eric Andersenc470f442003-07-28 09:56:35 +00003748 for (ap = argv; *ap; ap++)
3749 ;
3750 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003751 ap[1] = cmd;
3752 *ap = cmd = (char *)DEFAULT_SHELL;
3753 ap += 2;
3754 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003755 while ((*ap++ = *argv++))
3756 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003757 argv = new;
3758 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003759 }
Eric Andersencb57d552001-06-28 07:25:16 +00003760}
3761
Eric Andersenc470f442003-07-28 09:56:35 +00003762
Eric Andersencb57d552001-06-28 07:25:16 +00003763
3764/*
3765 * Do a path search. The variable path (passed by reference) should be
3766 * set to the start of the path before the first call; padvance will update
3767 * this value as it proceeds. Successive calls to padvance will return
3768 * the possible path expansions in sequence. If an option (indicated by
3769 * a percent sign) appears in the path entry then the global variable
3770 * pathopt will be set to point to it; otherwise pathopt will be set to
3771 * NULL.
3772 */
3773
Eric Andersenc470f442003-07-28 09:56:35 +00003774static char *
3775padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003776{
Eric Andersencb57d552001-06-28 07:25:16 +00003777 const char *p;
3778 char *q;
3779 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003780 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003781
3782 if (*path == NULL)
3783 return NULL;
3784 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003785 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3786 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003787 while (stackblocksize() < len)
3788 growstackblock();
3789 q = stackblock();
3790 if (p != start) {
3791 memcpy(q, start, p - start);
3792 q += p - start;
3793 *q++ = '/';
3794 }
3795 strcpy(q, name);
3796 pathopt = NULL;
3797 if (*p == '%') {
3798 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003799 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003800 }
3801 if (*p == ':')
3802 *path = p + 1;
3803 else
3804 *path = NULL;
3805 return stalloc(len);
3806}
3807
3808
Eric Andersencb57d552001-06-28 07:25:16 +00003809/*** Command hashing code ***/
3810
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003811static void
3812printentry(struct tblentry *cmdp)
3813{
3814 int idx;
3815 const char *path;
3816 char *name;
3817
3818 idx = cmdp->param.index;
3819 path = pathval();
3820 do {
3821 name = padvance(&path, cmdp->cmdname);
3822 stunalloc(name);
3823 } while (--idx >= 0);
3824 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3825}
3826
Eric Andersenc470f442003-07-28 09:56:35 +00003827
3828static int
3829hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003830{
3831 struct tblentry **pp;
3832 struct tblentry *cmdp;
3833 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003834 struct cmdentry entry;
3835 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003836
Eric Andersenc470f442003-07-28 09:56:35 +00003837 while ((c = nextopt("r")) != '\0') {
3838 clearcmdentry(0);
3839 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003840 }
3841 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003842 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3843 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3844 if (cmdp->cmdtype == CMDNORMAL)
3845 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003846 }
3847 }
3848 return 0;
3849 }
3850 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003851 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003852 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003853 && (cmdp->cmdtype == CMDNORMAL
3854 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003855 delete_cmd_entry();
3856 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003857 if (entry.cmdtype == CMDUNKNOWN)
3858 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003859 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003860 }
3861 return c;
3862}
3863
Eric Andersenc470f442003-07-28 09:56:35 +00003864
Eric Andersencb57d552001-06-28 07:25:16 +00003865/*
3866 * Resolve a command name. If you change this routine, you may have to
3867 * change the shellexec routine as well.
3868 */
3869
3870static void
Eric Andersenc470f442003-07-28 09:56:35 +00003871find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003872{
3873 struct tblentry *cmdp;
3874 int idx;
3875 int prev;
3876 char *fullname;
3877 struct stat statb;
3878 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003879 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003880 struct builtincmd *bcmd;
3881
Eric Andersenc470f442003-07-28 09:56:35 +00003882 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003883 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003884 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003885 if (act & DO_ABS) {
3886 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003887#ifdef SYSV
3888 if (errno == EINTR)
3889 continue;
3890#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003891 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003892 return;
3893 }
Eric Andersencb57d552001-06-28 07:25:16 +00003894 }
3895 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003896 return;
3897 }
3898
Eric Andersenbf8bf102002-09-17 08:41:08 +00003899#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3900 if (find_applet_by_name(name)) {
3901 entry->cmdtype = CMDNORMAL;
3902 entry->u.index = -1;
3903 return;
3904 }
3905#endif
3906
Eric Andersenc470f442003-07-28 09:56:35 +00003907 updatetbl = (path == pathval());
3908 if (!updatetbl) {
3909 act |= DO_ALTPATH;
3910 if (strstr(path, "%builtin") != NULL)
3911 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003912 }
3913
Eric Andersenc470f442003-07-28 09:56:35 +00003914 /* If name is in the table, check answer will be ok */
3915 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3916 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003917
Eric Andersenc470f442003-07-28 09:56:35 +00003918 switch (cmdp->cmdtype) {
3919 default:
3920#if DEBUG
3921 abort();
3922#endif
3923 case CMDNORMAL:
3924 bit = DO_ALTPATH;
3925 break;
3926 case CMDFUNCTION:
3927 bit = DO_NOFUNC;
3928 break;
3929 case CMDBUILTIN:
3930 bit = DO_ALTBLTIN;
3931 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003932 }
Eric Andersenc470f442003-07-28 09:56:35 +00003933 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003934 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003935 cmdp = NULL;
3936 } else if (cmdp->rehash == 0)
3937 /* if not invalidated by cd, we're done */
3938 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003939 }
3940
3941 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003942 bcmd = find_builtin(name);
3943 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3944 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3945 )))
3946 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003947
3948 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003949 prev = -1; /* where to start */
3950 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003951 if (cmdp->cmdtype == CMDBUILTIN)
3952 prev = builtinloc;
3953 else
3954 prev = cmdp->param.index;
3955 }
3956
3957 e = ENOENT;
3958 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003959loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003960 while ((fullname = padvance(&path, name)) != NULL) {
3961 stunalloc(fullname);
3962 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003963 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003964 if (prefix(pathopt, "builtin")) {
3965 if (bcmd)
3966 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003967 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003968 } else if (!(act & DO_NOFUNC) &&
3969 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003970 /* handled below */
3971 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003972 /* ignore unimplemented options */
3973 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003974 }
3975 }
3976 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003977 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003978 if (idx < prev)
3979 continue;
3980 TRACE(("searchexec \"%s\": no change\n", name));
3981 goto success;
3982 }
3983 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003984#ifdef SYSV
3985 if (errno == EINTR)
3986 continue;
3987#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003988 if (errno != ENOENT && errno != ENOTDIR)
3989 e = errno;
3990 goto loop;
3991 }
Eric Andersenc470f442003-07-28 09:56:35 +00003992 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003993 if (!S_ISREG(statb.st_mode))
3994 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003995 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003996 stalloc(strlen(fullname) + 1);
3997 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00003998 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3999 cmdp->cmdtype != CMDFUNCTION)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004000 sh_error("%s not defined in %s", name, fullname);
Eric Andersencb57d552001-06-28 07:25:16 +00004001 stunalloc(fullname);
4002 goto success;
4003 }
Eric Andersencb57d552001-06-28 07:25:16 +00004004 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004005 if (!updatetbl) {
4006 entry->cmdtype = CMDNORMAL;
4007 entry->u.index = idx;
4008 return;
4009 }
4010 INTOFF;
4011 cmdp = cmdlookup(name, 1);
4012 cmdp->cmdtype = CMDNORMAL;
4013 cmdp->param.index = idx;
4014 INTON;
4015 goto success;
4016 }
4017
4018 /* We failed. If there was an entry for this command, delete it */
4019 if (cmdp && updatetbl)
4020 delete_cmd_entry();
4021 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004022 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004023 entry->cmdtype = CMDUNKNOWN;
4024 return;
4025
Eric Andersenc470f442003-07-28 09:56:35 +00004026builtin_success:
4027 if (!updatetbl) {
4028 entry->cmdtype = CMDBUILTIN;
4029 entry->u.cmd = bcmd;
4030 return;
4031 }
4032 INTOFF;
4033 cmdp = cmdlookup(name, 1);
4034 cmdp->cmdtype = CMDBUILTIN;
4035 cmdp->param.cmd = bcmd;
4036 INTON;
4037success:
Eric Andersencb57d552001-06-28 07:25:16 +00004038 cmdp->rehash = 0;
4039 entry->cmdtype = cmdp->cmdtype;
4040 entry->u = cmdp->param;
4041}
4042
4043
Eric Andersenc470f442003-07-28 09:56:35 +00004044/*
4045 * Wrapper around strcmp for qsort/bsearch/...
4046 */
4047static int pstrcmp(const void *a, const void *b)
4048{
4049 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4050}
Eric Andersencb57d552001-06-28 07:25:16 +00004051
4052/*
4053 * Search the table of builtin commands.
4054 */
4055
Eric Andersenc470f442003-07-28 09:56:35 +00004056static struct builtincmd *
4057find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004058{
4059 struct builtincmd *bp;
4060
Eric Andersenc470f442003-07-28 09:56:35 +00004061 bp = bsearch(
4062 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4063 pstrcmp
4064 );
Eric Andersencb57d552001-06-28 07:25:16 +00004065 return bp;
4066}
4067
4068
Eric Andersenc470f442003-07-28 09:56:35 +00004069
Eric Andersencb57d552001-06-28 07:25:16 +00004070/*
4071 * Called when a cd is done. Marks all commands so the next time they
4072 * are executed they will be rehashed.
4073 */
4074
Eric Andersenc470f442003-07-28 09:56:35 +00004075static void
4076hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004077{
Eric Andersencb57d552001-06-28 07:25:16 +00004078 struct tblentry **pp;
4079 struct tblentry *cmdp;
4080
Eric Andersenc470f442003-07-28 09:56:35 +00004081 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4082 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4083 if (cmdp->cmdtype == CMDNORMAL || (
4084 cmdp->cmdtype == CMDBUILTIN &&
4085 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4086 builtinloc > 0
4087 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004088 cmdp->rehash = 1;
4089 }
4090 }
4091}
4092
4093
4094
4095/*
Eric Andersenc470f442003-07-28 09:56:35 +00004096 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004097 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004098 * pathval() still returns the old value at this point.
4099 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004100 */
4101
Eric Andersenc470f442003-07-28 09:56:35 +00004102static void
4103changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004104{
Eric Andersenc470f442003-07-28 09:56:35 +00004105 const char *old, *new;
4106 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004107 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004108 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004109
Eric Andersenc470f442003-07-28 09:56:35 +00004110 old = pathval();
4111 new = newval;
4112 firstchange = 9999; /* assume no change */
4113 idx = 0;
4114 idx_bltin = -1;
4115 for (;;) {
4116 if (*old != *new) {
4117 firstchange = idx;
4118 if ((*old == '\0' && *new == ':')
4119 || (*old == ':' && *new == '\0'))
4120 firstchange++;
4121 old = new; /* ignore subsequent differences */
4122 }
4123 if (*new == '\0')
4124 break;
4125 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4126 idx_bltin = idx;
4127 if (*new == ':') {
4128 idx++;
4129 }
4130 new++, old++;
4131 }
4132 if (builtinloc < 0 && idx_bltin >= 0)
4133 builtinloc = idx_bltin; /* zap builtins */
4134 if (builtinloc >= 0 && idx_bltin < 0)
4135 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004136 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004137 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004138}
4139
4140
4141/*
4142 * Clear out command entries. The argument specifies the first entry in
4143 * PATH which has changed.
4144 */
4145
Eric Andersenc470f442003-07-28 09:56:35 +00004146static void
4147clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004148{
4149 struct tblentry **tblp;
4150 struct tblentry **pp;
4151 struct tblentry *cmdp;
4152
4153 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004154 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004155 pp = tblp;
4156 while ((cmdp = *pp) != NULL) {
4157 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004158 cmdp->param.index >= firstchange)
4159 || (cmdp->cmdtype == CMDBUILTIN &&
4160 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004161 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004162 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004163 } else {
4164 pp = &cmdp->next;
4165 }
4166 }
4167 }
4168 INTON;
4169}
4170
4171
Eric Andersenc470f442003-07-28 09:56:35 +00004172
Eric Andersencb57d552001-06-28 07:25:16 +00004173/*
Eric Andersencb57d552001-06-28 07:25:16 +00004174 * Locate a command in the command hash table. If "add" is nonzero,
4175 * add the command to the table if it is not already present. The
4176 * variable "lastcmdentry" is set to point to the address of the link
4177 * pointing to the entry, so that delete_cmd_entry can delete the
4178 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004179 *
4180 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004181 */
4182
Eric Andersen2870d962001-07-02 17:27:21 +00004183static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004184
Eric Andersenc470f442003-07-28 09:56:35 +00004185
4186static struct tblentry *
4187cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004188{
Eric Andersenc470f442003-07-28 09:56:35 +00004189 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004190 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004191 struct tblentry *cmdp;
4192 struct tblentry **pp;
4193
4194 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004195 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004196 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004197 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004198 hashval &= 0x7FFF;
4199 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004200 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004201 if (equal(cmdp->cmdname, name))
4202 break;
4203 pp = &cmdp->next;
4204 }
4205 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004206 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4207 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004208 cmdp->next = NULL;
4209 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004210 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004211 }
4212 lastcmdentry = pp;
4213 return cmdp;
4214}
4215
4216/*
4217 * Delete the command entry returned on the last lookup.
4218 */
4219
Eric Andersenc470f442003-07-28 09:56:35 +00004220static void
4221delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004222{
Eric Andersencb57d552001-06-28 07:25:16 +00004223 struct tblentry *cmdp;
4224
4225 INTOFF;
4226 cmdp = *lastcmdentry;
4227 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004228 if (cmdp->cmdtype == CMDFUNCTION)
4229 freefunc(cmdp->param.func);
4230 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004231 INTON;
4232}
4233
4234
Eric Andersenc470f442003-07-28 09:56:35 +00004235/*
4236 * Add a new command entry, replacing any existing command entry for
4237 * the same name - except special builtins.
4238 */
Eric Andersencb57d552001-06-28 07:25:16 +00004239
Eric Andersenc470f442003-07-28 09:56:35 +00004240static inline void
4241addcmdentry(char *name, struct cmdentry *entry)
4242{
4243 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004244
Eric Andersenc470f442003-07-28 09:56:35 +00004245 cmdp = cmdlookup(name, 1);
4246 if (cmdp->cmdtype == CMDFUNCTION) {
4247 freefunc(cmdp->param.func);
4248 }
4249 cmdp->cmdtype = entry->cmdtype;
4250 cmdp->param = entry->u;
4251 cmdp->rehash = 0;
4252}
Eric Andersencb57d552001-06-28 07:25:16 +00004253
Eric Andersenc470f442003-07-28 09:56:35 +00004254/*
4255 * Make a copy of a parse tree.
4256 */
Eric Andersencb57d552001-06-28 07:25:16 +00004257
Eric Andersenc470f442003-07-28 09:56:35 +00004258static inline struct funcnode *
4259copyfunc(union node *n)
4260{
4261 struct funcnode *f;
4262 size_t blocksize;
4263
4264 funcblocksize = offsetof(struct funcnode, n);
4265 funcstringsize = 0;
4266 calcsize(n);
4267 blocksize = funcblocksize;
4268 f = ckmalloc(blocksize + funcstringsize);
4269 funcblock = (char *) f + offsetof(struct funcnode, n);
4270 funcstring = (char *) f + blocksize;
4271 copynode(n);
4272 f->count = 0;
4273 return f;
4274}
4275
4276/*
4277 * Define a shell function.
4278 */
4279
4280static void
4281defun(char *name, union node *func)
4282{
4283 struct cmdentry entry;
4284
4285 INTOFF;
4286 entry.cmdtype = CMDFUNCTION;
4287 entry.u.func = copyfunc(func);
4288 addcmdentry(name, &entry);
4289 INTON;
4290}
Eric Andersencb57d552001-06-28 07:25:16 +00004291
4292
4293/*
4294 * Delete a function if it exists.
4295 */
4296
Eric Andersenc470f442003-07-28 09:56:35 +00004297static void
4298unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004299{
Eric Andersencb57d552001-06-28 07:25:16 +00004300 struct tblentry *cmdp;
4301
Eric Andersenc470f442003-07-28 09:56:35 +00004302 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4303 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004304 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004305}
4306
Eric Andersen2870d962001-07-02 17:27:21 +00004307/*
Eric Andersencb57d552001-06-28 07:25:16 +00004308 * Locate and print what a word is...
4309 */
4310
Eric Andersenc470f442003-07-28 09:56:35 +00004311
4312#ifdef CONFIG_ASH_CMDCMD
4313static int
4314describe_command(char *command, int describe_command_verbose)
4315#else
4316#define describe_command_verbose 1
4317static int
4318describe_command(char *command)
4319#endif
4320{
4321 struct cmdentry entry;
4322 struct tblentry *cmdp;
4323#ifdef CONFIG_ASH_ALIAS
4324 const struct alias *ap;
4325#endif
4326 const char *path = pathval();
4327
4328 if (describe_command_verbose) {
4329 out1str(command);
4330 }
4331
4332 /* First look at the keywords */
4333 if (findkwd(command)) {
4334 out1str(describe_command_verbose ? " is a shell keyword" : command);
4335 goto out;
4336 }
4337
4338#ifdef CONFIG_ASH_ALIAS
4339 /* Then look at the aliases */
4340 if ((ap = lookupalias(command, 0)) != NULL) {
4341 if (describe_command_verbose) {
4342 out1fmt(" is an alias for %s", ap->val);
4343 } else {
4344 out1str("alias ");
4345 printalias(ap);
4346 return 0;
4347 }
4348 goto out;
4349 }
4350#endif
4351 /* Then check if it is a tracked alias */
4352 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4353 entry.cmdtype = cmdp->cmdtype;
4354 entry.u = cmdp->param;
4355 } else {
4356 /* Finally use brute force */
4357 find_command(command, &entry, DO_ABS, path);
4358 }
4359
4360 switch (entry.cmdtype) {
4361 case CMDNORMAL: {
4362 int j = entry.u.index;
4363 char *p;
4364 if (j == -1) {
4365 p = command;
4366 } else {
4367 do {
4368 p = padvance(&path, command);
4369 stunalloc(p);
4370 } while (--j >= 0);
4371 }
4372 if (describe_command_verbose) {
4373 out1fmt(" is%s %s",
4374 (cmdp ? " a tracked alias for" : nullstr), p
4375 );
4376 } else {
4377 out1str(p);
4378 }
4379 break;
4380 }
4381
4382 case CMDFUNCTION:
4383 if (describe_command_verbose) {
4384 out1str(" is a shell function");
4385 } else {
4386 out1str(command);
4387 }
4388 break;
4389
4390 case CMDBUILTIN:
4391 if (describe_command_verbose) {
4392 out1fmt(" is a %sshell builtin",
4393 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4394 "special " : nullstr
4395 );
4396 } else {
4397 out1str(command);
4398 }
4399 break;
4400
4401 default:
4402 if (describe_command_verbose) {
4403 out1str(": not found\n");
4404 }
4405 return 127;
4406 }
4407
4408out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004409 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004410 return 0;
4411}
4412
4413static int
4414typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004415{
4416 int i;
4417 int err = 0;
4418
4419 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004420#ifdef CONFIG_ASH_CMDCMD
4421 err |= describe_command(argv[i], 1);
4422#else
4423 err |= describe_command(argv[i]);
4424#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004425 }
4426 return err;
4427}
4428
Eric Andersend35c5df2002-01-09 15:37:36 +00004429#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004430static int
4431commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004432{
4433 int c;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004434 enum {
4435 VERIFY_BRIEF = 1,
4436 VERIFY_VERBOSE = 2,
4437 } verify = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004438
4439 while ((c = nextopt("pvV")) != '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004440 if (c == 'V')
4441 verify |= VERIFY_VERBOSE;
4442 else if (c == 'v')
4443 verify |= VERIFY_BRIEF;
Eric Andersenc470f442003-07-28 09:56:35 +00004444#ifdef DEBUG
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004445 else if (c != 'p')
4446 abort();
Eric Andersenc470f442003-07-28 09:56:35 +00004447#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004448 if (verify)
4449 return describe_command(*argptr, verify - VERIFY_BRIEF);
Eric Andersencb57d552001-06-28 07:25:16 +00004450
4451 return 0;
4452}
Eric Andersen2870d962001-07-02 17:27:21 +00004453#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004454
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004455/* expand.c */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004456
Eric Andersencb57d552001-06-28 07:25:16 +00004457/*
4458 * Routines to expand arguments to commands. We have to deal with
4459 * backquotes, shell variables, and file metacharacters.
4460 */
Eric Andersenc470f442003-07-28 09:56:35 +00004461
Eric Andersencb57d552001-06-28 07:25:16 +00004462/*
4463 * _rmescape() flags
4464 */
Eric Andersenc470f442003-07-28 09:56:35 +00004465#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4466#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4467#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4468#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4469#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004470
4471/*
4472 * Structure specifying which parts of the string should be searched
4473 * for IFS characters.
4474 */
4475
4476struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004477 struct ifsregion *next; /* next region in list */
4478 int begoff; /* offset of start of region */
4479 int endoff; /* offset of end of region */
4480 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004481};
4482
Eric Andersenc470f442003-07-28 09:56:35 +00004483/* output of current string */
4484static char *expdest;
4485/* list of back quote expressions */
4486static struct nodelist *argbackq;
4487/* first struct in list of ifs regions */
4488static struct ifsregion ifsfirst;
4489/* last struct in list */
4490static struct ifsregion *ifslastp;
4491/* holds expanded arg list */
4492static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004493
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004494static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004495static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004496static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004497static const char *subevalvar(char *, char *, int, int, int, int, int);
4498static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004499static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004500static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004501static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004502static void recordregion(int, int, int);
4503static void removerecordregions(int);
4504static void ifsbreakup(char *, struct arglist *);
4505static void ifsfree(void);
4506static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004507static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004508
Eric Andersened9ecf72004-06-22 08:29:45 +00004509static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004510static size_t esclen(const char *, const char *);
4511static char *scanleft(char *, char *, char *, char *, int, int);
4512static char *scanright(char *, char *, char *, char *, int, int);
4513static void varunset(const char *, const char *, const char *, int)
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00004514 ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004515
Eric Andersenc470f442003-07-28 09:56:35 +00004516
4517#define pmatch(a, b) !fnmatch((a), (b), 0)
4518/*
Eric Andersen90898442003-08-06 11:20:52 +00004519 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004520 *
4521 * Returns an stalloced string.
4522 */
4523
4524static inline char *
4525preglob(const char *pattern, int quoted, int flag) {
4526 flag |= RMESCAPE_GLOB;
4527 if (quoted) {
4528 flag |= RMESCAPE_QUOTED;
4529 }
4530 return _rmescapes((char *)pattern, flag);
4531}
4532
4533
4534static size_t
4535esclen(const char *start, const char *p) {
4536 size_t esc = 0;
4537
4538 while (p > start && *--p == CTLESC) {
4539 esc++;
4540 }
4541 return esc;
4542}
4543
Eric Andersencb57d552001-06-28 07:25:16 +00004544
4545/*
4546 * Expand shell variables and backquotes inside a here document.
4547 */
4548
Eric Andersenc470f442003-07-28 09:56:35 +00004549static inline void
4550expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004551{
Eric Andersencb57d552001-06-28 07:25:16 +00004552 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004553 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004554 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004555}
4556
4557
4558/*
4559 * Perform variable substitution and command substitution on an argument,
4560 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4561 * perform splitting and file name expansion. When arglist is NULL, perform
4562 * here document expansion.
4563 */
4564
Eric Andersenc470f442003-07-28 09:56:35 +00004565void
4566expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004567{
4568 struct strlist *sp;
4569 char *p;
4570
4571 argbackq = arg->narg.backquote;
4572 STARTSTACKSTR(expdest);
4573 ifsfirst.next = NULL;
4574 ifslastp = NULL;
4575 argstr(arg->narg.text, flag);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004576 p = _STPUTC('\0', expdest);
4577 expdest = p - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004578 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004579 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004580 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004581 p = grabstackstr(p);
Eric Andersencb57d552001-06-28 07:25:16 +00004582 exparg.lastp = &exparg.list;
4583 /*
4584 * TODO - EXP_REDIR
4585 */
4586 if (flag & EXP_FULL) {
4587 ifsbreakup(p, &exparg);
4588 *exparg.lastp = NULL;
4589 exparg.lastp = &exparg.list;
4590 expandmeta(exparg.list, flag);
4591 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004592 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004593 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004594 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004595 sp->text = p;
4596 *exparg.lastp = sp;
4597 exparg.lastp = &sp->next;
4598 }
Eric Andersenc470f442003-07-28 09:56:35 +00004599 if (ifsfirst.next)
4600 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004601 *exparg.lastp = NULL;
4602 if (exparg.list) {
4603 *arglist->lastp = exparg.list;
4604 arglist->lastp = exparg.lastp;
4605 }
4606}
4607
4608
Eric Andersenc470f442003-07-28 09:56:35 +00004609/*
4610 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4611 * characters to allow for further processing. Otherwise treat
4612 * $@ like $* since no splitting will be performed.
4613 */
4614
4615static void
4616argstr(char *p, int flag)
4617{
4618 static const char spclchars[] = {
4619 '=',
4620 ':',
4621 CTLQUOTEMARK,
4622 CTLENDVAR,
4623 CTLESC,
4624 CTLVAR,
4625 CTLBACKQ,
4626 CTLBACKQ | CTLQUOTE,
4627#ifdef CONFIG_ASH_MATH_SUPPORT
4628 CTLENDARI,
4629#endif
4630 0
4631 };
4632 const char *reject = spclchars;
4633 int c;
4634 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4635 int breakall = flag & EXP_WORD;
4636 int inquotes;
4637 size_t length;
4638 int startloc;
4639
4640 if (!(flag & EXP_VARTILDE)) {
4641 reject += 2;
4642 } else if (flag & EXP_VARTILDE2) {
4643 reject++;
4644 }
4645 inquotes = 0;
4646 length = 0;
4647 if (flag & EXP_TILDE) {
4648 char *q;
4649
4650 flag &= ~EXP_TILDE;
4651tilde:
4652 q = p;
4653 if (*q == CTLESC && (flag & EXP_QWORD))
4654 q++;
4655 if (*q == '~')
4656 p = exptilde(p, q, flag);
4657 }
4658start:
4659 startloc = expdest - (char *)stackblock();
4660 for (;;) {
4661 length += strcspn(p + length, reject);
4662 c = p[length];
4663 if (c && (!(c & 0x80)
4664#ifdef CONFIG_ASH_MATH_SUPPORT
4665 || c == CTLENDARI
4666#endif
4667 )) {
4668 /* c == '=' || c == ':' || c == CTLENDARI */
4669 length++;
4670 }
4671 if (length > 0) {
4672 int newloc;
4673 expdest = stnputs(p, length, expdest);
4674 newloc = expdest - (char *)stackblock();
4675 if (breakall && !inquotes && newloc > startloc) {
4676 recordregion(startloc, newloc, 0);
4677 }
4678 startloc = newloc;
4679 }
4680 p += length + 1;
4681 length = 0;
4682
4683 switch (c) {
4684 case '\0':
4685 goto breakloop;
4686 case '=':
4687 if (flag & EXP_VARTILDE2) {
4688 p--;
4689 continue;
4690 }
4691 flag |= EXP_VARTILDE2;
4692 reject++;
4693 /* fall through */
4694 case ':':
4695 /*
4696 * sort of a hack - expand tildes in variable
4697 * assignments (after the first '=' and after ':'s).
4698 */
4699 if (*--p == '~') {
4700 goto tilde;
4701 }
4702 continue;
4703 }
4704
4705 switch (c) {
4706 case CTLENDVAR: /* ??? */
4707 goto breakloop;
4708 case CTLQUOTEMARK:
4709 /* "$@" syntax adherence hack */
4710 if (
4711 !inquotes &&
4712 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4713 (p[4] == CTLQUOTEMARK || (
4714 p[4] == CTLENDVAR &&
4715 p[5] == CTLQUOTEMARK
4716 ))
4717 ) {
4718 p = evalvar(p + 1, flag) + 1;
4719 goto start;
4720 }
4721 inquotes = !inquotes;
4722addquote:
4723 if (quotes) {
4724 p--;
4725 length++;
4726 startloc++;
4727 }
4728 break;
4729 case CTLESC:
4730 startloc++;
4731 length++;
4732 goto addquote;
4733 case CTLVAR:
4734 p = evalvar(p, flag);
4735 goto start;
4736 case CTLBACKQ:
4737 c = 0;
4738 case CTLBACKQ|CTLQUOTE:
4739 expbackq(argbackq->n, c, quotes);
4740 argbackq = argbackq->next;
4741 goto start;
4742#ifdef CONFIG_ASH_MATH_SUPPORT
4743 case CTLENDARI:
4744 p--;
4745 expari(quotes);
4746 goto start;
4747#endif
4748 }
4749 }
4750breakloop:
4751 ;
4752}
4753
4754static char *
4755exptilde(char *startp, char *p, int flag)
4756{
4757 char c;
4758 char *name;
4759 struct passwd *pw;
4760 const char *home;
4761 int quotes = flag & (EXP_FULL | EXP_CASE);
4762 int startloc;
4763
4764 name = p + 1;
4765
4766 while ((c = *++p) != '\0') {
4767 switch(c) {
4768 case CTLESC:
4769 return (startp);
4770 case CTLQUOTEMARK:
4771 return (startp);
4772 case ':':
4773 if (flag & EXP_VARTILDE)
4774 goto done;
4775 break;
4776 case '/':
4777 case CTLENDVAR:
4778 goto done;
4779 }
4780 }
4781done:
4782 *p = '\0';
4783 if (*name == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004784 home = lookupvar(homestr);
Eric Andersenc470f442003-07-28 09:56:35 +00004785 } else {
4786 if ((pw = getpwnam(name)) == NULL)
4787 goto lose;
4788 home = pw->pw_dir;
4789 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004790 if (!home || !*home)
Eric Andersenc470f442003-07-28 09:56:35 +00004791 goto lose;
4792 *p = c;
4793 startloc = expdest - (char *)stackblock();
4794 strtodest(home, SQSYNTAX, quotes);
4795 recordregion(startloc, expdest - (char *)stackblock(), 0);
4796 return (p);
4797lose:
4798 *p = c;
4799 return (startp);
4800}
4801
4802
4803static void
4804removerecordregions(int endoff)
4805{
4806 if (ifslastp == NULL)
4807 return;
4808
4809 if (ifsfirst.endoff > endoff) {
4810 while (ifsfirst.next != NULL) {
4811 struct ifsregion *ifsp;
4812 INTOFF;
4813 ifsp = ifsfirst.next->next;
4814 ckfree(ifsfirst.next);
4815 ifsfirst.next = ifsp;
4816 INTON;
4817 }
4818 if (ifsfirst.begoff > endoff)
4819 ifslastp = NULL;
4820 else {
4821 ifslastp = &ifsfirst;
4822 ifsfirst.endoff = endoff;
4823 }
4824 return;
4825 }
4826
4827 ifslastp = &ifsfirst;
4828 while (ifslastp->next && ifslastp->next->begoff < endoff)
4829 ifslastp=ifslastp->next;
4830 while (ifslastp->next != NULL) {
4831 struct ifsregion *ifsp;
4832 INTOFF;
4833 ifsp = ifslastp->next->next;
4834 ckfree(ifslastp->next);
4835 ifslastp->next = ifsp;
4836 INTON;
4837 }
4838 if (ifslastp->endoff > endoff)
4839 ifslastp->endoff = endoff;
4840}
4841
4842
4843#ifdef CONFIG_ASH_MATH_SUPPORT
4844/*
4845 * Expand arithmetic expression. Backup to start of expression,
4846 * evaluate, place result in (backed up) result, adjust string position.
4847 */
4848void
4849expari(int quotes)
4850{
4851 char *p, *start;
4852 int begoff;
4853 int flag;
4854 int len;
4855
4856 /* ifsfree(); */
4857
4858 /*
4859 * This routine is slightly over-complicated for
4860 * efficiency. Next we scan backwards looking for the
4861 * start of arithmetic.
4862 */
4863 start = stackblock();
4864 p = expdest - 1;
4865 *p = '\0';
4866 p--;
4867 do {
4868 int esc;
4869
4870 while (*p != CTLARI) {
4871 p--;
4872#ifdef DEBUG
4873 if (p < start) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00004874 sh_error("missing CTLARI (shouldn't happen)");
Eric Andersenc470f442003-07-28 09:56:35 +00004875 }
4876#endif
4877 }
4878
4879 esc = esclen(start, p);
4880 if (!(esc % 2)) {
4881 break;
4882 }
4883
4884 p -= esc + 1;
4885 } while (1);
4886
4887 begoff = p - start;
4888
4889 removerecordregions(begoff);
4890
4891 flag = p[1];
4892
4893 expdest = p;
4894
4895 if (quotes)
4896 rmescapes(p + 2);
4897
4898 len = cvtnum(dash_arith(p + 2));
4899
4900 if (flag != '"')
4901 recordregion(begoff, begoff + len, 0);
4902}
4903#endif
4904
4905/*
4906 * Expand stuff in backwards quotes.
4907 */
4908
4909static void
4910expbackq(union node *cmd, int quoted, int quotes)
4911{
4912 struct backcmd in;
4913 int i;
4914 char buf[128];
4915 char *p;
4916 char *dest;
4917 int startloc;
4918 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4919 struct stackmark smark;
4920
4921 INTOFF;
4922 setstackmark(&smark);
4923 dest = expdest;
4924 startloc = dest - (char *)stackblock();
4925 grabstackstr(dest);
4926 evalbackcmd(cmd, (struct backcmd *) &in);
4927 popstackmark(&smark);
4928
4929 p = in.buf;
4930 i = in.nleft;
4931 if (i == 0)
4932 goto read;
4933 for (;;) {
4934 memtodest(p, i, syntax, quotes);
4935read:
4936 if (in.fd < 0)
4937 break;
4938 i = safe_read(in.fd, buf, sizeof buf);
4939 TRACE(("expbackq: read returns %d\n", i));
4940 if (i <= 0)
4941 break;
4942 p = buf;
4943 }
4944
4945 if (in.buf)
4946 ckfree(in.buf);
4947 if (in.fd >= 0) {
4948 close(in.fd);
4949 back_exitstatus = waitforjob(in.jp);
4950 }
4951 INTON;
4952
4953 /* Eat all trailing newlines */
4954 dest = expdest;
4955 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4956 STUNPUTC(dest);
4957 expdest = dest;
4958
4959 if (quoted == 0)
4960 recordregion(startloc, dest - (char *)stackblock(), 0);
4961 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4962 (dest - (char *)stackblock()) - startloc,
4963 (dest - (char *)stackblock()) - startloc,
4964 stackblock() + startloc));
4965}
4966
4967
4968static char *
Eric Andersen90898442003-08-06 11:20:52 +00004969scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4970 int zero)
4971{
Eric Andersenc470f442003-07-28 09:56:35 +00004972 char *loc;
4973 char *loc2;
4974 char c;
4975
4976 loc = startp;
4977 loc2 = rmesc;
4978 do {
4979 int match;
4980 const char *s = loc2;
4981 c = *loc2;
4982 if (zero) {
4983 *loc2 = '\0';
4984 s = rmesc;
4985 }
4986 match = pmatch(str, s);
4987 *loc2 = c;
4988 if (match)
4989 return loc;
4990 if (quotes && *loc == CTLESC)
4991 loc++;
4992 loc++;
4993 loc2++;
4994 } while (c);
4995 return 0;
4996}
4997
4998
4999static char *
Eric Andersen90898442003-08-06 11:20:52 +00005000scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5001 int zero)
5002{
Eric Andersenc470f442003-07-28 09:56:35 +00005003 int esc = 0;
5004 char *loc;
5005 char *loc2;
5006
5007 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5008 int match;
5009 char c = *loc2;
5010 const char *s = loc2;
5011 if (zero) {
5012 *loc2 = '\0';
5013 s = rmesc;
5014 }
5015 match = pmatch(str, s);
5016 *loc2 = c;
5017 if (match)
5018 return loc;
5019 loc--;
5020 if (quotes) {
5021 if (--esc < 0) {
5022 esc = esclen(startp, loc);
5023 }
5024 if (esc % 2) {
5025 esc--;
5026 loc--;
5027 }
5028 }
5029 }
5030 return 0;
5031}
5032
5033static const char *
5034subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5035{
5036 char *startp;
5037 char *loc;
5038 int saveherefd = herefd;
5039 struct nodelist *saveargbackq = argbackq;
5040 int amount;
5041 char *rmesc, *rmescend;
5042 int zero;
5043 char *(*scan)(char *, char *, char *, char *, int , int);
5044
5045 herefd = -1;
5046 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5047 STPUTC('\0', expdest);
5048 herefd = saveherefd;
5049 argbackq = saveargbackq;
5050 startp = stackblock() + startloc;
5051
5052 switch (subtype) {
5053 case VSASSIGN:
5054 setvar(str, startp, 0);
5055 amount = startp - expdest;
5056 STADJUST(amount, expdest);
5057 return startp;
5058
5059 case VSQUESTION:
5060 varunset(p, str, startp, varflags);
5061 /* NOTREACHED */
5062 }
5063
5064 subtype -= VSTRIMRIGHT;
5065#ifdef DEBUG
5066 if (subtype < 0 || subtype > 3)
5067 abort();
5068#endif
5069
5070 rmesc = startp;
5071 rmescend = stackblock() + strloc;
5072 if (quotes) {
5073 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5074 if (rmesc != startp) {
5075 rmescend = expdest;
5076 startp = stackblock() + startloc;
5077 }
5078 }
5079 rmescend--;
5080 str = stackblock() + strloc;
5081 preglob(str, varflags & VSQUOTE, 0);
5082
5083 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5084 zero = subtype >> 1;
5085 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5086 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5087
5088 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5089 if (loc) {
5090 if (zero) {
5091 memmove(startp, loc, str - loc);
5092 loc = startp + (str - loc) - 1;
5093 }
5094 *loc = '\0';
5095 amount = loc - expdest;
5096 STADJUST(amount, expdest);
5097 }
5098 return loc;
5099}
5100
5101
Eric Andersen62483552001-07-10 06:09:16 +00005102/*
5103 * Expand a variable, and return a pointer to the next character in the
5104 * input string.
5105 */
Eric Andersenc470f442003-07-28 09:56:35 +00005106static char *
5107evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005108{
5109 int subtype;
5110 int varflags;
5111 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005112 int patloc;
5113 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005114 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005115 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005116 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005117 int quotes;
5118 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005119
Eric Andersenc470f442003-07-28 09:56:35 +00005120 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005121 varflags = *p++;
5122 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005123 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005124 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005125 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005126 startloc = expdest - (char *)stackblock();
5127 p = strchr(p, '=') + 1;
5128
Eric Andersenc470f442003-07-28 09:56:35 +00005129again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005130 varlen = varvalue(var, varflags, flag);
5131 if (varflags & VSNUL)
5132 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005133
Glenn L McGrath76620622004-01-13 10:19:37 +00005134 if (subtype == VSPLUS) {
5135 varlen = -1 - varlen;
5136 goto vsplus;
5137 }
Eric Andersen62483552001-07-10 06:09:16 +00005138
Eric Andersenc470f442003-07-28 09:56:35 +00005139 if (subtype == VSMINUS) {
5140vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005141 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005142 argstr(
5143 p, flag | EXP_TILDE |
5144 (quoted ? EXP_QWORD : EXP_WORD)
5145 );
5146 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005147 }
5148 if (easy)
5149 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005150 goto end;
5151 }
Eric Andersen62483552001-07-10 06:09:16 +00005152
Eric Andersenc470f442003-07-28 09:56:35 +00005153 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005154 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005155 if (subevalvar(p, var, 0, subtype, startloc,
5156 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005157 varflags &= ~VSNUL;
5158 /*
5159 * Remove any recorded regions beyond
5160 * start of variable
5161 */
5162 removerecordregions(startloc);
5163 goto again;
5164 }
Eric Andersenc470f442003-07-28 09:56:35 +00005165 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005166 }
5167 if (easy)
5168 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005169 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005170 }
5171
Glenn L McGrath76620622004-01-13 10:19:37 +00005172 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005173 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005174
Eric Andersenc470f442003-07-28 09:56:35 +00005175 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005176 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005177 goto record;
5178 }
5179
5180 if (subtype == VSNORMAL) {
5181 if (!easy)
5182 goto end;
5183record:
5184 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5185 goto end;
5186 }
5187
5188#ifdef DEBUG
5189 switch (subtype) {
5190 case VSTRIMLEFT:
5191 case VSTRIMLEFTMAX:
5192 case VSTRIMRIGHT:
5193 case VSTRIMRIGHTMAX:
5194 break;
5195 default:
5196 abort();
5197 }
5198#endif
5199
Glenn L McGrath76620622004-01-13 10:19:37 +00005200 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005201 /*
5202 * Terminate the string and start recording the pattern
5203 * right after it
5204 */
5205 STPUTC('\0', expdest);
5206 patloc = expdest - (char *)stackblock();
5207 if (subevalvar(p, NULL, patloc, subtype,
5208 startloc, varflags, quotes) == 0) {
5209 int amount = expdest - (
5210 (char *)stackblock() + patloc - 1
5211 );
5212 STADJUST(-amount, expdest);
5213 }
5214 /* Remove any recorded regions beyond start of variable */
5215 removerecordregions(startloc);
5216 goto record;
5217 }
5218
5219end:
5220 if (subtype != VSNORMAL) { /* skip to end of alternative */
5221 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005222 for (;;) {
5223 if ((c = *p++) == CTLESC)
5224 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005225 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005226 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005227 argbackq = argbackq->next;
5228 } else if (c == CTLVAR) {
5229 if ((*p++ & VSTYPE) != VSNORMAL)
5230 nesting++;
5231 } else if (c == CTLENDVAR) {
5232 if (--nesting == 0)
5233 break;
5234 }
5235 }
5236 }
5237 return p;
5238}
5239
Eric Andersencb57d552001-06-28 07:25:16 +00005240
Eric Andersencb57d552001-06-28 07:25:16 +00005241/*
5242 * Put a string on the stack.
5243 */
5244
Eric Andersenc470f442003-07-28 09:56:35 +00005245static void
5246memtodest(const char *p, size_t len, int syntax, int quotes) {
5247 char *q = expdest;
5248
5249 q = makestrspace(len * 2, q);
5250
5251 while (len--) {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005252 int c = SC2INT(*p++);
Eric Andersenc470f442003-07-28 09:56:35 +00005253 if (!c)
5254 continue;
5255 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5256 USTPUTC(CTLESC, q);
5257 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005258 }
Eric Andersenc470f442003-07-28 09:56:35 +00005259
5260 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005261}
5262
Eric Andersenc470f442003-07-28 09:56:35 +00005263
5264static void
5265strtodest(const char *p, int syntax, int quotes)
5266{
5267 memtodest(p, strlen(p), syntax, quotes);
5268}
5269
5270
Eric Andersencb57d552001-06-28 07:25:16 +00005271/*
5272 * Add the value of a specialized variable to the stack string.
5273 */
5274
Glenn L McGrath76620622004-01-13 10:19:37 +00005275static ssize_t
5276varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005277{
5278 int num;
5279 char *p;
5280 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005281 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005282 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005283 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005284 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005285 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005286 int quoted = varflags & VSQUOTE;
5287 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005288 int quotes = flags & (EXP_FULL | EXP_CASE);
5289
Glenn L McGrath76620622004-01-13 10:19:37 +00005290 if (quoted && (flags & EXP_FULL))
5291 sep = 1 << CHAR_BIT;
5292
Eric Andersencb57d552001-06-28 07:25:16 +00005293 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5294 switch (*name) {
5295 case '$':
5296 num = rootpid;
5297 goto numvar;
5298 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005299 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005300 goto numvar;
5301 case '#':
5302 num = shellparam.nparam;
5303 goto numvar;
5304 case '!':
5305 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005306 if (num == 0)
5307 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005308numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005309 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005310 break;
5311 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005312 p = makestrspace(NOPTS, expdest);
5313 for (i = NOPTS - 1; i >= 0; i--) {
5314 if (optlist[i]) {
5315 USTPUTC(optletters(i), p);
5316 len++;
5317 }
Eric Andersencb57d552001-06-28 07:25:16 +00005318 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005319 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005320 break;
5321 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005322 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005323 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005324 /* fall through */
5325 case '*':
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005326 sep = ifsset() ? SC2INT(ifsval()[0]) : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005327 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5328 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005329param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005330 if (!(ap = shellparam.p))
5331 return -1;
5332 while ((p = *ap++)) {
5333 size_t partlen;
5334
5335 partlen = strlen(p);
Glenn L McGrath76620622004-01-13 10:19:37 +00005336 len += partlen;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00005337
5338 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5339 memtodest(p, partlen, syntax, quotes);
5340
5341 if (*ap && sep) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005342 char *q;
5343
5344 len++;
5345 if (subtype == VSPLUS || subtype == VSLENGTH) {
5346 continue;
5347 }
5348 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005349 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005350 STPUTC(CTLESC, q);
5351 STPUTC(sep, q);
5352 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005353 }
5354 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005355 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005356 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005357 case '1':
5358 case '2':
5359 case '3':
5360 case '4':
5361 case '5':
5362 case '6':
5363 case '7':
5364 case '8':
5365 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005366 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005367 if (num < 0 || num > shellparam.nparam)
5368 return -1;
5369 p = num ? shellparam.p[num - 1] : arg0;
5370 goto value;
5371 default:
5372 p = lookupvar(name);
5373value:
5374 if (!p)
5375 return -1;
5376
5377 len = strlen(p);
5378 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5379 memtodest(p, len, syntax, quotes);
5380 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005381 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005382
5383 if (subtype == VSPLUS || subtype == VSLENGTH)
5384 STADJUST(-len, expdest);
5385 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005386}
5387
5388
Eric Andersencb57d552001-06-28 07:25:16 +00005389/*
5390 * Record the fact that we have to scan this region of the
5391 * string for IFS characters.
5392 */
5393
Eric Andersenc470f442003-07-28 09:56:35 +00005394static void
5395recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005396{
5397 struct ifsregion *ifsp;
5398
5399 if (ifslastp == NULL) {
5400 ifsp = &ifsfirst;
5401 } else {
5402 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005403 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005404 ifsp->next = NULL;
5405 ifslastp->next = ifsp;
5406 INTON;
5407 }
5408 ifslastp = ifsp;
5409 ifslastp->begoff = start;
5410 ifslastp->endoff = end;
5411 ifslastp->nulonly = nulonly;
5412}
5413
5414
Eric Andersencb57d552001-06-28 07:25:16 +00005415/*
5416 * Break the argument string into pieces based upon IFS and add the
5417 * strings to the argument list. The regions of the string to be
5418 * searched for IFS characters have been stored by recordregion.
5419 */
Eric Andersenc470f442003-07-28 09:56:35 +00005420static void
5421ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005422{
Eric Andersencb57d552001-06-28 07:25:16 +00005423 struct ifsregion *ifsp;
5424 struct strlist *sp;
5425 char *start;
5426 char *p;
5427 char *q;
5428 const char *ifs, *realifs;
5429 int ifsspc;
5430 int nulonly;
5431
5432
5433 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005434 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005435 ifsspc = 0;
5436 nulonly = 0;
5437 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005438 ifsp = &ifsfirst;
5439 do {
5440 p = string + ifsp->begoff;
5441 nulonly = ifsp->nulonly;
5442 ifs = nulonly ? nullstr : realifs;
5443 ifsspc = 0;
5444 while (p < string + ifsp->endoff) {
5445 q = p;
5446 if (*p == CTLESC)
5447 p++;
5448 if (strchr(ifs, *p)) {
5449 if (!nulonly)
5450 ifsspc = (strchr(defifs, *p) != NULL);
5451 /* Ignore IFS whitespace at start */
5452 if (q == start && ifsspc) {
5453 p++;
5454 start = p;
5455 continue;
5456 }
5457 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005458 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005459 sp->text = start;
5460 *arglist->lastp = sp;
5461 arglist->lastp = &sp->next;
5462 p++;
5463 if (!nulonly) {
5464 for (;;) {
5465 if (p >= string + ifsp->endoff) {
5466 break;
5467 }
5468 q = p;
5469 if (*p == CTLESC)
5470 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005471 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005472 p = q;
5473 break;
5474 } else if (strchr(defifs, *p) == NULL) {
5475 if (ifsspc) {
5476 p++;
5477 ifsspc = 0;
5478 } else {
5479 p = q;
5480 break;
5481 }
5482 } else
5483 p++;
5484 }
5485 }
5486 start = p;
5487 } else
5488 p++;
5489 }
5490 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005491 if (nulonly)
5492 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005493 }
5494
Eric Andersenc470f442003-07-28 09:56:35 +00005495 if (!*start)
5496 return;
5497
5498add:
5499 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005500 sp->text = start;
5501 *arglist->lastp = sp;
5502 arglist->lastp = &sp->next;
5503}
5504
Eric Andersenc470f442003-07-28 09:56:35 +00005505static void
5506ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005507{
Eric Andersenc470f442003-07-28 09:56:35 +00005508 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005509
Eric Andersenc470f442003-07-28 09:56:35 +00005510 INTOFF;
5511 p = ifsfirst.next;
5512 do {
5513 struct ifsregion *ifsp;
5514 ifsp = p->next;
5515 ckfree(p);
5516 p = ifsp;
5517 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005518 ifslastp = NULL;
5519 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005520 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005521}
5522
Eric Andersen90898442003-08-06 11:20:52 +00005523static void expmeta(char *, char *);
5524static struct strlist *expsort(struct strlist *);
5525static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005526
Eric Andersen90898442003-08-06 11:20:52 +00005527static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005528
Eric Andersencb57d552001-06-28 07:25:16 +00005529
Eric Andersenc470f442003-07-28 09:56:35 +00005530static void
Eric Andersen90898442003-08-06 11:20:52 +00005531expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005532{
Eric Andersen90898442003-08-06 11:20:52 +00005533 static const char metachars[] = {
5534 '*', '?', '[', 0
5535 };
Eric Andersencb57d552001-06-28 07:25:16 +00005536 /* TODO - EXP_REDIR */
5537
5538 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005539 struct strlist **savelastp;
5540 struct strlist *sp;
5541 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005542
Eric Andersencb57d552001-06-28 07:25:16 +00005543 if (fflag)
5544 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005545 if (!strpbrk(str->text, metachars))
5546 goto nometa;
5547 savelastp = exparg.lastp;
5548
Eric Andersencb57d552001-06-28 07:25:16 +00005549 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005550 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005551 {
5552 int i = strlen(str->text);
5553 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5554 }
5555
5556 expmeta(expdir, p);
5557 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005558 if (p != str->text)
5559 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005560 INTON;
5561 if (exparg.lastp == savelastp) {
5562 /*
5563 * no matches
5564 */
Eric Andersenc470f442003-07-28 09:56:35 +00005565nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005566 *exparg.lastp = str;
5567 rmescapes(str->text);
5568 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005569 } else {
5570 *exparg.lastp = NULL;
5571 *savelastp = sp = expsort(*savelastp);
5572 while (sp->next != NULL)
5573 sp = sp->next;
5574 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005575 }
5576 str = str->next;
5577 }
5578}
5579
Eric Andersencb57d552001-06-28 07:25:16 +00005580/*
Eric Andersenc470f442003-07-28 09:56:35 +00005581 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005582 */
5583
Eric Andersenc470f442003-07-28 09:56:35 +00005584static void
Eric Andersen90898442003-08-06 11:20:52 +00005585addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005586{
Eric Andersencb57d552001-06-28 07:25:16 +00005587 struct strlist *sp;
5588
Eric Andersenc470f442003-07-28 09:56:35 +00005589 sp = (struct strlist *)stalloc(sizeof *sp);
5590 sp->text = sstrdup(name);
5591 *exparg.lastp = sp;
5592 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005593}
5594
5595
Eric Andersencb57d552001-06-28 07:25:16 +00005596/*
Eric Andersen90898442003-08-06 11:20:52 +00005597 * Do metacharacter (i.e. *, ?, [...]) expansion.
5598 */
5599
5600static void
5601expmeta(char *enddir, char *name)
5602{
5603 char *p;
5604 const char *cp;
5605 char *start;
5606 char *endname;
5607 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005608 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005609 DIR *dirp;
5610 struct dirent *dp;
5611 int atend;
5612 int matchdot;
5613
5614 metaflag = 0;
5615 start = name;
5616 for (p = name; *p; p++) {
5617 if (*p == '*' || *p == '?')
5618 metaflag = 1;
5619 else if (*p == '[') {
5620 char *q = p + 1;
5621 if (*q == '!')
5622 q++;
5623 for (;;) {
5624 if (*q == '\\')
5625 q++;
5626 if (*q == '/' || *q == '\0')
5627 break;
5628 if (*++q == ']') {
5629 metaflag = 1;
5630 break;
5631 }
5632 }
5633 } else if (*p == '\\')
5634 p++;
5635 else if (*p == '/') {
5636 if (metaflag)
5637 goto out;
5638 start = p + 1;
5639 }
5640 }
5641out:
5642 if (metaflag == 0) { /* we've reached the end of the file name */
5643 if (enddir != expdir)
5644 metaflag++;
5645 p = name;
5646 do {
5647 if (*p == '\\')
5648 p++;
5649 *enddir++ = *p;
5650 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005651 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005652 addfname(expdir);
5653 return;
5654 }
5655 endname = p;
5656 if (name < start) {
5657 p = name;
5658 do {
5659 if (*p == '\\')
5660 p++;
5661 *enddir++ = *p++;
5662 } while (p < start);
5663 }
5664 if (enddir == expdir) {
5665 cp = ".";
5666 } else if (enddir == expdir + 1 && *expdir == '/') {
5667 cp = "/";
5668 } else {
5669 cp = expdir;
5670 enddir[-1] = '\0';
5671 }
5672 if ((dirp = opendir(cp)) == NULL)
5673 return;
5674 if (enddir != expdir)
5675 enddir[-1] = '/';
5676 if (*endname == 0) {
5677 atend = 1;
5678 } else {
5679 atend = 0;
5680 *endname++ = '\0';
5681 }
5682 matchdot = 0;
5683 p = start;
5684 if (*p == '\\')
5685 p++;
5686 if (*p == '.')
5687 matchdot++;
5688 while (! intpending && (dp = readdir(dirp)) != NULL) {
5689 if (dp->d_name[0] == '.' && ! matchdot)
5690 continue;
5691 if (pmatch(start, dp->d_name)) {
5692 if (atend) {
5693 scopy(dp->d_name, enddir);
5694 addfname(expdir);
5695 } else {
5696 for (p = enddir, cp = dp->d_name;
5697 (*p++ = *cp++) != '\0';)
5698 continue;
5699 p[-1] = '/';
5700 expmeta(p, endname);
5701 }
5702 }
5703 }
5704 closedir(dirp);
5705 if (! atend)
5706 endname[-1] = '/';
5707}
5708
5709/*
5710 * Sort the results of file name expansion. It calculates the number of
5711 * strings to sort and then calls msort (short for merge sort) to do the
5712 * work.
5713 */
5714
5715static struct strlist *
5716expsort(struct strlist *str)
5717{
5718 int len;
5719 struct strlist *sp;
5720
5721 len = 0;
5722 for (sp = str ; sp ; sp = sp->next)
5723 len++;
5724 return msort(str, len);
5725}
5726
5727
5728static struct strlist *
5729msort(struct strlist *list, int len)
5730{
5731 struct strlist *p, *q = NULL;
5732 struct strlist **lpp;
5733 int half;
5734 int n;
5735
5736 if (len <= 1)
5737 return list;
5738 half = len >> 1;
5739 p = list;
5740 for (n = half ; --n >= 0 ; ) {
5741 q = p;
5742 p = p->next;
5743 }
5744 q->next = NULL; /* terminate first half of list */
5745 q = msort(list, half); /* sort first half of list */
5746 p = msort(p, len - half); /* sort second half */
5747 lpp = &list;
5748 for (;;) {
5749#ifdef CONFIG_LOCALE_SUPPORT
5750 if (strcoll(p->text, q->text) < 0)
5751#else
5752 if (strcmp(p->text, q->text) < 0)
5753#endif
5754 {
5755 *lpp = p;
5756 lpp = &p->next;
5757 if ((p = *lpp) == NULL) {
5758 *lpp = q;
5759 break;
5760 }
5761 } else {
5762 *lpp = q;
5763 lpp = &q->next;
5764 if ((q = *lpp) == NULL) {
5765 *lpp = p;
5766 break;
5767 }
5768 }
5769 }
5770 return list;
5771}
5772
5773
5774/*
Eric Andersencb57d552001-06-28 07:25:16 +00005775 * Returns true if the pattern matches the string.
5776 */
5777
Eric Andersenc470f442003-07-28 09:56:35 +00005778static inline int
5779patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005780{
Eric Andersenc470f442003-07-28 09:56:35 +00005781 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005782}
5783
5784
Eric Andersencb57d552001-06-28 07:25:16 +00005785/*
5786 * Remove any CTLESC characters from a string.
5787 */
5788
Eric Andersenc470f442003-07-28 09:56:35 +00005789static char *
5790_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005791{
5792 char *p, *q, *r;
5793 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005794 unsigned inquotes;
5795 int notescaped;
5796 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005797
5798 p = strpbrk(str, qchars);
5799 if (!p) {
5800 return str;
5801 }
5802 q = p;
5803 r = str;
5804 if (flag & RMESCAPE_ALLOC) {
5805 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005806 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005807
Eric Andersenc470f442003-07-28 09:56:35 +00005808 if (flag & RMESCAPE_GROW) {
5809 r = makestrspace(fulllen, expdest);
5810 } else if (flag & RMESCAPE_HEAP) {
5811 r = ckmalloc(fulllen);
5812 } else {
5813 r = stalloc(fulllen);
5814 }
5815 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005816 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005817 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005818 }
5819 }
Eric Andersenc470f442003-07-28 09:56:35 +00005820 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5821 globbing = flag & RMESCAPE_GLOB;
5822 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005823 while (*p) {
5824 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005825 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005826 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005827 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005828 continue;
5829 }
Eric Andersenc470f442003-07-28 09:56:35 +00005830 if (*p == '\\') {
5831 /* naked back slash */
5832 notescaped = 0;
5833 goto copy;
5834 }
Eric Andersencb57d552001-06-28 07:25:16 +00005835 if (*p == CTLESC) {
5836 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005837 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005838 *q++ = '\\';
5839 }
5840 }
Eric Andersenc470f442003-07-28 09:56:35 +00005841 notescaped = globbing;
5842copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005843 *q++ = *p++;
5844 }
5845 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005846 if (flag & RMESCAPE_GROW) {
5847 expdest = r;
5848 STADJUST(q - r + 1, expdest);
5849 }
Eric Andersencb57d552001-06-28 07:25:16 +00005850 return r;
5851}
Eric Andersencb57d552001-06-28 07:25:16 +00005852
5853
Eric Andersencb57d552001-06-28 07:25:16 +00005854/*
5855 * See if a pattern matches in a case statement.
5856 */
5857
Eric Andersenc470f442003-07-28 09:56:35 +00005858int
5859casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005860{
Eric Andersencb57d552001-06-28 07:25:16 +00005861 struct stackmark smark;
5862 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005863
5864 setstackmark(&smark);
5865 argbackq = pattern->narg.backquote;
5866 STARTSTACKSTR(expdest);
5867 ifslastp = NULL;
5868 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005869 STACKSTRNUL(expdest);
5870 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005871 popstackmark(&smark);
5872 return result;
5873}
5874
5875/*
5876 * Our own itoa().
5877 */
5878
Eric Andersenc470f442003-07-28 09:56:35 +00005879static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005880cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005881{
Eric Andersencb57d552001-06-28 07:25:16 +00005882 int len;
5883
Eric Andersenc470f442003-07-28 09:56:35 +00005884 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005885#ifdef CONFIG_ASH_MATH_SUPPORT_64
5886 len = fmtstr(expdest, 32, "%lld", (long long) num);
5887#else
Eric Andersenc470f442003-07-28 09:56:35 +00005888 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005889#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005890 STADJUST(len, expdest);
5891 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005892}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005893
Eric Andersenc470f442003-07-28 09:56:35 +00005894static void
5895varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005896{
Eric Andersenc470f442003-07-28 09:56:35 +00005897 const char *msg;
5898 const char *tail;
5899
5900 tail = nullstr;
5901 msg = "parameter not set";
5902 if (umsg) {
5903 if (*end == CTLENDVAR) {
5904 if (varflags & VSNUL)
5905 tail = " or null";
5906 } else
5907 msg = umsg;
5908 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005909 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005910}
Eric Andersen90898442003-08-06 11:20:52 +00005911
5912
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00005913/* input.c */
Eric Andersencb57d552001-06-28 07:25:16 +00005914
Eric Andersencb57d552001-06-28 07:25:16 +00005915/*
Eric Andersen90898442003-08-06 11:20:52 +00005916 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005917 */
5918
Eric Andersenc470f442003-07-28 09:56:35 +00005919#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005920
Eric Andersenc470f442003-07-28 09:56:35 +00005921static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005922
Eric Andersencb57d552001-06-28 07:25:16 +00005923/*
Eric Andersenc470f442003-07-28 09:56:35 +00005924 * Read a character from the script, returning PEOF on end of file.
5925 * Nul characters in the input are silently discarded.
5926 */
5927
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00005928
5929#define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer())
Eric Andersenc470f442003-07-28 09:56:35 +00005930
5931#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5932#define pgetc_macro() pgetc()
5933static int
5934pgetc(void)
5935{
5936 return pgetc_as_macro();
5937}
5938#else
5939#define pgetc_macro() pgetc_as_macro()
5940static int
5941pgetc(void)
5942{
5943 return pgetc_macro();
5944}
5945#endif
5946
5947
5948/*
5949 * Same as pgetc(), but ignores PEOA.
5950 */
5951#ifdef CONFIG_ASH_ALIAS
5952static int pgetc2(void)
5953{
5954 int c;
5955
5956 do {
5957 c = pgetc_macro();
5958 } while (c == PEOA);
5959 return c;
5960}
5961#else
5962static inline int pgetc2(void)
5963{
5964 return pgetc_macro();
5965}
5966#endif
5967
Glenn L McGrath28939ad2004-07-21 10:20:19 +00005968/*
5969 * Read a line from the script.
5970 */
5971
5972static inline char *
5973pfgets(char *line, int len)
5974{
5975 char *p = line;
5976 int nleft = len;
5977 int c;
5978
5979 while (--nleft > 0) {
5980 c = pgetc2();
5981 if (c == PEOF) {
5982 if (p == line)
5983 return NULL;
5984 break;
5985 }
5986 *p++ = c;
5987 if (c == '\n')
5988 break;
5989 }
5990 *p = '\0';
5991 return line;
5992}
5993
5994
Eric Andersenc470f442003-07-28 09:56:35 +00005995
5996#ifdef CONFIG_FEATURE_COMMAND_EDITING
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00005997#ifdef CONFIG_ASH_EXPAND_PRMT
5998static char *cmdedit_prompt;
5999#else
Eric Andersenc470f442003-07-28 09:56:35 +00006000static const char *cmdedit_prompt;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006001#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006002static inline void putprompt(const char *s)
6003{
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006004#ifdef CONFIG_ASH_EXPAND_PRMT
6005 free(cmdedit_prompt);
6006 cmdedit_prompt = bb_xstrdup(s);
6007#else
Eric Andersenc470f442003-07-28 09:56:35 +00006008 cmdedit_prompt = s;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006009#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006010}
6011#else
6012static inline void putprompt(const char *s)
6013{
6014 out2str(s);
6015}
6016#endif
6017
6018static inline int
6019preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006020{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006021 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006022 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006023 parsenextc = buf;
6024
Eric Andersenc470f442003-07-28 09:56:35 +00006025retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006026#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006027 if (!iflag || parsefile->fd)
6028 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6029 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006030#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006031 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006032#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006033 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6034 if(nr == 0) {
6035 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006036 if(trap[SIGINT]) {
6037 buf[0] = '\n';
6038 buf[1] = 0;
6039 raise(SIGINT);
6040 return 1;
6041 }
Eric Andersenc470f442003-07-28 09:56:35 +00006042 goto retry;
6043 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006044 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006045 /* Ctrl+D presend */
6046 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006047 }
Eric Andersencb57d552001-06-28 07:25:16 +00006048 }
6049#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006050 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006051#endif
6052
6053 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006054 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6055 int flags = fcntl(0, F_GETFL, 0);
6056 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006057 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006058 if (fcntl(0, F_SETFL, flags) >= 0) {
6059 out2str("sh: turning off NDELAY mode\n");
6060 goto retry;
6061 }
6062 }
6063 }
6064 }
6065 return nr;
6066}
6067
6068/*
6069 * Refill the input buffer and return the next input character:
6070 *
6071 * 1) If a string was pushed back on the input, pop it;
6072 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6073 * from a string so we can't refill the buffer, return EOF.
6074 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6075 * 4) Process input up to the next newline, deleting nul characters.
6076 */
6077
Eric Andersenc470f442003-07-28 09:56:35 +00006078int
6079preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006080{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006081 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00006082 int more;
6083 char savec;
6084
6085 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006086#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006087 if (parsenleft == -1 && parsefile->strpush->ap &&
6088 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006089 return PEOA;
6090 }
Eric Andersen2870d962001-07-02 17:27:21 +00006091#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006092 popstring();
6093 if (--parsenleft >= 0)
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006094 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006095 }
6096 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6097 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006098 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006099
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006100 more = parselleft;
6101 if (more <= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006102again:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006103 if ((more = preadfd()) <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006104 parselleft = parsenleft = EOF_NLEFT;
6105 return PEOF;
6106 }
6107 }
6108
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006109 q = parsenextc;
Eric Andersencb57d552001-06-28 07:25:16 +00006110
6111 /* delete nul characters */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006112 for (;;) {
6113 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00006114
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006115 more--;
6116 c = *q;
Eric Andersenc470f442003-07-28 09:56:35 +00006117
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006118 if (!c)
6119 memmove(q, q + 1, more);
6120 else {
6121 q++;
6122 if (c == '\n') {
6123 parsenleft = q - parsenextc - 1;
6124 break;
6125 }
Eric Andersencb57d552001-06-28 07:25:16 +00006126 }
6127
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006128 if (more <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006129 parsenleft = q - parsenextc - 1;
6130 if (parsenleft < 0)
6131 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006132 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006133 }
6134 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006135 parselleft = more;
Eric Andersencb57d552001-06-28 07:25:16 +00006136
6137 savec = *q;
6138 *q = '\0';
6139
6140 if (vflag) {
6141 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006142 }
6143
6144 *q = savec;
6145
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +00006146 return SC2INT(*parsenextc++);
Eric Andersencb57d552001-06-28 07:25:16 +00006147}
6148
Eric Andersenc470f442003-07-28 09:56:35 +00006149/*
6150 * Undo the last call to pgetc. Only one character may be pushed back.
6151 * PEOF may be pushed back.
6152 */
6153
6154void
6155pungetc(void)
6156{
6157 parsenleft++;
6158 parsenextc--;
6159}
Eric Andersencb57d552001-06-28 07:25:16 +00006160
6161/*
6162 * Push a string back onto the input at this current parsefile level.
6163 * We handle aliases this way.
6164 */
Eric Andersenc470f442003-07-28 09:56:35 +00006165void
6166pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006167{
Eric Andersencb57d552001-06-28 07:25:16 +00006168 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006169 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006170
Eric Andersenc470f442003-07-28 09:56:35 +00006171 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006172 INTOFF;
6173/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6174 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006175 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006176 sp->prev = parsefile->strpush;
6177 parsefile->strpush = sp;
6178 } else
6179 sp = parsefile->strpush = &(parsefile->basestrpush);
6180 sp->prevstring = parsenextc;
6181 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006182#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006183 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006184 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006185 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006186 sp->string = s;
6187 }
Eric Andersen2870d962001-07-02 17:27:21 +00006188#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006189 parsenextc = s;
6190 parsenleft = len;
6191 INTON;
6192}
6193
Eric Andersenc470f442003-07-28 09:56:35 +00006194void
6195popstring(void)
6196{
6197 struct strpush *sp = parsefile->strpush;
6198
6199 INTOFF;
6200#ifdef CONFIG_ASH_ALIAS
6201 if (sp->ap) {
6202 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6203 checkkwd |= CHKALIAS;
6204 }
6205 if (sp->string != sp->ap->val) {
6206 ckfree(sp->string);
6207 }
6208 sp->ap->flag &= ~ALIASINUSE;
6209 if (sp->ap->flag & ALIASDEAD) {
6210 unalias(sp->ap->name);
6211 }
6212 }
6213#endif
6214 parsenextc = sp->prevstring;
6215 parsenleft = sp->prevnleft;
6216/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6217 parsefile->strpush = sp->prev;
6218 if (sp != &(parsefile->basestrpush))
6219 ckfree(sp);
6220 INTON;
6221}
6222
6223/*
6224 * Set the input to take input from a file. If push is set, push the
6225 * old input onto the stack first.
6226 */
6227
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006228static int
6229setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00006230{
6231 int fd;
6232 int fd2;
6233
6234 INTOFF;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006235 if ((fd = open(fname, O_RDONLY)) < 0) {
6236 if (flags & INPUT_NOFILE_OK)
6237 goto out;
6238 sh_error("Can't open %s", fname);
6239 }
Eric Andersenc470f442003-07-28 09:56:35 +00006240 if (fd < 10) {
6241 fd2 = copyfd(fd, 10);
6242 close(fd);
6243 if (fd2 < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006244 sh_error("Out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +00006245 fd = fd2;
6246 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006247 setinputfd(fd, flags & INPUT_PUSH_FILE);
6248out:
Eric Andersenc470f442003-07-28 09:56:35 +00006249 INTON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006250 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +00006251}
6252
6253
6254/*
6255 * Like setinputfile, but takes an open file descriptor. Call this with
6256 * interrupts off.
6257 */
6258
6259static void
6260setinputfd(int fd, int push)
6261{
6262 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6263 if (push) {
6264 pushfile();
6265 parsefile->buf = 0;
6266 }
6267 parsefile->fd = fd;
6268 if (parsefile->buf == NULL)
6269 parsefile->buf = ckmalloc(IBUFSIZ);
6270 parselleft = parsenleft = 0;
6271 plinno = 1;
6272}
6273
Eric Andersencb57d552001-06-28 07:25:16 +00006274
Eric Andersencb57d552001-06-28 07:25:16 +00006275/*
6276 * Like setinputfile, but takes input from a string.
6277 */
6278
Eric Andersenc470f442003-07-28 09:56:35 +00006279static void
6280setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006281{
Eric Andersencb57d552001-06-28 07:25:16 +00006282 INTOFF;
6283 pushfile();
6284 parsenextc = string;
6285 parsenleft = strlen(string);
6286 parsefile->buf = NULL;
6287 plinno = 1;
6288 INTON;
6289}
6290
6291
Eric Andersencb57d552001-06-28 07:25:16 +00006292/*
6293 * To handle the "." command, a stack of input files is used. Pushfile
6294 * adds a new entry to the stack and popfile restores the previous level.
6295 */
6296
Eric Andersenc470f442003-07-28 09:56:35 +00006297static void
6298pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006299{
Eric Andersencb57d552001-06-28 07:25:16 +00006300 struct parsefile *pf;
6301
6302 parsefile->nleft = parsenleft;
6303 parsefile->lleft = parselleft;
6304 parsefile->nextc = parsenextc;
6305 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006306 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006307 pf->prev = parsefile;
6308 pf->fd = -1;
6309 pf->strpush = NULL;
6310 pf->basestrpush.prev = NULL;
6311 parsefile = pf;
6312}
6313
Eric Andersenc470f442003-07-28 09:56:35 +00006314
6315static void
6316popfile(void)
6317{
6318 struct parsefile *pf = parsefile;
6319
6320 INTOFF;
6321 if (pf->fd >= 0)
6322 close(pf->fd);
6323 if (pf->buf)
6324 ckfree(pf->buf);
6325 while (pf->strpush)
6326 popstring();
6327 parsefile = pf->prev;
6328 ckfree(pf);
6329 parsenleft = parsefile->nleft;
6330 parselleft = parsefile->lleft;
6331 parsenextc = parsefile->nextc;
6332 plinno = parsefile->linno;
6333 INTON;
6334}
Eric Andersencb57d552001-06-28 07:25:16 +00006335
6336
Eric Andersen2870d962001-07-02 17:27:21 +00006337/*
Eric Andersenc470f442003-07-28 09:56:35 +00006338 * Return to top level.
6339 */
Eric Andersen2870d962001-07-02 17:27:21 +00006340
Eric Andersenc470f442003-07-28 09:56:35 +00006341static void
6342popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006343{
Eric Andersenc470f442003-07-28 09:56:35 +00006344 while (parsefile != &basepf)
6345 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006346}
6347
Eric Andersen2870d962001-07-02 17:27:21 +00006348
Eric Andersenc470f442003-07-28 09:56:35 +00006349/*
6350 * Close the file(s) that the shell is reading commands from. Called
6351 * after a fork is done.
6352 */
6353
6354static void
6355closescript(void)
6356{
6357 popallfiles();
6358 if (parsefile->fd > 0) {
6359 close(parsefile->fd);
6360 parsefile->fd = 0;
6361 }
6362}
Eric Andersenc470f442003-07-28 09:56:35 +00006363
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006364/* jobs.c */
Eric Andersenc470f442003-07-28 09:56:35 +00006365
6366/* mode flags for set_curjob */
6367#define CUR_DELETE 2
6368#define CUR_RUNNING 1
6369#define CUR_STOPPED 0
6370
6371/* mode flags for dowait */
6372#define DOWAIT_NORMAL 0
6373#define DOWAIT_BLOCK 1
6374
6375/* array of jobs */
6376static struct job *jobtab;
6377/* size of array */
6378static unsigned njobs;
6379#if JOBS
6380/* pgrp of shell on invocation */
6381static int initialpgrp;
6382static int ttyfd = -1;
6383#endif
6384/* current job */
6385static struct job *curjob;
6386/* number of presumed living untracked jobs */
6387static int jobless;
6388
6389static void set_curjob(struct job *, unsigned);
6390#if JOBS
6391static int restartjob(struct job *, int);
6392static void xtcsetpgrp(int, pid_t);
6393static char *commandtext(union node *);
6394static void cmdlist(union node *, int);
6395static void cmdtxt(union node *);
6396static void cmdputs(const char *);
6397static void showpipe(struct job *, FILE *);
6398#endif
6399static int sprint_status(char *, int, int);
6400static void freejob(struct job *);
6401static struct job *getjob(const char *, int);
6402static struct job *growjobtab(void);
6403static void forkchild(struct job *, union node *, int);
6404static void forkparent(struct job *, union node *, int, pid_t);
6405static int dowait(int, struct job *);
6406static int getstatus(struct job *);
6407
6408static void
6409set_curjob(struct job *jp, unsigned mode)
6410{
6411 struct job *jp1;
6412 struct job **jpp, **curp;
6413
6414 /* first remove from list */
6415 jpp = curp = &curjob;
6416 do {
6417 jp1 = *jpp;
6418 if (jp1 == jp)
6419 break;
6420 jpp = &jp1->prev_job;
6421 } while (1);
6422 *jpp = jp1->prev_job;
6423
6424 /* Then re-insert in correct position */
6425 jpp = curp;
6426 switch (mode) {
6427 default:
6428#ifdef DEBUG
6429 abort();
6430#endif
6431 case CUR_DELETE:
6432 /* job being deleted */
6433 break;
6434 case CUR_RUNNING:
6435 /* newly created job or backgrounded job,
6436 put after all stopped jobs. */
6437 do {
6438 jp1 = *jpp;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006439#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006440 if (!jp1 || jp1->state != JOBSTOPPED)
6441#endif
6442 break;
6443 jpp = &jp1->prev_job;
6444 } while (1);
6445 /* FALLTHROUGH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006446#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006447 case CUR_STOPPED:
6448#endif
6449 /* newly stopped job - becomes curjob */
6450 jp->prev_job = *jpp;
6451 *jpp = jp;
6452 break;
6453 }
6454}
6455
6456#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006457/*
6458 * Turn job control on and off.
6459 *
6460 * Note: This code assumes that the third arg to ioctl is a character
6461 * pointer, which is true on Berkeley systems but not System V. Since
6462 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006463 *
6464 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006465 */
6466
Eric Andersenc470f442003-07-28 09:56:35 +00006467void
6468setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006469{
Eric Andersenc470f442003-07-28 09:56:35 +00006470 int fd;
6471 int pgrp;
6472
6473 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006474 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006475 if (on) {
6476 int ofd;
6477 ofd = fd = open(_PATH_TTY, O_RDWR);
6478 if (fd < 0) {
6479 fd += 3;
6480 while (!isatty(fd) && --fd >= 0)
6481 ;
6482 }
6483 fd = fcntl(fd, F_DUPFD, 10);
6484 close(ofd);
6485 if (fd < 0)
6486 goto out;
6487 fcntl(fd, F_SETFD, FD_CLOEXEC);
6488 do { /* while we are in the background */
6489 if ((pgrp = tcgetpgrp(fd)) < 0) {
6490out:
6491 sh_warnx("can't access tty; job control turned off");
6492 mflag = on = 0;
6493 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006494 }
Eric Andersenc470f442003-07-28 09:56:35 +00006495 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006496 break;
6497 killpg(0, SIGTTIN);
6498 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006499 initialpgrp = pgrp;
6500
Eric Andersencb57d552001-06-28 07:25:16 +00006501 setsignal(SIGTSTP);
6502 setsignal(SIGTTOU);
6503 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006504 pgrp = rootpid;
6505 setpgid(0, pgrp);
6506 xtcsetpgrp(fd, pgrp);
6507 } else {
6508 /* turning job control off */
6509 fd = ttyfd;
6510 pgrp = initialpgrp;
6511 xtcsetpgrp(fd, pgrp);
6512 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006513 setsignal(SIGTSTP);
6514 setsignal(SIGTTOU);
6515 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006516close:
6517 close(fd);
6518 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006519 }
Eric Andersenc470f442003-07-28 09:56:35 +00006520 ttyfd = fd;
6521 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006522}
Eric Andersencb57d552001-06-28 07:25:16 +00006523
Eric Andersenc470f442003-07-28 09:56:35 +00006524static int
Eric Andersen90898442003-08-06 11:20:52 +00006525killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006526{
6527 int signo = -1;
6528 int list = 0;
6529 int i;
6530 pid_t pid;
6531 struct job *jp;
6532
6533 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006534usage:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006535 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006536"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6537"kill -l [exitstatus]"
6538 );
Eric Andersencb57d552001-06-28 07:25:16 +00006539 }
6540
Eric Andersenc470f442003-07-28 09:56:35 +00006541 if (**++argv == '-') {
6542 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006543 if (signo < 0) {
6544 int c;
6545
6546 while ((c = nextopt("ls:")) != '\0')
6547 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006548 default:
6549#ifdef DEBUG
6550 abort();
6551#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006552 case 'l':
6553 list = 1;
6554 break;
6555 case 's':
6556 signo = decode_signal(optionarg, 1);
6557 if (signo < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006558 sh_error(
Eric Andersenc470f442003-07-28 09:56:35 +00006559 "invalid signal number or name: %s",
6560 optionarg
6561 );
Eric Andersencb57d552001-06-28 07:25:16 +00006562 }
Eric Andersen2870d962001-07-02 17:27:21 +00006563 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006564 }
Eric Andersenc470f442003-07-28 09:56:35 +00006565 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006566 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006567 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006568 }
6569
6570 if (!list && signo < 0)
6571 signo = SIGTERM;
6572
Eric Andersenc470f442003-07-28 09:56:35 +00006573 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006574 goto usage;
6575 }
6576
6577 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006578 const char *name;
6579
Eric Andersenc470f442003-07-28 09:56:35 +00006580 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006581 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006582 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006583 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006584 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006585 }
6586 return 0;
6587 }
Eric Andersen34506362001-08-02 05:02:46 +00006588 name = u_signal_names(*argptr, &signo, -1);
6589 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006590 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006591 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006592 sh_error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006593 return 0;
6594 }
6595
Eric Andersenc470f442003-07-28 09:56:35 +00006596 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006597 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006598 if (**argv == '%') {
6599 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006600 pid = -jp->ps[0].pid;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006601 } else {
6602 pid = **argv == '-' ?
6603 -number(*argv + 1) : number(*argv);
6604 }
Eric Andersenc470f442003-07-28 09:56:35 +00006605 if (kill(pid, signo) != 0) {
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006606 sh_warnx("(%d) - %m", pid);
Eric Andersenc470f442003-07-28 09:56:35 +00006607 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006608 }
Eric Andersenc470f442003-07-28 09:56:35 +00006609 } while (*++argv);
6610
6611 return i;
6612}
6613#endif /* JOBS */
6614
6615#if defined(JOBS) || defined(DEBUG)
6616static int
6617jobno(const struct job *jp)
6618{
6619 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006620}
6621#endif
6622
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00006623#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006624static int
6625fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006626{
Eric Andersenc470f442003-07-28 09:56:35 +00006627 struct job *jp;
6628 FILE *out;
6629 int mode;
6630 int retval;
6631
6632 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6633 nextopt(nullstr);
6634 argv = argptr;
6635 out = stdout;
6636 do {
6637 jp = getjob(*argv, 1);
6638 if (mode == FORK_BG) {
6639 set_curjob(jp, CUR_RUNNING);
6640 fprintf(out, "[%d] ", jobno(jp));
6641 }
6642 outstr(jp->ps->cmd, out);
6643 showpipe(jp, out);
6644 retval = restartjob(jp, mode);
6645 } while (*argv && *++argv);
6646 return retval;
6647}
6648
6649static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6650
6651
6652static int
6653restartjob(struct job *jp, int mode)
6654{
6655 struct procstat *ps;
6656 int i;
6657 int status;
6658 pid_t pgid;
6659
6660 INTOFF;
6661 if (jp->state == JOBDONE)
6662 goto out;
6663 jp->state = JOBRUNNING;
6664 pgid = jp->ps->pid;
6665 if (mode == FORK_FG)
6666 xtcsetpgrp(ttyfd, pgid);
6667 killpg(pgid, SIGCONT);
6668 ps = jp->ps;
6669 i = jp->nprocs;
6670 do {
6671 if (WIFSTOPPED(ps->status)) {
6672 ps->status = -1;
6673 }
6674 } while (ps++, --i);
6675out:
6676 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6677 INTON;
6678 return status;
6679}
6680#endif
6681
6682static int
6683sprint_status(char *s, int status, int sigonly)
6684{
6685 int col;
6686 int st;
6687
6688 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006689 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006690#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006691 if (WIFSTOPPED(status))
6692 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006693 else
Eric Andersenc470f442003-07-28 09:56:35 +00006694#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006695 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006696 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006697 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006698 goto out;
6699#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006700 if (WIFSTOPPED(status))
6701 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006702#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006703 }
6704 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006705 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006706 if (WCOREDUMP(status)) {
6707 col += fmtstr(s + col, 16, " (core dumped)");
6708 }
6709 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006710 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006711 if (st)
6712 col = fmtstr(s, 16, "Done(%d)", st);
6713 else
6714 col = fmtstr(s, 16, "Done");
6715 }
6716
6717out:
6718 return col;
6719}
6720
6721#if JOBS
6722static void
6723showjob(FILE *out, struct job *jp, int mode)
6724{
6725 struct procstat *ps;
6726 struct procstat *psend;
6727 int col;
6728 int indent;
6729 char s[80];
6730
6731 ps = jp->ps;
6732
6733 if (mode & SHOW_PGID) {
6734 /* just output process (group) id of pipeline */
6735 fprintf(out, "%d\n", ps->pid);
6736 return;
6737 }
6738
6739 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6740 indent = col;
6741
6742 if (jp == curjob)
6743 s[col - 2] = '+';
6744 else if (curjob && jp == curjob->prev_job)
6745 s[col - 2] = '-';
6746
6747 if (mode & SHOW_PID)
6748 col += fmtstr(s + col, 16, "%d ", ps->pid);
6749
6750 psend = ps + jp->nprocs;
6751
6752 if (jp->state == JOBRUNNING) {
6753 scopy("Running", s + col);
6754 col += strlen("Running");
6755 } else {
6756 int status = psend[-1].status;
6757#if JOBS
6758 if (jp->state == JOBSTOPPED)
6759 status = jp->stopstatus;
6760#endif
6761 col += sprint_status(s + col, status, 0);
6762 }
6763
6764 goto start;
6765
6766 do {
6767 /* for each process */
6768 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6769
6770start:
Eric Andersen90898442003-08-06 11:20:52 +00006771 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006772 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6773 );
6774 if (!(mode & SHOW_PID)) {
6775 showpipe(jp, out);
6776 break;
6777 }
6778 if (++ps == psend) {
6779 outcslow('\n', out);
6780 break;
6781 }
6782 } while (1);
6783
6784 jp->changed = 0;
6785
6786 if (jp->state == JOBDONE) {
6787 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6788 freejob(jp);
6789 }
6790}
6791
6792
6793static int
6794jobscmd(int argc, char **argv)
6795{
6796 int mode, m;
6797 FILE *out;
6798
6799 mode = 0;
6800 while ((m = nextopt("lp")))
6801 if (m == 'l')
6802 mode = SHOW_PID;
6803 else
6804 mode = SHOW_PGID;
6805
6806 out = stdout;
6807 argv = argptr;
6808 if (*argv)
6809 do
6810 showjob(out, getjob(*argv,0), mode);
6811 while (*++argv);
6812 else
6813 showjobs(out, mode);
6814
Eric Andersencb57d552001-06-28 07:25:16 +00006815 return 0;
6816}
6817
6818
6819/*
6820 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6821 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006822 */
6823
Eric Andersenc470f442003-07-28 09:56:35 +00006824static void
6825showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006826{
Eric Andersencb57d552001-06-28 07:25:16 +00006827 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006828
Eric Andersenc470f442003-07-28 09:56:35 +00006829 TRACE(("showjobs(%x) called\n", mode));
6830
6831 /* If not even one one job changed, there is nothing to do */
6832 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6833 continue;
6834
6835 for (jp = curjob; jp; jp = jp->prev_job) {
6836 if (!(mode & SHOW_CHANGED) || jp->changed)
6837 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006838 }
6839}
Eric Andersenc470f442003-07-28 09:56:35 +00006840#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006841
6842/*
6843 * Mark a job structure as unused.
6844 */
6845
Eric Andersenc470f442003-07-28 09:56:35 +00006846static void
6847freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006848{
Eric Andersenc470f442003-07-28 09:56:35 +00006849 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006850 int i;
6851
6852 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006853 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006854 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006855 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006856 }
6857 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006858 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006859 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006860 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006861 INTON;
6862}
6863
6864
Eric Andersenc470f442003-07-28 09:56:35 +00006865static int
6866waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006867{
6868 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006869 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006870 struct job *jp;
6871
Eric Andersenc470f442003-07-28 09:56:35 +00006872 EXSIGON();
6873
6874 nextopt(nullstr);
6875 retval = 0;
6876
6877 argv = argptr;
6878 if (!*argv) {
6879 /* wait for all jobs */
6880 for (;;) {
6881 jp = curjob;
6882 while (1) {
6883 if (!jp) {
6884 /* no running procs */
6885 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006886 }
Eric Andersenc470f442003-07-28 09:56:35 +00006887 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006888 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006889 jp->waited = 1;
6890 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006891 }
Eric Andersenc470f442003-07-28 09:56:35 +00006892 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006893 }
6894 }
Eric Andersenc470f442003-07-28 09:56:35 +00006895
6896 retval = 127;
6897 do {
6898 if (**argv != '%') {
6899 pid_t pid = number(*argv);
6900 job = curjob;
6901 goto start;
6902 do {
6903 if (job->ps[job->nprocs - 1].pid == pid)
6904 break;
6905 job = job->prev_job;
6906start:
6907 if (!job)
6908 goto repeat;
6909 } while (1);
6910 } else
6911 job = getjob(*argv, 0);
6912 /* loop until process terminated or stopped */
6913 while (job->state == JOBRUNNING)
6914 dowait(DOWAIT_BLOCK, 0);
6915 job->waited = 1;
6916 retval = getstatus(job);
6917repeat:
6918 ;
6919 } while (*++argv);
6920
6921out:
6922 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006923}
6924
6925
Eric Andersencb57d552001-06-28 07:25:16 +00006926/*
6927 * Convert a job name to a job structure.
6928 */
6929
Eric Andersenc470f442003-07-28 09:56:35 +00006930static struct job *
6931getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006932{
Eric Andersencb57d552001-06-28 07:25:16 +00006933 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006934 struct job *found;
6935 const char *err_msg = "No such job: %s";
6936 unsigned num;
6937 int c;
6938 const char *p;
6939 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006940
Eric Andersenc470f442003-07-28 09:56:35 +00006941 jp = curjob;
6942 p = name;
6943 if (!p)
6944 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006945
Eric Andersenc470f442003-07-28 09:56:35 +00006946 if (*p != '%')
6947 goto err;
6948
6949 c = *++p;
6950 if (!c)
6951 goto currentjob;
6952
6953 if (!p[1]) {
6954 if (c == '+' || c == '%') {
6955currentjob:
6956 err_msg = "No current job";
6957 goto check;
6958 } else if (c == '-') {
6959 if (jp)
6960 jp = jp->prev_job;
6961 err_msg = "No previous job";
6962check:
6963 if (!jp)
6964 goto err;
6965 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006966 }
6967 }
Eric Andersenc470f442003-07-28 09:56:35 +00006968
6969 if (is_number(p)) {
6970 num = atoi(p);
6971 if (num < njobs) {
6972 jp = jobtab + num - 1;
6973 if (jp->used)
6974 goto gotit;
6975 goto err;
6976 }
6977 }
6978
6979 match = prefix;
6980 if (*p == '?') {
6981 match = strstr;
6982 p++;
6983 }
6984
6985 found = 0;
6986 while (1) {
6987 if (!jp)
6988 goto err;
6989 if (match(jp->ps[0].cmd, p)) {
6990 if (found)
6991 goto err;
6992 found = jp;
6993 err_msg = "%s: ambiguous";
6994 }
6995 jp = jp->prev_job;
6996 }
6997
6998gotit:
6999#if JOBS
7000 err_msg = "job %s not created under job control";
7001 if (getctl && jp->jobctl == 0)
7002 goto err;
7003#endif
7004 return jp;
7005err:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007006 sh_error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007007}
7008
7009
Eric Andersencb57d552001-06-28 07:25:16 +00007010/*
Eric Andersenc470f442003-07-28 09:56:35 +00007011 * Return a new job structure.
7012 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007013 */
7014
Eric Andersenc470f442003-07-28 09:56:35 +00007015static struct job *
7016makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007017{
7018 int i;
7019 struct job *jp;
7020
Eric Andersenc470f442003-07-28 09:56:35 +00007021 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007022 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007023 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007024 break;
7025 }
7026 if (jp->used == 0)
7027 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007028 if (jp->state != JOBDONE || !jp->waited)
7029 continue;
7030#if JOBS
7031 if (jobctl)
7032 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007033#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007034 freejob(jp);
7035 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007036 }
Eric Andersenc470f442003-07-28 09:56:35 +00007037 memset(jp, 0, sizeof(*jp));
7038#if JOBS
7039 if (jobctl)
7040 jp->jobctl = 1;
7041#endif
7042 jp->prev_job = curjob;
7043 curjob = jp;
7044 jp->used = 1;
7045 jp->ps = &jp->ps0;
7046 if (nprocs > 1) {
7047 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7048 }
7049 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7050 jobno(jp)));
7051 return jp;
7052}
7053
7054static struct job *
7055growjobtab(void)
7056{
7057 size_t len;
7058 ptrdiff_t offset;
7059 struct job *jp, *jq;
7060
7061 len = njobs * sizeof(*jp);
7062 jq = jobtab;
7063 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7064
7065 offset = (char *)jp - (char *)jq;
7066 if (offset) {
7067 /* Relocate pointers */
7068 size_t l = len;
7069
7070 jq = (struct job *)((char *)jq + l);
7071 while (l) {
7072 l -= sizeof(*jp);
7073 jq--;
7074#define joff(p) ((struct job *)((char *)(p) + l))
7075#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007076 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007077 jmove(joff(jp)->ps);
7078 if (joff(jp)->prev_job)
7079 jmove(joff(jp)->prev_job);
7080 }
7081 if (curjob)
7082 jmove(curjob);
7083#undef joff
7084#undef jmove
7085 }
7086
7087 njobs += 4;
7088 jobtab = jp;
7089 jp = (struct job *)((char *)jp + len);
7090 jq = jp + 3;
7091 do {
7092 jq->used = 0;
7093 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007094 return jp;
7095}
7096
7097
7098/*
Eric Andersenc470f442003-07-28 09:56:35 +00007099 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007100 * own process group. Jp is a job structure that the job is to be added to.
7101 * N is the command that will be evaluated by the child. Both jp and n may
7102 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007103 * FORK_FG - Fork off a foreground process.
7104 * FORK_BG - Fork off a background process.
7105 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7106 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007107 *
7108 * When job control is turned off, background processes have their standard
7109 * input redirected to /dev/null (except for the second and later processes
7110 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007111 *
7112 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007113 */
7114
Eric Andersenc470f442003-07-28 09:56:35 +00007115static inline void
7116forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007117{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007118 int oldlvl;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007119
Eric Andersenc470f442003-07-28 09:56:35 +00007120 TRACE(("Child shell %d\n", getpid()));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007121 oldlvl = shlvl;
7122 shlvl++;
Eric Andersenc470f442003-07-28 09:56:35 +00007123
7124 closescript();
7125 clear_traps();
7126#if JOBS
7127 /* do job control only in root shell */
7128 jobctl = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007129 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007130 pid_t pgrp;
7131
7132 if (jp->nprocs == 0)
7133 pgrp = getpid();
7134 else
7135 pgrp = jp->ps[0].pid;
7136 /* This can fail because we are doing it in the parent also */
7137 (void)setpgid(0, pgrp);
7138 if (mode == FORK_FG)
7139 xtcsetpgrp(ttyfd, pgrp);
7140 setsignal(SIGTSTP);
7141 setsignal(SIGTTOU);
7142 } else
Eric Andersen62483552001-07-10 06:09:16 +00007143#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007144 if (mode == FORK_BG) {
7145 ignoresig(SIGINT);
7146 ignoresig(SIGQUIT);
7147 if (jp->nprocs == 0) {
7148 close(0);
7149 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007150 sh_error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007151 }
Eric Andersencb57d552001-06-28 07:25:16 +00007152 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007153 if (!oldlvl && iflag) {
Eric Andersenc470f442003-07-28 09:56:35 +00007154 setsignal(SIGINT);
7155 setsignal(SIGQUIT);
7156 setsignal(SIGTERM);
7157 }
7158 for (jp = curjob; jp; jp = jp->prev_job)
7159 freejob(jp);
7160 jobless = 0;
7161}
7162
7163static inline void
7164forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7165{
7166 TRACE(("In parent shell: child = %d\n", pid));
7167 if (!jp) {
7168 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7169 jobless++;
7170 return;
7171 }
7172#if JOBS
7173 if (mode != FORK_NOJOB && jp->jobctl) {
7174 int pgrp;
7175
7176 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007177 pgrp = pid;
7178 else
7179 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007180 /* This can fail because we are doing it in the child also */
7181 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007182 }
Eric Andersen62483552001-07-10 06:09:16 +00007183#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007184 if (mode == FORK_BG) {
7185 backgndpid = pid; /* set $! */
7186 set_curjob(jp, CUR_RUNNING);
7187 }
Eric Andersencb57d552001-06-28 07:25:16 +00007188 if (jp) {
7189 struct procstat *ps = &jp->ps[jp->nprocs++];
7190 ps->pid = pid;
7191 ps->status = -1;
7192 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007193#if JOBS
7194 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007195 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007196#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007197 }
Eric Andersencb57d552001-06-28 07:25:16 +00007198}
7199
Eric Andersenc470f442003-07-28 09:56:35 +00007200static int
7201forkshell(struct job *jp, union node *n, int mode)
7202{
7203 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007204
Eric Andersenc470f442003-07-28 09:56:35 +00007205 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7206 pid = fork();
7207 if (pid < 0) {
7208 TRACE(("Fork failed, errno=%d", errno));
7209 if (jp)
7210 freejob(jp);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007211 sh_error("Cannot fork");
Eric Andersenc470f442003-07-28 09:56:35 +00007212 }
7213 if (pid == 0)
7214 forkchild(jp, n, mode);
7215 else
7216 forkparent(jp, n, mode, pid);
7217 return pid;
7218}
Eric Andersencb57d552001-06-28 07:25:16 +00007219
7220/*
7221 * Wait for job to finish.
7222 *
7223 * Under job control we have the problem that while a child process is
7224 * running interrupts generated by the user are sent to the child but not
7225 * to the shell. This means that an infinite loop started by an inter-
7226 * active user may be hard to kill. With job control turned off, an
7227 * interactive user may place an interactive program inside a loop. If
7228 * the interactive program catches interrupts, the user doesn't want
7229 * these interrupts to also abort the loop. The approach we take here
7230 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007231 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007232 * signal if the child process was terminated by an interrupt signal.
7233 * Unfortunately, some programs want to do a bit of cleanup and then
7234 * exit on interrupt; unless these processes terminate themselves by
7235 * sending a signal to themselves (instead of calling exit) they will
7236 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007237 *
7238 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007239 */
7240
Eric Andersenc470f442003-07-28 09:56:35 +00007241int
7242waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007243{
Eric Andersencb57d552001-06-28 07:25:16 +00007244 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007245
Eric Andersenc470f442003-07-28 09:56:35 +00007246 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7247 while (jp->state == JOBRUNNING) {
7248 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007249 }
Eric Andersenc470f442003-07-28 09:56:35 +00007250 st = getstatus(jp);
7251#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007252 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007253 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007254 /*
7255 * This is truly gross.
7256 * If we're doing job control, then we did a TIOCSPGRP which
7257 * caused us (the shell) to no longer be in the controlling
7258 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7259 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007260 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007261 */
Eric Andersenc470f442003-07-28 09:56:35 +00007262 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007263 raise(SIGINT);
7264 }
Eric Andersen2870d962001-07-02 17:27:21 +00007265 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007266#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007267 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007268 return st;
7269}
7270
7271
Eric Andersen62483552001-07-10 06:09:16 +00007272/*
7273 * Do a wait system call. If job control is compiled in, we accept
7274 * stopped processes. If block is zero, we return a value of zero
7275 * rather than blocking.
7276 *
7277 * System V doesn't have a non-blocking wait system call. It does
7278 * have a SIGCLD signal that is sent to a process when one of it's
7279 * children dies. The obvious way to use SIGCLD would be to install
7280 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7281 * was received, and have waitproc bump another counter when it got
7282 * the status of a process. Waitproc would then know that a wait
7283 * system call would not block if the two counters were different.
7284 * This approach doesn't work because if a process has children that
7285 * have not been waited for, System V will send it a SIGCLD when it
7286 * installs a signal handler for SIGCLD. What this means is that when
7287 * a child exits, the shell will be sent SIGCLD signals continuously
7288 * until is runs out of stack space, unless it does a wait call before
7289 * restoring the signal handler. The code below takes advantage of
7290 * this (mis)feature by installing a signal handler for SIGCLD and
7291 * then checking to see whether it was called. If there are any
7292 * children to be waited for, it will be.
7293 *
Eric Andersenc470f442003-07-28 09:56:35 +00007294 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7295 * waits at all. In this case, the user will not be informed when
7296 * a background process until the next time she runs a real program
7297 * (as opposed to running a builtin command or just typing return),
7298 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007299 */
7300
Eric Andersenc470f442003-07-28 09:56:35 +00007301static inline int
7302waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007303{
Eric Andersenc470f442003-07-28 09:56:35 +00007304 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007305
Eric Andersenc470f442003-07-28 09:56:35 +00007306#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007307 if (jobctl)
7308 flags |= WUNTRACED;
7309#endif
7310 if (block == 0)
7311 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007312 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007313}
7314
Eric Andersenc470f442003-07-28 09:56:35 +00007315/*
7316 * Wait for a process to terminate.
7317 */
7318
7319static int
7320dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007321{
7322 int pid;
7323 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007324 struct job *jp;
7325 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007326 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007327
7328 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007329 pid = waitproc(block, &status);
7330 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007331 if (pid <= 0)
7332 return pid;
7333 INTOFF;
7334 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007335 for (jp = curjob; jp; jp = jp->prev_job) {
7336 struct procstat *sp;
7337 struct procstat *spend;
7338 if (jp->state == JOBDONE)
7339 continue;
7340 state = JOBDONE;
7341 spend = jp->ps + jp->nprocs;
7342 sp = jp->ps;
7343 do {
7344 if (sp->pid == pid) {
7345 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7346 sp->status = status;
7347 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007348 }
Eric Andersenc470f442003-07-28 09:56:35 +00007349 if (sp->status == -1)
7350 state = JOBRUNNING;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007351#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007352 if (state == JOBRUNNING)
7353 continue;
7354 if (WIFSTOPPED(sp->status)) {
7355 jp->stopstatus = sp->status;
7356 state = JOBSTOPPED;
7357 }
Eric Andersencb57d552001-06-28 07:25:16 +00007358#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007359 } while (++sp < spend);
7360 if (thisjob)
7361 goto gotjob;
7362 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007363#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007364 if (!WIFSTOPPED(status))
7365#endif
7366
7367 jobless--;
7368 goto out;
7369
7370gotjob:
7371 if (state != JOBRUNNING) {
7372 thisjob->changed = 1;
7373
7374 if (thisjob->state != state) {
7375 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7376 thisjob->state = state;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007377#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00007378 if (state == JOBSTOPPED) {
7379 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007380 }
Eric Andersenc470f442003-07-28 09:56:35 +00007381#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007382 }
7383 }
Eric Andersencb57d552001-06-28 07:25:16 +00007384
Eric Andersenc470f442003-07-28 09:56:35 +00007385out:
7386 INTON;
7387
7388 if (thisjob && thisjob == job) {
7389 char s[48 + 1];
7390 int len;
7391
7392 len = sprint_status(s, status, 1);
7393 if (len) {
7394 s[len] = '\n';
7395 s[len + 1] = 0;
7396 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007397 }
Eric Andersencb57d552001-06-28 07:25:16 +00007398 }
7399 return pid;
7400}
7401
7402
Eric Andersencb57d552001-06-28 07:25:16 +00007403/*
7404 * return 1 if there are stopped jobs, otherwise 0
7405 */
Eric Andersen90898442003-08-06 11:20:52 +00007406
Eric Andersenc470f442003-07-28 09:56:35 +00007407int
7408stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007409{
Eric Andersencb57d552001-06-28 07:25:16 +00007410 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007411 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007412
Eric Andersenc470f442003-07-28 09:56:35 +00007413 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007414 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007415 goto out;
7416 jp = curjob;
7417 if (jp && jp->state == JOBSTOPPED) {
7418 out2str("You have stopped jobs.\n");
7419 job_warning = 2;
7420 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007421 }
7422
Eric Andersenc470f442003-07-28 09:56:35 +00007423out:
7424 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007425}
7426
7427/*
7428 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007429 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007430 */
7431
Eric Andersenc470f442003-07-28 09:56:35 +00007432#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007433static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007434
Eric Andersenc470f442003-07-28 09:56:35 +00007435static char *
7436commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007437{
Eric Andersenc470f442003-07-28 09:56:35 +00007438 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007439
Eric Andersenc470f442003-07-28 09:56:35 +00007440 STARTSTACKSTR(cmdnextc);
7441 cmdtxt(n);
7442 name = stackblock();
7443 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7444 name, cmdnextc, cmdnextc));
7445 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007446}
7447
Eric Andersenc470f442003-07-28 09:56:35 +00007448static void
7449cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007450{
Eric Andersencb57d552001-06-28 07:25:16 +00007451 union node *np;
7452 struct nodelist *lp;
7453 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007454 char s[2];
7455
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007456 if (!n)
7457 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007458 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007459 default:
7460#if DEBUG
7461 abort();
7462#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007463 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007464 lp = n->npipe.cmdlist;
7465 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007466 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007467 lp = lp->next;
7468 if (!lp)
7469 break;
7470 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007471 }
7472 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007473 case NSEMI:
7474 p = "; ";
7475 goto binop;
7476 case NAND:
7477 p = " && ";
7478 goto binop;
7479 case NOR:
7480 p = " || ";
7481binop:
7482 cmdtxt(n->nbinary.ch1);
7483 cmdputs(p);
7484 n = n->nbinary.ch2;
7485 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007486 case NREDIR:
7487 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007488 n = n->nredir.n;
7489 goto donode;
7490 case NNOT:
7491 cmdputs("!");
7492 n = n->nnot.com;
7493donode:
7494 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007495 break;
7496 case NIF:
7497 cmdputs("if ");
7498 cmdtxt(n->nif.test);
7499 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007500 n = n->nif.ifpart;
7501 if (n->nif.elsepart) {
7502 cmdtxt(n);
7503 cmdputs("; else ");
7504 n = n->nif.elsepart;
7505 }
7506 p = "; fi";
7507 goto dotail;
7508 case NSUBSHELL:
7509 cmdputs("(");
7510 n = n->nredir.n;
7511 p = ")";
7512 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007513 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007514 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007515 goto until;
7516 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007517 p = "until ";
7518until:
7519 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007520 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007521 n = n->nbinary.ch2;
7522 p = "; done";
7523dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007524 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007525dotail:
7526 cmdtxt(n);
7527 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007528 case NFOR:
7529 cmdputs("for ");
7530 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007531 cmdputs(" in ");
7532 cmdlist(n->nfor.args, 1);
7533 n = n->nfor.body;
7534 p = "; done";
7535 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007536 case NDEFUN:
7537 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007538 p = "() { ... }";
7539 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007540 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007541 cmdlist(n->ncmd.args, 1);
7542 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007543 break;
7544 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007545 p = n->narg.text;
7546dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007547 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007548 break;
7549 case NHERE:
7550 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007551 p = "<<...";
7552 goto dotail2;
7553 case NCASE:
7554 cmdputs("case ");
7555 cmdputs(n->ncase.expr->narg.text);
7556 cmdputs(" in ");
7557 for (np = n->ncase.cases; np; np = np->nclist.next) {
7558 cmdtxt(np->nclist.pattern);
7559 cmdputs(") ");
7560 cmdtxt(np->nclist.body);
7561 cmdputs(";; ");
7562 }
7563 p = "esac";
7564 goto dotail2;
7565 case NTO:
7566 p = ">";
7567 goto redir;
7568 case NCLOBBER:
7569 p = ">|";
7570 goto redir;
7571 case NAPPEND:
7572 p = ">>";
7573 goto redir;
7574 case NTOFD:
7575 p = ">&";
7576 goto redir;
7577 case NFROM:
7578 p = "<";
7579 goto redir;
7580 case NFROMFD:
7581 p = "<&";
7582 goto redir;
7583 case NFROMTO:
7584 p = "<>";
7585redir:
7586 s[0] = n->nfile.fd + '0';
7587 s[1] = '\0';
7588 cmdputs(s);
7589 cmdputs(p);
7590 if (n->type == NTOFD || n->type == NFROMFD) {
7591 s[0] = n->ndup.dupfd + '0';
7592 p = s;
7593 goto dotail2;
7594 } else {
7595 n = n->nfile.fname;
7596 goto donode;
7597 }
Eric Andersencb57d552001-06-28 07:25:16 +00007598 }
7599}
Eric Andersencb57d552001-06-28 07:25:16 +00007600
Eric Andersenc470f442003-07-28 09:56:35 +00007601static void
7602cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007603{
Eric Andersenc470f442003-07-28 09:56:35 +00007604 for (; np; np = np->narg.next) {
7605 if (!sep)
7606 cmdputs(spcstr);
7607 cmdtxt(np);
7608 if (sep && np->narg.next)
7609 cmdputs(spcstr);
7610 }
Eric Andersencb57d552001-06-28 07:25:16 +00007611}
7612
Eric Andersenc470f442003-07-28 09:56:35 +00007613static void
7614cmdputs(const char *s)
7615{
7616 const char *p, *str;
7617 char c, cc[2] = " ";
7618 char *nextc;
7619 int subtype = 0;
7620 int quoted = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007621 static const char vstype[VSTYPE + 1][4] = {
7622 "", "}", "-", "+", "?", "=",
7623 "%", "%%", "#", "##"
Eric Andersenc470f442003-07-28 09:56:35 +00007624 };
Eric Andersenc470f442003-07-28 09:56:35 +00007625 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7626 p = s;
7627 while ((c = *p++) != 0) {
7628 str = 0;
7629 switch (c) {
7630 case CTLESC:
7631 c = *p++;
7632 break;
7633 case CTLVAR:
7634 subtype = *p++;
7635 if ((subtype & VSTYPE) == VSLENGTH)
7636 str = "${#";
7637 else
7638 str = "${";
7639 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7640 quoted ^= 1;
7641 c = '"';
7642 } else
7643 goto dostr;
7644 break;
7645 case CTLENDVAR:
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007646 str = "\"}" + !(quoted & 1);
Eric Andersenc470f442003-07-28 09:56:35 +00007647 quoted >>= 1;
7648 subtype = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007649 goto dostr;
Eric Andersenc470f442003-07-28 09:56:35 +00007650 case CTLBACKQ:
7651 str = "$(...)";
7652 goto dostr;
7653 case CTLBACKQ+CTLQUOTE:
7654 str = "\"$(...)\"";
7655 goto dostr;
7656#ifdef CONFIG_ASH_MATH_SUPPORT
7657 case CTLARI:
7658 str = "$((";
7659 goto dostr;
7660 case CTLENDARI:
7661 str = "))";
7662 goto dostr;
7663#endif
7664 case CTLQUOTEMARK:
7665 quoted ^= 1;
7666 c = '"';
7667 break;
7668 case '=':
7669 if (subtype == 0)
7670 break;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007671 if ((subtype & VSTYPE) != VSNORMAL)
7672 quoted <<= 1;
Eric Andersenc470f442003-07-28 09:56:35 +00007673 str = vstype[subtype & VSTYPE];
7674 if (subtype & VSNUL)
7675 c = ':';
7676 else
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007677 goto checkstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007678 break;
7679 case '\'':
7680 case '\\':
7681 case '"':
7682 case '$':
7683 /* These can only happen inside quotes */
7684 cc[0] = c;
7685 str = cc;
7686 c = '\\';
7687 break;
7688 default:
7689 break;
7690 }
7691 USTPUTC(c, nextc);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007692checkstr:
Eric Andersenc470f442003-07-28 09:56:35 +00007693 if (!str)
7694 continue;
7695dostr:
7696 while ((c = *str++)) {
7697 USTPUTC(c, nextc);
7698 }
7699 }
7700 if (quoted & 1) {
7701 USTPUTC('"', nextc);
7702 }
7703 *nextc = 0;
7704 cmdnextc = nextc;
7705}
7706
7707
7708static void
7709showpipe(struct job *jp, FILE *out)
7710{
7711 struct procstat *sp;
7712 struct procstat *spend;
7713
7714 spend = jp->ps + jp->nprocs;
7715 for (sp = jp->ps + 1; sp < spend; sp++)
7716 fprintf(out, " | %s", sp->cmd);
7717 outcslow('\n', out);
7718 flushall();
7719}
7720
7721static void
7722xtcsetpgrp(int fd, pid_t pgrp)
7723{
7724 if (tcsetpgrp(fd, pgrp))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007725 sh_error("Cannot set tty process group (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +00007726}
7727#endif /* JOBS */
7728
7729static int
7730getstatus(struct job *job) {
7731 int status;
7732 int retval;
7733
7734 status = job->ps[job->nprocs - 1].status;
7735 retval = WEXITSTATUS(status);
7736 if (!WIFEXITED(status)) {
7737#if JOBS
7738 retval = WSTOPSIG(status);
7739 if (!WIFSTOPPED(status))
7740#endif
7741 {
7742 /* XXX: limits number of signals */
7743 retval = WTERMSIG(status);
7744#if JOBS
7745 if (retval == SIGINT)
7746 job->sigint = 1;
7747#endif
7748 }
7749 retval += 128;
7750 }
7751 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7752 jobno(job), job->nprocs, status, retval));
7753 return retval;
7754}
7755
Eric Andersend35c5df2002-01-09 15:37:36 +00007756#ifdef CONFIG_ASH_MAIL
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007757/* mail.c */
Eric Andersenec074692001-10-31 11:05:49 +00007758
Eric Andersencb57d552001-06-28 07:25:16 +00007759/*
Eric Andersenc470f442003-07-28 09:56:35 +00007760 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007761 */
7762
Eric Andersencb57d552001-06-28 07:25:16 +00007763#define MAXMBOXES 10
7764
Eric Andersenc470f442003-07-28 09:56:35 +00007765/* times of mailboxes */
7766static time_t mailtime[MAXMBOXES];
7767/* Set if MAIL or MAILPATH is changed. */
7768static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007769
7770
7771
7772/*
Eric Andersenc470f442003-07-28 09:56:35 +00007773 * Print appropriate message(s) if mail has arrived.
7774 * If mail_var_path_changed is set,
7775 * then the value of MAIL has mail_var_path_changed,
7776 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007777 */
7778
Eric Andersenc470f442003-07-28 09:56:35 +00007779static void
7780chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007781{
Eric Andersencb57d552001-06-28 07:25:16 +00007782 const char *mpath;
7783 char *p;
7784 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007785 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007786 struct stackmark smark;
7787 struct stat statb;
7788
Eric Andersencb57d552001-06-28 07:25:16 +00007789 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007790 mpath = mpathset() ? mpathval() : mailval();
7791 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007792 p = padvance(&mpath, nullstr);
7793 if (p == NULL)
7794 break;
7795 if (*p == '\0')
7796 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007797 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007798#ifdef DEBUG
7799 if (q[-1] != '/')
7800 abort();
7801#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007802 q[-1] = '\0'; /* delete trailing '/' */
7803 if (stat(p, &statb) < 0) {
7804 *mtp = 0;
7805 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007806 }
Eric Andersenc470f442003-07-28 09:56:35 +00007807 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7808 fprintf(
7809 stderr, snlfmt,
7810 pathopt ? pathopt : "you have mail"
7811 );
7812 }
7813 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007814 }
Eric Andersenc470f442003-07-28 09:56:35 +00007815 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007816 popstackmark(&smark);
7817}
Eric Andersencb57d552001-06-28 07:25:16 +00007818
Eric Andersenec074692001-10-31 11:05:49 +00007819
Eric Andersenc470f442003-07-28 09:56:35 +00007820static void
7821changemail(const char *val)
7822{
7823 mail_var_path_changed++;
7824}
7825
7826#endif /* CONFIG_ASH_MAIL */
7827
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007828/* main.c */
Eric Andersenc470f442003-07-28 09:56:35 +00007829
Eric Andersencb57d552001-06-28 07:25:16 +00007830
Eric Andersencb57d552001-06-28 07:25:16 +00007831#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007832static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007833extern int etext();
7834#endif
7835
Eric Andersenc470f442003-07-28 09:56:35 +00007836static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007837
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007838static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007839
Eric Andersencb57d552001-06-28 07:25:16 +00007840/*
7841 * Main routine. We initialize things, parse the arguments, execute
7842 * profiles if we're a login shell, and then call cmdloop to execute
7843 * commands. The setjmp call sets up the location to jump to when an
7844 * exception occurs. When an exception occurs the variable "state"
7845 * is used to figure out how far we had gotten.
7846 */
7847
Eric Andersenc470f442003-07-28 09:56:35 +00007848int
7849ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007850{
Eric Andersenc470f442003-07-28 09:56:35 +00007851 char *shinit;
7852 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007853 struct jmploc jmploc;
7854 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007855
Eric Andersenc470f442003-07-28 09:56:35 +00007856#ifdef __GLIBC__
7857 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007858#endif
7859
Eric Andersencb57d552001-06-28 07:25:16 +00007860#if PROFILE
7861 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7862#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007863 state = 0;
7864 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007865 int e;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007866 int s;
Eric Andersenc470f442003-07-28 09:56:35 +00007867
Eric Andersencb57d552001-06-28 07:25:16 +00007868 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007869
7870 e = exception;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007871 if (e == EXERROR)
7872 exitstatus = 2;
7873 s = state;
7874 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl)
Eric Andersenc470f442003-07-28 09:56:35 +00007875 exitshell();
7876
Eric Andersen90898442003-08-06 11:20:52 +00007877 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007878 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007879 }
7880 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007881 FORCEINTON; /* enable interrupts */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007882 if (s == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00007883 goto state1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007884 else if (s == 2)
Eric Andersencb57d552001-06-28 07:25:16 +00007885 goto state2;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007886 else if (s == 3)
Eric Andersencb57d552001-06-28 07:25:16 +00007887 goto state3;
7888 else
7889 goto state4;
7890 }
7891 handler = &jmploc;
7892#ifdef DEBUG
7893 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007894 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007895#endif
7896 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007897
7898#ifdef CONFIG_ASH_RANDOM_SUPPORT
7899 rseed = rootpid + ((time_t)time((time_t *)0));
7900#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007901 init();
7902 setstackmark(&smark);
7903 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007904#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7905 if ( iflag ) {
7906 const char *hp = lookupvar("HISTFILE");
7907
7908 if(hp == NULL ) {
7909 hp = lookupvar("HOME");
7910 if(hp != NULL) {
7911 char *defhp = concat_path_file(hp, ".ash_history");
7912 setvar("HISTFILE", defhp, 0);
7913 free(defhp);
7914 }
7915 }
7916 }
7917#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007918 if (argv[0] && argv[0][0] == '-')
7919 isloginsh = 1;
7920 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007921 state = 1;
7922 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007923state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007924 state = 2;
7925 read_profile(".profile");
7926 }
Eric Andersenc470f442003-07-28 09:56:35 +00007927state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007928 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007929 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007930#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007931 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007932#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007933 iflag
7934 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007935 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007936 read_profile(shinit);
7937 }
Eric Andersencb57d552001-06-28 07:25:16 +00007938 }
Eric Andersenc470f442003-07-28 09:56:35 +00007939state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007940 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007941 if (minusc)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007942 evalstring(minusc, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007943
7944 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007945#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007946 if ( iflag ) {
7947 const char *hp = lookupvar("HISTFILE");
7948
7949 if(hp != NULL )
7950 load_history ( hp );
7951 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007952#endif
Eric Andersen90898442003-08-06 11:20:52 +00007953state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007954 cmdloop(1);
7955 }
7956#if PROFILE
7957 monitor(0);
7958#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007959#if GPROF
7960 {
7961 extern void _mcleanup(void);
7962 _mcleanup();
7963 }
7964#endif
7965 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007966 /* NOTREACHED */
7967}
7968
7969
7970/*
7971 * Read and execute commands. "Top" is nonzero for the top level command
7972 * loop; it turns on prompting if the shell is interactive.
7973 */
7974
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007975static int
Eric Andersenc470f442003-07-28 09:56:35 +00007976cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007977{
7978 union node *n;
7979 struct stackmark smark;
7980 int inter;
7981 int numeof = 0;
7982
7983 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00007984 for (;;) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00007985 int skip;
7986
Glenn L McGrath76620622004-01-13 10:19:37 +00007987 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007988#if JOBS
7989 if (jobctl)
7990 showjobs(stderr, SHOW_CHANGED);
7991#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007992 inter = 0;
7993 if (iflag && top) {
7994 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00007995#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007996 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00007997#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007998 }
7999 n = parsecmd(inter);
8000 /* showtree(n); DEBUG */
8001 if (n == NEOF) {
8002 if (!top || numeof >= 50)
8003 break;
8004 if (!stoppedjobs()) {
8005 if (!Iflag)
8006 break;
8007 out2str("\nUse \"exit\" to leave shell.\n");
8008 }
8009 numeof++;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008010 } else if (nflag == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008011 job_warning = (job_warning == 2) ? 1 : 0;
8012 numeof = 0;
8013 evaltree(n, 0);
8014 }
8015 popstackmark(&smark);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008016 skip = evalskip;
8017
8018 if (skip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008019 evalskip = 0;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008020 return skip & SKIPEVAL;
Eric Andersencb57d552001-06-28 07:25:16 +00008021 }
8022 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008023
8024 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008025}
8026
8027
Eric Andersencb57d552001-06-28 07:25:16 +00008028/*
8029 * Read /etc/profile or .profile. Return on error.
8030 */
8031
Eric Andersenc470f442003-07-28 09:56:35 +00008032static void
8033read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008034{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008035 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008036
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008037 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00008038 return;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008039
8040 skip = cmdloop(0);
Eric Andersencb57d552001-06-28 07:25:16 +00008041 popfile();
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008042
8043 if (skip)
8044 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00008045}
8046
8047
Eric Andersencb57d552001-06-28 07:25:16 +00008048/*
8049 * Read a file containing shell functions.
8050 */
8051
Eric Andersenc470f442003-07-28 09:56:35 +00008052static void
8053readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008054{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008055 setinputfile(name, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008056 cmdloop(0);
8057 popfile();
8058}
8059
8060
Eric Andersencb57d552001-06-28 07:25:16 +00008061/*
Eric Andersenc470f442003-07-28 09:56:35 +00008062 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008063 * search for the file, which is necessary to find sub-commands.
8064 */
8065
Eric Andersenc470f442003-07-28 09:56:35 +00008066static inline char *
8067find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008068{
8069 char *fullname;
8070 const char *path = pathval();
8071 struct stat statb;
8072
8073 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008074 if (strchr(name, '/'))
8075 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008076
Eric Andersenc470f442003-07-28 09:56:35 +00008077 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008078 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8079 /*
8080 * Don't bother freeing here, since it will
8081 * be freed by the caller.
8082 */
8083 return fullname;
8084 }
8085 stunalloc(fullname);
8086 }
8087
8088 /* not found in the PATH */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008089 sh_error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008090 /* NOTREACHED */
8091}
8092
Eric Andersen1e6aba92004-04-12 19:12:13 +00008093static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008094{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008095 struct strlist *sp;
8096 volatile struct shparam saveparam;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008097 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008098
Eric Andersen1e6aba92004-04-12 19:12:13 +00008099 for (sp = cmdenviron; sp; sp = sp->next)
8100 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8101
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00008102 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008103 char *fullname;
Eric Andersencb57d552001-06-28 07:25:16 +00008104
Eric Andersencb57d552001-06-28 07:25:16 +00008105 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008106
8107 if (argc > 2) {
8108 saveparam = shellparam;
8109 shellparam.malloc = 0;
8110 shellparam.nparam = argc - 2;
8111 shellparam.p = argv + 2;
8112 };
8113
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008114 setinputfile(fullname, INPUT_PUSH_FILE);
Eric Andersencb57d552001-06-28 07:25:16 +00008115 commandname = fullname;
8116 cmdloop(0);
8117 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008118
8119 if (argc > 2) {
8120 freeparam(&shellparam);
8121 shellparam = saveparam;
8122 };
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008123 status = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00008124 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008125 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008126}
8127
8128
Eric Andersenc470f442003-07-28 09:56:35 +00008129static int
8130exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008131{
8132 if (stoppedjobs())
8133 return 0;
8134 if (argc > 1)
8135 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008136 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008137 /* NOTREACHED */
8138}
Eric Andersen62483552001-07-10 06:09:16 +00008139
Paul Fox0b621582005-08-09 19:38:05 +00008140#ifdef CONFIG_ASH_BUILTIN_ECHO
8141static int
8142echocmd(int argc, char **argv)
8143{
8144 return bb_echo(argc, argv);
8145}
8146#endif
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008147/* memalloc.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008148
8149/*
Eric Andersen90898442003-08-06 11:20:52 +00008150 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008151 */
8152
8153static pointer
8154ckrealloc(pointer p, size_t nbytes)
8155{
8156 p = realloc(p, nbytes);
8157 if (p == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008158 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008159 return p;
8160}
8161
Eric Andersen90898442003-08-06 11:20:52 +00008162static pointer
8163ckmalloc(size_t nbytes)
8164{
8165 return ckrealloc(NULL, nbytes);
8166}
Eric Andersenc470f442003-07-28 09:56:35 +00008167
8168/*
8169 * Make a copy of a string in safe storage.
8170 */
8171
8172static char *
8173savestr(const char *s)
8174{
8175 char *p = strdup(s);
8176 if (!p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008177 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008178 return p;
8179}
8180
8181
8182/*
8183 * Parse trees for commands are allocated in lifo order, so we use a stack
8184 * to make this more efficient, and also to avoid all sorts of exception
8185 * handling code to handle interrupts in the middle of a parse.
8186 *
8187 * The size 504 was chosen because the Ultrix malloc handles that size
8188 * well.
8189 */
8190
8191
8192static pointer
8193stalloc(size_t nbytes)
8194{
8195 char *p;
8196 size_t aligned;
8197
8198 aligned = SHELL_ALIGN(nbytes);
8199 if (aligned > stacknleft) {
8200 size_t len;
8201 size_t blocksize;
8202 struct stack_block *sp;
8203
8204 blocksize = aligned;
8205 if (blocksize < MINSIZE)
8206 blocksize = MINSIZE;
8207 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8208 if (len < blocksize)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008209 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008210 INTOFF;
8211 sp = ckmalloc(len);
8212 sp->prev = stackp;
8213 stacknxt = sp->space;
8214 stacknleft = blocksize;
8215 sstrend = stacknxt + blocksize;
8216 stackp = sp;
8217 INTON;
8218 }
8219 p = stacknxt;
8220 stacknxt += aligned;
8221 stacknleft -= aligned;
8222 return p;
8223}
8224
8225
8226void
8227stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008228{
Eric Andersencb57d552001-06-28 07:25:16 +00008229#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008230 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008231 write(2, "stunalloc\n", 10);
8232 abort();
8233 }
8234#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008235 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008236 stacknxt = p;
8237}
8238
8239
Eric Andersenc470f442003-07-28 09:56:35 +00008240void
8241setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008242{
Eric Andersencb57d552001-06-28 07:25:16 +00008243 mark->stackp = stackp;
8244 mark->stacknxt = stacknxt;
8245 mark->stacknleft = stacknleft;
8246 mark->marknext = markp;
8247 markp = mark;
8248}
8249
8250
Eric Andersenc470f442003-07-28 09:56:35 +00008251void
8252popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008253{
Eric Andersencb57d552001-06-28 07:25:16 +00008254 struct stack_block *sp;
8255
8256 INTOFF;
8257 markp = mark->marknext;
8258 while (stackp != mark->stackp) {
8259 sp = stackp;
8260 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008261 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008262 }
8263 stacknxt = mark->stacknxt;
8264 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008265 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008266 INTON;
8267}
8268
8269
8270/*
8271 * When the parser reads in a string, it wants to stick the string on the
8272 * stack and only adjust the stack pointer when it knows how big the
8273 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8274 * of space on top of the stack and stackblocklen returns the length of
8275 * this block. Growstackblock will grow this space by at least one byte,
8276 * possibly moving it (like realloc). Grabstackblock actually allocates the
8277 * part of the block that has been used.
8278 */
8279
Eric Andersenc470f442003-07-28 09:56:35 +00008280void
8281growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008282{
Eric Andersenc470f442003-07-28 09:56:35 +00008283 size_t newlen;
8284
8285 newlen = stacknleft * 2;
8286 if (newlen < stacknleft)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008287 sh_error(bb_msg_memory_exhausted);
Eric Andersenc470f442003-07-28 09:56:35 +00008288 if (newlen < 128)
8289 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008290
8291 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008292 struct stack_block *oldstackp;
8293 struct stackmark *xmark;
8294 struct stack_block *sp;
8295 struct stack_block *prevstackp;
8296 size_t grosslen;
8297
Eric Andersencb57d552001-06-28 07:25:16 +00008298 INTOFF;
8299 oldstackp = stackp;
8300 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008301 prevstackp = sp->prev;
8302 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8303 sp = ckrealloc((pointer)sp, grosslen);
8304 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008305 stackp = sp;
8306 stacknxt = sp->space;
8307 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008308 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008309
Eric Andersenc470f442003-07-28 09:56:35 +00008310 /*
8311 * Stack marks pointing to the start of the old block
8312 * must be relocated to point to the new block
8313 */
8314 xmark = markp;
8315 while (xmark != NULL && xmark->stackp == oldstackp) {
8316 xmark->stackp = stackp;
8317 xmark->stacknxt = stacknxt;
8318 xmark->stacknleft = stacknleft;
8319 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008320 }
8321 INTON;
8322 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008323 char *oldspace = stacknxt;
8324 int oldlen = stacknleft;
8325 char *p = stalloc(newlen);
8326
8327 /* free the space we just allocated */
8328 stacknxt = memcpy(p, oldspace, oldlen);
8329 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008330 }
8331}
8332
Eric Andersenc470f442003-07-28 09:56:35 +00008333static inline void
8334grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008335{
Eric Andersenc470f442003-07-28 09:56:35 +00008336 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008337 stacknxt += len;
8338 stacknleft -= len;
8339}
8340
Eric Andersencb57d552001-06-28 07:25:16 +00008341/*
Eric Andersenc470f442003-07-28 09:56:35 +00008342 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008343 * The user declares a variable of type STACKSTR, which may be declared
8344 * to be a register. The macro STARTSTACKSTR initializes things. Then
8345 * the user uses the macro STPUTC to add characters to the string. In
8346 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8347 * grown as necessary. When the user is done, she can just leave the
8348 * string there and refer to it using stackblock(). Or she can allocate
8349 * the space for it using grabstackstr(). If it is necessary to allow
8350 * someone else to use the stack temporarily and then continue to grow
8351 * the string, the user should use grabstack to allocate the space, and
8352 * then call ungrabstr(p) to return to the previous mode of operation.
8353 *
8354 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8355 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8356 * is space for at least one character.
8357 */
8358
Eric Andersenc470f442003-07-28 09:56:35 +00008359void *
8360growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008361{
Eric Andersenc470f442003-07-28 09:56:35 +00008362 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008363 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008364 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008365 return stackblock();
8366 }
8367 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008368 return stackblock() + len;
8369}
8370
Eric Andersencb57d552001-06-28 07:25:16 +00008371/*
8372 * Called from CHECKSTRSPACE.
8373 */
8374
Eric Andersenc470f442003-07-28 09:56:35 +00008375char *
8376makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008377{
Eric Andersenc470f442003-07-28 09:56:35 +00008378 size_t len = p - stacknxt;
8379 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008380
Eric Andersenc470f442003-07-28 09:56:35 +00008381 for (;;) {
8382 size_t nleft;
8383
8384 size = stackblocksize();
8385 nleft = size - len;
8386 if (nleft >= newlen)
8387 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008388 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008389 }
Eric Andersencb57d552001-06-28 07:25:16 +00008390 return stackblock() + len;
8391}
8392
Eric Andersenc470f442003-07-28 09:56:35 +00008393char *
8394stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008395{
Eric Andersenc470f442003-07-28 09:56:35 +00008396 p = makestrspace(n, p);
8397 p = mempcpy(p, s, n);
8398 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008399}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008400
Eric Andersenc470f442003-07-28 09:56:35 +00008401char *
8402stputs(const char *s, char *p)
8403{
8404 return stnputs(s, strlen(s), p);
8405}
8406
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008407/* mystring.c */
Eric Andersenc470f442003-07-28 09:56:35 +00008408
Eric Andersencb57d552001-06-28 07:25:16 +00008409/*
Eric Andersenc470f442003-07-28 09:56:35 +00008410 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008411 *
Eric Andersenc470f442003-07-28 09:56:35 +00008412 * number(s) Convert a string of digits to an integer.
8413 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008414 */
8415
Eric Andersencb57d552001-06-28 07:25:16 +00008416/*
8417 * prefix -- see if pfx is a prefix of string.
8418 */
8419
Eric Andersenc470f442003-07-28 09:56:35 +00008420char *
8421prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008422{
Eric Andersencb57d552001-06-28 07:25:16 +00008423 while (*pfx) {
8424 if (*pfx++ != *string++)
8425 return 0;
8426 }
Eric Andersenc470f442003-07-28 09:56:35 +00008427 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008428}
8429
8430
8431/*
8432 * Convert a string of digits to an integer, printing an error message on
8433 * failure.
8434 */
8435
Eric Andersenc470f442003-07-28 09:56:35 +00008436int
8437number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008438{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008439
Eric Andersenc470f442003-07-28 09:56:35 +00008440 if (! is_number(s))
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008441 sh_error(illnum, s);
Eric Andersenc470f442003-07-28 09:56:35 +00008442 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008443}
8444
Eric Andersenc470f442003-07-28 09:56:35 +00008445
Eric Andersenc470f442003-07-28 09:56:35 +00008446/*
8447 * Check for a valid number. This should be elsewhere.
8448 */
8449
8450int
8451is_number(const char *p)
8452{
8453 do {
8454 if (! is_digit(*p))
8455 return 0;
8456 } while (*++p != '\0');
8457 return 1;
8458}
8459
8460
Eric Andersencb57d552001-06-28 07:25:16 +00008461/*
8462 * Produce a possibly single quoted string suitable as input to the shell.
8463 * The return string is allocated on the stack.
8464 */
8465
Eric Andersenc470f442003-07-28 09:56:35 +00008466char *
8467single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008468 char *p;
8469
8470 STARTSTACKSTR(p);
8471
8472 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008473 char *q;
8474 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008475
Eric Andersenc470f442003-07-28 09:56:35 +00008476 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008477
Eric Andersenc470f442003-07-28 09:56:35 +00008478 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008479
Eric Andersenc470f442003-07-28 09:56:35 +00008480 *q++ = '\'';
8481 q = mempcpy(q, s, len);
8482 *q++ = '\'';
8483 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008484
Eric Andersenc470f442003-07-28 09:56:35 +00008485 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008486
Eric Andersenc470f442003-07-28 09:56:35 +00008487 len = strspn(s, "'");
8488 if (!len)
8489 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008490
Eric Andersenc470f442003-07-28 09:56:35 +00008491 q = p = makestrspace(len + 3, p);
8492
8493 *q++ = '"';
8494 q = mempcpy(q, s, len);
8495 *q++ = '"';
8496 s += len;
8497
8498 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008499 } while (*s);
8500
8501 USTPUTC(0, p);
8502
Eric Andersenc470f442003-07-28 09:56:35 +00008503 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008504}
8505
8506/*
Eric Andersenc470f442003-07-28 09:56:35 +00008507 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008508 */
8509
Eric Andersenc470f442003-07-28 09:56:35 +00008510char *
8511sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008512{
Eric Andersenc470f442003-07-28 09:56:35 +00008513 size_t len = strlen(p) + 1;
8514 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008515}
Eric Andersenc470f442003-07-28 09:56:35 +00008516
8517
8518static void
8519calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008520{
Eric Andersenc470f442003-07-28 09:56:35 +00008521 if (n == NULL)
8522 return;
8523 funcblocksize += nodesize[n->type];
8524 switch (n->type) {
8525 case NCMD:
8526 calcsize(n->ncmd.redirect);
8527 calcsize(n->ncmd.args);
8528 calcsize(n->ncmd.assign);
8529 break;
8530 case NPIPE:
8531 sizenodelist(n->npipe.cmdlist);
8532 break;
8533 case NREDIR:
8534 case NBACKGND:
8535 case NSUBSHELL:
8536 calcsize(n->nredir.redirect);
8537 calcsize(n->nredir.n);
8538 break;
8539 case NAND:
8540 case NOR:
8541 case NSEMI:
8542 case NWHILE:
8543 case NUNTIL:
8544 calcsize(n->nbinary.ch2);
8545 calcsize(n->nbinary.ch1);
8546 break;
8547 case NIF:
8548 calcsize(n->nif.elsepart);
8549 calcsize(n->nif.ifpart);
8550 calcsize(n->nif.test);
8551 break;
8552 case NFOR:
8553 funcstringsize += strlen(n->nfor.var) + 1;
8554 calcsize(n->nfor.body);
8555 calcsize(n->nfor.args);
8556 break;
8557 case NCASE:
8558 calcsize(n->ncase.cases);
8559 calcsize(n->ncase.expr);
8560 break;
8561 case NCLIST:
8562 calcsize(n->nclist.body);
8563 calcsize(n->nclist.pattern);
8564 calcsize(n->nclist.next);
8565 break;
8566 case NDEFUN:
8567 case NARG:
8568 sizenodelist(n->narg.backquote);
8569 funcstringsize += strlen(n->narg.text) + 1;
8570 calcsize(n->narg.next);
8571 break;
8572 case NTO:
8573 case NCLOBBER:
8574 case NFROM:
8575 case NFROMTO:
8576 case NAPPEND:
8577 calcsize(n->nfile.fname);
8578 calcsize(n->nfile.next);
8579 break;
8580 case NTOFD:
8581 case NFROMFD:
8582 calcsize(n->ndup.vname);
8583 calcsize(n->ndup.next);
8584 break;
8585 case NHERE:
8586 case NXHERE:
8587 calcsize(n->nhere.doc);
8588 calcsize(n->nhere.next);
8589 break;
8590 case NNOT:
8591 calcsize(n->nnot.com);
8592 break;
8593 };
Eric Andersencb57d552001-06-28 07:25:16 +00008594}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008595
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008596
Eric Andersenc470f442003-07-28 09:56:35 +00008597static void
8598sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008599{
8600 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008601 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008602 calcsize(lp->n);
8603 lp = lp->next;
8604 }
8605}
Eric Andersencb57d552001-06-28 07:25:16 +00008606
8607
Eric Andersenc470f442003-07-28 09:56:35 +00008608static union node *
8609copynode(union node *n)
8610{
8611 union node *new;
8612
8613 if (n == NULL)
8614 return NULL;
8615 new = funcblock;
8616 funcblock = (char *) funcblock + nodesize[n->type];
8617 switch (n->type) {
8618 case NCMD:
8619 new->ncmd.redirect = copynode(n->ncmd.redirect);
8620 new->ncmd.args = copynode(n->ncmd.args);
8621 new->ncmd.assign = copynode(n->ncmd.assign);
8622 break;
8623 case NPIPE:
8624 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8625 new->npipe.backgnd = n->npipe.backgnd;
8626 break;
8627 case NREDIR:
8628 case NBACKGND:
8629 case NSUBSHELL:
8630 new->nredir.redirect = copynode(n->nredir.redirect);
8631 new->nredir.n = copynode(n->nredir.n);
8632 break;
8633 case NAND:
8634 case NOR:
8635 case NSEMI:
8636 case NWHILE:
8637 case NUNTIL:
8638 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8639 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8640 break;
8641 case NIF:
8642 new->nif.elsepart = copynode(n->nif.elsepart);
8643 new->nif.ifpart = copynode(n->nif.ifpart);
8644 new->nif.test = copynode(n->nif.test);
8645 break;
8646 case NFOR:
8647 new->nfor.var = nodesavestr(n->nfor.var);
8648 new->nfor.body = copynode(n->nfor.body);
8649 new->nfor.args = copynode(n->nfor.args);
8650 break;
8651 case NCASE:
8652 new->ncase.cases = copynode(n->ncase.cases);
8653 new->ncase.expr = copynode(n->ncase.expr);
8654 break;
8655 case NCLIST:
8656 new->nclist.body = copynode(n->nclist.body);
8657 new->nclist.pattern = copynode(n->nclist.pattern);
8658 new->nclist.next = copynode(n->nclist.next);
8659 break;
8660 case NDEFUN:
8661 case NARG:
8662 new->narg.backquote = copynodelist(n->narg.backquote);
8663 new->narg.text = nodesavestr(n->narg.text);
8664 new->narg.next = copynode(n->narg.next);
8665 break;
8666 case NTO:
8667 case NCLOBBER:
8668 case NFROM:
8669 case NFROMTO:
8670 case NAPPEND:
8671 new->nfile.fname = copynode(n->nfile.fname);
8672 new->nfile.fd = n->nfile.fd;
8673 new->nfile.next = copynode(n->nfile.next);
8674 break;
8675 case NTOFD:
8676 case NFROMFD:
8677 new->ndup.vname = copynode(n->ndup.vname);
8678 new->ndup.dupfd = n->ndup.dupfd;
8679 new->ndup.fd = n->ndup.fd;
8680 new->ndup.next = copynode(n->ndup.next);
8681 break;
8682 case NHERE:
8683 case NXHERE:
8684 new->nhere.doc = copynode(n->nhere.doc);
8685 new->nhere.fd = n->nhere.fd;
8686 new->nhere.next = copynode(n->nhere.next);
8687 break;
8688 case NNOT:
8689 new->nnot.com = copynode(n->nnot.com);
8690 break;
8691 };
8692 new->type = n->type;
8693 return new;
8694}
8695
8696
8697static struct nodelist *
8698copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008699{
8700 struct nodelist *start;
8701 struct nodelist **lpp;
8702
8703 lpp = &start;
8704 while (lp) {
8705 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008706 funcblock = (char *) funcblock +
8707 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008708 (*lpp)->n = copynode(lp->n);
8709 lp = lp->next;
8710 lpp = &(*lpp)->next;
8711 }
8712 *lpp = NULL;
8713 return start;
8714}
8715
8716
Eric Andersenc470f442003-07-28 09:56:35 +00008717static char *
8718nodesavestr(char *s)
8719{
8720 char *rtn = funcstring;
8721
8722 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008723 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008724}
8725
Eric Andersenc470f442003-07-28 09:56:35 +00008726
Eric Andersenc470f442003-07-28 09:56:35 +00008727/*
8728 * Free a parse tree.
8729 */
8730
8731static void
8732freefunc(struct funcnode *f)
8733{
8734 if (f && --f->count < 0)
8735 ckfree(f);
8736}
8737
8738
8739static void options(int);
8740static void setoption(int, int);
8741
Eric Andersencb57d552001-06-28 07:25:16 +00008742
Eric Andersencb57d552001-06-28 07:25:16 +00008743/*
8744 * Process the shell command line arguments.
8745 */
8746
Eric Andersenc470f442003-07-28 09:56:35 +00008747void
8748procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008749{
8750 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008751 const char *xminusc;
8752 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008753
Eric Andersenc470f442003-07-28 09:56:35 +00008754 xargv = argv;
8755 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008756 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008757 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008758 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008759 optlist[i] = 2;
8760 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008761 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008762 xargv = argptr;
8763 xminusc = minusc;
8764 if (*xargv == NULL) {
8765 if (xminusc)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008766 sh_error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008767 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008768 }
Eric Andersencb57d552001-06-28 07:25:16 +00008769 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8770 iflag = 1;
8771 if (mflag == 2)
8772 mflag = iflag;
8773 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008774 if (optlist[i] == 2)
8775 optlist[i] = 0;
8776#if DEBUG == 2
8777 debug = 1;
8778#endif
8779 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8780 if (xminusc) {
8781 minusc = *xargv++;
8782 if (*xargv)
8783 goto setarg0;
8784 } else if (!sflag) {
8785 setinputfile(*xargv, 0);
8786setarg0:
8787 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008788 commandname = arg0;
8789 }
Eric Andersencb57d552001-06-28 07:25:16 +00008790
Eric Andersenc470f442003-07-28 09:56:35 +00008791 shellparam.p = xargv;
8792#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008793 shellparam.optind = 1;
8794 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008795#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008796 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008797 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008798 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008799 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008800 }
8801 optschanged();
8802}
8803
8804
Eric Andersenc470f442003-07-28 09:56:35 +00008805void
8806optschanged(void)
8807{
8808#ifdef DEBUG
8809 opentrace();
8810#endif
8811 setinteractive(iflag);
8812 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008813 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008814}
Eric Andersencb57d552001-06-28 07:25:16 +00008815
Eric Andersenc470f442003-07-28 09:56:35 +00008816static inline void
8817minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008818{
8819 int i;
8820
8821 if (name == NULL) {
8822 out1str("Current option settings\n");
8823 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008824 out1fmt("%-16s%s\n", optnames(i),
8825 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008826 } else {
8827 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008828 if (equal(name, optnames(i))) {
8829 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008830 return;
8831 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008832 sh_error("Illegal option -o %s", name);
Eric Andersen62483552001-07-10 06:09:16 +00008833 }
8834}
8835
Eric Andersenc470f442003-07-28 09:56:35 +00008836/*
8837 * Process shell options. The global variable argptr contains a pointer
8838 * to the argument list; we advance it past the options.
8839 */
Eric Andersen62483552001-07-10 06:09:16 +00008840
Eric Andersenc470f442003-07-28 09:56:35 +00008841static void
8842options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008843{
8844 char *p;
8845 int val;
8846 int c;
8847
8848 if (cmdline)
8849 minusc = NULL;
8850 while ((p = *argptr) != NULL) {
8851 argptr++;
8852 if ((c = *p++) == '-') {
8853 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008854 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8855 if (!cmdline) {
8856 /* "-" means turn off -x and -v */
8857 if (p[0] == '\0')
8858 xflag = vflag = 0;
8859 /* "--" means reset params */
8860 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008861 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008862 }
Eric Andersenc470f442003-07-28 09:56:35 +00008863 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008864 }
8865 } else if (c == '+') {
8866 val = 0;
8867 } else {
8868 argptr--;
8869 break;
8870 }
8871 while ((c = *p++) != '\0') {
8872 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008873 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008874 } else if (c == 'o') {
8875 minus_o(*argptr, val);
8876 if (*argptr)
8877 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008878 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008879 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008880 isloginsh = 1;
8881 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008882 } else {
8883 setoption(c, val);
8884 }
8885 }
8886 }
8887}
8888
Eric Andersencb57d552001-06-28 07:25:16 +00008889
Eric Andersenc470f442003-07-28 09:56:35 +00008890static void
8891setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008892{
Eric Andersencb57d552001-06-28 07:25:16 +00008893 int i;
8894
8895 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008896 if (optletters(i) == flag) {
8897 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008898 return;
8899 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008900 sh_error("Illegal option -%c", flag);
Eric Andersencb57d552001-06-28 07:25:16 +00008901 /* NOTREACHED */
8902}
8903
8904
8905
Eric Andersencb57d552001-06-28 07:25:16 +00008906/*
8907 * Set the shell parameters.
8908 */
8909
Eric Andersenc470f442003-07-28 09:56:35 +00008910void
8911setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008912{
Eric Andersencb57d552001-06-28 07:25:16 +00008913 char **newparam;
8914 char **ap;
8915 int nparam;
8916
Eric Andersenc470f442003-07-28 09:56:35 +00008917 for (nparam = 0 ; argv[nparam] ; nparam++);
8918 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008919 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008920 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008921 }
8922 *ap = NULL;
8923 freeparam(&shellparam);
8924 shellparam.malloc = 1;
8925 shellparam.nparam = nparam;
8926 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008927#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008928 shellparam.optind = 1;
8929 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008930#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008931}
8932
8933
8934/*
8935 * Free the list of positional parameters.
8936 */
8937
Eric Andersenc470f442003-07-28 09:56:35 +00008938void
8939freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008940{
Eric Andersencb57d552001-06-28 07:25:16 +00008941 char **ap;
8942
8943 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008944 for (ap = param->p ; *ap ; ap++)
8945 ckfree(*ap);
8946 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008947 }
8948}
8949
8950
8951
8952/*
8953 * The shift builtin command.
8954 */
8955
Eric Andersenc470f442003-07-28 09:56:35 +00008956int
8957shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008958{
8959 int n;
8960 char **ap1, **ap2;
8961
8962 n = 1;
8963 if (argc > 1)
8964 n = number(argv[1]);
8965 if (n > shellparam.nparam)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008966 sh_error("can't shift that many");
Eric Andersencb57d552001-06-28 07:25:16 +00008967 INTOFF;
8968 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008969 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008970 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008971 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008972 }
8973 ap2 = shellparam.p;
8974 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008975#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008976 shellparam.optind = 1;
8977 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008978#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008979 INTON;
8980 return 0;
8981}
8982
8983
8984
8985/*
8986 * The set command builtin.
8987 */
8988
Eric Andersenc470f442003-07-28 09:56:35 +00008989int
8990setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008991{
8992 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00008993 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00008994 INTOFF;
8995 options(0);
8996 optschanged();
8997 if (*argptr != NULL) {
8998 setparam(argptr);
8999 }
9000 INTON;
9001 return 0;
9002}
9003
9004
Eric Andersenc470f442003-07-28 09:56:35 +00009005#ifdef CONFIG_ASH_GETOPTS
9006static void
9007getoptsreset(value)
9008 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009009{
9010 shellparam.optind = number(value);
9011 shellparam.optoff = -1;
9012}
Eric Andersenc470f442003-07-28 09:56:35 +00009013#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009014
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009015#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009016static void change_lc_all(const char *value)
9017{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009018 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009019 setlocale(LC_ALL, value);
9020}
9021
9022static void change_lc_ctype(const char *value)
9023{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009024 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009025 setlocale(LC_CTYPE, value);
9026}
9027
9028#endif
9029
Eric Andersen16767e22004-03-16 05:14:10 +00009030#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009031/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009032static void change_random(const char *value)
9033{
Eric Andersen16767e22004-03-16 05:14:10 +00009034 if(value == NULL) {
9035 /* "get", generate */
9036 char buf[16];
9037
9038 rseed = rseed * 1103515245 + 12345;
9039 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9040 /* set without recursion */
9041 setvar(vrandom.text, buf, VNOFUNC);
9042 vrandom.flags &= ~VNOFUNC;
9043 } else {
9044 /* set/reset */
9045 rseed = strtoul(value, (char **)NULL, 10);
9046 }
Eric Andersenef02f822004-03-11 13:34:24 +00009047}
Eric Andersen16767e22004-03-16 05:14:10 +00009048#endif
9049
Eric Andersenef02f822004-03-11 13:34:24 +00009050
Eric Andersend35c5df2002-01-09 15:37:36 +00009051#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009052static int
Eric Andersenc470f442003-07-28 09:56:35 +00009053getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009054{
9055 char *p, *q;
9056 char c = '?';
9057 int done = 0;
9058 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009059 char s[12];
9060 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009061
Eric Andersena48b0a32003-10-22 10:56:47 +00009062 if(*param_optind < 1)
9063 return 1;
9064 optnext = optfirst + *param_optind - 1;
9065
9066 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009067 p = NULL;
9068 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009069 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009070 if (p == NULL || *p == '\0') {
9071 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009072 p = *optnext;
9073 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009074atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009075 p = NULL;
9076 done = 1;
9077 goto out;
9078 }
9079 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009080 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009081 goto atend;
9082 }
9083
9084 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009085 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009086 if (*q == '\0') {
9087 if (optstr[0] == ':') {
9088 s[0] = c;
9089 s[1] = '\0';
9090 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009091 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009092 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009093 (void) unsetvar("OPTARG");
9094 }
9095 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009096 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009097 }
9098 if (*++q == ':')
9099 q++;
9100 }
9101
9102 if (*++q == ':') {
9103 if (*p == '\0' && (p = *optnext) == NULL) {
9104 if (optstr[0] == ':') {
9105 s[0] = c;
9106 s[1] = '\0';
9107 err |= setvarsafe("OPTARG", s, 0);
9108 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009109 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009110 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009111 (void) unsetvar("OPTARG");
9112 c = '?';
9113 }
Eric Andersenc470f442003-07-28 09:56:35 +00009114 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009115 }
9116
9117 if (p == *optnext)
9118 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009119 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009120 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009121 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009122 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009123
Eric Andersenc470f442003-07-28 09:56:35 +00009124out:
Eric Andersencb57d552001-06-28 07:25:16 +00009125 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009126 *param_optind = optnext - optfirst + 1;
9127 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009128 err |= setvarsafe("OPTIND", s, VNOFUNC);
9129 s[0] = c;
9130 s[1] = '\0';
9131 err |= setvarsafe(optvar, s, 0);
9132 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009133 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009134 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009135 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009136 exraise(EXERROR);
9137 }
9138 return done;
9139}
Eric Andersenc470f442003-07-28 09:56:35 +00009140
9141/*
9142 * The getopts builtin. Shellparam.optnext points to the next argument
9143 * to be processed. Shellparam.optptr points to the next character to
9144 * be processed in the current argument. If shellparam.optnext is NULL,
9145 * then it's the first time getopts has been called.
9146 */
9147
9148int
9149getoptscmd(int argc, char **argv)
9150{
9151 char **optbase;
9152
9153 if (argc < 3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009154 sh_error("Usage: getopts optstring var [arg]");
Eric Andersenc470f442003-07-28 09:56:35 +00009155 else if (argc == 3) {
9156 optbase = shellparam.p;
9157 if (shellparam.optind > shellparam.nparam + 1) {
9158 shellparam.optind = 1;
9159 shellparam.optoff = -1;
9160 }
9161 }
9162 else {
9163 optbase = &argv[3];
9164 if (shellparam.optind > argc - 2) {
9165 shellparam.optind = 1;
9166 shellparam.optoff = -1;
9167 }
9168 }
9169
9170 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9171 &shellparam.optoff);
9172}
9173#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009174
9175/*
9176 * XXX - should get rid of. have all builtins use getopt(3). the
9177 * library getopt must have the BSD extension static variable "optreset"
9178 * otherwise it can't be used within the shell safely.
9179 *
9180 * Standard option processing (a la getopt) for builtin routines. The
9181 * only argument that is passed to nextopt is the option string; the
9182 * other arguments are unnecessary. It return the character, or '\0' on
9183 * end of input.
9184 */
9185
Eric Andersenc470f442003-07-28 09:56:35 +00009186static int
9187nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009188{
Eric Andersencb57d552001-06-28 07:25:16 +00009189 char *p;
9190 const char *q;
9191 char c;
9192
9193 if ((p = optptr) == NULL || *p == '\0') {
9194 p = *argptr;
9195 if (p == NULL || *p != '-' || *++p == '\0')
9196 return '\0';
9197 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009198 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009199 return '\0';
9200 }
9201 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009202 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009203 if (*q == '\0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009204 sh_error("Illegal option -%c", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009205 if (*++q == ':')
9206 q++;
9207 }
9208 if (*++q == ':') {
9209 if (*p == '\0' && (p = *argptr++) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009210 sh_error("No arg for -%c option", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009211 optionarg = p;
9212 p = NULL;
9213 }
9214 optptr = p;
9215 return c;
9216}
9217
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009218
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009219/* output.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009220
Eric Andersenc470f442003-07-28 09:56:35 +00009221void
9222outstr(const char *p, FILE *file)
9223{
9224 INTOFF;
9225 fputs(p, file);
9226 INTON;
9227}
9228
9229void
9230flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009231{
Eric Andersencb57d552001-06-28 07:25:16 +00009232 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009233 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009234 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009235 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009236}
9237
Eric Andersenc470f442003-07-28 09:56:35 +00009238void
Eric Andersen16767e22004-03-16 05:14:10 +00009239flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009240{
9241 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009242 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009243 INTON;
9244}
9245
9246static void
9247outcslow(int c, FILE *dest)
9248{
9249 INTOFF;
9250 putc(c, dest);
9251 fflush(dest);
9252 INTON;
9253}
9254
9255
9256static int
9257out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009258{
9259 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009260 int r;
9261
9262 INTOFF;
9263 va_start(ap, fmt);
9264 r = vprintf(fmt, ap);
9265 va_end(ap);
9266 INTON;
9267 return r;
9268}
9269
9270
9271int
9272fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9273{
9274 va_list ap;
9275 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009276
Eric Andersencb57d552001-06-28 07:25:16 +00009277 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009278 INTOFF;
9279 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009280 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009281 INTON;
9282 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009283}
9284
Eric Andersenc470f442003-07-28 09:56:35 +00009285
Eric Andersencb57d552001-06-28 07:25:16 +00009286
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009287/* parser.c */
Eric Andersenc470f442003-07-28 09:56:35 +00009288
9289
Eric Andersencb57d552001-06-28 07:25:16 +00009290/*
9291 * Shell command parser.
9292 */
9293
9294#define EOFMARKLEN 79
9295
9296
Eric Andersencb57d552001-06-28 07:25:16 +00009297struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009298 struct heredoc *next; /* next here document in list */
9299 union node *here; /* redirection node */
9300 char *eofmark; /* string indicating end of input */
9301 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009302};
9303
9304
9305
Eric Andersenc470f442003-07-28 09:56:35 +00009306static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009307
9308
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009309static union node *list(int);
9310static union node *andor(void);
9311static union node *pipeline(void);
9312static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009313static union node *simplecmd(void);
9314static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009315static void parsefname(void);
9316static void parseheredoc(void);
9317static char peektoken(void);
9318static int readtoken(void);
9319static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009320static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009321static int noexpand(char *);
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00009322static void synexpect(int) ATTRIBUTE_NORETURN;
9323static void synerror(const char *) ATTRIBUTE_NORETURN;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009324static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009325
9326
Eric Andersenc470f442003-07-28 09:56:35 +00009327
Eric Andersenc470f442003-07-28 09:56:35 +00009328
Eric Andersencb57d552001-06-28 07:25:16 +00009329/*
9330 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9331 * valid parse tree indicating a blank line.)
9332 */
9333
Eric Andersenc470f442003-07-28 09:56:35 +00009334union node *
9335parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009336{
9337 int t;
9338
9339 tokpushback = 0;
9340 doprompt = interact;
9341 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009342 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009343 needprompt = 0;
9344 t = readtoken();
9345 if (t == TEOF)
9346 return NEOF;
9347 if (t == TNL)
9348 return NULL;
9349 tokpushback++;
9350 return list(1);
9351}
9352
9353
Eric Andersenc470f442003-07-28 09:56:35 +00009354static union node *
9355list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009356{
9357 union node *n1, *n2, *n3;
9358 int tok;
9359
Eric Andersenc470f442003-07-28 09:56:35 +00009360 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9361 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009362 return NULL;
9363 n1 = NULL;
9364 for (;;) {
9365 n2 = andor();
9366 tok = readtoken();
9367 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009368 if (n2->type == NPIPE) {
9369 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009370 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009371 if (n2->type != NREDIR) {
9372 n3 = stalloc(sizeof(struct nredir));
9373 n3->nredir.n = n2;
9374 n3->nredir.redirect = NULL;
9375 n2 = n3;
9376 }
9377 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009378 }
9379 }
9380 if (n1 == NULL) {
9381 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009382 }
9383 else {
9384 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009385 n3->type = NSEMI;
9386 n3->nbinary.ch1 = n1;
9387 n3->nbinary.ch2 = n2;
9388 n1 = n3;
9389 }
9390 switch (tok) {
9391 case TBACKGND:
9392 case TSEMI:
9393 tok = readtoken();
9394 /* fall through */
9395 case TNL:
9396 if (tok == TNL) {
9397 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009398 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009399 return n1;
9400 } else {
9401 tokpushback++;
9402 }
Eric Andersenc470f442003-07-28 09:56:35 +00009403 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009404 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009405 return n1;
9406 break;
9407 case TEOF:
9408 if (heredoclist)
9409 parseheredoc();
9410 else
Eric Andersenc470f442003-07-28 09:56:35 +00009411 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009412 return n1;
9413 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009414 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009415 synexpect(-1);
9416 tokpushback++;
9417 return n1;
9418 }
9419 }
9420}
9421
9422
9423
Eric Andersenc470f442003-07-28 09:56:35 +00009424static union node *
9425andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009426{
Eric Andersencb57d552001-06-28 07:25:16 +00009427 union node *n1, *n2, *n3;
9428 int t;
9429
Eric Andersencb57d552001-06-28 07:25:16 +00009430 n1 = pipeline();
9431 for (;;) {
9432 if ((t = readtoken()) == TAND) {
9433 t = NAND;
9434 } else if (t == TOR) {
9435 t = NOR;
9436 } else {
9437 tokpushback++;
9438 return n1;
9439 }
Eric Andersenc470f442003-07-28 09:56:35 +00009440 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009441 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009442 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009443 n3->type = t;
9444 n3->nbinary.ch1 = n1;
9445 n3->nbinary.ch2 = n2;
9446 n1 = n3;
9447 }
9448}
9449
9450
9451
Eric Andersenc470f442003-07-28 09:56:35 +00009452static union node *
9453pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009454{
Eric Andersencb57d552001-06-28 07:25:16 +00009455 union node *n1, *n2, *pipenode;
9456 struct nodelist *lp, *prev;
9457 int negate;
9458
9459 negate = 0;
9460 TRACE(("pipeline: entered\n"));
9461 if (readtoken() == TNOT) {
9462 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009463 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009464 } else
9465 tokpushback++;
9466 n1 = command();
9467 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009468 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009469 pipenode->type = NPIPE;
9470 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009471 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009472 pipenode->npipe.cmdlist = lp;
9473 lp->n = n1;
9474 do {
9475 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009476 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9477 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009478 lp->n = command();
9479 prev->next = lp;
9480 } while (readtoken() == TPIPE);
9481 lp->next = NULL;
9482 n1 = pipenode;
9483 }
9484 tokpushback++;
9485 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009486 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009487 n2->type = NNOT;
9488 n2->nnot.com = n1;
9489 return n2;
9490 } else
9491 return n1;
9492}
9493
9494
9495
Eric Andersenc470f442003-07-28 09:56:35 +00009496static union node *
9497command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009498{
Eric Andersencb57d552001-06-28 07:25:16 +00009499 union node *n1, *n2;
9500 union node *ap, **app;
9501 union node *cp, **cpp;
9502 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009503 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009504 int t;
9505
9506 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009507 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009508
Eric Andersencb57d552001-06-28 07:25:16 +00009509 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009510 default:
9511 synexpect(-1);
9512 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009513 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009514 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009515 n1->type = NIF;
9516 n1->nif.test = list(0);
9517 if (readtoken() != TTHEN)
9518 synexpect(TTHEN);
9519 n1->nif.ifpart = list(0);
9520 n2 = n1;
9521 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009522 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009523 n2 = n2->nif.elsepart;
9524 n2->type = NIF;
9525 n2->nif.test = list(0);
9526 if (readtoken() != TTHEN)
9527 synexpect(TTHEN);
9528 n2->nif.ifpart = list(0);
9529 }
9530 if (lasttoken == TELSE)
9531 n2->nif.elsepart = list(0);
9532 else {
9533 n2->nif.elsepart = NULL;
9534 tokpushback++;
9535 }
Eric Andersenc470f442003-07-28 09:56:35 +00009536 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009537 break;
9538 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009539 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009540 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009541 n1 = (union node *)stalloc(sizeof (struct nbinary));
9542 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009543 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009544 if ((got=readtoken()) != TDO) {
9545TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009546 synexpect(TDO);
9547 }
9548 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009549 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009550 break;
9551 }
9552 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009553 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009554 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009555 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009556 n1->type = NFOR;
9557 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009558 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009559 if (readtoken() == TIN) {
9560 app = &ap;
9561 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009562 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009563 n2->type = NARG;
9564 n2->narg.text = wordtext;
9565 n2->narg.backquote = backquotelist;
9566 *app = n2;
9567 app = &n2->narg.next;
9568 }
9569 *app = NULL;
9570 n1->nfor.args = ap;
9571 if (lasttoken != TNL && lasttoken != TSEMI)
9572 synexpect(-1);
9573 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009574 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009575 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009576 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009577 n2->narg.backquote = NULL;
9578 n2->narg.next = NULL;
9579 n1->nfor.args = n2;
9580 /*
9581 * Newline or semicolon here is optional (but note
9582 * that the original Bourne shell only allowed NL).
9583 */
9584 if (lasttoken != TNL && lasttoken != TSEMI)
9585 tokpushback++;
9586 }
Eric Andersenc470f442003-07-28 09:56:35 +00009587 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009588 if (readtoken() != TDO)
9589 synexpect(TDO);
9590 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009591 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009592 break;
9593 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009594 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009595 n1->type = NCASE;
9596 if (readtoken() != TWORD)
9597 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009598 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009599 n2->type = NARG;
9600 n2->narg.text = wordtext;
9601 n2->narg.backquote = backquotelist;
9602 n2->narg.next = NULL;
9603 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009604 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009605 } while (readtoken() == TNL);
9606 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009607 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009608 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009609next_case:
9610 checkkwd = CHKNL | CHKKWD;
9611 t = readtoken();
9612 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009613 if (lasttoken == TLP)
9614 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009615 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009616 cp->type = NCLIST;
9617 app = &cp->nclist.pattern;
9618 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009619 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009620 ap->type = NARG;
9621 ap->narg.text = wordtext;
9622 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009623 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009624 break;
9625 app = &ap->narg.next;
9626 readtoken();
9627 }
9628 ap->narg.next = NULL;
9629 if (lasttoken != TRP)
9630 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009631 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009632
Eric Andersenc470f442003-07-28 09:56:35 +00009633 cpp = &cp->nclist.next;
9634
9635 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009636 if ((t = readtoken()) != TESAC) {
9637 if (t != TENDCASE)
9638 synexpect(TENDCASE);
9639 else
Eric Andersenc470f442003-07-28 09:56:35 +00009640 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009641 }
Eric Andersenc470f442003-07-28 09:56:35 +00009642 }
Eric Andersencb57d552001-06-28 07:25:16 +00009643 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009644 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009645 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009646 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009647 n1->type = NSUBSHELL;
9648 n1->nredir.n = list(0);
9649 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009650 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009651 break;
9652 case TBEGIN:
9653 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009654 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009655 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009656 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009657 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009658 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009659 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009660 }
9661
Eric Andersenc470f442003-07-28 09:56:35 +00009662 if (readtoken() != t)
9663 synexpect(t);
9664
9665redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009666 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009667 checkkwd = CHKKWD | CHKALIAS;
9668 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009669 while (readtoken() == TREDIR) {
9670 *rpp = n2 = redirnode;
9671 rpp = &n2->nfile.next;
9672 parsefname();
9673 }
9674 tokpushback++;
9675 *rpp = NULL;
9676 if (redir) {
9677 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009678 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009679 n2->type = NREDIR;
9680 n2->nredir.n = n1;
9681 n1 = n2;
9682 }
9683 n1->nredir.redirect = redir;
9684 }
9685
9686 return n1;
9687}
9688
9689
Eric Andersenc470f442003-07-28 09:56:35 +00009690static union node *
9691simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009692 union node *args, **app;
9693 union node *n = NULL;
9694 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009695 union node **rpp, *redir;
9696 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009697
9698 args = NULL;
9699 app = &args;
9700 vars = NULL;
9701 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009702 redir = NULL;
9703 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009704
Eric Andersenc470f442003-07-28 09:56:35 +00009705 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009706 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009707 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009708 switch (readtoken()) {
9709 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009710 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009711 n->type = NARG;
9712 n->narg.text = wordtext;
9713 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009714 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009715 *vpp = n;
9716 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009717 } else {
9718 *app = n;
9719 app = &n->narg.next;
9720 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009721 }
9722 break;
9723 case TREDIR:
9724 *rpp = n = redirnode;
9725 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009726 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009727 break;
9728 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009729 if (
9730 args && app == &args->narg.next &&
9731 !vars && !redir
9732 ) {
9733 struct builtincmd *bcmd;
9734 const char *name;
9735
Eric Andersencb57d552001-06-28 07:25:16 +00009736 /* We have a function */
9737 if (readtoken() != TRP)
9738 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009739 name = n->narg.text;
9740 if (
9741 !goodname(name) || (
9742 (bcmd = find_builtin(name)) &&
9743 IS_BUILTIN_SPECIAL(bcmd)
9744 )
9745 )
9746 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009747 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009748 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009749 n->narg.next = command();
9750 return n;
9751 }
9752 /* fall through */
9753 default:
9754 tokpushback++;
9755 goto out;
9756 }
9757 }
Eric Andersenc470f442003-07-28 09:56:35 +00009758out:
Eric Andersencb57d552001-06-28 07:25:16 +00009759 *app = NULL;
9760 *vpp = NULL;
9761 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009762 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009763 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009764 n->ncmd.args = args;
9765 n->ncmd.assign = vars;
9766 n->ncmd.redirect = redir;
9767 return n;
9768}
9769
Eric Andersenc470f442003-07-28 09:56:35 +00009770static union node *
9771makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009772{
Eric Andersencb57d552001-06-28 07:25:16 +00009773 union node *n;
9774
Eric Andersenc470f442003-07-28 09:56:35 +00009775 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009776 n->type = NARG;
9777 n->narg.next = NULL;
9778 n->narg.text = wordtext;
9779 n->narg.backquote = backquotelist;
9780 return n;
9781}
9782
Eric Andersenc470f442003-07-28 09:56:35 +00009783void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009784{
Eric Andersencb57d552001-06-28 07:25:16 +00009785 TRACE(("Fix redir %s %d\n", text, err));
9786 if (!err)
9787 n->ndup.vname = NULL;
9788
9789 if (is_digit(text[0]) && text[1] == '\0')
9790 n->ndup.dupfd = digit_val(text[0]);
9791 else if (text[0] == '-' && text[1] == '\0')
9792 n->ndup.dupfd = -1;
9793 else {
9794
9795 if (err)
9796 synerror("Bad fd number");
9797 else
9798 n->ndup.vname = makename();
9799 }
9800}
9801
9802
Eric Andersenc470f442003-07-28 09:56:35 +00009803static void
9804parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009805{
Eric Andersencb57d552001-06-28 07:25:16 +00009806 union node *n = redirnode;
9807
9808 if (readtoken() != TWORD)
9809 synexpect(-1);
9810 if (n->type == NHERE) {
9811 struct heredoc *here = heredoc;
9812 struct heredoc *p;
9813 int i;
9814
9815 if (quoteflag == 0)
9816 n->type = NXHERE;
9817 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009818 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009819 synerror("Illegal eof marker for << redirection");
9820 rmescapes(wordtext);
9821 here->eofmark = wordtext;
9822 here->next = NULL;
9823 if (heredoclist == NULL)
9824 heredoclist = here;
9825 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009826 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009827 p->next = here;
9828 }
9829 } else if (n->type == NTOFD || n->type == NFROMFD) {
9830 fixredir(n, wordtext, 0);
9831 } else {
9832 n->nfile.fname = makename();
9833 }
9834}
9835
9836
9837/*
9838 * Input any here documents.
9839 */
9840
Eric Andersenc470f442003-07-28 09:56:35 +00009841static void
9842parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009843{
Eric Andersencb57d552001-06-28 07:25:16 +00009844 struct heredoc *here;
9845 union node *n;
9846
Eric Andersenc470f442003-07-28 09:56:35 +00009847 here = heredoclist;
9848 heredoclist = 0;
9849
9850 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009851 if (needprompt) {
9852 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009853 }
Eric Andersenc470f442003-07-28 09:56:35 +00009854 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9855 here->eofmark, here->striptabs);
9856 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009857 n->narg.type = NARG;
9858 n->narg.next = NULL;
9859 n->narg.text = wordtext;
9860 n->narg.backquote = backquotelist;
9861 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009862 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009863 }
9864}
9865
Eric Andersenc470f442003-07-28 09:56:35 +00009866static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009867{
Eric Andersencb57d552001-06-28 07:25:16 +00009868 int t;
9869
9870 t = readtoken();
9871 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009872 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009873}
9874
Eric Andersenc470f442003-07-28 09:56:35 +00009875static int
9876readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009877{
Eric Andersencb57d552001-06-28 07:25:16 +00009878 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009879#ifdef DEBUG
9880 int alreadyseen = tokpushback;
9881#endif
9882
Eric Andersend35c5df2002-01-09 15:37:36 +00009883#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009884top:
Eric Andersen2870d962001-07-02 17:27:21 +00009885#endif
9886
Eric Andersencb57d552001-06-28 07:25:16 +00009887 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009888
Eric Andersenc470f442003-07-28 09:56:35 +00009889 /*
9890 * eat newlines
9891 */
9892 if (checkkwd & CHKNL) {
9893 while (t == TNL) {
9894 parseheredoc();
9895 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009896 }
9897 }
9898
Eric Andersenc470f442003-07-28 09:56:35 +00009899 if (t != TWORD || quoteflag) {
9900 goto out;
9901 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009902
Eric Andersenc470f442003-07-28 09:56:35 +00009903 /*
9904 * check for keywords
9905 */
9906 if (checkkwd & CHKKWD) {
9907 const char *const *pp;
9908
9909 if ((pp = findkwd(wordtext))) {
9910 lasttoken = t = pp - tokname_array;
9911 TRACE(("keyword %s recognized\n", tokname(t)));
9912 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009913 }
Eric Andersenc470f442003-07-28 09:56:35 +00009914 }
9915
9916 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009917#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009918 struct alias *ap;
9919 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009920 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009921 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009922 }
Eric Andersencb57d552001-06-28 07:25:16 +00009923 goto top;
9924 }
Eric Andersen2870d962001-07-02 17:27:21 +00009925#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009926 }
Eric Andersenc470f442003-07-28 09:56:35 +00009927out:
9928 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009929#ifdef DEBUG
9930 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009931 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009932 else
Eric Andersenc470f442003-07-28 09:56:35 +00009933 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009934#endif
9935 return (t);
9936}
9937
9938
9939/*
9940 * Read the next input token.
9941 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009942 * backquotes. We set quoteflag to true if any part of the word was
9943 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009944 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009945 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009946 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009947 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009948 *
9949 * [Change comment: here documents and internal procedures]
9950 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9951 * word parsing code into a separate routine. In this case, readtoken
9952 * doesn't need to have any internal procedures, but parseword does.
9953 * We could also make parseoperator in essence the main routine, and
9954 * have parseword (readtoken1?) handle both words and redirection.]
9955 */
9956
Eric Andersen81fe1232003-07-29 06:38:40 +00009957#define NEW_xxreadtoken
9958#ifdef NEW_xxreadtoken
9959
9960/* singles must be first! */
9961static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9962
9963static const char xxreadtoken_tokens[] = {
9964 TNL, TLP, TRP, /* only single occurrence allowed */
9965 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9966 TEOF, /* corresponds to trailing nul */
9967 TAND, TOR, TENDCASE, /* if double occurrence */
9968};
9969
9970#define xxreadtoken_doubles \
9971 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9972#define xxreadtoken_singles \
9973 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9974
9975static int xxreadtoken()
9976{
9977 int c;
9978
9979 if (tokpushback) {
9980 tokpushback = 0;
9981 return lasttoken;
9982 }
9983 if (needprompt) {
9984 setprompt(2);
Eric Andersen81fe1232003-07-29 06:38:40 +00009985 }
9986 startlinno = plinno;
9987 for (;;) { /* until token or start of word found */
9988 c = pgetc_macro();
9989
9990 if ((c != ' ') && (c != '\t')
9991#ifdef CONFIG_ASH_ALIAS
9992 && (c != PEOA)
9993#endif
9994 ) {
9995 if (c == '#') {
9996 while ((c = pgetc()) != '\n' && c != PEOF);
9997 pungetc();
9998 } else if (c == '\\') {
9999 if (pgetc() != '\n') {
10000 pungetc();
10001 goto READTOKEN1;
10002 }
10003 startlinno = ++plinno;
10004 if (doprompt)
10005 setprompt(2);
10006 } else {
10007 const char *p
10008 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10009
10010 if (c != PEOF) {
10011 if (c == '\n') {
10012 plinno++;
10013 needprompt = doprompt;
10014 }
10015
10016 p = strchr(xxreadtoken_chars, c);
10017 if (p == NULL) {
10018 READTOKEN1:
10019 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10020 }
10021
10022 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10023 if (pgetc() == *p) { /* double occurrence? */
10024 p += xxreadtoken_doubles + 1;
10025 } else {
10026 pungetc();
10027 }
10028 }
10029 }
10030
10031 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10032 }
10033 }
10034 }
10035}
10036
10037
10038#else
Eric Andersen2870d962001-07-02 17:27:21 +000010039#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010040
Eric Andersenc470f442003-07-28 09:56:35 +000010041static int
10042xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010043{
Eric Andersencb57d552001-06-28 07:25:16 +000010044 int c;
10045
10046 if (tokpushback) {
10047 tokpushback = 0;
10048 return lasttoken;
10049 }
10050 if (needprompt) {
10051 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010052 }
10053 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010054 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010055 c = pgetc_macro();
10056 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010057 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010058#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010059 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010060#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010061 continue;
10062 case '#':
10063 while ((c = pgetc()) != '\n' && c != PEOF);
10064 pungetc();
10065 continue;
10066 case '\\':
10067 if (pgetc() == '\n') {
10068 startlinno = ++plinno;
10069 if (doprompt)
10070 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010071 continue;
10072 }
10073 pungetc();
10074 goto breakloop;
10075 case '\n':
10076 plinno++;
10077 needprompt = doprompt;
10078 RETURN(TNL);
10079 case PEOF:
10080 RETURN(TEOF);
10081 case '&':
10082 if (pgetc() == '&')
10083 RETURN(TAND);
10084 pungetc();
10085 RETURN(TBACKGND);
10086 case '|':
10087 if (pgetc() == '|')
10088 RETURN(TOR);
10089 pungetc();
10090 RETURN(TPIPE);
10091 case ';':
10092 if (pgetc() == ';')
10093 RETURN(TENDCASE);
10094 pungetc();
10095 RETURN(TSEMI);
10096 case '(':
10097 RETURN(TLP);
10098 case ')':
10099 RETURN(TRP);
10100 default:
10101 goto breakloop;
10102 }
10103 }
Eric Andersenc470f442003-07-28 09:56:35 +000010104breakloop:
10105 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010106#undef RETURN
10107}
Eric Andersen81fe1232003-07-29 06:38:40 +000010108#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010109
Eric Andersencb57d552001-06-28 07:25:16 +000010110
Eric Andersencb57d552001-06-28 07:25:16 +000010111/*
10112 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10113 * is not NULL, read a here document. In the latter case, eofmark is the
10114 * word which marks the end of the document and striptabs is true if
10115 * leading tabs should be stripped from the document. The argument firstc
10116 * is the first character of the input token or document.
10117 *
10118 * Because C does not have internal subroutines, I have simulated them
10119 * using goto's to implement the subroutine linkage. The following macros
10120 * will run code that appears at the end of readtoken1.
10121 */
10122
Eric Andersen2870d962001-07-02 17:27:21 +000010123#define CHECKEND() {goto checkend; checkend_return:;}
10124#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10125#define PARSESUB() {goto parsesub; parsesub_return:;}
10126#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10127#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10128#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010129
10130static int
Eric Andersenc470f442003-07-28 09:56:35 +000010131readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010132{
Eric Andersencb57d552001-06-28 07:25:16 +000010133 int c = firstc;
10134 char *out;
10135 int len;
10136 char line[EOFMARKLEN + 1];
Eric Andersena68ea1c2006-01-30 22:48:39 +000010137 struct nodelist *bqlist = 0;
10138 int quotef = 0;
10139 int dblquote = 0;
10140 int varnest = 0; /* levels of variables expansion */
10141 int arinest = 0; /* levels of arithmetic expansion */
10142 int parenlevel = 0; /* levels of parens in arithmetic */
10143 int dqvarnest = 0; /* levels of variables expansion within double quotes */
10144 int oldstyle = 0;
10145 int prevsyntax = 0; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010146#if __GNUC__
10147 /* Avoid longjmp clobbering */
10148 (void) &out;
10149 (void) &quotef;
10150 (void) &dblquote;
10151 (void) &varnest;
10152 (void) &arinest;
10153 (void) &parenlevel;
10154 (void) &dqvarnest;
10155 (void) &oldstyle;
10156 (void) &prevsyntax;
10157 (void) &syntax;
10158#endif
10159
10160 startlinno = plinno;
10161 dblquote = 0;
10162 if (syntax == DQSYNTAX)
10163 dblquote = 1;
10164 quotef = 0;
10165 bqlist = NULL;
10166 varnest = 0;
10167 arinest = 0;
10168 parenlevel = 0;
10169 dqvarnest = 0;
10170
10171 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010172 loop: { /* for each line, until end of word */
10173 CHECKEND(); /* set c to PEOF if at end of here document */
10174 for (;;) { /* until end of line or end of word */
10175 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10176 switch(SIT(c, syntax)) {
10177 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010178 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010179 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010180 USTPUTC(c, out);
10181 plinno++;
10182 if (doprompt)
10183 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010184 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010185 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010186 case CWORD:
10187 USTPUTC(c, out);
10188 break;
10189 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010190 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010191 USTPUTC(CTLESC, out);
10192 USTPUTC(c, out);
10193 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010194 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010195 c = pgetc2();
10196 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010197 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010198 USTPUTC('\\', out);
10199 pungetc();
10200 } else if (c == '\n') {
10201 if (doprompt)
10202 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010203 } else {
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010204 if (dblquote &&
Eric Andersenc470f442003-07-28 09:56:35 +000010205 c != '\\' && c != '`' &&
10206 c != '$' && (
10207 c != '"' ||
"Vladimir N. Oleynik"84005af2006-01-25 17:53:04 +000010208 eofmark != NULL)
Eric Andersenc470f442003-07-28 09:56:35 +000010209 ) {
10210 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010211 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010212 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010213 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010214 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010215 USTPUTC(c, out);
10216 quotef++;
10217 }
10218 break;
10219 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010220 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010221quotemark:
10222 if (eofmark == NULL) {
10223 USTPUTC(CTLQUOTEMARK, out);
10224 }
Eric Andersencb57d552001-06-28 07:25:16 +000010225 break;
10226 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010227 syntax = DQSYNTAX;
10228 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010229 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010230 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010231 if (eofmark != NULL && arinest == 0 &&
10232 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010233 USTPUTC(c, out);
10234 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010235 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010236 syntax = BASESYNTAX;
10237 dblquote = 0;
10238 }
10239 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010240 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010241 }
10242 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010243 case CVAR: /* '$' */
10244 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010245 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010246 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010247 if (varnest > 0) {
10248 varnest--;
10249 if (dqvarnest > 0) {
10250 dqvarnest--;
10251 }
10252 USTPUTC(CTLENDVAR, out);
10253 } else {
10254 USTPUTC(c, out);
10255 }
10256 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010257#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010258 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010259 parenlevel++;
10260 USTPUTC(c, out);
10261 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010262 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010263 if (parenlevel > 0) {
10264 USTPUTC(c, out);
10265 --parenlevel;
10266 } else {
10267 if (pgetc() == ')') {
10268 if (--arinest == 0) {
10269 USTPUTC(CTLENDARI, out);
10270 syntax = prevsyntax;
10271 if (syntax == DQSYNTAX)
10272 dblquote = 1;
10273 else
10274 dblquote = 0;
10275 } else
10276 USTPUTC(')', out);
10277 } else {
10278 /*
10279 * unbalanced parens
10280 * (don't 2nd guess - no error)
10281 */
10282 pungetc();
10283 USTPUTC(')', out);
10284 }
10285 }
10286 break;
10287#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010288 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010289 PARSEBACKQOLD();
10290 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010291 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010292 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010293 case CIGN:
10294 break;
10295 default:
10296 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010297 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010298#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010299 if (c != PEOA)
10300#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010301 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010302
Eric Andersencb57d552001-06-28 07:25:16 +000010303 }
10304 c = pgetc_macro();
10305 }
10306 }
Eric Andersenc470f442003-07-28 09:56:35 +000010307endword:
10308#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010309 if (syntax == ARISYNTAX)
10310 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010311#endif
10312 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010313 synerror("Unterminated quoted string");
10314 if (varnest != 0) {
10315 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010316 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010317 synerror("Missing '}'");
10318 }
10319 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010320 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010321 out = stackblock();
10322 if (eofmark == NULL) {
10323 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010324 && quotef == 0
10325 && len <= 2
10326 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010327 PARSEREDIR();
10328 return lasttoken = TREDIR;
10329 } else {
10330 pungetc();
10331 }
10332 }
10333 quoteflag = quotef;
10334 backquotelist = bqlist;
10335 grabstackblock(len);
10336 wordtext = out;
10337 return lasttoken = TWORD;
10338/* end of readtoken routine */
10339
10340
10341
10342/*
10343 * Check to see whether we are at the end of the here document. When this
10344 * is called, c is set to the first character of the next input line. If
10345 * we are at the end of the here document, this routine sets the c to PEOF.
10346 */
10347
Eric Andersenc470f442003-07-28 09:56:35 +000010348checkend: {
10349 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010350#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010351 if (c == PEOA) {
10352 c = pgetc2();
10353 }
10354#endif
10355 if (striptabs) {
10356 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010357 c = pgetc2();
10358 }
Eric Andersenc470f442003-07-28 09:56:35 +000010359 }
10360 if (c == *eofmark) {
10361 if (pfgets(line, sizeof line) != NULL) {
10362 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010363
Eric Andersenc470f442003-07-28 09:56:35 +000010364 p = line;
10365 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10366 if (*p == '\n' && *q == '\0') {
10367 c = PEOF;
10368 plinno++;
10369 needprompt = doprompt;
10370 } else {
10371 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010372 }
10373 }
10374 }
10375 }
Eric Andersenc470f442003-07-28 09:56:35 +000010376 goto checkend_return;
10377}
Eric Andersencb57d552001-06-28 07:25:16 +000010378
10379
10380/*
10381 * Parse a redirection operator. The variable "out" points to a string
10382 * specifying the fd to be redirected. The variable "c" contains the
10383 * first character of the redirection operator.
10384 */
10385
Eric Andersenc470f442003-07-28 09:56:35 +000010386parseredir: {
10387 char fd = *out;
10388 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010389
Eric Andersenc470f442003-07-28 09:56:35 +000010390 np = (union node *)stalloc(sizeof (struct nfile));
10391 if (c == '>') {
10392 np->nfile.fd = 1;
10393 c = pgetc();
10394 if (c == '>')
10395 np->type = NAPPEND;
10396 else if (c == '|')
10397 np->type = NCLOBBER;
10398 else if (c == '&')
10399 np->type = NTOFD;
10400 else {
10401 np->type = NTO;
10402 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010403 }
Eric Andersenc470f442003-07-28 09:56:35 +000010404 } else { /* c == '<' */
10405 np->nfile.fd = 0;
10406 switch (c = pgetc()) {
10407 case '<':
10408 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10409 np = (union node *)stalloc(sizeof (struct nhere));
10410 np->nfile.fd = 0;
10411 }
10412 np->type = NHERE;
10413 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10414 heredoc->here = np;
10415 if ((c = pgetc()) == '-') {
10416 heredoc->striptabs = 1;
10417 } else {
10418 heredoc->striptabs = 0;
10419 pungetc();
10420 }
10421 break;
10422
10423 case '&':
10424 np->type = NFROMFD;
10425 break;
10426
10427 case '>':
10428 np->type = NFROMTO;
10429 break;
10430
10431 default:
10432 np->type = NFROM;
10433 pungetc();
10434 break;
10435 }
Eric Andersencb57d552001-06-28 07:25:16 +000010436 }
Eric Andersenc470f442003-07-28 09:56:35 +000010437 if (fd != '\0')
10438 np->nfile.fd = digit_val(fd);
10439 redirnode = np;
10440 goto parseredir_return;
10441}
Eric Andersencb57d552001-06-28 07:25:16 +000010442
10443
10444/*
10445 * Parse a substitution. At this point, we have read the dollar sign
10446 * and nothing else.
10447 */
10448
Eric Andersenc470f442003-07-28 09:56:35 +000010449parsesub: {
10450 int subtype;
10451 int typeloc;
10452 int flags;
10453 char *p;
10454 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010455
Eric Andersenc470f442003-07-28 09:56:35 +000010456 c = pgetc();
10457 if (
10458 c <= PEOA_OR_PEOF ||
10459 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10460 ) {
10461 USTPUTC('$', out);
10462 pungetc();
10463 } else if (c == '(') { /* $(command) or $((arith)) */
10464 if (pgetc() == '(') {
10465#ifdef CONFIG_ASH_MATH_SUPPORT
10466 PARSEARITH();
10467#else
10468 synerror("We unsupport $((arith))");
10469#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010470 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010471 pungetc();
10472 PARSEBACKQNEW();
10473 }
10474 } else {
10475 USTPUTC(CTLVAR, out);
10476 typeloc = out - (char *)stackblock();
10477 USTPUTC(VSNORMAL, out);
10478 subtype = VSNORMAL;
10479 if (c == '{') {
10480 c = pgetc();
10481 if (c == '#') {
10482 if ((c = pgetc()) == '}')
10483 c = '#';
10484 else
10485 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010486 }
Eric Andersenc470f442003-07-28 09:56:35 +000010487 else
10488 subtype = 0;
10489 }
10490 if (c > PEOA_OR_PEOF && is_name(c)) {
10491 do {
10492 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010493 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010494 } while (c > PEOA_OR_PEOF && is_in_name(c));
10495 } else if (is_digit(c)) {
10496 do {
10497 STPUTC(c, out);
10498 c = pgetc();
10499 } while (is_digit(c));
10500 }
10501 else if (is_special(c)) {
10502 USTPUTC(c, out);
10503 c = pgetc();
10504 }
10505 else
10506badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010507
Eric Andersenc470f442003-07-28 09:56:35 +000010508 STPUTC('=', out);
10509 flags = 0;
10510 if (subtype == 0) {
10511 switch (c) {
10512 case ':':
10513 flags = VSNUL;
10514 c = pgetc();
10515 /*FALLTHROUGH*/
10516 default:
10517 p = strchr(types, c);
10518 if (p == NULL)
10519 goto badsub;
10520 subtype = p - types + VSNORMAL;
10521 break;
10522 case '%':
10523 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010524 {
10525 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010526 subtype = c == '#' ? VSTRIMLEFT :
10527 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010528 c = pgetc();
10529 if (c == cc)
10530 subtype++;
10531 else
10532 pungetc();
10533 break;
10534 }
10535 }
Eric Andersenc470f442003-07-28 09:56:35 +000010536 } else {
10537 pungetc();
10538 }
10539 if (dblquote || arinest)
10540 flags |= VSQUOTE;
10541 *((char *)stackblock() + typeloc) = subtype | flags;
10542 if (subtype != VSNORMAL) {
10543 varnest++;
10544 if (dblquote || arinest) {
10545 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010546 }
10547 }
10548 }
Eric Andersenc470f442003-07-28 09:56:35 +000010549 goto parsesub_return;
10550}
Eric Andersencb57d552001-06-28 07:25:16 +000010551
10552
10553/*
10554 * Called to parse command substitutions. Newstyle is set if the command
10555 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10556 * list of commands (passed by reference), and savelen is the number of
10557 * characters on the top of the stack which must be preserved.
10558 */
10559
Eric Andersenc470f442003-07-28 09:56:35 +000010560parsebackq: {
10561 struct nodelist **nlpp;
10562 int savepbq;
10563 union node *n;
10564 char *volatile str;
10565 struct jmploc jmploc;
10566 struct jmploc *volatile savehandler;
10567 size_t savelen;
Eric Andersena68ea1c2006-01-30 22:48:39 +000010568 int saveprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010569#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010570 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010571#endif
10572
Eric Andersenc470f442003-07-28 09:56:35 +000010573 savepbq = parsebackquote;
10574 if (setjmp(jmploc.loc)) {
10575 if (str)
10576 ckfree(str);
10577 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010578 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010579 longjmp(handler->loc, 1);
10580 }
10581 INTOFF;
10582 str = NULL;
10583 savelen = out - (char *)stackblock();
10584 if (savelen > 0) {
10585 str = ckmalloc(savelen);
10586 memcpy(str, stackblock(), savelen);
10587 }
10588 savehandler = handler;
10589 handler = &jmploc;
10590 INTON;
10591 if (oldstyle) {
10592 /* We must read until the closing backquote, giving special
10593 treatment to some slashes, and then push the string and
10594 reread it as input, interpreting it normally. */
10595 char *pout;
10596 int pc;
10597 size_t psavelen;
10598 char *pstr;
10599
10600
10601 STARTSTACKSTR(pout);
10602 for (;;) {
10603 if (needprompt) {
10604 setprompt(2);
Eric Andersenc470f442003-07-28 09:56:35 +000010605 }
10606 switch (pc = pgetc()) {
10607 case '`':
10608 goto done;
10609
10610 case '\\':
10611 if ((pc = pgetc()) == '\n') {
10612 plinno++;
10613 if (doprompt)
10614 setprompt(2);
10615 /*
10616 * If eating a newline, avoid putting
10617 * the newline into the new character
10618 * stream (via the STPUTC after the
10619 * switch).
10620 */
10621 continue;
10622 }
10623 if (pc != '\\' && pc != '`' && pc != '$'
10624 && (!dblquote || pc != '"'))
10625 STPUTC('\\', pout);
10626 if (pc > PEOA_OR_PEOF) {
10627 break;
10628 }
10629 /* fall through */
10630
10631 case PEOF:
10632#ifdef CONFIG_ASH_ALIAS
10633 case PEOA:
10634#endif
10635 startlinno = plinno;
10636 synerror("EOF in backquote substitution");
10637
10638 case '\n':
10639 plinno++;
10640 needprompt = doprompt;
10641 break;
10642
10643 default:
10644 break;
10645 }
10646 STPUTC(pc, pout);
10647 }
10648done:
10649 STPUTC('\0', pout);
10650 psavelen = pout - (char *)stackblock();
10651 if (psavelen > 0) {
10652 pstr = grabstackstr(pout);
10653 setinputstring(pstr);
10654 }
10655 }
10656 nlpp = &bqlist;
10657 while (*nlpp)
10658 nlpp = &(*nlpp)->next;
10659 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10660 (*nlpp)->next = NULL;
10661 parsebackquote = oldstyle;
10662
10663 if (oldstyle) {
10664 saveprompt = doprompt;
10665 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010666 }
10667
Eric Andersenc470f442003-07-28 09:56:35 +000010668 n = list(2);
10669
10670 if (oldstyle)
10671 doprompt = saveprompt;
10672 else {
10673 if (readtoken() != TRP)
10674 synexpect(TRP);
10675 }
10676
10677 (*nlpp)->n = n;
10678 if (oldstyle) {
10679 /*
10680 * Start reading from old file again, ignoring any pushed back
10681 * tokens left from the backquote parsing
10682 */
10683 popfile();
10684 tokpushback = 0;
10685 }
10686 while (stackblocksize() <= savelen)
10687 growstackblock();
10688 STARTSTACKSTR(out);
10689 if (str) {
10690 memcpy(out, str, savelen);
10691 STADJUST(savelen, out);
10692 INTOFF;
10693 ckfree(str);
10694 str = NULL;
10695 INTON;
10696 }
10697 parsebackquote = savepbq;
10698 handler = savehandler;
10699 if (arinest || dblquote)
10700 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10701 else
10702 USTPUTC(CTLBACKQ, out);
10703 if (oldstyle)
10704 goto parsebackq_oldreturn;
10705 else
10706 goto parsebackq_newreturn;
10707}
10708
10709#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010710/*
10711 * Parse an arithmetic expansion (indicate start of one and set state)
10712 */
Eric Andersenc470f442003-07-28 09:56:35 +000010713parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010714
Eric Andersenc470f442003-07-28 09:56:35 +000010715 if (++arinest == 1) {
10716 prevsyntax = syntax;
10717 syntax = ARISYNTAX;
10718 USTPUTC(CTLARI, out);
10719 if (dblquote)
10720 USTPUTC('"',out);
10721 else
10722 USTPUTC(' ',out);
10723 } else {
10724 /*
10725 * we collapse embedded arithmetic expansion to
10726 * parenthesis, which should be equivalent
10727 */
10728 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010729 }
Eric Andersenc470f442003-07-28 09:56:35 +000010730 goto parsearith_return;
10731}
10732#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010733
Eric Andersenc470f442003-07-28 09:56:35 +000010734} /* end of readtoken */
10735
Eric Andersencb57d552001-06-28 07:25:16 +000010736
10737
Eric Andersencb57d552001-06-28 07:25:16 +000010738/*
10739 * Returns true if the text contains nothing to expand (no dollar signs
10740 * or backquotes).
10741 */
10742
Eric Andersenc470f442003-07-28 09:56:35 +000010743static int
10744noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010745{
Eric Andersencb57d552001-06-28 07:25:16 +000010746 char *p;
10747 char c;
10748
10749 p = text;
10750 while ((c = *p++) != '\0') {
10751 if (c == CTLQUOTEMARK)
10752 continue;
10753 if (c == CTLESC)
10754 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010755 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010756 return 0;
10757 }
10758 return 1;
10759}
10760
10761
10762/*
Eric Andersenc470f442003-07-28 09:56:35 +000010763 * Return of a legal variable name (a letter or underscore followed by zero or
10764 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010765 */
10766
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010767static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010768endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010769{
Eric Andersenc470f442003-07-28 09:56:35 +000010770 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010771
Eric Andersenc470f442003-07-28 09:56:35 +000010772 p = (char *) name;
10773 if (! is_name(*p))
10774 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010775 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010776 if (! is_in_name(*p))
10777 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010778 }
Eric Andersenc470f442003-07-28 09:56:35 +000010779 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010780}
10781
10782
10783/*
10784 * Called when an unexpected token is read during the parse. The argument
10785 * is the token that is expected, or -1 if more than one type of token can
10786 * occur at this point.
10787 */
10788
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010789static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010790{
10791 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010792 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010793
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010794 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10795 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010796 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010797 synerror(msg);
10798 /* NOTREACHED */
10799}
10800
Eric Andersenc470f442003-07-28 09:56:35 +000010801static void
10802synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010803{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010804 sh_error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010805 /* NOTREACHED */
10806}
10807
Eric Andersencb57d552001-06-28 07:25:16 +000010808
10809/*
10810 * called by editline -- any expansions to the prompt
10811 * should be added here.
10812 */
Eric Andersenc470f442003-07-28 09:56:35 +000010813
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010814#ifdef CONFIG_ASH_EXPAND_PRMT
10815static const char *
10816expandstr(const char *ps)
10817{
10818 union node n;
10819
10820 /* XXX Fix (char *) cast. */
10821 setinputstring((char *)ps);
10822 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10823 popfile();
10824
10825 n.narg.type = NARG;
10826 n.narg.next = NULL;
10827 n.narg.text = wordtext;
10828 n.narg.backquote = backquotelist;
10829
10830 expandarg(&n, NULL, 0);
10831 return stackblock();
10832}
10833#endif
10834
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010835static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010836{
Eric Andersenc470f442003-07-28 09:56:35 +000010837 const char *prompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010838#ifdef CONFIG_ASH_EXPAND_PRMT
10839 struct stackmark smark;
10840#endif
10841
10842 needprompt = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010843
10844 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010845 case 1:
10846 prompt = ps1val();
10847 break;
10848 case 2:
10849 prompt = ps2val();
10850 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010851 default: /* 0 */
10852 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010853 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010854#ifdef CONFIG_ASH_EXPAND_PRMT
10855 setstackmark(&smark);
10856 stalloc(stackblocksize());
10857#endif
10858 putprompt(expandstr(prompt));
10859#ifdef CONFIG_ASH_EXPAND_PRMT
10860 popstackmark(&smark);
10861#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010862}
10863
Eric Andersencb57d552001-06-28 07:25:16 +000010864
Eric Andersenc470f442003-07-28 09:56:35 +000010865static const char *const *findkwd(const char *s)
10866{
10867 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010868 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010869 sizeof(const char *), pstrcmp);
10870}
10871
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010872/* redir.c */
Eric Andersenc470f442003-07-28 09:56:35 +000010873
Eric Andersencb57d552001-06-28 07:25:16 +000010874/*
10875 * Code for dealing with input/output redirection.
10876 */
10877
Eric Andersenc470f442003-07-28 09:56:35 +000010878#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010879#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010880# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010881#else
10882# define PIPESIZE PIPE_BUF
10883#endif
10884
Eric Andersen62483552001-07-10 06:09:16 +000010885/*
10886 * Open a file in noclobber mode.
10887 * The code was copied from bash.
10888 */
Eric Andersenc470f442003-07-28 09:56:35 +000010889static inline int
10890noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010891{
10892 int r, fd;
10893 struct stat finfo, finfo2;
10894
10895 /*
10896 * If the file exists and is a regular file, return an error
10897 * immediately.
10898 */
10899 r = stat(fname, &finfo);
10900 if (r == 0 && S_ISREG(finfo.st_mode)) {
10901 errno = EEXIST;
10902 return -1;
10903 }
10904
10905 /*
10906 * If the file was not present (r != 0), make sure we open it
10907 * exclusively so that if it is created before we open it, our open
10908 * will fail. Make sure that we do not truncate an existing file.
10909 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10910 * file was not a regular file, we leave O_EXCL off.
10911 */
10912 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010913 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10914 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010915
10916 /* If the open failed, return the file descriptor right away. */
10917 if (fd < 0)
10918 return fd;
10919
10920 /*
10921 * OK, the open succeeded, but the file may have been changed from a
10922 * non-regular file to a regular file between the stat and the open.
10923 * We are assuming that the O_EXCL open handles the case where FILENAME
10924 * did not exist and is symlinked to an existing file between the stat
10925 * and open.
10926 */
10927
10928 /*
10929 * If we can open it and fstat the file descriptor, and neither check
10930 * revealed that it was a regular file, and the file has not been
10931 * replaced, return the file descriptor.
10932 */
Eric Andersenc470f442003-07-28 09:56:35 +000010933 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10934 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010935 return fd;
10936
10937 /* The file has been replaced. badness. */
10938 close(fd);
10939 errno = EEXIST;
10940 return -1;
10941}
Eric Andersencb57d552001-06-28 07:25:16 +000010942
10943/*
Eric Andersen62483552001-07-10 06:09:16 +000010944 * Handle here documents. Normally we fork off a process to write the
10945 * data to a pipe. If the document is short, we can stuff the data in
10946 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010947 */
10948
Eric Andersenc470f442003-07-28 09:56:35 +000010949static inline int
10950openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010951{
10952 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010953 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010954
Eric Andersen62483552001-07-10 06:09:16 +000010955 if (pipe(pip) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010956 sh_error("Pipe call failed");
Eric Andersen62483552001-07-10 06:09:16 +000010957 if (redir->type == NHERE) {
10958 len = strlen(redir->nhere.doc->narg.text);
10959 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010960 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010961 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010962 }
Eric Andersencb57d552001-06-28 07:25:16 +000010963 }
Eric Andersenc470f442003-07-28 09:56:35 +000010964 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010965 close(pip[0]);
10966 signal(SIGINT, SIG_IGN);
10967 signal(SIGQUIT, SIG_IGN);
10968 signal(SIGHUP, SIG_IGN);
10969#ifdef SIGTSTP
10970 signal(SIGTSTP, SIG_IGN);
10971#endif
10972 signal(SIGPIPE, SIG_DFL);
10973 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000010974 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010975 else
10976 expandhere(redir->nhere.doc, pip[1]);
10977 _exit(0);
10978 }
Eric Andersenc470f442003-07-28 09:56:35 +000010979out:
Eric Andersen62483552001-07-10 06:09:16 +000010980 close(pip[1]);
10981 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010982}
10983
Eric Andersenc470f442003-07-28 09:56:35 +000010984static int
10985openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010986{
Eric Andersencb57d552001-06-28 07:25:16 +000010987 char *fname;
10988 int f;
10989
10990 switch (redir->nfile.type) {
10991 case NFROM:
10992 fname = redir->nfile.expfname;
10993 if ((f = open(fname, O_RDONLY)) < 0)
10994 goto eopen;
10995 break;
10996 case NFROMTO:
10997 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010998 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010999 goto ecreate;
11000 break;
11001 case NTO:
11002 /* Take care of noclobber mode. */
11003 if (Cflag) {
11004 fname = redir->nfile.expfname;
11005 if ((f = noclobberopen(fname)) < 0)
11006 goto ecreate;
11007 break;
11008 }
Eric Andersenc470f442003-07-28 09:56:35 +000011009 /* FALLTHROUGH */
11010 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011011 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011012 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011013 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011014 break;
11015 case NAPPEND:
11016 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011017 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011018 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011019 break;
11020 default:
11021#ifdef DEBUG
11022 abort();
11023#endif
11024 /* Fall through to eliminate warning. */
11025 case NTOFD:
11026 case NFROMFD:
11027 f = -1;
11028 break;
11029 case NHERE:
11030 case NXHERE:
11031 f = openhere(redir);
11032 break;
11033 }
11034
11035 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011036ecreate:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011037 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011038eopen:
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011039 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
Eric Andersencb57d552001-06-28 07:25:16 +000011040}
11041
Eric Andersenc470f442003-07-28 09:56:35 +000011042static inline void
11043dupredirect(union node *redir, int f)
11044{
11045 int fd = redir->nfile.fd;
11046
11047 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11048 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11049 copyfd(redir->ndup.dupfd, fd);
11050 }
11051 return;
11052 }
11053
11054 if (f != fd) {
11055 copyfd(f, fd);
11056 close(f);
11057 }
11058 return;
11059}
Eric Andersencb57d552001-06-28 07:25:16 +000011060
Eric Andersen62483552001-07-10 06:09:16 +000011061/*
11062 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11063 * old file descriptors are stashed away so that the redirection can be
11064 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11065 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011066 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011067 */
11068
Eric Andersenc470f442003-07-28 09:56:35 +000011069static void
11070redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011071{
11072 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011073 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011074 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011075 int fd;
11076 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011077 int *p;
11078 nullredirs++;
11079 if (!redir) {
11080 return;
Eric Andersen62483552001-07-10 06:09:16 +000011081 }
Eric Andersenc470f442003-07-28 09:56:35 +000011082 sv = NULL;
11083 INTOFF;
11084 if (flags & REDIR_PUSH) {
11085 struct redirtab *q;
11086 q = ckmalloc(sizeof (struct redirtab));
11087 q->next = redirlist;
11088 redirlist = q;
11089 q->nullredirs = nullredirs - 1;
11090 for (i = 0 ; i < 10 ; i++)
11091 q->renamed[i] = EMPTY;
11092 nullredirs = 0;
11093 sv = q;
11094 }
11095 n = redir;
11096 do {
Eric Andersen62483552001-07-10 06:09:16 +000011097 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011098 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011099 n->ndup.dupfd == fd)
11100 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011101
Eric Andersen62483552001-07-10 06:09:16 +000011102 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011103 if (fd == newfd)
11104 continue;
11105 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11106 i = fcntl(fd, F_DUPFD, 10);
11107
11108 if (i == -1) {
11109 i = errno;
11110 if (i != EBADF) {
11111 close(newfd);
11112 errno = i;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011113 sh_error("%d: %m", fd);
Eric Andersen62483552001-07-10 06:09:16 +000011114 /* NOTREACHED */
11115 }
Eric Andersenc470f442003-07-28 09:56:35 +000011116 } else {
11117 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011118 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011119 }
Eric Andersenc470f442003-07-28 09:56:35 +000011120 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011121 close(fd);
11122 }
Eric Andersenc470f442003-07-28 09:56:35 +000011123 dupredirect(n, newfd);
11124 } while ((n = n->nfile.next));
11125 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011126 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11127 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011128}
11129
11130
Eric Andersencb57d552001-06-28 07:25:16 +000011131/*
11132 * Undo the effects of the last redirection.
11133 */
11134
Eric Andersenc470f442003-07-28 09:56:35 +000011135void
11136popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011137{
Eric Andersenc470f442003-07-28 09:56:35 +000011138 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011139 int i;
11140
Eric Andersenc470f442003-07-28 09:56:35 +000011141 if (--nullredirs >= 0)
11142 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011143 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011144 rp = redirlist;
11145 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011146 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011147 if (!drop) {
11148 close(i);
11149 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011150 }
Eric Andersenc470f442003-07-28 09:56:35 +000011151 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011152 }
11153 }
11154 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011155 nullredirs = rp->nullredirs;
11156 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011157 INTON;
11158}
11159
11160/*
Eric Andersenc470f442003-07-28 09:56:35 +000011161 * Undo all redirections. Called on error or interrupt.
11162 */
11163
11164/*
Eric Andersencb57d552001-06-28 07:25:16 +000011165 * Discard all saved file descriptors.
11166 */
11167
Eric Andersenc470f442003-07-28 09:56:35 +000011168void
11169clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011170{
Eric Andersenc470f442003-07-28 09:56:35 +000011171 for (;;) {
11172 nullredirs = 0;
11173 if (!redirlist)
11174 break;
11175 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011176 }
Eric Andersencb57d552001-06-28 07:25:16 +000011177}
11178
11179
Eric Andersencb57d552001-06-28 07:25:16 +000011180/*
11181 * Copy a file descriptor to be >= to. Returns -1
11182 * if the source file descriptor is closed, EMPTY if there are no unused
11183 * file descriptors left.
11184 */
11185
Eric Andersenc470f442003-07-28 09:56:35 +000011186int
11187copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011188{
11189 int newfd;
11190
11191 newfd = fcntl(from, F_DUPFD, to);
11192 if (newfd < 0) {
11193 if (errno == EMFILE)
11194 return EMPTY;
11195 else
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011196 sh_error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011197 }
11198 return newfd;
11199}
11200
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011201
Eric Andersenc470f442003-07-28 09:56:35 +000011202int
11203redirectsafe(union node *redir, int flags)
11204{
11205 int err;
11206 volatile int saveint;
11207 struct jmploc *volatile savehandler = handler;
11208 struct jmploc jmploc;
11209
11210 SAVEINT(saveint);
11211 if (!(err = setjmp(jmploc.loc) * 2)) {
11212 handler = &jmploc;
11213 redirect(redir, flags);
11214 }
11215 handler = savehandler;
11216 if (err && exception != EXERROR)
11217 longjmp(handler->loc, 1);
11218 RESTOREINT(saveint);
11219 return err;
11220}
11221
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011222/* show.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011223
11224#ifdef DEBUG
11225static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011226static void shcmd(union node *, FILE *);
11227static void sharg(union node *, FILE *);
11228static void indent(int, char *, FILE *);
11229static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011230
11231
Eric Andersenc470f442003-07-28 09:56:35 +000011232void
11233showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011234{
11235 trputs("showtree called\n");
11236 shtree(n, 1, NULL, stdout);
11237}
Eric Andersencb57d552001-06-28 07:25:16 +000011238
Eric Andersenc470f442003-07-28 09:56:35 +000011239
11240static void
11241shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011242{
11243 struct nodelist *lp;
11244 const char *s;
11245
11246 if (n == NULL)
11247 return;
11248
11249 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011250 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011251 case NSEMI:
11252 s = "; ";
11253 goto binop;
11254 case NAND:
11255 s = " && ";
11256 goto binop;
11257 case NOR:
11258 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011259binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011260 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011261 /* if (ind < 0) */
11262 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011263 shtree(n->nbinary.ch2, ind, NULL, fp);
11264 break;
11265 case NCMD:
11266 shcmd(n, fp);
11267 if (ind >= 0)
11268 putc('\n', fp);
11269 break;
11270 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011271 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011272 shcmd(lp->n, fp);
11273 if (lp->next)
11274 fputs(" | ", fp);
11275 }
11276 if (n->npipe.backgnd)
11277 fputs(" &", fp);
11278 if (ind >= 0)
11279 putc('\n', fp);
11280 break;
11281 default:
11282 fprintf(fp, "<node type %d>", n->type);
11283 if (ind >= 0)
11284 putc('\n', fp);
11285 break;
11286 }
11287}
11288
11289
Eric Andersenc470f442003-07-28 09:56:35 +000011290static void
11291shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011292{
11293 union node *np;
11294 int first;
11295 const char *s;
11296 int dftfd;
11297
11298 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011299 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11300 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011301 putchar(' ');
11302 sharg(np, fp);
11303 first = 0;
11304 }
Eric Andersenc470f442003-07-28 09:56:35 +000011305 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11306 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011307 putchar(' ');
11308 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011309 case NTO: s = ">"; dftfd = 1; break;
11310 case NCLOBBER: s = ">|"; dftfd = 1; break;
11311 case NAPPEND: s = ">>"; dftfd = 1; break;
11312 case NTOFD: s = ">&"; dftfd = 1; break;
11313 case NFROM: s = "<"; dftfd = 0; break;
11314 case NFROMFD: s = "<&"; dftfd = 0; break;
11315 case NFROMTO: s = "<>"; dftfd = 0; break;
11316 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011317 }
11318 if (np->nfile.fd != dftfd)
11319 fprintf(fp, "%d", np->nfile.fd);
11320 fputs(s, fp);
11321 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11322 fprintf(fp, "%d", np->ndup.dupfd);
11323 } else {
11324 sharg(np->nfile.fname, fp);
11325 }
11326 first = 0;
11327 }
11328}
11329
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011330
Eric Andersenc470f442003-07-28 09:56:35 +000011331
11332static void
11333sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011334{
Eric Andersencb57d552001-06-28 07:25:16 +000011335 char *p;
11336 struct nodelist *bqlist;
11337 int subtype;
11338
11339 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011340 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011341 abort();
11342 }
11343 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011344 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011345 switch (*p) {
11346 case CTLESC:
11347 putc(*++p, fp);
11348 break;
11349 case CTLVAR:
11350 putc('$', fp);
11351 putc('{', fp);
11352 subtype = *++p;
11353 if (subtype == VSLENGTH)
11354 putc('#', fp);
11355
11356 while (*p != '=')
11357 putc(*p++, fp);
11358
11359 if (subtype & VSNUL)
11360 putc(':', fp);
11361
11362 switch (subtype & VSTYPE) {
11363 case VSNORMAL:
11364 putc('}', fp);
11365 break;
11366 case VSMINUS:
11367 putc('-', fp);
11368 break;
11369 case VSPLUS:
11370 putc('+', fp);
11371 break;
11372 case VSQUESTION:
11373 putc('?', fp);
11374 break;
11375 case VSASSIGN:
11376 putc('=', fp);
11377 break;
11378 case VSTRIMLEFT:
11379 putc('#', fp);
11380 break;
11381 case VSTRIMLEFTMAX:
11382 putc('#', fp);
11383 putc('#', fp);
11384 break;
11385 case VSTRIMRIGHT:
11386 putc('%', fp);
11387 break;
11388 case VSTRIMRIGHTMAX:
11389 putc('%', fp);
11390 putc('%', fp);
11391 break;
11392 case VSLENGTH:
11393 break;
11394 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011395 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011396 }
11397 break;
11398 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011399 putc('}', fp);
11400 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011401 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011402 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011403 putc('$', fp);
11404 putc('(', fp);
11405 shtree(bqlist->n, -1, NULL, fp);
11406 putc(')', fp);
11407 break;
11408 default:
11409 putc(*p, fp);
11410 break;
11411 }
11412 }
11413}
11414
11415
Eric Andersenc470f442003-07-28 09:56:35 +000011416static void
11417indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011418{
11419 int i;
11420
Eric Andersenc470f442003-07-28 09:56:35 +000011421 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011422 if (pfx && i == amount - 1)
11423 fputs(pfx, fp);
11424 putc('\t', fp);
11425 }
11426}
Eric Andersencb57d552001-06-28 07:25:16 +000011427
Eric Andersenc470f442003-07-28 09:56:35 +000011428
11429
11430/*
11431 * Debugging stuff.
11432 */
11433
11434
Eric Andersencb57d552001-06-28 07:25:16 +000011435FILE *tracefile;
11436
Eric Andersencb57d552001-06-28 07:25:16 +000011437
Eric Andersenc470f442003-07-28 09:56:35 +000011438void
11439trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011440{
Eric Andersenc470f442003-07-28 09:56:35 +000011441 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011442 return;
11443 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011444}
11445
Eric Andersenc470f442003-07-28 09:56:35 +000011446void
11447trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011448{
11449 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011450
Eric Andersenc470f442003-07-28 09:56:35 +000011451 if (debug != 1)
11452 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011453 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011454 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011455 va_end(va);
11456}
11457
Eric Andersenc470f442003-07-28 09:56:35 +000011458void
11459tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011460{
Eric Andersenc470f442003-07-28 09:56:35 +000011461 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011462 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011463 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011464}
11465
11466
Eric Andersenc470f442003-07-28 09:56:35 +000011467void
11468trputs(const char *s)
11469{
11470 if (debug != 1)
11471 return;
11472 fputs(s, tracefile);
11473}
11474
11475
11476static void
11477trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011478{
11479 char *p;
11480 char c;
11481
Eric Andersenc470f442003-07-28 09:56:35 +000011482 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011483 return;
11484 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011485 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011486 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011487 case '\n': c = 'n'; goto backslash;
11488 case '\t': c = 't'; goto backslash;
11489 case '\r': c = 'r'; goto backslash;
11490 case '"': c = '"'; goto backslash;
11491 case '\\': c = '\\'; goto backslash;
11492 case CTLESC: c = 'e'; goto backslash;
11493 case CTLVAR: c = 'v'; goto backslash;
11494 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11495 case CTLBACKQ: c = 'q'; goto backslash;
11496 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11497backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011498 putc(c, tracefile);
11499 break;
11500 default:
11501 if (*p >= ' ' && *p <= '~')
11502 putc(*p, tracefile);
11503 else {
11504 putc('\\', tracefile);
11505 putc(*p >> 6 & 03, tracefile);
11506 putc(*p >> 3 & 07, tracefile);
11507 putc(*p & 07, tracefile);
11508 }
11509 break;
11510 }
11511 }
11512 putc('"', tracefile);
11513}
11514
11515
Eric Andersenc470f442003-07-28 09:56:35 +000011516void
11517trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011518{
Eric Andersenc470f442003-07-28 09:56:35 +000011519 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011520 return;
11521 while (*ap) {
11522 trstring(*ap++);
11523 if (*ap)
11524 putc(' ', tracefile);
11525 else
11526 putc('\n', tracefile);
11527 }
Eric Andersencb57d552001-06-28 07:25:16 +000011528}
11529
11530
Eric Andersenc470f442003-07-28 09:56:35 +000011531void
11532opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011533{
Eric Andersencb57d552001-06-28 07:25:16 +000011534 char s[100];
11535#ifdef O_APPEND
11536 int flags;
11537#endif
11538
Eric Andersenc470f442003-07-28 09:56:35 +000011539 if (debug != 1) {
11540 if (tracefile)
11541 fflush(tracefile);
11542 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011543 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011544 }
Eric Andersenc470f442003-07-28 09:56:35 +000011545 scopy("./trace", s);
11546 if (tracefile) {
11547 if (!freopen(s, "a", tracefile)) {
11548 fprintf(stderr, "Can't re-open %s\n", s);
11549 debug = 0;
11550 return;
11551 }
11552 } else {
11553 if ((tracefile = fopen(s, "a")) == NULL) {
11554 fprintf(stderr, "Can't open %s\n", s);
11555 debug = 0;
11556 return;
11557 }
11558 }
Eric Andersencb57d552001-06-28 07:25:16 +000011559#ifdef O_APPEND
11560 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11561 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11562#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011563 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011564 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011565}
Eric Andersenc470f442003-07-28 09:56:35 +000011566#endif /* DEBUG */
11567
11568
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011569/* trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011570
11571/*
11572 * Sigmode records the current value of the signal handlers for the various
11573 * modes. A value of zero means that the current handler is not known.
11574 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11575 */
11576
11577#define S_DFL 1 /* default signal handling (SIG_DFL) */
11578#define S_CATCH 2 /* signal is caught */
11579#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11580#define S_HARD_IGN 4 /* signal is ignored permenantly */
11581#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11582
Eric Andersencb57d552001-06-28 07:25:16 +000011583
11584
11585/*
Eric Andersencb57d552001-06-28 07:25:16 +000011586 * The trap builtin.
11587 */
11588
Eric Andersenc470f442003-07-28 09:56:35 +000011589int
11590trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011591{
11592 char *action;
11593 char **ap;
11594 int signo;
11595
Eric Andersenc470f442003-07-28 09:56:35 +000011596 nextopt(nullstr);
11597 ap = argptr;
11598 if (!*ap) {
11599 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011600 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011601 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011602
Eric Andersenc470f442003-07-28 09:56:35 +000011603 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011604 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011605 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011606 out1fmt("trap -- %s %s\n",
11607 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011608 }
11609 }
11610 return 0;
11611 }
Eric Andersenc470f442003-07-28 09:56:35 +000011612 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011613 action = NULL;
11614 else
11615 action = *ap++;
11616 while (*ap) {
11617 if ((signo = decode_signal(*ap, 0)) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011618 sh_error("%s: bad trap", *ap);
Eric Andersencb57d552001-06-28 07:25:16 +000011619 INTOFF;
11620 if (action) {
11621 if (action[0] == '-' && action[1] == '\0')
11622 action = NULL;
11623 else
Eric Andersenc470f442003-07-28 09:56:35 +000011624 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011625 }
Eric Andersenc470f442003-07-28 09:56:35 +000011626 if (trap[signo])
11627 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011628 trap[signo] = action;
11629 if (signo != 0)
11630 setsignal(signo);
11631 INTON;
11632 ap++;
11633 }
11634 return 0;
11635}
11636
11637
Eric Andersenc470f442003-07-28 09:56:35 +000011638/*
11639 * Clear traps on a fork.
11640 */
11641
11642void
11643clear_traps(void)
11644{
11645 char **tp;
11646
11647 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11648 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11649 INTOFF;
11650 ckfree(*tp);
11651 *tp = NULL;
11652 if (tp != &trap[0])
11653 setsignal(tp - trap);
11654 INTON;
11655 }
11656 }
11657}
11658
11659
Eric Andersencb57d552001-06-28 07:25:16 +000011660/*
11661 * Set the signal handler for the specified signal. The routine figures
11662 * out what it should be set to.
11663 */
11664
Eric Andersenc470f442003-07-28 09:56:35 +000011665void
11666setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011667{
11668 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011669 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011670 struct sigaction act;
11671
11672 if ((t = trap[signo]) == NULL)
11673 action = S_DFL;
11674 else if (*t != '\0')
11675 action = S_CATCH;
11676 else
11677 action = S_IGN;
11678 if (rootshell && action == S_DFL) {
11679 switch (signo) {
11680 case SIGINT:
11681 if (iflag || minusc || sflag == 0)
11682 action = S_CATCH;
11683 break;
11684 case SIGQUIT:
11685#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011686 if (debug)
11687 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011688#endif
11689 /* FALLTHROUGH */
11690 case SIGTERM:
11691 if (iflag)
11692 action = S_IGN;
11693 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011694#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011695 case SIGTSTP:
11696 case SIGTTOU:
11697 if (mflag)
11698 action = S_IGN;
11699 break;
11700#endif
11701 }
11702 }
11703
11704 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011705 tsig = *t;
11706 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011707 /*
11708 * current setting unknown
11709 */
11710 if (sigaction(signo, 0, &act) == -1) {
11711 /*
11712 * Pretend it worked; maybe we should give a warning
11713 * here, but other shells don't. We don't alter
11714 * sigmode, so that we retry every time.
11715 */
11716 return;
11717 }
11718 if (act.sa_handler == SIG_IGN) {
11719 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011720 signo == SIGTTIN || signo == SIGTTOU)) {
11721 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011722 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011723 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011724 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011725 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011726 }
11727 }
Eric Andersenc470f442003-07-28 09:56:35 +000011728 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011729 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011730 switch (action) {
11731 case S_CATCH:
11732 act.sa_handler = onsig;
11733 break;
11734 case S_IGN:
11735 act.sa_handler = SIG_IGN;
11736 break;
11737 default:
11738 act.sa_handler = SIG_DFL;
11739 }
Eric Andersencb57d552001-06-28 07:25:16 +000011740 *t = action;
11741 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011742 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011743 sigaction(signo, &act, 0);
11744}
11745
11746/*
11747 * Ignore a signal.
11748 */
11749
Eric Andersenc470f442003-07-28 09:56:35 +000011750void
11751ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011752{
11753 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11754 signal(signo, SIG_IGN);
11755 }
11756 sigmode[signo - 1] = S_HARD_IGN;
11757}
11758
11759
Eric Andersencb57d552001-06-28 07:25:16 +000011760/*
11761 * Signal handler.
11762 */
11763
Eric Andersenc470f442003-07-28 09:56:35 +000011764void
11765onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011766{
Eric Andersencb57d552001-06-28 07:25:16 +000011767 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011768 pendingsigs = signo;
11769
11770 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11771 if (!suppressint)
11772 onint();
11773 intpending = 1;
11774 }
Eric Andersencb57d552001-06-28 07:25:16 +000011775}
11776
11777
Eric Andersencb57d552001-06-28 07:25:16 +000011778/*
11779 * Called to execute a trap. Perhaps we should avoid entering new trap
11780 * handlers while we are executing a trap handler.
11781 */
11782
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011783int
Eric Andersenc470f442003-07-28 09:56:35 +000011784dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011785{
Eric Andersenc470f442003-07-28 09:56:35 +000011786 char *p;
11787 char *q;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011788 int i;
Eric Andersencb57d552001-06-28 07:25:16 +000011789 int savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011790 int skip = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011791
Eric Andersenc470f442003-07-28 09:56:35 +000011792 savestatus = exitstatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011793 pendingsigs = 0;
11794 xbarrier();
11795
11796 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
11797 if (!*q)
11798 continue;
11799 *q = 0;
11800
11801 p = trap[i + 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011802 if (!p)
11803 continue;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011804 skip = evalstring(p, SKIPEVAL);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011805 exitstatus = savestatus;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011806 if (skip)
11807 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011808 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011809
11810 return skip;
Eric Andersencb57d552001-06-28 07:25:16 +000011811}
11812
Eric Andersenc470f442003-07-28 09:56:35 +000011813
Eric Andersenc470f442003-07-28 09:56:35 +000011814/*
11815 * Controls whether the shell is interactive or not.
11816 */
11817
Eric Andersenc470f442003-07-28 09:56:35 +000011818void
11819setinteractive(int on)
11820{
11821 static int is_interactive;
11822
11823 if (++on == is_interactive)
11824 return;
11825 is_interactive = on;
11826 setsignal(SIGINT);
11827 setsignal(SIGQUIT);
11828 setsignal(SIGTERM);
11829#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11830 if(is_interactive > 1) {
11831 /* Looks like they want an interactive shell */
11832 static int do_banner;
11833
11834 if(!do_banner) {
11835 out1fmt(
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +000011836 "\n\n%s Built-in shell (ash)\n"
11837 "Enter 'help' for a list of built-in commands.\n\n",
11838 BB_BANNER);
Eric Andersenc470f442003-07-28 09:56:35 +000011839 do_banner++;
11840 }
11841 }
11842#endif
11843}
11844
11845
11846#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11847/*** List the available builtins ***/
11848
11849static int helpcmd(int argc, char **argv)
11850{
11851 int col, i;
11852
11853 out1fmt("\nBuilt-in commands:\n-------------------\n");
11854 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11855 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11856 builtincmd[i].name + 1);
11857 if (col > 60) {
11858 out1fmt("\n");
11859 col = 0;
11860 }
11861 }
11862#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11863 {
11864 extern const struct BB_applet applets[];
11865 extern const size_t NUM_APPLETS;
11866
11867 for (i = 0; i < NUM_APPLETS; i++) {
11868
11869 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11870 if (col > 60) {
11871 out1fmt("\n");
11872 col = 0;
11873 }
11874 }
11875 }
11876#endif
11877 out1fmt("\n\n");
11878 return EXIT_SUCCESS;
11879}
11880#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11881
Eric Andersencb57d552001-06-28 07:25:16 +000011882/*
11883 * Called to exit the shell.
11884 */
11885
Eric Andersenc470f442003-07-28 09:56:35 +000011886void
11887exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011888{
Eric Andersenc470f442003-07-28 09:56:35 +000011889 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011890 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011891 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011892
Eric Andersenc470f442003-07-28 09:56:35 +000011893 status = exitstatus;
11894 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011895 if (setjmp(loc.loc)) {
11896 if (exception == EXEXIT)
11897 _exit(exitstatus);
Eric Andersenc470f442003-07-28 09:56:35 +000011898 goto out;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011899 }
Eric Andersenc470f442003-07-28 09:56:35 +000011900 handler = &loc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011901 if ((p = trap[0])) {
Eric Andersencb57d552001-06-28 07:25:16 +000011902 trap[0] = NULL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011903 evalstring(p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000011904 }
Eric Andersencb57d552001-06-28 07:25:16 +000011905 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011906 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011907#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11908 if (iflag && rootshell) {
11909 const char *hp = lookupvar("HISTFILE");
11910
11911 if(hp != NULL )
11912 save_history ( hp );
11913 }
11914#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011915out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011916 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011917 /* NOTREACHED */
11918}
11919
11920static int decode_signal(const char *string, int minsig)
11921{
11922 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011923 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011924
Eric Andersen34506362001-08-02 05:02:46 +000011925 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011926}
Eric Andersen34506362001-08-02 05:02:46 +000011927
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011928/* var.c */
Eric Andersenc470f442003-07-28 09:56:35 +000011929
11930static struct var *vartab[VTABSIZE];
11931
11932static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011933static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011934
11935/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011936 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011937 */
11938
Eric Andersenc470f442003-07-28 09:56:35 +000011939
11940#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011941/*
Eric Andersenc470f442003-07-28 09:56:35 +000011942 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011943 */
11944
Eric Andersenc470f442003-07-28 09:56:35 +000011945int
11946setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011947{
Eric Andersenc470f442003-07-28 09:56:35 +000011948 int err;
11949 volatile int saveint;
11950 struct jmploc *volatile savehandler = handler;
11951 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011952
Eric Andersenc470f442003-07-28 09:56:35 +000011953 SAVEINT(saveint);
11954 if (setjmp(jmploc.loc))
11955 err = 1;
11956 else {
11957 handler = &jmploc;
11958 setvar(name, val, flags);
11959 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011960 }
Eric Andersenc470f442003-07-28 09:56:35 +000011961 handler = savehandler;
11962 RESTOREINT(saveint);
11963 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011964}
Eric Andersenc470f442003-07-28 09:56:35 +000011965#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011966
11967/*
11968 * Set the value of a variable. The flags argument is ored with the
11969 * flags of the variable. If val is NULL, the variable is unset.
11970 */
11971
Eric Andersenc470f442003-07-28 09:56:35 +000011972static void
11973setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011974{
Eric Andersenc470f442003-07-28 09:56:35 +000011975 char *p, *q;
11976 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011977 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011978 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011979
Eric Andersenc470f442003-07-28 09:56:35 +000011980 q = endofname(name);
11981 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011982 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011983 if (!namelen || p != q)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011984 sh_error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011985 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011986 if (val == NULL) {
11987 flags |= VUNSET;
11988 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011989 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011990 }
11991 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011992 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
Paul Fox8de331d2005-07-21 12:03:05 +000011993 if (val) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000011994 *p++ = '=';
Eric Andersenc470f442003-07-28 09:56:35 +000011995 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011996 }
Eric Andersenc470f442003-07-28 09:56:35 +000011997 *p = '\0';
11998 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011999 INTON;
12000}
12001
12002
Eric Andersencb57d552001-06-28 07:25:16 +000012003/*
12004 * Same as setvar except that the variable and value are passed in
12005 * the first argument as name=value. Since the first argument will
12006 * be actually stored in the table, it should not be a string that
12007 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012008 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012009 */
12010
Eric Andersenc470f442003-07-28 09:56:35 +000012011void
12012setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012013{
12014 struct var *vp, **vpp;
12015
12016 vpp = hashvar(s);
12017 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012018 vp = *findvar(vpp, s);
12019 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012020 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12021 const char *n;
12022
Eric Andersenc470f442003-07-28 09:56:35 +000012023 if (flags & VNOSAVE)
12024 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012025 n = vp->text;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012026 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012027 }
Eric Andersenc470f442003-07-28 09:56:35 +000012028
12029 if (flags & VNOSET)
12030 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012031
12032 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012033 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012034
Eric Andersenc470f442003-07-28 09:56:35 +000012035 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12036 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012037
Eric Andersenc470f442003-07-28 09:56:35 +000012038 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12039 } else {
12040 if (flags & VNOSET)
12041 return;
12042 /* not found */
12043 vp = ckmalloc(sizeof (*vp));
12044 vp->next = *vpp;
12045 vp->func = NULL;
12046 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012047 }
Eric Andersenc470f442003-07-28 09:56:35 +000012048 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12049 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012050 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012051 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012052}
12053
12054
Eric Andersencb57d552001-06-28 07:25:16 +000012055/*
12056 * Process a linked list of variable assignments.
12057 */
12058
Eric Andersenc470f442003-07-28 09:56:35 +000012059static void
12060listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012061{
Eric Andersenc470f442003-07-28 09:56:35 +000012062 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012063
Eric Andersenc470f442003-07-28 09:56:35 +000012064 if (!lp)
12065 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012066 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012067 do {
12068 setvareq(lp->text, flags);
12069 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012070 INTON;
12071}
12072
12073
Eric Andersencb57d552001-06-28 07:25:16 +000012074/*
12075 * Find the value of a variable. Returns NULL if not set.
12076 */
12077
Eric Andersenc470f442003-07-28 09:56:35 +000012078static char *
12079lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012080{
Eric Andersencb57d552001-06-28 07:25:16 +000012081 struct var *v;
12082
Eric Andersen16767e22004-03-16 05:14:10 +000012083 if ((v = *findvar(hashvar(name), name))) {
12084#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012085 /*
12086 * Dynamic variables are implemented roughly the same way they are
12087 * in bash. Namely, they're "special" so long as they aren't unset.
12088 * As soon as they're unset, they're no longer dynamic, and dynamic
12089 * lookup will no longer happen at that point. -- PFM.
12090 */
Eric Andersen16767e22004-03-16 05:14:10 +000012091 if((v->flags & VDYNAMIC))
12092 (*v->func)(NULL);
12093#endif
12094 if(!(v->flags & VUNSET))
12095 return strchrnul(v->text, '=') + 1;
12096 }
Eric Andersenef02f822004-03-11 13:34:24 +000012097
Eric Andersencb57d552001-06-28 07:25:16 +000012098 return NULL;
12099}
12100
12101
Eric Andersencb57d552001-06-28 07:25:16 +000012102/*
12103 * Search the environment of a builtin command.
12104 */
12105
Eric Andersenc470f442003-07-28 09:56:35 +000012106static char *
12107bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012108{
Eric Andersenc470f442003-07-28 09:56:35 +000012109 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012110
Eric Andersenc470f442003-07-28 09:56:35 +000012111 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012112 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012113 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012114 }
12115 return lookupvar(name);
12116}
12117
12118
Eric Andersencb57d552001-06-28 07:25:16 +000012119/*
Eric Andersenc470f442003-07-28 09:56:35 +000012120 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012121 */
12122
Eric Andersenc470f442003-07-28 09:56:35 +000012123static char **
12124listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012125{
Eric Andersencb57d552001-06-28 07:25:16 +000012126 struct var **vpp;
12127 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012128 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012129 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012130
Eric Andersenc470f442003-07-28 09:56:35 +000012131 STARTSTACKSTR(ep);
12132 vpp = vartab;
12133 mask = on | off;
12134 do {
12135 for (vp = *vpp ; vp ; vp = vp->next)
12136 if ((vp->flags & mask) == on) {
12137 if (ep == stackstrend())
12138 ep = growstackstr();
12139 *ep++ = (char *) vp->text;
12140 }
12141 } while (++vpp < vartab + VTABSIZE);
12142 if (ep == stackstrend())
12143 ep = growstackstr();
12144 if (end)
12145 *end = ep;
12146 *ep++ = NULL;
12147 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012148}
12149
12150
12151/*
Eric Andersenc470f442003-07-28 09:56:35 +000012152 * POSIX requires that 'set' (but not export or readonly) output the
12153 * variables in lexicographic order - by the locale's collating order (sigh).
12154 * Maybe we could keep them in an ordered balanced binary tree
12155 * instead of hashed lists.
12156 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012157 */
12158
Eric Andersenc470f442003-07-28 09:56:35 +000012159static int
12160showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012161{
Eric Andersenc470f442003-07-28 09:56:35 +000012162 const char *sep;
12163 char **ep, **epend;
12164
12165 ep = listvars(on, off, &epend);
12166 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12167
12168 sep = *sep_prefix ? spcstr : sep_prefix;
12169
12170 for (; ep < epend; ep++) {
12171 const char *p;
12172 const char *q;
12173
12174 p = strchrnul(*ep, '=');
12175 q = nullstr;
12176 if (*p)
12177 q = single_quote(++p);
12178
12179 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12180 }
12181
Eric Andersencb57d552001-06-28 07:25:16 +000012182 return 0;
12183}
12184
12185
12186
12187/*
12188 * The export and readonly commands.
12189 */
12190
Eric Andersenc470f442003-07-28 09:56:35 +000012191static int
12192exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012193{
12194 struct var *vp;
12195 char *name;
12196 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012197 char **aptr;
12198 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12199 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012200
Eric Andersenc470f442003-07-28 09:56:35 +000012201 notp = nextopt("p") - 'p';
12202 if (notp && ((name = *(aptr = argptr)))) {
12203 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012204 if ((p = strchr(name, '=')) != NULL) {
12205 p++;
12206 } else {
12207 if ((vp = *findvar(hashvar(name), name))) {
12208 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012209 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012210 }
12211 }
12212 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012213 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012214 } else {
12215 showvars(argv[0], flag, 0);
12216 }
12217 return 0;
12218}
12219
Eric Andersen34506362001-08-02 05:02:46 +000012220
Eric Andersencb57d552001-06-28 07:25:16 +000012221/*
Eric Andersencb57d552001-06-28 07:25:16 +000012222 * Make a variable a local variable. When a variable is made local, it's
12223 * value and flags are saved in a localvar structure. The saved values
12224 * will be restored when the shell function returns. We handle the name
12225 * "-" as a special case.
12226 */
12227
Eric Andersenc470f442003-07-28 09:56:35 +000012228static inline void
12229mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012230{
Eric Andersencb57d552001-06-28 07:25:16 +000012231 struct localvar *lvp;
12232 struct var **vpp;
12233 struct var *vp;
12234
12235 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012236 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012237 if (name[0] == '-' && name[1] == '\0') {
12238 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012239 p = ckmalloc(sizeof(optlist));
12240 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012241 vp = NULL;
12242 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012243 char *eq;
12244
Eric Andersencb57d552001-06-28 07:25:16 +000012245 vpp = hashvar(name);
12246 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012247 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012248 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012249 if (eq)
12250 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012251 else
12252 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012253 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012254 lvp->flags = VUNSET;
12255 } else {
12256 lvp->text = vp->text;
12257 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012258 vp->flags |= VSTRFIXED|VTEXTFIXED;
12259 if (eq)
12260 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012261 }
12262 }
12263 lvp->vp = vp;
12264 lvp->next = localvars;
12265 localvars = lvp;
12266 INTON;
12267}
12268
Eric Andersenc470f442003-07-28 09:56:35 +000012269/*
12270 * The "local" command.
12271 */
12272
12273static int
12274localcmd(int argc, char **argv)
12275{
12276 char *name;
12277
12278 argv = argptr;
12279 while ((name = *argv++) != NULL) {
12280 mklocal(name);
12281 }
12282 return 0;
12283}
12284
12285
Eric Andersencb57d552001-06-28 07:25:16 +000012286/*
12287 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012288 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012289 */
12290
Eric Andersenc470f442003-07-28 09:56:35 +000012291static void
12292poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012293{
Eric Andersencb57d552001-06-28 07:25:16 +000012294 struct localvar *lvp;
12295 struct var *vp;
12296
12297 while ((lvp = localvars) != NULL) {
12298 localvars = lvp->next;
12299 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012300 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12301 if (vp == NULL) { /* $- saved */
12302 memcpy(optlist, lvp->text, sizeof(optlist));
12303 ckfree(lvp->text);
12304 optschanged();
12305 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12306 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012307 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012308 if (vp->func)
12309 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12310 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12311 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012312 vp->flags = lvp->flags;
12313 vp->text = lvp->text;
12314 }
Eric Andersenc470f442003-07-28 09:56:35 +000012315 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012316 }
12317}
12318
12319
Eric Andersencb57d552001-06-28 07:25:16 +000012320/*
12321 * The unset builtin command. We unset the function before we unset the
12322 * variable to allow a function to be unset when there is a readonly variable
12323 * with the same name.
12324 */
12325
Eric Andersenc470f442003-07-28 09:56:35 +000012326int
12327unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012328{
12329 char **ap;
12330 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012331 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012332 int ret = 0;
12333
12334 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012335 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012336 }
Eric Andersencb57d552001-06-28 07:25:16 +000012337
Eric Andersenc470f442003-07-28 09:56:35 +000012338 for (ap = argptr; *ap ; ap++) {
12339 if (flag != 'f') {
12340 i = unsetvar(*ap);
12341 ret |= i;
12342 if (!(i & 2))
12343 continue;
12344 }
12345 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012346 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012347 }
Eric Andersenc470f442003-07-28 09:56:35 +000012348 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012349}
12350
12351
12352/*
12353 * Unset the specified variable.
12354 */
12355
Eric Andersenc470f442003-07-28 09:56:35 +000012356int
12357unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012358{
Eric Andersencb57d552001-06-28 07:25:16 +000012359 struct var **vpp;
12360 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012361 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012362
12363 vpp = findvar(hashvar(s), s);
12364 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012365 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012366 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012367 int flags = vp->flags;
12368
12369 retval = 1;
12370 if (flags & VREADONLY)
12371 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012372#ifdef DYNAMIC_VAR
12373 vp->flags &= ~VDYNAMIC;
12374#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012375 if (flags & VUNSET)
12376 goto ok;
12377 if ((flags & VSTRFIXED) == 0) {
12378 INTOFF;
12379 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12380 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012381 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012382 ckfree(vp);
12383 INTON;
12384 } else {
12385 setvar(s, 0, 0);
12386 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012387 }
Eric Andersenc470f442003-07-28 09:56:35 +000012388ok:
12389 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012390 }
12391
Eric Andersenc470f442003-07-28 09:56:35 +000012392out:
12393 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012394}
12395
12396
12397
12398/*
12399 * Find the appropriate entry in the hash table from the name.
12400 */
12401
Eric Andersenc470f442003-07-28 09:56:35 +000012402static struct var **
12403hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012404{
Eric Andersencb57d552001-06-28 07:25:16 +000012405 unsigned int hashval;
12406
12407 hashval = ((unsigned char) *p) << 4;
12408 while (*p && *p != '=')
12409 hashval += (unsigned char) *p++;
12410 return &vartab[hashval % VTABSIZE];
12411}
12412
12413
12414
12415/*
Eric Andersenc470f442003-07-28 09:56:35 +000012416 * Compares two strings up to the first = or '\0'. The first
12417 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012418 * either '=' or '\0'.
12419 */
12420
Eric Andersenc470f442003-07-28 09:56:35 +000012421int
12422varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012423{
Eric Andersenc470f442003-07-28 09:56:35 +000012424 int c, d;
12425
12426 while ((c = *p) == (d = *q)) {
12427 if (!c || c == '=')
12428 goto out;
12429 p++;
12430 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012431 }
Eric Andersenc470f442003-07-28 09:56:35 +000012432 if (c == '=')
12433 c = 0;
12434 if (d == '=')
12435 d = 0;
12436out:
12437 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012438}
12439
Eric Andersenc470f442003-07-28 09:56:35 +000012440static int
12441vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012442{
Eric Andersenc470f442003-07-28 09:56:35 +000012443 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012444}
12445
Eric Andersenc470f442003-07-28 09:56:35 +000012446static struct var **
12447findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012448{
12449 for (; *vpp; vpp = &(*vpp)->next) {
12450 if (varequal((*vpp)->text, name)) {
12451 break;
12452 }
12453 }
12454 return vpp;
12455}
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012456/* setmode.c */
Eric Andersencb57d552001-06-28 07:25:16 +000012457
Eric Andersenc470f442003-07-28 09:56:35 +000012458#include <sys/times.h>
12459
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012460static const unsigned char timescmd_str[] = {
12461 ' ', offsetof(struct tms, tms_utime),
12462 '\n', offsetof(struct tms, tms_stime),
12463 ' ', offsetof(struct tms, tms_cutime),
12464 '\n', offsetof(struct tms, tms_cstime),
12465 0
12466};
Eric Andersencb57d552001-06-28 07:25:16 +000012467
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012468static int timescmd(int ac, char **av)
12469{
12470 long int clk_tck, s, t;
12471 const unsigned char *p;
12472 struct tms buf;
12473
12474 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012475 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012476
12477 p = timescmd_str;
12478 do {
12479 t = *(clock_t *)(((char *) &buf) + p[1]);
12480 s = t / clk_tck;
12481 out1fmt("%ldm%ld.%.3lds%c",
12482 s/60, s%60,
12483 ((t - s * clk_tck) * 1000) / clk_tck,
12484 p[0]);
12485 } while (*(p += 2));
12486
Eric Andersencb57d552001-06-28 07:25:16 +000012487 return 0;
12488}
12489
Eric Andersend35c5df2002-01-09 15:37:36 +000012490#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012491static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012492dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012493{
Eric Andersened9ecf72004-06-22 08:29:45 +000012494 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012495 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012496
Eric Andersenc470f442003-07-28 09:56:35 +000012497 INTOFF;
12498 result = arith(s, &errcode);
12499 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012500 if (errcode == -3)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012501 sh_error("exponent less than 0");
Eric Andersen90898442003-08-06 11:20:52 +000012502 else if (errcode == -2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012503 sh_error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012504 else if (errcode == -5)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012505 sh_error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012506 else
12507 synerror(s);
12508 }
12509 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012510
Eric Andersenc470f442003-07-28 09:56:35 +000012511 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012512}
Eric Andersenc470f442003-07-28 09:56:35 +000012513
12514
12515/*
Eric Andersen90898442003-08-06 11:20:52 +000012516 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12517 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12518 *
12519 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012520 */
Eric Andersen90898442003-08-06 11:20:52 +000012521
Eric Andersenc470f442003-07-28 09:56:35 +000012522static int
Eric Andersen90898442003-08-06 11:20:52 +000012523letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012524{
Eric Andersenc470f442003-07-28 09:56:35 +000012525 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012526 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012527
Eric Andersen90898442003-08-06 11:20:52 +000012528 ap = argv + 1;
12529 if(!*ap)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012530 sh_error("expression expected");
Eric Andersen90898442003-08-06 11:20:52 +000012531 for (ap = argv + 1; *ap; ap++) {
12532 i = dash_arith(*ap);
12533 }
Eric Andersenc470f442003-07-28 09:56:35 +000012534
Eric Andersen90898442003-08-06 11:20:52 +000012535 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012536}
12537#endif /* CONFIG_ASH_MATH_SUPPORT */
12538
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012539/* miscbltin.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012540
12541/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012542 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012543 */
12544
12545#undef rflag
12546
12547#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012548#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012549typedef enum __rlimit_resource rlim_t;
12550#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012551#endif
12552
12553
Eric Andersenc470f442003-07-28 09:56:35 +000012554/*
12555 * The read builtin. The -e option causes backslashes to escape the
12556 * following character.
12557 *
12558 * This uses unbuffered input, which may be avoidable in some cases.
12559 */
12560
12561static int
12562readcmd(int argc, char **argv)
12563{
12564 char **ap;
12565 int backslash;
12566 char c;
12567 int rflag;
12568 char *prompt;
12569 const char *ifs;
12570 char *p;
12571 int startword;
12572 int status;
12573 int i;
Paul Fox02eb9342005-09-07 16:56:02 +000012574#if defined(CONFIG_ASH_READ_NCHARS)
12575 int nch_flag = 0;
12576 int nchars = 0;
12577 int silent = 0;
12578 struct termios tty, old_tty;
12579#endif
12580#if defined(CONFIG_ASH_READ_TIMEOUT)
12581 fd_set set;
12582 struct timeval ts;
12583
12584 ts.tv_sec = ts.tv_usec = 0;
12585#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012586
12587 rflag = 0;
12588 prompt = NULL;
Paul Fox02eb9342005-09-07 16:56:02 +000012589#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12590 while ((i = nextopt("p:rt:n:s")) != '\0')
12591#elif defined(CONFIG_ASH_READ_NCHARS)
12592 while ((i = nextopt("p:rn:s")) != '\0')
12593#elif defined(CONFIG_ASH_READ_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012594 while ((i = nextopt("p:rt:")) != '\0')
12595#else
12596 while ((i = nextopt("p:r")) != '\0')
12597#endif
12598 {
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012599 switch(i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012600 case 'p':
Eric Andersenc470f442003-07-28 09:56:35 +000012601 prompt = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012602 break;
12603#if defined(CONFIG_ASH_READ_NCHARS)
12604 case 'n':
12605 nchars = strtol(optionarg, &p, 10);
12606 if (*p)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012607 sh_error("invalid count");
Paul Fox02eb9342005-09-07 16:56:02 +000012608 nch_flag = (nchars > 0);
12609 break;
12610 case 's':
12611 silent = 1;
12612 break;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012613#endif
Paul Fox02eb9342005-09-07 16:56:02 +000012614#if defined(CONFIG_ASH_READ_TIMEOUT)
12615 case 't':
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012616 ts.tv_sec = strtol(optionarg, &p, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012617 ts.tv_usec = 0;
12618 if (*p == '.') {
12619 char *p2;
12620 if (*++p) {
12621 int scale;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012622 ts.tv_usec = strtol(p, &p2, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012623 if (*p2)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012624 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012625 scale = p2 - p;
12626 /* normalize to usec */
12627 if (scale > 6)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012628 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012629 while (scale++ < 6)
12630 ts.tv_usec *= 10;
12631 }
12632 } else if (*p) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012633 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012634 }
12635 if ( ! ts.tv_sec && ! ts.tv_usec)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012636 sh_error("invalid timeout");
Paul Fox02eb9342005-09-07 16:56:02 +000012637 break;
12638#endif
12639 case 'r':
12640 rflag = 1;
12641 break;
12642 default:
12643 break;
12644 }
Eric Andersenc470f442003-07-28 09:56:35 +000012645 }
12646 if (prompt && isatty(0)) {
12647 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012648 }
12649 if (*(ap = argptr) == NULL)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012650 sh_error("arg count");
Eric Andersenc470f442003-07-28 09:56:35 +000012651 if ((ifs = bltinlookup("IFS")) == NULL)
12652 ifs = defifs;
Paul Fox02eb9342005-09-07 16:56:02 +000012653#if defined(CONFIG_ASH_READ_NCHARS)
12654 if (nch_flag || silent) {
12655 tcgetattr(0, &tty);
12656 old_tty = tty;
12657 if (nch_flag) {
12658 tty.c_lflag &= ~ICANON;
12659 tty.c_cc[VMIN] = nchars;
12660 }
12661 if (silent) {
12662 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12663
12664 }
12665 tcsetattr(0, TCSANOW, &tty);
12666 }
12667#endif
12668#if defined(CONFIG_ASH_READ_TIMEOUT)
12669 if (ts.tv_sec || ts.tv_usec) {
12670 FD_ZERO (&set);
12671 FD_SET (0, &set);
12672
12673 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12674 if (!i) {
12675#if defined(CONFIG_ASH_READ_NCHARS)
12676 if (nch_flag)
12677 tcsetattr(0, TCSANOW, &old_tty);
12678#endif
12679 return 1;
12680 }
12681 }
Ned Ludd2123b7c2005-02-09 21:07:23 +000012682#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012683 status = 0;
12684 startword = 1;
12685 backslash = 0;
12686 STARTSTACKSTR(p);
Paul Fox02eb9342005-09-07 16:56:02 +000012687#if defined(CONFIG_ASH_READ_NCHARS)
12688 while (!nch_flag || nchars--)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012689#else
12690 for (;;)
12691#endif
12692 {
Eric Andersenc470f442003-07-28 09:56:35 +000012693 if (read(0, &c, 1) != 1) {
12694 status = 1;
12695 break;
12696 }
12697 if (c == '\0')
12698 continue;
12699 if (backslash) {
12700 backslash = 0;
12701 if (c != '\n')
12702 goto put;
12703 continue;
12704 }
12705 if (!rflag && c == '\\') {
12706 backslash++;
12707 continue;
12708 }
12709 if (c == '\n')
12710 break;
12711 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12712 continue;
12713 }
12714 startword = 0;
12715 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12716 STACKSTRNUL(p);
12717 setvar(*ap, stackblock(), 0);
12718 ap++;
12719 startword = 1;
12720 STARTSTACKSTR(p);
12721 } else {
12722put:
12723 STPUTC(c, p);
12724 }
12725 }
Paul Fox02eb9342005-09-07 16:56:02 +000012726#if defined(CONFIG_ASH_READ_NCHARS)
12727 if (nch_flag || silent)
12728 tcsetattr(0, TCSANOW, &old_tty);
12729#endif
12730
Eric Andersenc470f442003-07-28 09:56:35 +000012731 STACKSTRNUL(p);
12732 /* Remove trailing blanks */
12733 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12734 *p = '\0';
12735 setvar(*ap, stackblock(), 0);
12736 while (*++ap != NULL)
12737 setvar(*ap, nullstr, 0);
12738 return status;
12739}
12740
12741
12742static int umaskcmd(int argc, char **argv)
12743{
12744 static const char permuser[3] = "ugo";
12745 static const char permmode[3] = "rwx";
12746 static const short int permmask[] = {
12747 S_IRUSR, S_IWUSR, S_IXUSR,
12748 S_IRGRP, S_IWGRP, S_IXGRP,
12749 S_IROTH, S_IWOTH, S_IXOTH
12750 };
12751
12752 char *ap;
12753 mode_t mask;
12754 int i;
12755 int symbolic_mode = 0;
12756
12757 while (nextopt("S") != '\0') {
12758 symbolic_mode = 1;
12759 }
12760
12761 INTOFF;
12762 mask = umask(0);
12763 umask(mask);
12764 INTON;
12765
12766 if ((ap = *argptr) == NULL) {
12767 if (symbolic_mode) {
12768 char buf[18];
12769 char *p = buf;
12770
12771 for (i = 0; i < 3; i++) {
12772 int j;
12773
12774 *p++ = permuser[i];
12775 *p++ = '=';
12776 for (j = 0; j < 3; j++) {
12777 if ((mask & permmask[3 * i + j]) == 0) {
12778 *p++ = permmode[j];
12779 }
12780 }
12781 *p++ = ',';
12782 }
12783 *--p = 0;
12784 puts(buf);
12785 } else {
12786 out1fmt("%.4o\n", mask);
12787 }
12788 } else {
12789 if (is_digit((unsigned char) *ap)) {
12790 mask = 0;
12791 do {
12792 if (*ap >= '8' || *ap < '0')
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012793 sh_error(illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012794 mask = (mask << 3) + (*ap - '0');
12795 } while (*++ap != '\0');
12796 umask(mask);
12797 } else {
12798 mask = ~mask & 0777;
12799 if (!bb_parse_mode(ap, &mask)) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012800 sh_error("Illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012801 }
12802 umask(~mask & 0777);
12803 }
12804 }
12805 return 0;
12806}
12807
12808/*
12809 * ulimit builtin
12810 *
12811 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12812 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12813 * ash by J.T. Conklin.
12814 *
12815 * Public domain.
12816 */
12817
12818struct limits {
12819 const char *name;
12820 int cmd;
12821 int factor; /* multiply by to get rlim_{cur,max} values */
12822 char option;
12823};
12824
12825static const struct limits limits[] = {
12826#ifdef RLIMIT_CPU
12827 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12828#endif
12829#ifdef RLIMIT_FSIZE
12830 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12831#endif
12832#ifdef RLIMIT_DATA
12833 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12834#endif
12835#ifdef RLIMIT_STACK
12836 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12837#endif
12838#ifdef RLIMIT_CORE
12839 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12840#endif
12841#ifdef RLIMIT_RSS
12842 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12843#endif
12844#ifdef RLIMIT_MEMLOCK
12845 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12846#endif
12847#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012848 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012849#endif
12850#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012851 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012852#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012853#ifdef RLIMIT_AS
12854 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012855#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012856#ifdef RLIMIT_LOCKS
12857 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012858#endif
12859 { (char *) 0, 0, 0, '\0' }
12860};
12861
Glenn L McGrath76620622004-01-13 10:19:37 +000012862enum limtype { SOFT = 0x1, HARD = 0x2 };
12863
12864static void printlim(enum limtype how, const struct rlimit *limit,
12865 const struct limits *l)
12866{
12867 rlim_t val;
12868
12869 val = limit->rlim_max;
12870 if (how & SOFT)
12871 val = limit->rlim_cur;
12872
12873 if (val == RLIM_INFINITY)
12874 out1fmt("unlimited\n");
12875 else {
12876 val /= l->factor;
12877 out1fmt("%lld\n", (long long) val);
12878 }
12879}
12880
Eric Andersenc470f442003-07-28 09:56:35 +000012881int
12882ulimitcmd(int argc, char **argv)
12883{
12884 int c;
12885 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012886 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012887 const struct limits *l;
12888 int set, all = 0;
12889 int optc, what;
12890 struct rlimit limit;
12891
12892 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012893 while ((optc = nextopt("HSa"
12894#ifdef RLIMIT_CPU
12895 "t"
12896#endif
12897#ifdef RLIMIT_FSIZE
12898 "f"
12899#endif
12900#ifdef RLIMIT_DATA
12901 "d"
12902#endif
12903#ifdef RLIMIT_STACK
12904 "s"
12905#endif
12906#ifdef RLIMIT_CORE
12907 "c"
12908#endif
12909#ifdef RLIMIT_RSS
12910 "m"
12911#endif
12912#ifdef RLIMIT_MEMLOCK
12913 "l"
12914#endif
12915#ifdef RLIMIT_NPROC
12916 "p"
12917#endif
12918#ifdef RLIMIT_NOFILE
12919 "n"
12920#endif
12921#ifdef RLIMIT_AS
12922 "v"
12923#endif
12924#ifdef RLIMIT_LOCKS
12925 "w"
12926#endif
12927 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012928 switch (optc) {
12929 case 'H':
12930 how = HARD;
12931 break;
12932 case 'S':
12933 how = SOFT;
12934 break;
12935 case 'a':
12936 all = 1;
12937 break;
12938 default:
12939 what = optc;
12940 }
12941
Glenn L McGrath76620622004-01-13 10:19:37 +000012942 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012943 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012944
12945 set = *argptr ? 1 : 0;
12946 if (set) {
12947 char *p = *argptr;
12948
12949 if (all || argptr[1])
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012950 sh_error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012951 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012952 val = RLIM_INFINITY;
12953 else {
12954 val = (rlim_t) 0;
12955
12956 while ((c = *p++) >= '0' && c <= '9')
12957 {
12958 val = (val * 10) + (long)(c - '0');
12959 if (val < (rlim_t) 0)
12960 break;
12961 }
12962 if (c)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012963 sh_error("bad number");
Eric Andersenc470f442003-07-28 09:56:35 +000012964 val *= l->factor;
12965 }
12966 }
12967 if (all) {
12968 for (l = limits; l->name; l++) {
12969 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012970 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012971 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012972 }
12973 return 0;
12974 }
12975
12976 getrlimit(l->cmd, &limit);
12977 if (set) {
12978 if (how & HARD)
12979 limit.rlim_max = val;
12980 if (how & SOFT)
12981 limit.rlim_cur = val;
12982 if (setrlimit(l->cmd, &limit) < 0)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000012983 sh_error("error setting limit (%m)");
Eric Andersenc470f442003-07-28 09:56:35 +000012984 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012985 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012986 }
12987 return 0;
12988}
12989
Eric Andersen90898442003-08-06 11:20:52 +000012990
12991#ifdef CONFIG_ASH_MATH_SUPPORT
12992
12993/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12994
12995 Permission is hereby granted, free of charge, to any person obtaining
12996 a copy of this software and associated documentation files (the
12997 "Software"), to deal in the Software without restriction, including
12998 without limitation the rights to use, copy, modify, merge, publish,
12999 distribute, sublicense, and/or sell copies of the Software, and to
13000 permit persons to whom the Software is furnished to do so, subject to
13001 the following conditions:
13002
13003 The above copyright notice and this permission notice shall be
13004 included in all copies or substantial portions of the Software.
13005
13006 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13007 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13008 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13009 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13010 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13011 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13012 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13013*/
13014
13015/* This is my infix parser/evaluator. It is optimized for size, intended
13016 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000013017 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000013018 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000013019 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000013020 * be that which POSIX specifies for shells. */
13021
13022/* The code uses a simple two-stack algorithm. See
13023 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000013024 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000013025 * this is based (this code differs in that it applies operators immediately
13026 * to the stack instead of adding them to a queue to end up with an
13027 * expression). */
13028
13029/* To use the routine, call it with an expression string and error return
13030 * pointer */
13031
13032/*
13033 * Aug 24, 2001 Manuel Novoa III
13034 *
13035 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13036 *
13037 * 1) In arith_apply():
13038 * a) Cached values of *numptr and &(numptr[-1]).
13039 * b) Removed redundant test for zero denominator.
13040 *
13041 * 2) In arith():
13042 * a) Eliminated redundant code for processing operator tokens by moving
13043 * to a table-based implementation. Also folded handling of parens
13044 * into the table.
13045 * b) Combined all 3 loops which called arith_apply to reduce generated
13046 * code size at the cost of speed.
13047 *
13048 * 3) The following expressions were treated as valid by the original code:
13049 * 1() , 0! , 1 ( *3 ) .
13050 * These bugs have been fixed by internally enclosing the expression in
13051 * parens and then checking that all binary ops and right parens are
13052 * preceded by a valid expression (NUM_TOKEN).
13053 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013054 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013055 * ctype's isspace() if it is used by another busybox applet or if additional
13056 * whitespace chars should be considered. Look below the "#include"s for a
13057 * precompiler test.
13058 */
13059
13060/*
13061 * Aug 26, 2001 Manuel Novoa III
13062 *
13063 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13064 *
13065 * Merge in Aaron's comments previously posted to the busybox list,
13066 * modified slightly to take account of my changes to the code.
13067 *
13068 */
13069
13070/*
13071 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13072 *
13073 * - allow access to variable,
13074 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13075 * - realize assign syntax (VAR=expr, +=, *= etc)
13076 * - realize exponentiation (** operator)
13077 * - realize comma separated - expr, expr
13078 * - realise ++expr --expr expr++ expr--
13079 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013080 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013081 * - was restored loses XOR operator
13082 * - remove one goto label, added three ;-)
13083 * - protect $((num num)) as true zero expr (Manuel`s error)
13084 * - always use special isspace(), see comment from bash ;-)
13085 */
13086
13087
13088#define arith_isspace(arithval) \
13089 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13090
13091
13092typedef unsigned char operator;
13093
13094/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013095 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013096 * precedence. The ID portion is so that multiple operators can have the
13097 * same precedence, ensuring that the leftmost one is evaluated first.
13098 * Consider * and /. */
13099
13100#define tok_decl(prec,id) (((id)<<5)|(prec))
13101#define PREC(op) ((op) & 0x1F)
13102
13103#define TOK_LPAREN tok_decl(0,0)
13104
13105#define TOK_COMMA tok_decl(1,0)
13106
13107#define TOK_ASSIGN tok_decl(2,0)
13108#define TOK_AND_ASSIGN tok_decl(2,1)
13109#define TOK_OR_ASSIGN tok_decl(2,2)
13110#define TOK_XOR_ASSIGN tok_decl(2,3)
13111#define TOK_PLUS_ASSIGN tok_decl(2,4)
13112#define TOK_MINUS_ASSIGN tok_decl(2,5)
13113#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13114#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13115
13116#define TOK_MUL_ASSIGN tok_decl(3,0)
13117#define TOK_DIV_ASSIGN tok_decl(3,1)
13118#define TOK_REM_ASSIGN tok_decl(3,2)
13119
13120/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13121#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13122
13123/* conditional is right associativity too */
13124#define TOK_CONDITIONAL tok_decl(4,0)
13125#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13126
13127#define TOK_OR tok_decl(5,0)
13128
13129#define TOK_AND tok_decl(6,0)
13130
13131#define TOK_BOR tok_decl(7,0)
13132
13133#define TOK_BXOR tok_decl(8,0)
13134
13135#define TOK_BAND tok_decl(9,0)
13136
13137#define TOK_EQ tok_decl(10,0)
13138#define TOK_NE tok_decl(10,1)
13139
13140#define TOK_LT tok_decl(11,0)
13141#define TOK_GT tok_decl(11,1)
13142#define TOK_GE tok_decl(11,2)
13143#define TOK_LE tok_decl(11,3)
13144
13145#define TOK_LSHIFT tok_decl(12,0)
13146#define TOK_RSHIFT tok_decl(12,1)
13147
13148#define TOK_ADD tok_decl(13,0)
13149#define TOK_SUB tok_decl(13,1)
13150
13151#define TOK_MUL tok_decl(14,0)
13152#define TOK_DIV tok_decl(14,1)
13153#define TOK_REM tok_decl(14,2)
13154
13155/* exponent is right associativity */
13156#define TOK_EXPONENT tok_decl(15,1)
13157
13158/* For now unary operators. */
13159#define UNARYPREC 16
13160#define TOK_BNOT tok_decl(UNARYPREC,0)
13161#define TOK_NOT tok_decl(UNARYPREC,1)
13162
13163#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13164#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13165
13166#define PREC_PRE (UNARYPREC+2)
13167
13168#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13169#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13170
13171#define PREC_POST (UNARYPREC+3)
13172
13173#define TOK_POST_INC tok_decl(PREC_POST, 0)
13174#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13175
13176#define SPEC_PREC (UNARYPREC+4)
13177
13178#define TOK_NUM tok_decl(SPEC_PREC, 0)
13179#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13180
13181#define NUMPTR (*numstackptr)
13182
13183static inline int tok_have_assign(operator op)
13184{
13185 operator prec = PREC(op);
13186
13187 convert_prec_is_assing(prec);
13188 return (prec == PREC(TOK_ASSIGN) ||
13189 prec == PREC_PRE || prec == PREC_POST);
13190}
13191
13192static inline int is_right_associativity(operator prec)
13193{
13194 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13195 prec == PREC(TOK_CONDITIONAL));
13196}
13197
13198
13199typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013200 arith_t val;
13201 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013202 char contidional_second_val_initialized;
13203 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013204 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013205} v_n_t;
13206
13207
13208typedef struct CHK_VAR_RECURSIVE_LOOPED {
13209 const char *var;
13210 struct CHK_VAR_RECURSIVE_LOOPED *next;
13211} chk_var_recursive_looped_t;
13212
13213static chk_var_recursive_looped_t *prev_chk_var_recursive;
13214
13215
13216static int arith_lookup_val(v_n_t *t)
13217{
13218 if(t->var) {
13219 const char * p = lookupvar(t->var);
13220
13221 if(p) {
13222 int errcode;
13223
13224 /* recursive try as expression */
13225 chk_var_recursive_looped_t *cur;
13226 chk_var_recursive_looped_t cur_save;
13227
13228 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13229 if(strcmp(cur->var, t->var) == 0) {
13230 /* expression recursion loop detected */
13231 return -5;
13232 }
13233 }
13234 /* save current lookuped var name */
13235 cur = prev_chk_var_recursive;
13236 cur_save.var = t->var;
13237 cur_save.next = cur;
13238 prev_chk_var_recursive = &cur_save;
13239
13240 t->val = arith (p, &errcode);
13241 /* restore previous ptr after recursiving */
13242 prev_chk_var_recursive = cur;
13243 return errcode;
13244 } else {
13245 /* allow undefined var as 0 */
13246 t->val = 0;
13247 }
13248 }
13249 return 0;
13250}
13251
13252/* "applying" a token means performing it on the top elements on the integer
13253 * stack. For a unary operator it will only change the top element, but a
13254 * binary operator will pop two arguments and push a result */
13255static inline int
13256arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13257{
Eric Andersen90898442003-08-06 11:20:52 +000013258 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013259 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013260 int ret_arith_lookup_val;
13261
13262 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13263 without arguments */
13264 numptr_m1 = NUMPTR - 1;
13265
13266 /* check operand is var with noninteger value */
13267 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13268 if(ret_arith_lookup_val)
13269 return ret_arith_lookup_val;
13270
13271 rez = numptr_m1->val;
13272 if (op == TOK_UMINUS)
13273 rez *= -1;
13274 else if (op == TOK_NOT)
13275 rez = !rez;
13276 else if (op == TOK_BNOT)
13277 rez = ~rez;
13278 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13279 rez++;
13280 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13281 rez--;
13282 else if (op != TOK_UPLUS) {
13283 /* Binary operators */
13284
13285 /* check and binary operators need two arguments */
13286 if (numptr_m1 == numstack) goto err;
13287
13288 /* ... and they pop one */
13289 --NUMPTR;
13290 numptr_val = rez;
13291 if (op == TOK_CONDITIONAL) {
13292 if(! numptr_m1->contidional_second_val_initialized) {
13293 /* protect $((expr1 ? expr2)) without ": expr" */
13294 goto err;
13295 }
13296 rez = numptr_m1->contidional_second_val;
13297 } else if(numptr_m1->contidional_second_val_initialized) {
13298 /* protect $((expr1 : expr2)) without "expr ? " */
13299 goto err;
13300 }
13301 numptr_m1 = NUMPTR - 1;
13302 if(op != TOK_ASSIGN) {
13303 /* check operand is var with noninteger value for not '=' */
13304 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13305 if(ret_arith_lookup_val)
13306 return ret_arith_lookup_val;
13307 }
13308 if (op == TOK_CONDITIONAL) {
13309 numptr_m1->contidional_second_val = rez;
13310 }
13311 rez = numptr_m1->val;
13312 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13313 rez |= numptr_val;
13314 else if (op == TOK_OR)
13315 rez = numptr_val || rez;
13316 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13317 rez &= numptr_val;
13318 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13319 rez ^= numptr_val;
13320 else if (op == TOK_AND)
13321 rez = rez && numptr_val;
13322 else if (op == TOK_EQ)
13323 rez = (rez == numptr_val);
13324 else if (op == TOK_NE)
13325 rez = (rez != numptr_val);
13326 else if (op == TOK_GE)
13327 rez = (rez >= numptr_val);
13328 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13329 rez >>= numptr_val;
13330 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13331 rez <<= numptr_val;
13332 else if (op == TOK_GT)
13333 rez = (rez > numptr_val);
13334 else if (op == TOK_LT)
13335 rez = (rez < numptr_val);
13336 else if (op == TOK_LE)
13337 rez = (rez <= numptr_val);
13338 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13339 rez *= numptr_val;
13340 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13341 rez += numptr_val;
13342 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13343 rez -= numptr_val;
13344 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13345 rez = numptr_val;
13346 else if (op == TOK_CONDITIONAL_SEP) {
13347 if (numptr_m1 == numstack) {
13348 /* protect $((expr : expr)) without "expr ? " */
13349 goto err;
13350 }
13351 numptr_m1->contidional_second_val_initialized = op;
13352 numptr_m1->contidional_second_val = numptr_val;
13353 }
13354 else if (op == TOK_CONDITIONAL) {
13355 rez = rez ?
13356 numptr_val : numptr_m1->contidional_second_val;
13357 }
13358 else if(op == TOK_EXPONENT) {
13359 if(numptr_val < 0)
13360 return -3; /* exponent less than 0 */
13361 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013362 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013363
13364 if(numptr_val)
13365 while(numptr_val--)
13366 c *= rez;
13367 rez = c;
13368 }
13369 }
13370 else if(numptr_val==0) /* zero divisor check */
13371 return -2;
13372 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13373 rez /= numptr_val;
13374 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13375 rez %= numptr_val;
13376 }
13377 if(tok_have_assign(op)) {
13378 char buf[32];
13379
13380 if(numptr_m1->var == NULL) {
13381 /* Hmm, 1=2 ? */
13382 goto err;
13383 }
13384 /* save to shell variable */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013385#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersena68ea1c2006-01-30 22:48:39 +000013386 snprintf(buf, sizeof(buf), "%lld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013387#else
Eric Andersena68ea1c2006-01-30 22:48:39 +000013388 snprintf(buf, sizeof(buf), "%ld", arith_t_type rez);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013389#endif
Eric Andersen90898442003-08-06 11:20:52 +000013390 setvar(numptr_m1->var, buf, 0);
13391 /* after saving, make previous value for v++ or v-- */
13392 if(op == TOK_POST_INC)
13393 rez--;
13394 else if(op == TOK_POST_DEC)
13395 rez++;
13396 }
13397 numptr_m1->val = rez;
13398 /* protect geting var value, is number now */
13399 numptr_m1->var = NULL;
13400 return 0;
13401err: return(-1);
13402}
13403
13404/* longest must first */
13405static const char op_tokens[] = {
13406 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13407 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13408 '<','<', 0, TOK_LSHIFT,
13409 '>','>', 0, TOK_RSHIFT,
13410 '|','|', 0, TOK_OR,
13411 '&','&', 0, TOK_AND,
13412 '!','=', 0, TOK_NE,
13413 '<','=', 0, TOK_LE,
13414 '>','=', 0, TOK_GE,
13415 '=','=', 0, TOK_EQ,
13416 '|','=', 0, TOK_OR_ASSIGN,
13417 '&','=', 0, TOK_AND_ASSIGN,
13418 '*','=', 0, TOK_MUL_ASSIGN,
13419 '/','=', 0, TOK_DIV_ASSIGN,
13420 '%','=', 0, TOK_REM_ASSIGN,
13421 '+','=', 0, TOK_PLUS_ASSIGN,
13422 '-','=', 0, TOK_MINUS_ASSIGN,
13423 '-','-', 0, TOK_POST_DEC,
13424 '^','=', 0, TOK_XOR_ASSIGN,
13425 '+','+', 0, TOK_POST_INC,
13426 '*','*', 0, TOK_EXPONENT,
13427 '!', 0, TOK_NOT,
13428 '<', 0, TOK_LT,
13429 '>', 0, TOK_GT,
13430 '=', 0, TOK_ASSIGN,
13431 '|', 0, TOK_BOR,
13432 '&', 0, TOK_BAND,
13433 '*', 0, TOK_MUL,
13434 '/', 0, TOK_DIV,
13435 '%', 0, TOK_REM,
13436 '+', 0, TOK_ADD,
13437 '-', 0, TOK_SUB,
13438 '^', 0, TOK_BXOR,
13439 /* uniq */
13440 '~', 0, TOK_BNOT,
13441 ',', 0, TOK_COMMA,
13442 '?', 0, TOK_CONDITIONAL,
13443 ':', 0, TOK_CONDITIONAL_SEP,
13444 ')', 0, TOK_RPAREN,
13445 '(', 0, TOK_LPAREN,
13446 0
13447};
13448/* ptr to ")" */
13449#define endexpression &op_tokens[sizeof(op_tokens)-7]
13450
13451
Eric Andersened9ecf72004-06-22 08:29:45 +000013452static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013453{
13454 register char arithval; /* Current character under analysis */
13455 operator lasttok, op;
13456 operator prec;
13457
13458 const char *p = endexpression;
13459 int errcode;
13460
13461 size_t datasizes = strlen(expr) + 2;
13462
13463 /* Stack of integers */
13464 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013465 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013466 * the reader. */
13467 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13468 *numstackptr = numstack;
13469 /* Stack of operator tokens */
13470 operator *stack = alloca((datasizes) * sizeof(operator)),
13471 *stackptr = stack;
13472
13473 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13474 *perrcode = errcode = 0;
13475
13476 while(1) {
13477 if ((arithval = *expr) == 0) {
13478 if (p == endexpression) {
13479 /* Null expression. */
13480 return 0;
13481 }
13482
13483 /* This is only reached after all tokens have been extracted from the
13484 * input stream. If there are still tokens on the operator stack, they
13485 * are to be applied in order. At the end, there should be a final
13486 * result on the integer stack */
13487
13488 if (expr != endexpression + 1) {
13489 /* If we haven't done so already, */
13490 /* append a closing right paren */
13491 expr = endexpression;
13492 /* and let the loop process it. */
13493 continue;
13494 }
13495 /* At this point, we're done with the expression. */
13496 if (numstackptr != numstack+1) {
13497 /* ... but if there isn't, it's bad */
13498 err:
13499 return (*perrcode = -1);
13500 }
13501 if(numstack->var) {
13502 /* expression is $((var)) only, lookup now */
13503 errcode = arith_lookup_val(numstack);
13504 }
13505 ret:
13506 *perrcode = errcode;
13507 return numstack->val;
13508 } else {
13509 /* Continue processing the expression. */
13510 if (arith_isspace(arithval)) {
13511 /* Skip whitespace */
13512 goto prologue;
13513 }
13514 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013515 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013516
13517 numstackptr->var = alloca(var_name_size);
13518 safe_strncpy(numstackptr->var, expr, var_name_size);
13519 expr = p;
13520 num:
13521 numstackptr->contidional_second_val_initialized = 0;
13522 numstackptr++;
13523 lasttok = TOK_NUM;
13524 continue;
13525 } else if (is_digit(arithval)) {
13526 numstackptr->var = NULL;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013527#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersenad63cb22004-10-08 09:43:34 +000013528 numstackptr->val = strtoll(expr, (char **) &expr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013529#else
13530 numstackptr->val = strtol(expr, (char **) &expr, 0);
13531#endif
Eric Andersen90898442003-08-06 11:20:52 +000013532 goto num;
13533 }
13534 for(p = op_tokens; ; p++) {
13535 const char *o;
13536
13537 if(*p == 0) {
13538 /* strange operator not found */
13539 goto err;
13540 }
13541 for(o = expr; *p && *o == *p; p++)
13542 o++;
13543 if(! *p) {
13544 /* found */
13545 expr = o - 1;
13546 break;
13547 }
13548 /* skip tail uncompared token */
13549 while(*p)
13550 p++;
13551 /* skip zero delim */
13552 p++;
13553 }
13554 op = p[1];
13555
13556 /* post grammar: a++ reduce to num */
13557 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13558 lasttok = TOK_NUM;
13559
13560 /* Plus and minus are binary (not unary) _only_ if the last
13561 * token was as number, or a right paren (which pretends to be
13562 * a number, since it evaluates to one). Think about it.
13563 * It makes sense. */
13564 if (lasttok != TOK_NUM) {
13565 switch(op) {
13566 case TOK_ADD:
13567 op = TOK_UPLUS;
13568 break;
13569 case TOK_SUB:
13570 op = TOK_UMINUS;
13571 break;
13572 case TOK_POST_INC:
13573 op = TOK_PRE_INC;
13574 break;
13575 case TOK_POST_DEC:
13576 op = TOK_PRE_DEC;
13577 break;
13578 }
13579 }
13580 /* We don't want a unary operator to cause recursive descent on the
13581 * stack, because there can be many in a row and it could cause an
13582 * operator to be evaluated before its argument is pushed onto the
13583 * integer stack. */
13584 /* But for binary operators, "apply" everything on the operator
13585 * stack until we find an operator with a lesser priority than the
13586 * one we have just extracted. */
13587 /* Left paren is given the lowest priority so it will never be
13588 * "applied" in this way.
13589 * if associativity is right and priority eq, applied also skip
13590 */
13591 prec = PREC(op);
13592 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13593 /* not left paren or unary */
13594 if (lasttok != TOK_NUM) {
13595 /* binary op must be preceded by a num */
13596 goto err;
13597 }
13598 while (stackptr != stack) {
13599 if (op == TOK_RPAREN) {
13600 /* The algorithm employed here is simple: while we don't
13601 * hit an open paren nor the bottom of the stack, pop
13602 * tokens and apply them */
13603 if (stackptr[-1] == TOK_LPAREN) {
13604 --stackptr;
13605 /* Any operator directly after a */
13606 lasttok = TOK_NUM;
13607 /* close paren should consider itself binary */
13608 goto prologue;
13609 }
13610 } else {
13611 operator prev_prec = PREC(stackptr[-1]);
13612
13613 convert_prec_is_assing(prec);
13614 convert_prec_is_assing(prev_prec);
13615 if (prev_prec < prec)
13616 break;
13617 /* check right assoc */
13618 if(prev_prec == prec && is_right_associativity(prec))
13619 break;
13620 }
13621 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13622 if(errcode) goto ret;
13623 }
13624 if (op == TOK_RPAREN) {
13625 goto err;
13626 }
13627 }
13628
13629 /* Push this operator to the stack and remember it. */
13630 *stackptr++ = lasttok = op;
13631
13632 prologue:
13633 ++expr;
13634 }
13635 }
13636}
13637#endif /* CONFIG_ASH_MATH_SUPPORT */
13638
13639
Eric Andersenc470f442003-07-28 09:56:35 +000013640#ifdef DEBUG
13641const char *bb_applet_name = "debug stuff usage";
13642int main(int argc, char **argv)
13643{
13644 return ash_main(argc, argv);
13645}
13646#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013647
Eric Andersendf82f612001-06-28 07:46:40 +000013648/*-
13649 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013650 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013651 *
13652 * This code is derived from software contributed to Berkeley by
13653 * Kenneth Almquist.
13654 *
13655 * Redistribution and use in source and binary forms, with or without
13656 * modification, are permitted provided that the following conditions
13657 * are met:
13658 * 1. Redistributions of source code must retain the above copyright
13659 * notice, this list of conditions and the following disclaimer.
13660 * 2. Redistributions in binary form must reproduce the above copyright
13661 * notice, this list of conditions and the following disclaimer in the
13662 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013663 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013664 * may be used to endorse or promote products derived from this software
13665 * without specific prior written permission.
13666 *
13667 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13668 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13669 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13670 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13671 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13672 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13673 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13674 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13675 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13676 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13677 * SUCH DAMAGE.
13678 */