blob: 6c6c28693fd5a18f57db8f03e1761b0fb7156880 [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 *
Eric Andersen81fe1232003-07-29 06:38:40 +00008 * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9 * 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 *
Eric Andersendf82f612001-06-28 07:46:40 +000015 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000019 *
Eric Andersendf82f612001-06-28 07:46:40 +000020 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
Eric Andersen81fe1232003-07-29 06:38:40 +000029 * Original BSD copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000030 */
31
Eric Andersenc470f442003-07-28 09:56:35 +000032/*
Eric Andersen90898442003-08-06 11:20:52 +000033 * rewrite arith.y to micro stack based cryptic algorithm by
34 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
35 *
Eric Andersenef02f822004-03-11 13:34:24 +000036 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
37 * dynamic variables.
Eric Andersen16767e22004-03-16 05:14:10 +000038 *
39 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be
40 * used in busybox and size optimizations,
41 * rewrote arith (see notes to this), added locale support,
42 * rewrote dynamic variables.
43 *
Eric Andersen90898442003-08-06 11:20:52 +000044 */
45
46
47/*
Eric Andersenc470f442003-07-28 09:56:35 +000048 * The follow should be set to reflect the type of system you have:
49 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
50 * define SYSV if you are running under System V.
51 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
52 * define DEBUG=2 to compile in and turn on debugging.
53 *
54 * When debugging is on, debugging info will be written to ./trace and
55 * a quit signal will generate a core dump.
56 */
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058
Eric Andersenc470f442003-07-28 09:56:35 +000059
Eric Andersen5bb16772001-09-06 18:00:41 +000060#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000061
Eric Andersenc470f442003-07-28 09:56:35 +000062#define PROFILE 0
63
64#ifdef DEBUG
65#define _GNU_SOURCE
66#endif
67
68#include <sys/types.h>
69#include <sys/cdefs.h>
70#include <sys/ioctl.h>
71#include <sys/param.h>
72#include <sys/resource.h>
73#include <sys/stat.h>
74#include <sys/time.h>
75#include <sys/wait.h>
76
77#include <stdio.h>
78#include <stdlib.h>
79#include <string.h>
80#include <unistd.h>
81
82#include <stdarg.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000083#include <stddef.h>
Eric Andersenc470f442003-07-28 09:56:35 +000084#include <assert.h>
Eric Andersencb57d552001-06-28 07:25:16 +000085#include <ctype.h>
86#include <dirent.h>
87#include <errno.h>
88#include <fcntl.h>
89#include <limits.h>
90#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000091#include <setjmp.h>
92#include <signal.h>
Eric Andersenc470f442003-07-28 09:56:35 +000093#include <stdint.h>
Eric Andersencb57d552001-06-28 07:25:16 +000094#include <sysexits.h>
Eric Andersenef02f822004-03-11 13:34:24 +000095#include <time.h>
Eric Andersenc470f442003-07-28 09:56:35 +000096#include <fnmatch.h>
Eric Andersenc470f442003-07-28 09:56:35 +000097
98
Robert Grieblea1a63a2002-06-04 20:10:23 +000099#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +0000100#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +0000101
Eric Andersend35c5df2002-01-09 15:37:36 +0000102#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +0000103#define JOBS 1
104#else
Eric Andersenca162042003-07-29 07:15:17 +0000105#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +0000106#endif
107
108#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000109#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000110#endif
111
Eric Andersen2870d962001-07-02 17:27:21 +0000112#include "cmdedit.h"
113
Eric Andersenc470f442003-07-28 09:56:35 +0000114#ifdef __GLIBC__
115/* glibc sucks */
116static int *dash_errno;
117#undef errno
118#define errno (*dash_errno)
119#endif
120
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000121#if defined(__uClinux__)
122#error "Do not even bother, ash will not run on uClinux"
123#endif
124
Eric Andersenc470f442003-07-28 09:56:35 +0000125#ifdef DEBUG
126#define _DIAGASSERT(assert_expr) assert(assert_expr)
127#else
128#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000129#endif
130
Eric Andersen2870d962001-07-02 17:27:21 +0000131
Eric Andersenc470f442003-07-28 09:56:35 +0000132#ifdef CONFIG_ASH_ALIAS
133/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
134
135#define ALIASINUSE 1
136#define ALIASDEAD 2
137
138struct alias {
139 struct alias *next;
140 char *name;
141 char *val;
142 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000143};
144
Eric Andersenc470f442003-07-28 09:56:35 +0000145static struct alias *lookupalias(const char *, int);
146static int aliascmd(int, char **);
147static int unaliascmd(int, char **);
148static void rmaliases(void);
149static int unalias(const char *);
150static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000151#endif
152
Eric Andersenc470f442003-07-28 09:56:35 +0000153/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
154
155
156static void setpwd(const char *, int);
157
158/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
159
160
161/*
162 * Types of operations (passed to the errmsg routine).
163 */
164
165
166static const char not_found_msg[] = "%s: not found";
167
168
169#define E_OPEN "No such file" /* opening a file */
170#define E_CREAT "Directory nonexistent" /* creating a file */
171#define E_EXEC not_found_msg+4 /* executing a program */
172
173/*
174 * We enclose jmp_buf in a structure so that we can declare pointers to
175 * jump locations. The global variable handler contains the location to
176 * jump to when an exception occurs, and the global variable exception
Eric Andersenaff114c2004-04-14 17:51:38 +0000177 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000178 * exception handlers, the user should save the value of handler on entry
179 * to an inner scope, set handler to point to a jmploc structure for the
180 * inner scope, and restore handler on exit from the scope.
181 */
182
183struct jmploc {
184 jmp_buf loc;
185};
186
187static struct jmploc *handler;
188static int exception;
189static volatile int suppressint;
190static volatile sig_atomic_t intpending;
191
192static int exerrno; /* Last exec error, error for EXEXEC */
193
194/* exceptions */
195#define EXINT 0 /* SIGINT received */
196#define EXERROR 1 /* a generic error */
197#define EXSHELLPROC 2 /* execute a shell procedure */
198#define EXEXEC 3 /* command execution failed */
199#define EXEXIT 4 /* exit the shell */
200#define EXSIG 5 /* trapped signal in wait(1) */
201
202
203/* do we generate EXSIG events */
204static int exsig;
205/* last pending signal */
206static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000207
208/*
209 * These macros allow the user to suspend the handling of interrupt signals
210 * over a period of time. This is similar to SIGHOLD to or sigblock, but
211 * much more efficient and portable. (But hacking the kernel is so much
212 * more fun than worrying about efficiency and portability. :-))
213 */
214
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000215#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
Eric Andersenc470f442003-07-28 09:56:35 +0000216#define INTOFF \
217 ({ \
218 suppressint++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000219 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000220 0; \
221 })
222#define SAVEINT(v) ((v) = suppressint)
223#define RESTOREINT(v) \
224 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000225 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000226 if ((suppressint = (v)) == 0 && intpending) onint(); \
227 0; \
228 })
229#define EXSIGON() \
230 ({ \
231 exsig++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000232 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000233 if (pendingsigs) \
234 exraise(EXSIG); \
235 0; \
236 })
237/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000238
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000239
Eric Andersenc470f442003-07-28 09:56:35 +0000240static void exraise(int) __attribute__((__noreturn__));
241static void onint(void) __attribute__((__noreturn__));
242
243static void error(const char *, ...) __attribute__((__noreturn__));
244static void exerror(int, const char *, ...) __attribute__((__noreturn__));
245
246static void sh_warnx(const char *, ...);
247
248#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
249static void
250inton(void) {
251 if (--suppressint == 0 && intpending) {
252 onint();
253 }
254}
255#define INTON inton()
256static void forceinton(void)
257{
258 suppressint = 0;
259 if (intpending)
260 onint();
261}
Eric Andersen3102ac42001-07-06 04:26:23 +0000262#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000263#else
Eric Andersenc470f442003-07-28 09:56:35 +0000264#define INTON \
265 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000266 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000267 if (--suppressint == 0 && intpending) onint(); \
268 0; \
269 })
270#define FORCEINTON \
271 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000272 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000273 suppressint = 0; \
274 if (intpending) onint(); \
275 0; \
276 })
277#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000278
279/*
Eric Andersenc470f442003-07-28 09:56:35 +0000280 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
281 * so we use _setjmp instead.
Eric Andersen2870d962001-07-02 17:27:21 +0000282 */
Eric Andersen2870d962001-07-02 17:27:21 +0000283
Eric Andersenc470f442003-07-28 09:56:35 +0000284#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
285#define setjmp(jmploc) _setjmp(jmploc)
286#define longjmp(jmploc, val) _longjmp(jmploc, val)
287#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000288
Eric Andersenc470f442003-07-28 09:56:35 +0000289/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000290
291struct strlist {
292 struct strlist *next;
293 char *text;
294};
295
296
297struct arglist {
298 struct strlist *list;
299 struct strlist **lastp;
300};
301
Eric Andersenc470f442003-07-28 09:56:35 +0000302/*
303 * expandarg() flags
304 */
305#define EXP_FULL 0x1 /* perform word splitting & file globbing */
306#define EXP_TILDE 0x2 /* do normal tilde expansion */
307#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
308#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
309#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
310#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
311#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
312#define EXP_WORD 0x80 /* expand word in parameter expansion */
313#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
314
315
316union node;
317static void expandarg(union node *, struct arglist *, int);
318#define rmescapes(p) _rmescapes((p), 0)
319static char *_rmescapes(char *, int);
320static int casematch(union node *, char *);
321
322#ifdef CONFIG_ASH_MATH_SUPPORT
323static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000324#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000325
Eric Andersenc470f442003-07-28 09:56:35 +0000326/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000327
Eric Andersenc470f442003-07-28 09:56:35 +0000328static char *commandname; /* currently executing command */
329static struct strlist *cmdenviron; /* environment for builtin command */
330static int exitstatus; /* exit status of last command */
331static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000332
Eric Andersenc470f442003-07-28 09:56:35 +0000333
334struct backcmd { /* result of evalbackcmd */
335 int fd; /* file descriptor to read from */
336 char *buf; /* buffer */
337 int nleft; /* number of chars in buffer */
338 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000339};
340
Eric Andersen62483552001-07-10 06:09:16 +0000341/*
Eric Andersenc470f442003-07-28 09:56:35 +0000342 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000343 */
Eric Andersenc470f442003-07-28 09:56:35 +0000344
345#define NCMD 0
346#define NPIPE 1
347#define NREDIR 2
348#define NBACKGND 3
349#define NSUBSHELL 4
350#define NAND 5
351#define NOR 6
352#define NSEMI 7
353#define NIF 8
354#define NWHILE 9
355#define NUNTIL 10
356#define NFOR 11
357#define NCASE 12
358#define NCLIST 13
359#define NDEFUN 14
360#define NARG 15
361#define NTO 16
362#define NCLOBBER 17
363#define NFROM 18
364#define NFROMTO 19
365#define NAPPEND 20
366#define NTOFD 21
367#define NFROMFD 22
368#define NHERE 23
369#define NXHERE 24
370#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000371
372
373
Eric Andersenc470f442003-07-28 09:56:35 +0000374struct ncmd {
375 int type;
376 union node *assign;
377 union node *args;
378 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000379};
380
381
Eric Andersenc470f442003-07-28 09:56:35 +0000382struct npipe {
383 int type;
384 int backgnd;
385 struct nodelist *cmdlist;
386};
Eric Andersen62483552001-07-10 06:09:16 +0000387
388
Eric Andersenc470f442003-07-28 09:56:35 +0000389struct nredir {
390 int type;
391 union node *n;
392 union node *redirect;
393};
Eric Andersen62483552001-07-10 06:09:16 +0000394
395
Eric Andersenc470f442003-07-28 09:56:35 +0000396struct nbinary {
397 int type;
398 union node *ch1;
399 union node *ch2;
400};
Eric Andersen2870d962001-07-02 17:27:21 +0000401
Eric Andersen2870d962001-07-02 17:27:21 +0000402
Eric Andersenc470f442003-07-28 09:56:35 +0000403struct nif {
404 int type;
405 union node *test;
406 union node *ifpart;
407 union node *elsepart;
408};
409
410
411struct nfor {
412 int type;
413 union node *args;
414 union node *body;
415 char *var;
416};
417
418
419struct ncase {
420 int type;
421 union node *expr;
422 union node *cases;
423};
424
425
426struct nclist {
427 int type;
428 union node *next;
429 union node *pattern;
430 union node *body;
431};
432
433
434struct narg {
435 int type;
436 union node *next;
437 char *text;
438 struct nodelist *backquote;
439};
440
441
442struct nfile {
443 int type;
444 union node *next;
445 int fd;
446 union node *fname;
447 char *expfname;
448};
449
450
451struct ndup {
452 int type;
453 union node *next;
454 int fd;
455 int dupfd;
456 union node *vname;
457};
458
459
460struct nhere {
461 int type;
462 union node *next;
463 int fd;
464 union node *doc;
465};
466
467
468struct nnot {
469 int type;
470 union node *com;
471};
472
473
474union node {
475 int type;
476 struct ncmd ncmd;
477 struct npipe npipe;
478 struct nredir nredir;
479 struct nbinary nbinary;
480 struct nif nif;
481 struct nfor nfor;
482 struct ncase ncase;
483 struct nclist nclist;
484 struct narg narg;
485 struct nfile nfile;
486 struct ndup ndup;
487 struct nhere nhere;
488 struct nnot nnot;
489};
490
491
492struct nodelist {
493 struct nodelist *next;
494 union node *n;
495};
496
497
498struct funcnode {
499 int count;
500 union node n;
501};
502
503
504static void freefunc(struct funcnode *);
505/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
506
507/* control characters in argument strings */
508#define CTL_FIRST '\201' /* first 'special' character */
509#define CTLESC '\201' /* escape next character */
510#define CTLVAR '\202' /* variable defn */
511#define CTLENDVAR '\203'
512#define CTLBACKQ '\204'
513#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
514/* CTLBACKQ | CTLQUOTE == '\205' */
515#define CTLARI '\206' /* arithmetic expression */
516#define CTLENDARI '\207'
517#define CTLQUOTEMARK '\210'
518#define CTL_LAST '\210' /* last 'special' character */
519
520/* variable substitution byte (follows CTLVAR) */
521#define VSTYPE 0x0f /* type of variable substitution */
522#define VSNUL 0x10 /* colon--treat the empty string as unset */
523#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
524
525/* values of VSTYPE field */
526#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
527#define VSMINUS 0x2 /* ${var-text} */
528#define VSPLUS 0x3 /* ${var+text} */
529#define VSQUESTION 0x4 /* ${var?message} */
530#define VSASSIGN 0x5 /* ${var=text} */
531#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
532#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
533#define VSTRIMLEFT 0x8 /* ${var#pattern} */
534#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
535#define VSLENGTH 0xa /* ${#var} */
536
537/* values of checkkwd variable */
538#define CHKALIAS 0x1
539#define CHKKWD 0x2
540#define CHKNL 0x4
541
542#define IBUFSIZ (BUFSIZ + 1)
543
544/*
545 * NEOF is returned by parsecmd when it encounters an end of file. It
546 * must be distinct from NULL, so we use the address of a variable that
547 * happens to be handy.
548 */
549static int plinno = 1; /* input line number */
550
551/* number of characters left in input buffer */
552static int parsenleft; /* copy of parsefile->nleft */
553static int parselleft; /* copy of parsefile->lleft */
554
555/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000556static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000557
558struct strpush {
559 struct strpush *prev; /* preceding string on stack */
560 char *prevstring;
561 int prevnleft;
562#ifdef CONFIG_ASH_ALIAS
563 struct alias *ap; /* if push was associated with an alias */
564#endif
565 char *string; /* remember the string since it may change */
566};
567
568struct parsefile {
569 struct parsefile *prev; /* preceding file on stack */
570 int linno; /* current line */
571 int fd; /* file descriptor (or -1 if string) */
572 int nleft; /* number of chars left in this line */
573 int lleft; /* number of chars left in this buffer */
574 char *nextc; /* next char in buffer */
575 char *buf; /* input buffer */
576 struct strpush *strpush; /* for pushing strings at this level */
577 struct strpush basestrpush; /* so pushing one is fast */
578};
579
Eric Andersenc470f442003-07-28 09:56:35 +0000580static struct parsefile basepf; /* top level input file */
581static char basebuf[IBUFSIZ]; /* buffer for top level input file */
582static struct parsefile *parsefile = &basepf; /* current input file */
583
584
585static int tokpushback; /* last token pushed back */
586#define NEOF ((union node *)&tokpushback)
587static int parsebackquote; /* nonzero if we are inside backquotes */
588static int doprompt; /* if set, prompt the user */
589static int needprompt; /* true if interactive and at start of line */
590static int lasttoken; /* last token read */
591static char *wordtext; /* text of last word returned by readtoken */
592static int checkkwd;
593static struct nodelist *backquotelist;
594static union node *redirnode;
595static struct heredoc *heredoc;
596static int quoteflag; /* set if (part of) last token was quoted */
597static int startlinno; /* line # where last token started */
598
599static union node *parsecmd(int);
600static void fixredir(union node *, const char *, int);
601static const char *const *findkwd(const char *);
602static char *endofname(const char *);
603
604/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
605
606typedef void *pointer;
607
608static char nullstr[1]; /* zero length string */
609static const char spcstr[] = " ";
610static const char snlfmt[] = "%s\n";
611static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
612static const char illnum[] = "Illegal number: %s";
613static const char homestr[] = "HOME";
614
615#ifdef DEBUG
616#define TRACE(param) trace param
617#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000618#else
Eric Andersenc470f442003-07-28 09:56:35 +0000619#define TRACE(param)
620#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000621#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000622
Eric Andersenc470f442003-07-28 09:56:35 +0000623#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
624#define __builtin_expect(x, expected_value) (x)
625#endif
626
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000627#define xlikely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000628
Eric Andersenc470f442003-07-28 09:56:35 +0000629
630#define TEOF 0
631#define TNL 1
632#define TREDIR 2
633#define TWORD 3
634#define TSEMI 4
635#define TBACKGND 5
636#define TAND 6
637#define TOR 7
638#define TPIPE 8
639#define TLP 9
640#define TRP 10
641#define TENDCASE 11
642#define TENDBQUOTE 12
643#define TNOT 13
644#define TCASE 14
645#define TDO 15
646#define TDONE 16
647#define TELIF 17
648#define TELSE 18
649#define TESAC 19
650#define TFI 20
651#define TFOR 21
652#define TIF 22
653#define TIN 23
654#define TTHEN 24
655#define TUNTIL 25
656#define TWHILE 26
657#define TBEGIN 27
658#define TEND 28
659
660/* first char is indicating which tokens mark the end of a list */
661static const char *const tokname_array[] = {
662 "\1end of file",
663 "\0newline",
664 "\0redirection",
665 "\0word",
666 "\0;",
667 "\0&",
668 "\0&&",
669 "\0||",
670 "\0|",
671 "\0(",
672 "\1)",
673 "\1;;",
674 "\1`",
675#define KWDOFFSET 13
676 /* the following are keywords */
677 "\0!",
678 "\0case",
679 "\1do",
680 "\1done",
681 "\1elif",
682 "\1else",
683 "\1esac",
684 "\1fi",
685 "\0for",
686 "\0if",
687 "\0in",
688 "\1then",
689 "\0until",
690 "\0while",
691 "\0{",
692 "\1}",
693};
694
695static const char *tokname(int tok)
696{
697 static char buf[16];
698
699 if (tok >= TSEMI)
700 buf[0] = '"';
701 sprintf(buf + (tok >= TSEMI), "%s%c",
702 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
703 return buf;
704}
705
706/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
707
708/*
709 * Most machines require the value returned from malloc to be aligned
710 * in some way. The following macro will get this right on many machines.
711 */
712
713#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
714/*
715 * It appears that grabstackstr() will barf with such alignments
716 * because stalloc() will return a string allocated in a new stackblock.
717 */
718#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
719
720/*
721 * This file was generated by the mksyntax program.
722 */
723
724
725/* Syntax classes */
726#define CWORD 0 /* character is nothing special */
727#define CNL 1 /* newline character */
728#define CBACK 2 /* a backslash character */
729#define CSQUOTE 3 /* single quote */
730#define CDQUOTE 4 /* double quote */
731#define CENDQUOTE 5 /* a terminating quote */
732#define CBQUOTE 6 /* backwards single quote */
733#define CVAR 7 /* a dollar sign */
734#define CENDVAR 8 /* a '}' character */
735#define CLP 9 /* a left paren in arithmetic */
736#define CRP 10 /* a right paren in arithmetic */
737#define CENDFILE 11 /* end of file */
738#define CCTL 12 /* like CWORD, except it must be escaped */
739#define CSPCL 13 /* these terminate a word */
740#define CIGN 14 /* character should be ignored */
741
742#ifdef CONFIG_ASH_ALIAS
743#define SYNBASE 130
744#define PEOF -130
745#define PEOA -129
746#define PEOA_OR_PEOF PEOA
747#else
748#define SYNBASE 129
749#define PEOF -129
750#define PEOA_OR_PEOF PEOF
751#endif
752
753#define is_digit(c) ((unsigned)((c) - '0') <= 9)
754#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
755#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
756
757/*
758 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
759 * (assuming ascii char codes, as the original implementation did)
760 */
761#define is_special(c) \
762 ( (((unsigned int)c) - 33 < 32) \
763 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
764
765#define digit_val(c) ((c) - '0')
766
767/*
768 * This file was generated by the mksyntax program.
769 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000770
Eric Andersend35c5df2002-01-09 15:37:36 +0000771#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000772#define USE_SIT_FUNCTION
773#endif
774
775/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000776#define BASESYNTAX 0 /* not in quotes */
777#define DQSYNTAX 1 /* in double quotes */
778#define SQSYNTAX 2 /* in single quotes */
779#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000780
Eric Andersenc470f442003-07-28 09:56:35 +0000781#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000782static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000783#ifdef CONFIG_ASH_ALIAS
784 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
785#endif
786 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
787 {CNL, CNL, CNL, CNL}, /* 2, \n */
788 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
789 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
790 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
791 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
792 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
793 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
794 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
795 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
796 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000797#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000798 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
799 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
800 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000801#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000802};
Eric Andersenc470f442003-07-28 09:56:35 +0000803#else
804static const char S_I_T[][3] = {
805#ifdef CONFIG_ASH_ALIAS
806 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
807#endif
808 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
809 {CNL, CNL, CNL}, /* 2, \n */
810 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
811 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
812 {CVAR, CVAR, CWORD}, /* 5, $ */
813 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
814 {CSPCL, CWORD, CWORD}, /* 7, ( */
815 {CSPCL, CWORD, CWORD}, /* 8, ) */
816 {CBACK, CBACK, CCTL}, /* 9, \ */
817 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
818 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
819#ifndef USE_SIT_FUNCTION
820 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
821 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
822 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
823#endif
824};
825#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000826
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000827#ifdef USE_SIT_FUNCTION
828
829#define U_C(c) ((unsigned char)(c))
830
831static int SIT(int c, int syntax)
832{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000833 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000834#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000835 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000836 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
837 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
838 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
839 11, 3 /* "}~" */
840 };
841#else
842 static const char syntax_index_table[] = {
843 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
844 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
845 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
846 10, 2 /* "}~" */
847 };
848#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000849 const char *s;
850 int indx;
851
Eric Andersenc470f442003-07-28 09:56:35 +0000852 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000853 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000854#ifdef CONFIG_ASH_ALIAS
855 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000856 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000857 else
858#endif
859 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
860 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000861 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000862 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000863 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000864 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000865 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000866 }
867 return S_I_T[indx][syntax];
868}
869
Eric Andersenc470f442003-07-28 09:56:35 +0000870#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000871
872#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
873
Eric Andersenc470f442003-07-28 09:56:35 +0000874#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000875#define CSPCL_CIGN_CIGN_CIGN 0
876#define CSPCL_CWORD_CWORD_CWORD 1
877#define CNL_CNL_CNL_CNL 2
878#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000879#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000880#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000881#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000882#define CSPCL_CWORD_CWORD_CLP 7
883#define CSPCL_CWORD_CWORD_CRP 8
884#define CBACK_CBACK_CCTL_CBACK 9
885#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
886#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
887#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
888#define CWORD_CWORD_CWORD_CWORD 13
889#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000890#else
891#define CSPCL_CWORD_CWORD_CWORD 0
892#define CNL_CNL_CNL_CNL 1
893#define CWORD_CCTL_CCTL_CWORD 2
894#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
895#define CVAR_CVAR_CWORD_CVAR 4
896#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
897#define CSPCL_CWORD_CWORD_CLP 6
898#define CSPCL_CWORD_CWORD_CRP 7
899#define CBACK_CBACK_CCTL_CBACK 8
900#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
901#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
902#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
903#define CWORD_CWORD_CWORD_CWORD 12
904#define CCTL_CCTL_CCTL_CCTL 13
905#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000906
907static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000908 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000909 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
910#ifdef CONFIG_ASH_ALIAS
911 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
912#endif
913 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
914 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
915 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
916 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
917 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
918 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
919 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
920 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
921 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000922 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
923 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
924 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
925 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
926 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
927 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
928 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
929 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
930 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
931 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
932 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
933 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
934 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
935 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
936 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
937 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
938 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
939 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
940 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
941 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
942 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
943 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
944 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
945 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
946 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
947 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
948 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
949 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
950 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
951 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
952 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
953 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
954 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
955 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
956 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
957 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
958 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
959 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
960 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
961 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
962 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
963 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
964 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
965 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
966 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
967 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
968 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
969 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
970 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
971 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
972 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
973 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
974 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
975 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
976 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
977 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
978 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
979 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
980 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
981 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
982 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
983 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
984 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
985 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
986 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
987 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
988 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
989 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
990 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
991 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
992 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
993 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
994 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
995 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
996 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
997 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
998 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
999 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1051 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1052 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1053 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1054 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1055 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1056 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1057 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1058 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1059 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1060 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1061 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1062 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1063 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1064 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1065 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1066 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1067 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1068 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1069 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1070 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1071 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1072 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1073 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001075 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001076 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1077 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1078 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001080 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001081 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1082 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1083 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1084 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1086 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1087 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1088 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1089 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1100 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1101 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1102 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1103 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1104 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1105 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1133 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1134 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1135 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1138 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1143 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1144 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1145 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1146 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1147 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1148 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1149 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1150 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1151 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1152 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1153 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1154 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1155 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1156 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1157 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1158 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1159 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1160 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1161 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1162 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1163 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1164 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1165 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1166 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1167 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1168 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001169};
1170
Eric Andersenc470f442003-07-28 09:56:35 +00001171#endif /* USE_SIT_FUNCTION */
1172
1173/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001174
Eric Andersen2870d962001-07-02 17:27:21 +00001175
Eric Andersenc470f442003-07-28 09:56:35 +00001176#define ATABSIZE 39
1177
1178static int funcblocksize; /* size of structures in function */
1179static int funcstringsize; /* size of strings in node */
1180static pointer funcblock; /* block to allocate function from */
1181static char *funcstring; /* block to allocate strings from */
1182
1183static const short nodesize[26] = {
1184 SHELL_ALIGN(sizeof (struct ncmd)),
1185 SHELL_ALIGN(sizeof (struct npipe)),
1186 SHELL_ALIGN(sizeof (struct nredir)),
1187 SHELL_ALIGN(sizeof (struct nredir)),
1188 SHELL_ALIGN(sizeof (struct nredir)),
1189 SHELL_ALIGN(sizeof (struct nbinary)),
1190 SHELL_ALIGN(sizeof (struct nbinary)),
1191 SHELL_ALIGN(sizeof (struct nbinary)),
1192 SHELL_ALIGN(sizeof (struct nif)),
1193 SHELL_ALIGN(sizeof (struct nbinary)),
1194 SHELL_ALIGN(sizeof (struct nbinary)),
1195 SHELL_ALIGN(sizeof (struct nfor)),
1196 SHELL_ALIGN(sizeof (struct ncase)),
1197 SHELL_ALIGN(sizeof (struct nclist)),
1198 SHELL_ALIGN(sizeof (struct narg)),
1199 SHELL_ALIGN(sizeof (struct narg)),
1200 SHELL_ALIGN(sizeof (struct nfile)),
1201 SHELL_ALIGN(sizeof (struct nfile)),
1202 SHELL_ALIGN(sizeof (struct nfile)),
1203 SHELL_ALIGN(sizeof (struct nfile)),
1204 SHELL_ALIGN(sizeof (struct nfile)),
1205 SHELL_ALIGN(sizeof (struct ndup)),
1206 SHELL_ALIGN(sizeof (struct ndup)),
1207 SHELL_ALIGN(sizeof (struct nhere)),
1208 SHELL_ALIGN(sizeof (struct nhere)),
1209 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001210};
1211
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001212
Eric Andersenc470f442003-07-28 09:56:35 +00001213static void calcsize(union node *);
1214static void sizenodelist(struct nodelist *);
1215static union node *copynode(union node *);
1216static struct nodelist *copynodelist(struct nodelist *);
1217static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001218
1219
Eric Andersen2870d962001-07-02 17:27:21 +00001220
Glenn L McGrath76620622004-01-13 10:19:37 +00001221static void evalstring(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001222union node; /* BLETCH for ansi C */
1223static void evaltree(union node *, int);
1224static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001225
Eric Andersenc470f442003-07-28 09:56:35 +00001226/* in_function returns nonzero if we are currently evaluating a function */
1227#define in_function() funcnest
1228static int evalskip; /* set if we are skipping commands */
1229static int skipcount; /* number of levels to skip */
1230static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001231
1232/* reasons for skipping commands (see comment on breakcmd routine) */
1233#define SKIPBREAK 1
1234#define SKIPCONT 2
1235#define SKIPFUNC 3
1236#define SKIPFILE 4
1237
Eric Andersenc470f442003-07-28 09:56:35 +00001238/*
1239 * This file was generated by the mkbuiltins program.
1240 */
Eric Andersen2870d962001-07-02 17:27:21 +00001241
Eric Andersenc470f442003-07-28 09:56:35 +00001242#ifdef JOBS
1243static int bgcmd(int, char **);
1244#endif
1245static int breakcmd(int, char **);
1246static int cdcmd(int, char **);
1247#ifdef CONFIG_ASH_CMDCMD
1248static int commandcmd(int, char **);
1249#endif
1250static int dotcmd(int, char **);
1251static int evalcmd(int, char **);
1252static int execcmd(int, char **);
1253static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001254static int exportcmd(int, char **);
1255static int falsecmd(int, char **);
1256#ifdef JOBS
1257static int fgcmd(int, char **);
1258#endif
1259#ifdef CONFIG_ASH_GETOPTS
1260static int getoptscmd(int, char **);
1261#endif
1262static int hashcmd(int, char **);
1263#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1264static int helpcmd(int argc, char **argv);
1265#endif
1266#ifdef JOBS
1267static int jobscmd(int, char **);
1268#endif
Eric Andersen90898442003-08-06 11:20:52 +00001269#ifdef CONFIG_ASH_MATH_SUPPORT
1270static int letcmd(int, char **);
1271#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001272static int localcmd(int, char **);
1273static int pwdcmd(int, char **);
1274static int readcmd(int, char **);
1275static int returncmd(int, char **);
1276static int setcmd(int, char **);
1277static int shiftcmd(int, char **);
1278static int timescmd(int, char **);
1279static int trapcmd(int, char **);
1280static int truecmd(int, char **);
1281static int typecmd(int, char **);
1282static int umaskcmd(int, char **);
1283static int unsetcmd(int, char **);
1284static int waitcmd(int, char **);
1285static int ulimitcmd(int, char **);
1286#ifdef JOBS
1287static int killcmd(int, char **);
1288#endif
1289
1290/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1291
1292#ifdef CONFIG_ASH_MAIL
1293static void chkmail(void);
1294static void changemail(const char *);
1295#endif
1296
1297/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1298
1299/* values of cmdtype */
1300#define CMDUNKNOWN -1 /* no entry in table for command */
1301#define CMDNORMAL 0 /* command is an executable program */
1302#define CMDFUNCTION 1 /* command is a shell function */
1303#define CMDBUILTIN 2 /* command is a shell builtin */
1304
1305struct builtincmd {
1306 const char *name;
1307 int (*builtin)(int, char **);
1308 /* unsigned flags; */
1309};
1310
1311#ifdef CONFIG_ASH_CMDCMD
1312# ifdef JOBS
1313# ifdef CONFIG_ASH_ALIAS
1314# define COMMANDCMD (builtincmd + 7)
1315# define EXECCMD (builtincmd + 10)
1316# else
1317# define COMMANDCMD (builtincmd + 6)
1318# define EXECCMD (builtincmd + 9)
1319# endif
1320# else /* ! JOBS */
1321# ifdef CONFIG_ASH_ALIAS
1322# define COMMANDCMD (builtincmd + 6)
1323# define EXECCMD (builtincmd + 9)
1324# else
1325# define COMMANDCMD (builtincmd + 5)
1326# define EXECCMD (builtincmd + 8)
1327# endif
1328# endif /* JOBS */
1329#else /* ! CONFIG_ASH_CMDCMD */
1330# ifdef JOBS
1331# ifdef CONFIG_ASH_ALIAS
1332# define EXECCMD (builtincmd + 9)
1333# else
1334# define EXECCMD (builtincmd + 8)
1335# endif
1336# else /* ! JOBS */
1337# ifdef CONFIG_ASH_ALIAS
1338# define EXECCMD (builtincmd + 8)
1339# else
1340# define EXECCMD (builtincmd + 7)
1341# endif
1342# endif /* JOBS */
1343#endif /* CONFIG_ASH_CMDCMD */
1344
1345#define BUILTIN_NOSPEC "0"
1346#define BUILTIN_SPECIAL "1"
1347#define BUILTIN_REGULAR "2"
1348#define BUILTIN_SPEC_REG "3"
1349#define BUILTIN_ASSIGN "4"
1350#define BUILTIN_SPEC_ASSG "5"
1351#define BUILTIN_REG_ASSG "6"
1352#define BUILTIN_SPEC_REG_ASSG "7"
1353
1354#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1355#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1356
1357static const struct builtincmd builtincmd[] = {
1358 { BUILTIN_SPEC_REG ".", dotcmd },
1359 { BUILTIN_SPEC_REG ":", truecmd },
1360#ifdef CONFIG_ASH_ALIAS
1361 { BUILTIN_REG_ASSG "alias", aliascmd },
1362#endif
1363#ifdef JOBS
1364 { BUILTIN_REGULAR "bg", bgcmd },
1365#endif
1366 { BUILTIN_SPEC_REG "break", breakcmd },
1367 { BUILTIN_REGULAR "cd", cdcmd },
1368 { BUILTIN_NOSPEC "chdir", cdcmd },
1369#ifdef CONFIG_ASH_CMDCMD
1370 { BUILTIN_REGULAR "command", commandcmd },
1371#endif
1372 { BUILTIN_SPEC_REG "continue", breakcmd },
1373 { BUILTIN_SPEC_REG "eval", evalcmd },
1374 { BUILTIN_SPEC_REG "exec", execcmd },
1375 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001376 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1377 { BUILTIN_REGULAR "false", falsecmd },
1378#ifdef JOBS
1379 { BUILTIN_REGULAR "fg", fgcmd },
1380#endif
1381#ifdef CONFIG_ASH_GETOPTS
1382 { BUILTIN_REGULAR "getopts", getoptscmd },
1383#endif
1384 { BUILTIN_NOSPEC "hash", hashcmd },
1385#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1386 { BUILTIN_NOSPEC "help", helpcmd },
1387#endif
1388#ifdef JOBS
1389 { BUILTIN_REGULAR "jobs", jobscmd },
1390 { BUILTIN_REGULAR "kill", killcmd },
1391#endif
1392#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001393 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001394#endif
1395 { BUILTIN_ASSIGN "local", localcmd },
1396 { BUILTIN_NOSPEC "pwd", pwdcmd },
1397 { BUILTIN_REGULAR "read", readcmd },
1398 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1399 { BUILTIN_SPEC_REG "return", returncmd },
1400 { BUILTIN_SPEC_REG "set", setcmd },
1401 { BUILTIN_SPEC_REG "shift", shiftcmd },
1402 { BUILTIN_SPEC_REG "times", timescmd },
1403 { BUILTIN_SPEC_REG "trap", trapcmd },
1404 { BUILTIN_REGULAR "true", truecmd },
1405 { BUILTIN_NOSPEC "type", typecmd },
1406 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1407 { BUILTIN_REGULAR "umask", umaskcmd },
1408#ifdef CONFIG_ASH_ALIAS
1409 { BUILTIN_REGULAR "unalias", unaliascmd },
1410#endif
1411 { BUILTIN_SPEC_REG "unset", unsetcmd },
1412 { BUILTIN_REGULAR "wait", waitcmd },
1413};
1414
1415#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1416
1417
1418
1419struct cmdentry {
1420 int cmdtype;
1421 union param {
1422 int index;
1423 const struct builtincmd *cmd;
1424 struct funcnode *func;
1425 } u;
1426};
1427
1428
1429/* action to find_command() */
1430#define DO_ERR 0x01 /* prints errors */
1431#define DO_ABS 0x02 /* checks absolute paths */
1432#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1433#define DO_ALTPATH 0x08 /* using alternate path */
1434#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1435
1436static const char *pathopt; /* set by padvance */
1437
1438static void shellexec(char **, const char *, int)
1439 __attribute__((__noreturn__));
1440static char *padvance(const char **, const char *);
1441static void find_command(char *, struct cmdentry *, int, const char *);
1442static struct builtincmd *find_builtin(const char *);
1443static void hashcd(void);
1444static void changepath(const char *);
1445static void defun(char *, union node *);
1446static void unsetfunc(const char *);
1447
Eric Andersened9ecf72004-06-22 08:29:45 +00001448#ifdef CONFIG_ASH_MATH_SUPPORT_64
1449typedef int64_t arith_t;
1450#else
1451typedef long arith_t;
1452#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001453
1454#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001455static arith_t dash_arith(const char *);
1456static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001457#endif
1458
Eric Andersen16767e22004-03-16 05:14:10 +00001459#ifdef CONFIG_ASH_RANDOM_SUPPORT
1460static unsigned long rseed;
1461static void change_random(const char *);
1462# ifndef DYNAMIC_VAR
1463# define DYNAMIC_VAR
1464# endif
1465#endif
1466
Eric Andersenc470f442003-07-28 09:56:35 +00001467/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1468
1469static void reset(void);
1470
1471/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001472
1473/*
1474 * Shell variables.
1475 */
1476
1477/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001478#define VEXPORT 0x01 /* variable is exported */
1479#define VREADONLY 0x02 /* variable cannot be modified */
1480#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1481#define VTEXTFIXED 0x08 /* text is statically allocated */
1482#define VSTACK 0x10 /* text is allocated on the stack */
1483#define VUNSET 0x20 /* the variable is not set */
1484#define VNOFUNC 0x40 /* don't call the callback function */
1485#define VNOSET 0x80 /* do not set variable - just readonly test */
1486#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001487#ifdef DYNAMIC_VAR
1488# define VDYNAMIC 0x200 /* dynamic variable */
1489# else
1490# define VDYNAMIC 0
1491#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001492
1493struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001494 struct var *next; /* next entry in hash list */
1495 int flags; /* flags are defined above */
1496 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001497 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001498 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001499};
1500
1501struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001502 struct localvar *next; /* next local variable in list */
1503 struct var *vp; /* the variable that was made local */
1504 int flags; /* saved flags */
1505 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001506};
1507
1508
Eric Andersen2870d962001-07-02 17:27:21 +00001509static struct localvar *localvars;
1510
Eric Andersenc470f442003-07-28 09:56:35 +00001511/*
1512 * Shell variables.
1513 */
1514
1515#ifdef CONFIG_ASH_GETOPTS
1516static void getoptsreset(const char *);
1517#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001518
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001519#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001520#include <locale.h>
1521static void change_lc_all(const char *value);
1522static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001523#endif
1524
Eric Andersenef02f822004-03-11 13:34:24 +00001525
Eric Andersen2870d962001-07-02 17:27:21 +00001526#define VTABSIZE 39
1527
Eric Andersen90898442003-08-06 11:20:52 +00001528static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001529#ifdef IFS_BROKEN
1530static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001531#define defifs (defifsvar + 4)
1532#else
Eric Andersenc470f442003-07-28 09:56:35 +00001533static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001534#endif
1535
Eric Andersenc470f442003-07-28 09:56:35 +00001536
1537static struct var varinit[] = {
1538#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001539 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001540#else
Eric Andersen16767e22004-03-16 05:14:10 +00001541 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001542#endif
1543
1544#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001545 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1546 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001547#endif
1548
Eric Andersen16767e22004-03-16 05:14:10 +00001549 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1550 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1551 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1552 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001553#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001554 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1555#endif
1556#ifdef CONFIG_ASH_RANDOM_SUPPORT
1557 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001558#endif
1559#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001560 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1561 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001562#endif
1563#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001564 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001565#endif
1566};
1567
1568#define vifs varinit[0]
1569#ifdef CONFIG_ASH_MAIL
1570#define vmail (&vifs)[1]
1571#define vmpath (&vmail)[1]
1572#else
1573#define vmpath vifs
1574#endif
1575#define vpath (&vmpath)[1]
1576#define vps1 (&vpath)[1]
1577#define vps2 (&vps1)[1]
1578#define vps4 (&vps2)[1]
1579#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001580#ifdef CONFIG_ASH_GETOPTS
1581#define vrandom (&voptind)[1]
1582#else
1583#define vrandom (&vps4)[1]
1584#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001585#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001586
1587/*
1588 * The following macros access the values of the above variables.
1589 * They have to skip over the name. They return the null string
1590 * for unset variables.
1591 */
1592
1593#define ifsval() (vifs.text + 4)
1594#define ifsset() ((vifs.flags & VUNSET) == 0)
1595#define mailval() (vmail.text + 5)
1596#define mpathval() (vmpath.text + 9)
1597#define pathval() (vpath.text + 5)
1598#define ps1val() (vps1.text + 4)
1599#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001600#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001601#define optindval() (voptind.text + 7)
1602
1603#define mpathset() ((vmpath.flags & VUNSET) == 0)
1604
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001605static void setvar(const char *, const char *, int);
1606static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001607static void listsetvar(struct strlist *, int);
1608static char *lookupvar(const char *);
1609static char *bltinlookup(const char *);
1610static char **listvars(int, int, char ***);
1611#define environment() listvars(VEXPORT, VUNSET, 0)
1612static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001613static void poplocalvars(void);
1614static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001615#ifdef CONFIG_ASH_GETOPTS
1616static int setvarsafe(const char *, const char *, int);
1617#endif
1618static int varcmp(const char *, const char *);
1619static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001620
1621
Eric Andersenc470f442003-07-28 09:56:35 +00001622static inline int varequal(const char *a, const char *b) {
1623 return !varcmp(a, b);
1624}
Eric Andersen2870d962001-07-02 17:27:21 +00001625
1626
Eric Andersenc470f442003-07-28 09:56:35 +00001627static int loopnest; /* current loop nesting level */
1628
Eric Andersenc470f442003-07-28 09:56:35 +00001629/*
1630 * The parsefile structure pointed to by the global variable parsefile
1631 * contains information about the current file being read.
1632 */
1633
1634
1635struct redirtab {
1636 struct redirtab *next;
1637 int renamed[10];
1638 int nullredirs;
1639};
1640
1641static struct redirtab *redirlist;
1642static int nullredirs;
1643
1644extern char **environ;
1645
1646/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1647
1648
1649static void outstr(const char *, FILE *);
1650static void outcslow(int, FILE *);
1651static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001652static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001653static int out1fmt(const char *, ...)
1654 __attribute__((__format__(__printf__,1,2)));
1655static int fmtstr(char *, size_t, const char *, ...)
1656 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001657
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001658static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001659
Eric Andersenc470f442003-07-28 09:56:35 +00001660
1661static void out1str(const char *p)
1662{
1663 outstr(p, stdout);
1664}
1665
1666static void out2str(const char *p)
1667{
1668 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001669 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001670}
1671
1672/*
1673 * Initialization code.
1674 */
1675
1676/*
1677 * This routine initializes the builtin variables.
1678 */
1679
1680static inline void
1681initvar(void)
1682{
1683 struct var *vp;
1684 struct var *end;
1685 struct var **vpp;
1686
1687 /*
1688 * PS1 depends on uid
1689 */
1690#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1691 vps1.text = "PS1=\\w \\$ ";
1692#else
1693 if (!geteuid())
1694 vps1.text = "PS1=# ";
1695#endif
1696 vp = varinit;
1697 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1698 do {
1699 vpp = hashvar(vp->text);
1700 vp->next = *vpp;
1701 *vpp = vp;
1702 } while (++vp < end);
1703}
1704
1705static inline void
1706init(void)
1707{
1708
1709 /* from input.c: */
1710 {
1711 basepf.nextc = basepf.buf = basebuf;
1712 }
1713
1714 /* from trap.c: */
1715 {
1716 signal(SIGCHLD, SIG_DFL);
1717 }
1718
1719 /* from var.c: */
1720 {
1721 char **envp;
1722 char ppid[32];
1723
1724 initvar();
1725 for (envp = environ ; *envp ; envp++) {
1726 if (strchr(*envp, '=')) {
1727 setvareq(*envp, VEXPORT|VTEXTFIXED);
1728 }
1729 }
1730
1731 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1732 setvar("PPID", ppid, 0);
1733 setpwd(0, 0);
1734 }
1735}
1736
1737/* PEOF (the end of file marker) */
1738
1739/*
1740 * The input line number. Input.c just defines this variable, and saves
1741 * and restores it when files are pushed and popped. The user of this
1742 * package must set its value.
1743 */
1744
1745static int pgetc(void);
1746static int pgetc2(void);
1747static int preadbuffer(void);
1748static void pungetc(void);
1749static void pushstring(char *, void *);
1750static void popstring(void);
1751static void setinputfile(const char *, int);
1752static void setinputfd(int, int);
1753static void setinputstring(char *);
1754static void popfile(void);
1755static void popallfiles(void);
1756static void closescript(void);
1757
1758
1759/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1760
1761
1762/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1763#define FORK_FG 0
1764#define FORK_BG 1
1765#define FORK_NOJOB 2
1766
1767/* mode flags for showjob(s) */
1768#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1769#define SHOW_PID 0x04 /* include process pid */
1770#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1771
1772
1773/*
1774 * A job structure contains information about a job. A job is either a
1775 * single process or a set of processes contained in a pipeline. In the
1776 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1777 * array of pids.
1778 */
1779
1780struct procstat {
1781 pid_t pid; /* process id */
1782 int status; /* last process status from wait() */
1783 char *cmd; /* text of command being run */
1784};
1785
1786struct job {
1787 struct procstat ps0; /* status of process */
1788 struct procstat *ps; /* status or processes when more than one */
1789#if JOBS
1790 int stopstatus; /* status of a stopped job */
1791#endif
1792 uint32_t
1793 nprocs: 16, /* number of processes */
1794 state: 8,
1795#define JOBRUNNING 0 /* at least one proc running */
1796#define JOBSTOPPED 1 /* all procs are stopped */
1797#define JOBDONE 2 /* all procs are completed */
1798#if JOBS
1799 sigint: 1, /* job was killed by SIGINT */
1800 jobctl: 1, /* job running under job control */
1801#endif
1802 waited: 1, /* true if this entry has been waited for */
1803 used: 1, /* true if this entry is in used */
1804 changed: 1; /* true if status has changed */
1805 struct job *prev_job; /* previous job */
1806};
1807
1808static pid_t backgndpid; /* pid of last background process */
1809static int job_warning; /* user was warned about stopped jobs */
1810#if JOBS
1811static int jobctl; /* true if doing job control */
1812#endif
1813
1814static struct job *makejob(union node *, int);
1815static int forkshell(struct job *, union node *, int);
1816static int waitforjob(struct job *);
1817static int stoppedjobs(void);
1818
1819#if ! JOBS
1820#define setjobctl(on) /* do nothing */
1821#else
1822static void setjobctl(int);
1823static void showjobs(FILE *, int);
1824#endif
1825
1826/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1827
1828
1829/* pid of main shell */
1830static int rootpid;
1831/* true if we aren't a child of the main shell */
1832static int rootshell;
1833
1834static void readcmdfile(char *);
1835static void cmdloop(int);
1836
1837/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1838
1839
1840struct stackmark {
1841 struct stack_block *stackp;
1842 char *stacknxt;
1843 size_t stacknleft;
1844 struct stackmark *marknext;
1845};
1846
1847/* minimum size of a block */
1848#define MINSIZE SHELL_ALIGN(504)
1849
1850struct stack_block {
1851 struct stack_block *prev;
1852 char space[MINSIZE];
1853};
1854
1855static struct stack_block stackbase;
1856static struct stack_block *stackp = &stackbase;
1857static struct stackmark *markp;
1858static char *stacknxt = stackbase.space;
1859static size_t stacknleft = MINSIZE;
1860static char *sstrend = stackbase.space + MINSIZE;
1861static int herefd = -1;
1862
1863
1864static pointer ckmalloc(size_t);
1865static pointer ckrealloc(pointer, size_t);
1866static char *savestr(const char *);
1867static pointer stalloc(size_t);
1868static void stunalloc(pointer);
1869static void setstackmark(struct stackmark *);
1870static void popstackmark(struct stackmark *);
1871static void growstackblock(void);
1872static void *growstackstr(void);
1873static char *makestrspace(size_t, char *);
1874static char *stnputs(const char *, size_t, char *);
1875static char *stputs(const char *, char *);
1876
1877
1878static inline char *_STPUTC(char c, char *p) {
1879 if (p == sstrend)
1880 p = growstackstr();
1881 *p++ = c;
1882 return p;
1883}
1884
1885#define stackblock() ((void *)stacknxt)
1886#define stackblocksize() stacknleft
1887#define STARTSTACKSTR(p) ((p) = stackblock())
1888#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1889#define CHECKSTRSPACE(n, p) \
1890 ({ \
1891 char *q = (p); \
1892 size_t l = (n); \
1893 size_t m = sstrend - q; \
1894 if (l > m) \
1895 (p) = makestrspace(l, q); \
1896 0; \
1897 })
1898#define USTPUTC(c, p) (*p++ = (c))
1899#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1900#define STUNPUTC(p) (--p)
1901#define STTOPC(p) p[-1]
1902#define STADJUST(amount, p) (p += (amount))
1903
1904#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1905#define ungrabstackstr(s, p) stunalloc((s))
1906#define stackstrend() ((void *)sstrend)
1907
1908#define ckfree(p) free((pointer)(p))
1909
1910/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1911
1912
1913#define DOLATSTRLEN 4
1914
1915static char *prefix(const char *, const char *);
1916static int number(const char *);
1917static int is_number(const char *);
1918static char *single_quote(const char *);
1919static char *sstrdup(const char *);
1920
1921#define equal(s1, s2) (strcmp(s1, s2) == 0)
1922#define scopy(s1, s2) ((void)strcpy(s2, s1))
1923
1924/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1925
1926struct shparam {
1927 int nparam; /* # of positional parameters (without $0) */
1928 unsigned char malloc; /* if parameter list dynamically allocated */
1929 char **p; /* parameter list */
1930#ifdef CONFIG_ASH_GETOPTS
1931 int optind; /* next parameter to be processed by getopts */
1932 int optoff; /* used by getopts */
1933#endif
1934};
1935
1936
1937#define eflag optlist[0]
1938#define fflag optlist[1]
1939#define Iflag optlist[2]
1940#define iflag optlist[3]
1941#define mflag optlist[4]
1942#define nflag optlist[5]
1943#define sflag optlist[6]
1944#define xflag optlist[7]
1945#define vflag optlist[8]
1946#define Cflag optlist[9]
1947#define aflag optlist[10]
1948#define bflag optlist[11]
1949#define uflag optlist[12]
1950#define qflag optlist[13]
1951
1952#ifdef DEBUG
1953#define nolog optlist[14]
1954#define debug optlist[15]
1955#define NOPTS 16
1956#else
1957#define NOPTS 14
1958#endif
1959
1960/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1961
1962
1963static const char *const optletters_optnames[NOPTS] = {
1964 "e" "errexit",
1965 "f" "noglob",
1966 "I" "ignoreeof",
1967 "i" "interactive",
1968 "m" "monitor",
1969 "n" "noexec",
1970 "s" "stdin",
1971 "x" "xtrace",
1972 "v" "verbose",
1973 "C" "noclobber",
1974 "a" "allexport",
1975 "b" "notify",
1976 "u" "nounset",
1977 "q" "quietprofile",
1978#ifdef DEBUG
1979 "\0" "nolog",
1980 "\0" "debug",
1981#endif
1982};
1983
1984#define optletters(n) optletters_optnames[(n)][0]
1985#define optnames(n) (&optletters_optnames[(n)][1])
1986
1987
1988static char optlist[NOPTS];
1989
1990
1991static char *arg0; /* value of $0 */
1992static struct shparam shellparam; /* $@ current positional parameters */
1993static char **argptr; /* argument list for builtin commands */
1994static char *optionarg; /* set by nextopt (like getopt) */
1995static char *optptr; /* used by nextopt */
1996
1997static char *minusc; /* argument to -c option */
1998
1999
2000static void procargs(int, char **);
2001static void optschanged(void);
2002static void setparam(char **);
2003static void freeparam(volatile struct shparam *);
2004static int shiftcmd(int, char **);
2005static int setcmd(int, char **);
2006static int nextopt(const char *);
2007
2008/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
2009
2010/* flags passed to redirect */
2011#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002012#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00002013
2014union node;
2015static void redirect(union node *, int);
2016static void popredir(int);
2017static void clearredir(int);
2018static int copyfd(int, int);
2019static int redirectsafe(union node *, int);
2020
2021/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2022
2023
2024#ifdef DEBUG
2025static void showtree(union node *);
2026static void trace(const char *, ...);
2027static void tracev(const char *, va_list);
2028static void trargs(char **);
2029static void trputc(int);
2030static void trputs(const char *);
2031static void opentrace(void);
2032#endif
2033
2034/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2035
2036
2037/* trap handler commands */
2038static char *trap[NSIG];
2039/* current value of signal */
2040static char sigmode[NSIG - 1];
2041/* indicates specified signal received */
2042static char gotsig[NSIG - 1];
2043
2044static void clear_traps(void);
2045static void setsignal(int);
2046static void ignoresig(int);
2047static void onsig(int);
2048static void dotrap(void);
2049static void setinteractive(int);
2050static void exitshell(void) __attribute__((__noreturn__));
2051static int decode_signal(const char *, int);
2052
2053/*
2054 * This routine is called when an error or an interrupt occurs in an
2055 * interactive shell and control is returned to the main command loop.
2056 */
2057
2058static void
2059reset(void)
2060{
2061 /* from eval.c: */
2062 {
2063 evalskip = 0;
2064 loopnest = 0;
2065 funcnest = 0;
2066 }
2067
2068 /* from input.c: */
2069 {
2070 parselleft = parsenleft = 0; /* clear input buffer */
2071 popallfiles();
2072 }
2073
2074 /* from parser.c: */
2075 {
2076 tokpushback = 0;
2077 checkkwd = 0;
2078 }
2079
2080 /* from redir.c: */
2081 {
2082 clearredir(0);
2083 }
2084
2085}
2086
2087#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002088static struct alias *atab[ATABSIZE];
2089
Eric Andersenc470f442003-07-28 09:56:35 +00002090static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002091static struct alias *freealias(struct alias *);
2092static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002093
Eric Andersenc470f442003-07-28 09:56:35 +00002094static void
2095setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002096{
2097 struct alias *ap, **app;
2098
2099 app = __lookupalias(name);
2100 ap = *app;
2101 INTOFF;
2102 if (ap) {
2103 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002104 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002105 }
Eric Andersenc470f442003-07-28 09:56:35 +00002106 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002107 ap->flag &= ~ALIASDEAD;
2108 } else {
2109 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002110 ap = ckmalloc(sizeof (struct alias));
2111 ap->name = savestr(name);
2112 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002113 ap->flag = 0;
2114 ap->next = 0;
2115 *app = ap;
2116 }
2117 INTON;
2118}
2119
Eric Andersenc470f442003-07-28 09:56:35 +00002120static int
2121unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002122{
Eric Andersencb57d552001-06-28 07:25:16 +00002123 struct alias **app;
2124
2125 app = __lookupalias(name);
2126
2127 if (*app) {
2128 INTOFF;
2129 *app = freealias(*app);
2130 INTON;
2131 return (0);
2132 }
2133
2134 return (1);
2135}
2136
Eric Andersenc470f442003-07-28 09:56:35 +00002137static void
2138rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002139{
Eric Andersencb57d552001-06-28 07:25:16 +00002140 struct alias *ap, **app;
2141 int i;
2142
2143 INTOFF;
2144 for (i = 0; i < ATABSIZE; i++) {
2145 app = &atab[i];
2146 for (ap = *app; ap; ap = *app) {
2147 *app = freealias(*app);
2148 if (ap == *app) {
2149 app = &ap->next;
2150 }
2151 }
2152 }
2153 INTON;
2154}
2155
Eric Andersenc470f442003-07-28 09:56:35 +00002156static struct alias *
2157lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002158{
Eric Andersenc470f442003-07-28 09:56:35 +00002159 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002160
Eric Andersenc470f442003-07-28 09:56:35 +00002161 if (check && ap && (ap->flag & ALIASINUSE))
2162 return (NULL);
2163 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002164}
2165
Eric Andersencb57d552001-06-28 07:25:16 +00002166/*
2167 * TODO - sort output
2168 */
Eric Andersenc470f442003-07-28 09:56:35 +00002169static int
2170aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002171{
2172 char *n, *v;
2173 int ret = 0;
2174 struct alias *ap;
2175
2176 if (argc == 1) {
2177 int i;
2178
2179 for (i = 0; i < ATABSIZE; i++)
2180 for (ap = atab[i]; ap; ap = ap->next) {
2181 printalias(ap);
2182 }
2183 return (0);
2184 }
2185 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002186 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002187 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002188 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002189 ret = 1;
2190 } else
2191 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002192 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002193 *v++ = '\0';
2194 setalias(n, v);
2195 }
2196 }
2197
2198 return (ret);
2199}
2200
Eric Andersenc470f442003-07-28 09:56:35 +00002201static int
2202unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002203{
2204 int i;
2205
2206 while ((i = nextopt("a")) != '\0') {
2207 if (i == 'a') {
2208 rmaliases();
2209 return (0);
2210 }
2211 }
2212 for (i = 0; *argptr; argptr++) {
2213 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002214 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002215 i = 1;
2216 }
2217 }
2218
2219 return (i);
2220}
2221
Eric Andersenc470f442003-07-28 09:56:35 +00002222static struct alias *
2223freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002224 struct alias *next;
2225
2226 if (ap->flag & ALIASINUSE) {
2227 ap->flag |= ALIASDEAD;
2228 return ap;
2229 }
2230
2231 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002232 ckfree(ap->name);
2233 ckfree(ap->val);
2234 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002235 return next;
2236}
2237
Eric Andersenc470f442003-07-28 09:56:35 +00002238static void
2239printalias(const struct alias *ap) {
2240 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2241}
Eric Andersencb57d552001-06-28 07:25:16 +00002242
Eric Andersenc470f442003-07-28 09:56:35 +00002243static struct alias **
2244__lookupalias(const char *name) {
2245 unsigned int hashval;
2246 struct alias **app;
2247 const char *p;
2248 unsigned int ch;
2249
2250 p = name;
2251
2252 ch = (unsigned char)*p;
2253 hashval = ch << 4;
2254 while (ch) {
2255 hashval += ch;
2256 ch = (unsigned char)*++p;
2257 }
2258 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002259
2260 for (; *app; app = &(*app)->next) {
2261 if (equal(name, (*app)->name)) {
2262 break;
2263 }
2264 }
2265
2266 return app;
2267}
Eric Andersenc470f442003-07-28 09:56:35 +00002268#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002269
Eric Andersencb57d552001-06-28 07:25:16 +00002270
Eric Andersenc470f442003-07-28 09:56:35 +00002271/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00002272
Eric Andersencb57d552001-06-28 07:25:16 +00002273/*
Eric Andersenc470f442003-07-28 09:56:35 +00002274 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002275 */
2276
Eric Andersenc470f442003-07-28 09:56:35 +00002277#define CD_PHYSICAL 1
2278#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002279
Eric Andersenc470f442003-07-28 09:56:35 +00002280static int docd(const char *, int);
2281static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002282
Eric Andersenc470f442003-07-28 09:56:35 +00002283static char *curdir = nullstr; /* current working directory */
2284static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002285
Eric Andersenc470f442003-07-28 09:56:35 +00002286static int
2287cdopt(void)
2288{
2289 int flags = 0;
2290 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002291
Eric Andersenc470f442003-07-28 09:56:35 +00002292 j = 'L';
2293 while ((i = nextopt("LP"))) {
2294 if (i != j) {
2295 flags ^= CD_PHYSICAL;
2296 j = i;
2297 }
2298 }
Eric Andersencb57d552001-06-28 07:25:16 +00002299
Eric Andersenc470f442003-07-28 09:56:35 +00002300 return flags;
2301}
Eric Andersen2870d962001-07-02 17:27:21 +00002302
Eric Andersenc470f442003-07-28 09:56:35 +00002303static int
2304cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002305{
2306 const char *dest;
2307 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002308 const char *p;
2309 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002310 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002311 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002312
Eric Andersenc470f442003-07-28 09:56:35 +00002313 flags = cdopt();
2314 dest = *argptr;
2315 if (!dest)
2316 dest = bltinlookup(homestr);
2317 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002318 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002319 flags |= CD_PRINT;
2320 goto step7;
Eric Andersencb57d552001-06-28 07:25:16 +00002321 }
Eric Andersenc470f442003-07-28 09:56:35 +00002322 if (!dest)
2323 dest = nullstr;
2324 if (*dest == '/')
2325 goto step7;
2326 if (*dest == '.') {
2327 c = dest[1];
2328dotdot:
2329 switch (c) {
2330 case '\0':
2331 case '/':
2332 goto step6;
2333 case '.':
2334 c = dest[2];
2335 if (c != '.')
2336 goto dotdot;
2337 }
2338 }
2339 if (!*dest)
2340 dest = ".";
2341 if (!(path = bltinlookup("CDPATH"))) {
2342step6:
2343step7:
2344 p = dest;
2345 goto docd;
2346 }
2347 do {
2348 c = *path;
2349 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002350 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002351 if (c && c != ':')
2352 flags |= CD_PRINT;
2353docd:
2354 if (!docd(p, flags))
2355 goto out;
2356 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002357 }
Eric Andersenc470f442003-07-28 09:56:35 +00002358 } while (path);
Eric Andersencb57d552001-06-28 07:25:16 +00002359 error("can't cd to %s", dest);
2360 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002361out:
2362 if (flags & CD_PRINT)
2363 out1fmt(snlfmt, curdir);
2364 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002365}
2366
2367
2368/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002369 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002370 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002371 */
2372
Eric Andersenc470f442003-07-28 09:56:35 +00002373static inline const char *
2374updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002375{
Eric Andersenc470f442003-07-28 09:56:35 +00002376 char *new;
2377 char *p;
2378 char *cdcomppath;
2379 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002380
Eric Andersenc470f442003-07-28 09:56:35 +00002381 cdcomppath = sstrdup(dir);
2382 STARTSTACKSTR(new);
2383 if (*dir != '/') {
2384 if (curdir == nullstr)
2385 return 0;
2386 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002387 }
Eric Andersenc470f442003-07-28 09:56:35 +00002388 new = makestrspace(strlen(dir) + 2, new);
2389 lim = stackblock() + 1;
2390 if (*dir != '/') {
2391 if (new[-1] != '/')
2392 USTPUTC('/', new);
2393 if (new > lim && *lim == '/')
2394 lim++;
2395 } else {
2396 USTPUTC('/', new);
2397 cdcomppath++;
2398 if (dir[1] == '/' && dir[2] != '/') {
2399 USTPUTC('/', new);
2400 cdcomppath++;
2401 lim++;
2402 }
2403 }
2404 p = strtok(cdcomppath, "/");
2405 while (p) {
2406 switch(*p) {
2407 case '.':
2408 if (p[1] == '.' && p[2] == '\0') {
2409 while (new > lim) {
2410 STUNPUTC(new);
2411 if (new[-1] == '/')
2412 break;
2413 }
2414 break;
2415 } else if (p[1] == '\0')
2416 break;
2417 /* fall through */
2418 default:
2419 new = stputs(p, new);
2420 USTPUTC('/', new);
2421 }
2422 p = strtok(0, "/");
2423 }
2424 if (new > lim)
2425 STUNPUTC(new);
2426 *new = 0;
2427 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002428}
2429
2430/*
Eric Andersenc470f442003-07-28 09:56:35 +00002431 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2432 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002433 */
2434
Eric Andersenc470f442003-07-28 09:56:35 +00002435static int
2436docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002437{
Eric Andersenc470f442003-07-28 09:56:35 +00002438 const char *dir = 0;
2439 int err;
2440
2441 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2442
Eric Andersencb57d552001-06-28 07:25:16 +00002443 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002444 if (!(flags & CD_PHYSICAL)) {
2445 dir = updatepwd(dest);
2446 if (dir)
2447 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002448 }
Eric Andersenc470f442003-07-28 09:56:35 +00002449 err = chdir(dest);
2450 if (err)
2451 goto out;
2452 setpwd(dir, 1);
2453 hashcd();
2454out:
Eric Andersencb57d552001-06-28 07:25:16 +00002455 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002456 return err;
2457}
2458
2459/*
2460 * Find out what the current directory is. If we already know the current
2461 * directory, this routine returns immediately.
2462 */
2463static inline char *
2464getpwd(void)
2465{
2466 char *dir = getcwd(0, 0);
2467 return dir ? dir : nullstr;
2468}
2469
2470static int
2471pwdcmd(int argc, char **argv)
2472{
2473 int flags;
2474 const char *dir = curdir;
2475
2476 flags = cdopt();
2477 if (flags) {
2478 if (physdir == nullstr)
2479 setpwd(dir, 0);
2480 dir = physdir;
2481 }
2482 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002483 return 0;
2484}
2485
Eric Andersenc470f442003-07-28 09:56:35 +00002486static void
2487setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002488{
Eric Andersenc470f442003-07-28 09:56:35 +00002489 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002490
Eric Andersenc470f442003-07-28 09:56:35 +00002491 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002492
Eric Andersencb57d552001-06-28 07:25:16 +00002493 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002494 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002495 }
2496 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002497 if (physdir != nullstr) {
2498 if (physdir != oldcur)
2499 free(physdir);
2500 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002501 }
Eric Andersenc470f442003-07-28 09:56:35 +00002502 if (oldcur == val || !val) {
2503 char *s = getpwd();
2504 physdir = s;
2505 if (!val)
2506 dir = s;
2507 } else
2508 dir = savestr(val);
2509 if (oldcur != dir && oldcur != nullstr) {
2510 free(oldcur);
2511 }
2512 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002513 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002514 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002515}
2516
Eric Andersenc470f442003-07-28 09:56:35 +00002517/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2518
Eric Andersencb57d552001-06-28 07:25:16 +00002519/*
2520 * Errors and exceptions.
2521 */
2522
2523/*
2524 * Code to handle exceptions in C.
2525 */
2526
Eric Andersen2870d962001-07-02 17:27:21 +00002527
Eric Andersencb57d552001-06-28 07:25:16 +00002528
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002529static void exverror(int, const char *, va_list)
Eric Andersenc470f442003-07-28 09:56:35 +00002530 __attribute__((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00002531
2532/*
2533 * Called to raise an exception. Since C doesn't include exceptions, we
2534 * just do a longjmp to the exception handler. The type of exception is
2535 * stored in the global variable "exception".
2536 */
2537
Eric Andersenc470f442003-07-28 09:56:35 +00002538static void
2539exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002540{
2541#ifdef DEBUG
2542 if (handler == NULL)
2543 abort();
2544#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002545 INTOFF;
2546
Eric Andersencb57d552001-06-28 07:25:16 +00002547 exception = e;
2548 longjmp(handler->loc, 1);
2549}
2550
2551
2552/*
2553 * Called from trap.c when a SIGINT is received. (If the user specifies
2554 * that SIGINT is to be trapped or ignored using the trap builtin, then
2555 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002556 * are held using the INTOFF macro. (The test for iflag is just
2557 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002558 */
2559
Eric Andersenc470f442003-07-28 09:56:35 +00002560static void
2561onint(void) {
2562 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002563
Eric Andersencb57d552001-06-28 07:25:16 +00002564 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002565 sigsetmask(0);
2566 i = EXSIG;
2567 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2568 if (!(rootshell && iflag)) {
2569 signal(SIGINT, SIG_DFL);
2570 raise(SIGINT);
2571 }
2572 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002573 }
Eric Andersenc470f442003-07-28 09:56:35 +00002574 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002575 /* NOTREACHED */
2576}
2577
Eric Andersenc470f442003-07-28 09:56:35 +00002578static void
2579exvwarning(const char *msg, va_list ap)
2580{
2581 FILE *errs;
2582 const char *name;
2583 const char *fmt;
Eric Andersencb57d552001-06-28 07:25:16 +00002584
Eric Andersenc470f442003-07-28 09:56:35 +00002585 errs = stderr;
2586 name = arg0;
2587 fmt = "%s: ";
2588 if (commandname) {
2589 name = commandname;
2590 fmt = "%s: %d: ";
2591 }
2592 fprintf(errs, fmt, name, startlinno);
2593 vfprintf(errs, msg, ap);
2594 outcslow('\n', errs);
2595}
Eric Andersen2870d962001-07-02 17:27:21 +00002596
Eric Andersencb57d552001-06-28 07:25:16 +00002597/*
Eric Andersenc470f442003-07-28 09:56:35 +00002598 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002599 * is not NULL then error prints an error message using printf style
2600 * formatting. It then raises the error exception.
2601 */
Eric Andersenc470f442003-07-28 09:56:35 +00002602static void
2603exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002604{
Eric Andersencb57d552001-06-28 07:25:16 +00002605#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002606 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002607 TRACE(("exverror(%d, \"", cond));
2608 TRACEV((msg, ap));
2609 TRACE(("\") pid=%d\n", getpid()));
2610 } else
2611 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2612 if (msg)
2613#endif
2614 exvwarning(msg, ap);
2615
2616 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002617 exraise(cond);
2618 /* NOTREACHED */
2619}
2620
2621
Eric Andersenc470f442003-07-28 09:56:35 +00002622static void
2623error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002624{
Eric Andersencb57d552001-06-28 07:25:16 +00002625 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002626
Eric Andersencb57d552001-06-28 07:25:16 +00002627 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002628 exverror(EXERROR, msg, ap);
2629 /* NOTREACHED */
2630 va_end(ap);
2631}
2632
2633
Eric Andersenc470f442003-07-28 09:56:35 +00002634static void
2635exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002636{
Eric Andersencb57d552001-06-28 07:25:16 +00002637 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002638
Eric Andersencb57d552001-06-28 07:25:16 +00002639 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002640 exverror(cond, msg, ap);
2641 /* NOTREACHED */
2642 va_end(ap);
2643}
2644
Eric Andersencb57d552001-06-28 07:25:16 +00002645/*
Eric Andersenc470f442003-07-28 09:56:35 +00002646 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002647 */
2648
Eric Andersenc470f442003-07-28 09:56:35 +00002649static void
2650sh_warnx(const char *fmt, ...)
2651{
2652 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002653
Eric Andersenc470f442003-07-28 09:56:35 +00002654 va_start(ap, fmt);
2655 exvwarning(fmt, ap);
2656 va_end(ap);
2657}
Eric Andersen2870d962001-07-02 17:27:21 +00002658
Eric Andersencb57d552001-06-28 07:25:16 +00002659
2660/*
2661 * Return a string describing an error. The returned string may be a
2662 * pointer to a static buffer that will be overwritten on the next call.
2663 * Action describes the operation that got the error.
2664 */
2665
Eric Andersenc470f442003-07-28 09:56:35 +00002666static const char *
2667errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002668{
Eric Andersenc470f442003-07-28 09:56:35 +00002669 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002670
Eric Andersenc470f442003-07-28 09:56:35 +00002671 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002672 }
Eric Andersenc470f442003-07-28 09:56:35 +00002673 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002674}
2675
2676
Eric Andersenc470f442003-07-28 09:56:35 +00002677/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2678
2679/*
2680 * Evaluate a command.
2681 */
Eric Andersencb57d552001-06-28 07:25:16 +00002682
2683/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002684#define EV_EXIT 01 /* exit after evaluating tree */
2685#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2686#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002687
2688
Eric Andersenc470f442003-07-28 09:56:35 +00002689static void evalloop(union node *, int);
2690static void evalfor(union node *, int);
2691static void evalcase(union node *, int);
2692static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002693static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002694static void evalpipe(union node *, int);
2695static void evalcommand(union node *, int);
2696static int evalbltin(const struct builtincmd *, int, char **);
2697static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002698static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002699static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002700
Eric Andersenc470f442003-07-28 09:56:35 +00002701
2702static const struct builtincmd bltin = {
2703 "\0\0", bltincmd
2704};
2705
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002706
Eric Andersencb57d552001-06-28 07:25:16 +00002707/*
2708 * Called to reset things after an exception.
2709 */
2710
Eric Andersencb57d552001-06-28 07:25:16 +00002711/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002712 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002713 */
2714
Eric Andersenc470f442003-07-28 09:56:35 +00002715static int
2716evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002717{
Eric Andersen2870d962001-07-02 17:27:21 +00002718 char *p;
2719 char *concat;
2720 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002721
Eric Andersen2870d962001-07-02 17:27:21 +00002722 if (argc > 1) {
2723 p = argv[1];
2724 if (argc > 2) {
2725 STARTSTACKSTR(concat);
2726 ap = argv + 2;
2727 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002728 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002729 if ((p = *ap++) == NULL)
2730 break;
2731 STPUTC(' ', concat);
2732 }
2733 STPUTC('\0', concat);
2734 p = grabstackstr(concat);
2735 }
Glenn L McGrath76620622004-01-13 10:19:37 +00002736 evalstring(p);
Eric Andersen2870d962001-07-02 17:27:21 +00002737 }
2738 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002739}
2740
Eric Andersenc470f442003-07-28 09:56:35 +00002741
Eric Andersencb57d552001-06-28 07:25:16 +00002742/*
2743 * Execute a command or commands contained in a string.
2744 */
2745
Eric Andersenc470f442003-07-28 09:56:35 +00002746static void
Glenn L McGrath76620622004-01-13 10:19:37 +00002747evalstring(char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00002748{
Eric Andersencb57d552001-06-28 07:25:16 +00002749 union node *n;
2750 struct stackmark smark;
2751
2752 setstackmark(&smark);
2753 setinputstring(s);
Eric Andersenc470f442003-07-28 09:56:35 +00002754
Eric Andersencb57d552001-06-28 07:25:16 +00002755 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002756 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002757 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002758 if (evalskip)
2759 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002760 }
2761 popfile();
2762 popstackmark(&smark);
2763}
2764
Eric Andersenc470f442003-07-28 09:56:35 +00002765
Eric Andersen62483552001-07-10 06:09:16 +00002766
2767/*
Eric Andersenc470f442003-07-28 09:56:35 +00002768 * Evaluate a parse tree. The value is left in the global variable
2769 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002770 */
2771
Eric Andersenc470f442003-07-28 09:56:35 +00002772static void
2773evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002774{
Eric Andersenc470f442003-07-28 09:56:35 +00002775 int checkexit = 0;
2776 void (*evalfn)(union node *, int);
2777 unsigned isor;
2778 int status;
2779 if (n == NULL) {
2780 TRACE(("evaltree(NULL) called\n"));
2781 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002782 }
Eric Andersenc470f442003-07-28 09:56:35 +00002783 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2784 getpid(), n, n->type, flags));
2785 switch (n->type) {
2786 default:
2787#ifdef DEBUG
2788 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002789 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002790 break;
2791#endif
2792 case NNOT:
2793 evaltree(n->nnot.com, EV_TESTED);
2794 status = !exitstatus;
2795 goto setstatus;
2796 case NREDIR:
2797 expredir(n->nredir.redirect);
2798 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2799 if (!status) {
2800 evaltree(n->nredir.n, flags & EV_TESTED);
2801 status = exitstatus;
2802 }
2803 popredir(0);
2804 goto setstatus;
2805 case NCMD:
2806 evalfn = evalcommand;
2807checkexit:
2808 if (eflag && !(flags & EV_TESTED))
2809 checkexit = ~0;
2810 goto calleval;
2811 case NFOR:
2812 evalfn = evalfor;
2813 goto calleval;
2814 case NWHILE:
2815 case NUNTIL:
2816 evalfn = evalloop;
2817 goto calleval;
2818 case NSUBSHELL:
2819 case NBACKGND:
2820 evalfn = evalsubshell;
2821 goto calleval;
2822 case NPIPE:
2823 evalfn = evalpipe;
2824 goto checkexit;
2825 case NCASE:
2826 evalfn = evalcase;
2827 goto calleval;
2828 case NAND:
2829 case NOR:
2830 case NSEMI:
2831#if NAND + 1 != NOR
2832#error NAND + 1 != NOR
2833#endif
2834#if NOR + 1 != NSEMI
2835#error NOR + 1 != NSEMI
2836#endif
2837 isor = n->type - NAND;
2838 evaltree(
2839 n->nbinary.ch1,
2840 (flags | ((isor >> 1) - 1)) & EV_TESTED
2841 );
2842 if (!exitstatus == isor)
2843 break;
2844 if (!evalskip) {
2845 n = n->nbinary.ch2;
2846evaln:
2847 evalfn = evaltree;
2848calleval:
2849 evalfn(n, flags);
2850 break;
2851 }
2852 break;
2853 case NIF:
2854 evaltree(n->nif.test, EV_TESTED);
2855 if (evalskip)
2856 break;
2857 if (exitstatus == 0) {
2858 n = n->nif.ifpart;
2859 goto evaln;
2860 } else if (n->nif.elsepart) {
2861 n = n->nif.elsepart;
2862 goto evaln;
2863 }
2864 goto success;
2865 case NDEFUN:
2866 defun(n->narg.text, n->narg.next);
2867success:
2868 status = 0;
2869setstatus:
2870 exitstatus = status;
2871 break;
2872 }
2873out:
2874 if (pendingsigs)
2875 dotrap();
2876 if (flags & EV_EXIT || checkexit & exitstatus)
2877 exraise(EXEXIT);
Eric Andersen62483552001-07-10 06:09:16 +00002878}
2879
Eric Andersenc470f442003-07-28 09:56:35 +00002880
2881#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2882static
2883#endif
2884void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2885
2886
2887static void
2888evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002889{
2890 int status;
2891
2892 loopnest++;
2893 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002894 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002895 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002896 int i;
2897
Eric Andersencb57d552001-06-28 07:25:16 +00002898 evaltree(n->nbinary.ch1, EV_TESTED);
2899 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002900skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002901 evalskip = 0;
2902 continue;
2903 }
2904 if (evalskip == SKIPBREAK && --skipcount <= 0)
2905 evalskip = 0;
2906 break;
2907 }
Eric Andersenc470f442003-07-28 09:56:35 +00002908 i = exitstatus;
2909 if (n->type != NWHILE)
2910 i = !i;
2911 if (i != 0)
2912 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002913 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002914 status = exitstatus;
2915 if (evalskip)
2916 goto skipping;
2917 }
2918 loopnest--;
2919 exitstatus = status;
2920}
2921
Eric Andersenc470f442003-07-28 09:56:35 +00002922
2923
2924static void
2925evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002926{
2927 struct arglist arglist;
2928 union node *argp;
2929 struct strlist *sp;
2930 struct stackmark smark;
2931
2932 setstackmark(&smark);
2933 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002934 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002935 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002936 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002937 if (evalskip)
2938 goto out;
2939 }
2940 *arglist.lastp = NULL;
2941
2942 exitstatus = 0;
2943 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002944 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002945 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002946 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002947 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002948 if (evalskip) {
2949 if (evalskip == SKIPCONT && --skipcount <= 0) {
2950 evalskip = 0;
2951 continue;
2952 }
2953 if (evalskip == SKIPBREAK && --skipcount <= 0)
2954 evalskip = 0;
2955 break;
2956 }
2957 }
2958 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002959out:
Eric Andersencb57d552001-06-28 07:25:16 +00002960 popstackmark(&smark);
2961}
2962
Eric Andersenc470f442003-07-28 09:56:35 +00002963
2964
2965static void
2966evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002967{
2968 union node *cp;
2969 union node *patp;
2970 struct arglist arglist;
2971 struct stackmark smark;
2972
2973 setstackmark(&smark);
2974 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002975 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002976 exitstatus = 0;
2977 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2978 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002979 if (casematch(patp, arglist.list->text)) {
2980 if (evalskip == 0) {
2981 evaltree(cp->nclist.body, flags);
2982 }
2983 goto out;
2984 }
2985 }
2986 }
Eric Andersenc470f442003-07-28 09:56:35 +00002987out:
Eric Andersencb57d552001-06-28 07:25:16 +00002988 popstackmark(&smark);
2989}
2990
Eric Andersenc470f442003-07-28 09:56:35 +00002991
2992
2993/*
2994 * Kick off a subshell to evaluate a tree.
2995 */
2996
2997static void
2998evalsubshell(union node *n, int flags)
2999{
3000 struct job *jp;
3001 int backgnd = (n->type == NBACKGND);
3002 int status;
3003
3004 expredir(n->nredir.redirect);
3005 if (!backgnd && flags & EV_EXIT && !trap[0])
3006 goto nofork;
3007 INTOFF;
3008 jp = makejob(n, 1);
3009 if (forkshell(jp, n, backgnd) == 0) {
3010 INTON;
3011 flags |= EV_EXIT;
3012 if (backgnd)
3013 flags &=~ EV_TESTED;
3014nofork:
3015 redirect(n->nredir.redirect, 0);
3016 evaltreenr(n->nredir.n, flags);
3017 /* never returns */
3018 }
3019 status = 0;
3020 if (! backgnd)
3021 status = waitforjob(jp);
3022 exitstatus = status;
3023 INTON;
3024}
3025
3026
3027
3028/*
3029 * Compute the names of the files in a redirection list.
3030 */
3031
3032static void
3033expredir(union node *n)
3034{
3035 union node *redir;
3036
3037 for (redir = n ; redir ; redir = redir->nfile.next) {
3038 struct arglist fn;
3039 fn.lastp = &fn.list;
3040 switch (redir->type) {
3041 case NFROMTO:
3042 case NFROM:
3043 case NTO:
3044 case NCLOBBER:
3045 case NAPPEND:
3046 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3047 redir->nfile.expfname = fn.list->text;
3048 break;
3049 case NFROMFD:
3050 case NTOFD:
3051 if (redir->ndup.vname) {
3052 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3053 fixredir(redir, fn.list->text, 1);
3054 }
3055 break;
3056 }
3057 }
3058}
3059
3060
3061
Eric Andersencb57d552001-06-28 07:25:16 +00003062/*
Eric Andersencb57d552001-06-28 07:25:16 +00003063 * Evaluate a pipeline. All the processes in the pipeline are children
3064 * of the process creating the pipeline. (This differs from some versions
3065 * of the shell, which make the last process in a pipeline the parent
3066 * of all the rest.)
3067 */
3068
Eric Andersenc470f442003-07-28 09:56:35 +00003069static void
3070evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003071{
3072 struct job *jp;
3073 struct nodelist *lp;
3074 int pipelen;
3075 int prevfd;
3076 int pip[2];
3077
Eric Andersenc470f442003-07-28 09:56:35 +00003078 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003079 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003080 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003081 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003082 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003083 INTOFF;
3084 jp = makejob(n, pipelen);
3085 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003086 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003087 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003088 pip[1] = -1;
3089 if (lp->next) {
3090 if (pipe(pip) < 0) {
3091 close(prevfd);
3092 error("Pipe call failed");
3093 }
3094 }
3095 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3096 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003097 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003098 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003099 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003100 if (prevfd > 0) {
3101 dup2(prevfd, 0);
3102 close(prevfd);
3103 }
3104 if (pip[1] > 1) {
3105 dup2(pip[1], 1);
3106 close(pip[1]);
3107 }
Eric Andersenc470f442003-07-28 09:56:35 +00003108 evaltreenr(lp->n, flags);
3109 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003110 }
3111 if (prevfd >= 0)
3112 close(prevfd);
3113 prevfd = pip[0];
3114 close(pip[1]);
3115 }
Eric Andersencb57d552001-06-28 07:25:16 +00003116 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003117 exitstatus = waitforjob(jp);
3118 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003119 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003120 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003121}
3122
Eric Andersen62483552001-07-10 06:09:16 +00003123
3124
3125/*
3126 * Execute a command inside back quotes. If it's a builtin command, we
3127 * want to save its output in a block obtained from malloc. Otherwise
3128 * we fork off a subprocess and get the output of the command via a pipe.
3129 * Should be called with interrupts off.
3130 */
3131
Eric Andersenc470f442003-07-28 09:56:35 +00003132static void
3133evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003134{
Eric Andersenc470f442003-07-28 09:56:35 +00003135 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003136
Eric Andersen62483552001-07-10 06:09:16 +00003137 result->fd = -1;
3138 result->buf = NULL;
3139 result->nleft = 0;
3140 result->jp = NULL;
3141 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003142 goto out;
3143 }
Eric Andersenc470f442003-07-28 09:56:35 +00003144
3145 saveherefd = herefd;
3146 herefd = -1;
3147
3148 {
3149 int pip[2];
3150 struct job *jp;
3151
3152 if (pipe(pip) < 0)
3153 error("Pipe call failed");
3154 jp = makejob(n, 1);
3155 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3156 FORCEINTON;
3157 close(pip[0]);
3158 if (pip[1] != 1) {
3159 close(1);
3160 copyfd(pip[1], 1);
3161 close(pip[1]);
3162 }
3163 eflag = 0;
3164 evaltreenr(n, EV_EXIT);
3165 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003166 }
Eric Andersenc470f442003-07-28 09:56:35 +00003167 close(pip[1]);
3168 result->fd = pip[0];
3169 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003170 }
Eric Andersenc470f442003-07-28 09:56:35 +00003171 herefd = saveherefd;
3172out:
Eric Andersen62483552001-07-10 06:09:16 +00003173 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003174 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003175}
3176
Eric Andersenc470f442003-07-28 09:56:35 +00003177#ifdef CONFIG_ASH_CMDCMD
3178static inline char **
3179parse_command_args(char **argv, const char **path)
3180{
3181 char *cp, c;
3182
3183 for (;;) {
3184 cp = *++argv;
3185 if (!cp)
3186 return 0;
3187 if (*cp++ != '-')
3188 break;
3189 if (!(c = *cp++))
3190 break;
3191 if (c == '-' && !*cp) {
3192 argv++;
3193 break;
3194 }
3195 do {
3196 switch (c) {
3197 case 'p':
3198 *path = defpath;
3199 break;
3200 default:
3201 /* run 'typecmd' for other options */
3202 return 0;
3203 }
3204 } while ((c = *cp++));
3205 }
3206 return argv;
3207}
3208#endif
3209
3210
Eric Andersen62483552001-07-10 06:09:16 +00003211
3212/*
3213 * Execute a simple command.
3214 */
Eric Andersencb57d552001-06-28 07:25:16 +00003215
Eric Andersenc470f442003-07-28 09:56:35 +00003216static void
3217evalcommand(union node *cmd, int flags)
3218{
3219 struct stackmark smark;
3220 union node *argp;
3221 struct arglist arglist;
3222 struct arglist varlist;
3223 char **argv;
3224 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003225 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003226 struct cmdentry cmdentry;
3227 struct job *jp;
3228 char *lastarg;
3229 const char *path;
3230 int spclbltin;
3231 int cmd_is_exec;
3232 int status;
3233 char **nargv;
3234
3235 /* First expand the arguments. */
3236 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3237 setstackmark(&smark);
3238 back_exitstatus = 0;
3239
3240 cmdentry.cmdtype = CMDBUILTIN;
3241 cmdentry.u.cmd = &bltin;
3242 varlist.lastp = &varlist.list;
3243 *varlist.lastp = NULL;
3244 arglist.lastp = &arglist.list;
3245 *arglist.lastp = NULL;
3246
3247 argc = 0;
3248 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3249 struct strlist **spp;
3250
3251 spp = arglist.lastp;
3252 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3253 for (sp = *spp; sp; sp = sp->next)
3254 argc++;
3255 }
3256
3257 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3258 for (sp = arglist.list ; sp ; sp = sp->next) {
3259 TRACE(("evalcommand arg: %s\n", sp->text));
3260 *nargv++ = sp->text;
3261 }
3262 *nargv = NULL;
3263
3264 lastarg = NULL;
3265 if (iflag && funcnest == 0 && argc > 0)
3266 lastarg = nargv[-1];
3267
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003268 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003269 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003270 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003271
3272 path = vpath.text;
3273 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3274 struct strlist **spp;
3275 char *p;
3276
3277 spp = varlist.lastp;
3278 expandarg(argp, &varlist, EXP_VARTILDE);
3279
3280 /*
3281 * Modify the command lookup path, if a PATH= assignment
3282 * is present
3283 */
3284 p = (*spp)->text;
3285 if (varequal(p, path))
3286 path = p;
3287 }
3288
3289 /* Print the command if xflag is set. */
3290 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003291 int n;
3292 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003293
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003294 p++;
3295 dprintf(preverrout_fd, p, ps4val());
3296
3297 sp = varlist.list;
3298 for(n = 0; n < 2; n++) {
3299 while (sp) {
3300 dprintf(preverrout_fd, p, sp->text);
3301 sp = sp->next;
3302 if(*p == '%') {
3303 p--;
3304 }
3305 }
3306 sp = arglist.list;
3307 }
Eric Andersen16767e22004-03-16 05:14:10 +00003308 bb_full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003309 }
3310
3311 cmd_is_exec = 0;
3312 spclbltin = -1;
3313
3314 /* Now locate the command. */
3315 if (argc) {
3316 const char *oldpath;
3317 int cmd_flag = DO_ERR;
3318
3319 path += 5;
3320 oldpath = path;
3321 for (;;) {
3322 find_command(argv[0], &cmdentry, cmd_flag, path);
3323 if (cmdentry.cmdtype == CMDUNKNOWN) {
3324 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003325 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003326 goto bail;
3327 }
3328
3329 /* implement bltin and command here */
3330 if (cmdentry.cmdtype != CMDBUILTIN)
3331 break;
3332 if (spclbltin < 0)
3333 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3334 if (cmdentry.u.cmd == EXECCMD)
3335 cmd_is_exec++;
3336#ifdef CONFIG_ASH_CMDCMD
3337 if (cmdentry.u.cmd == COMMANDCMD) {
3338
3339 path = oldpath;
3340 nargv = parse_command_args(argv, &path);
3341 if (!nargv)
3342 break;
3343 argc -= nargv - argv;
3344 argv = nargv;
3345 cmd_flag |= DO_NOFUNC;
3346 } else
3347#endif
3348 break;
3349 }
3350 }
3351
3352 if (status) {
3353 /* We have a redirection error. */
3354 if (spclbltin > 0)
3355 exraise(EXERROR);
3356bail:
3357 exitstatus = status;
3358 goto out;
3359 }
3360
3361 /* Execute the command. */
3362 switch (cmdentry.cmdtype) {
3363 default:
3364 /* Fork off a child process if necessary. */
3365 if (!(flags & EV_EXIT) || trap[0]) {
3366 INTOFF;
3367 jp = makejob(cmd, 1);
3368 if (forkshell(jp, cmd, FORK_FG) != 0) {
3369 exitstatus = waitforjob(jp);
3370 INTON;
3371 break;
3372 }
3373 FORCEINTON;
3374 }
3375 listsetvar(varlist.list, VEXPORT|VSTACK);
3376 shellexec(argv, path, cmdentry.u.index);
3377 /* NOTREACHED */
3378
3379 case CMDBUILTIN:
3380 cmdenviron = varlist.list;
3381 if (cmdenviron) {
3382 struct strlist *list = cmdenviron;
3383 int i = VNOSET;
3384 if (spclbltin > 0 || argc == 0) {
3385 i = 0;
3386 if (cmd_is_exec && argc > 1)
3387 i = VEXPORT;
3388 }
3389 listsetvar(list, i);
3390 }
3391 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3392 int exit_status;
3393 int i, j;
3394
3395 i = exception;
3396 if (i == EXEXIT)
3397 goto raise;
3398
3399 exit_status = 2;
3400 j = 0;
3401 if (i == EXINT)
3402 j = SIGINT;
3403 if (i == EXSIG)
3404 j = pendingsigs;
3405 if (j)
3406 exit_status = j + 128;
3407 exitstatus = exit_status;
3408
3409 if (i == EXINT || spclbltin > 0) {
3410raise:
3411 longjmp(handler->loc, 1);
3412 }
3413 FORCEINTON;
3414 }
3415 break;
3416
3417 case CMDFUNCTION:
3418 listsetvar(varlist.list, 0);
3419 if (evalfun(cmdentry.u.func, argc, argv, flags))
3420 goto raise;
3421 break;
3422 }
3423
3424out:
3425 popredir(cmd_is_exec);
3426 if (lastarg)
3427 /* dsl: I think this is intended to be used to support
3428 * '_' in 'vi' command mode during line editing...
3429 * However I implemented that within libedit itself.
3430 */
3431 setvar("_", lastarg, 0);
3432 popstackmark(&smark);
3433}
3434
3435static int
3436evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3437 char *volatile savecmdname;
3438 struct jmploc *volatile savehandler;
3439 struct jmploc jmploc;
3440 int i;
3441
3442 savecmdname = commandname;
3443 if ((i = setjmp(jmploc.loc)))
3444 goto cmddone;
3445 savehandler = handler;
3446 handler = &jmploc;
3447 commandname = argv[0];
3448 argptr = argv + 1;
3449 optptr = NULL; /* initialize nextopt */
3450 exitstatus = (*cmd->builtin)(argc, argv);
3451 flushall();
3452cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003453 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003454 commandname = savecmdname;
3455 exsig = 0;
3456 handler = savehandler;
3457
3458 return i;
3459}
3460
3461static int
3462evalfun(struct funcnode *func, int argc, char **argv, int flags)
3463{
3464 volatile struct shparam saveparam;
3465 struct localvar *volatile savelocalvars;
3466 struct jmploc *volatile savehandler;
3467 struct jmploc jmploc;
3468 int e;
3469
3470 saveparam = shellparam;
3471 savelocalvars = localvars;
3472 if ((e = setjmp(jmploc.loc))) {
3473 goto funcdone;
3474 }
3475 INTOFF;
3476 savehandler = handler;
3477 handler = &jmploc;
3478 localvars = NULL;
3479 shellparam.malloc = 0;
3480 func->count++;
3481 INTON;
3482 shellparam.nparam = argc - 1;
3483 shellparam.p = argv + 1;
3484#ifdef CONFIG_ASH_GETOPTS
3485 shellparam.optind = 1;
3486 shellparam.optoff = -1;
3487#endif
3488 funcnest++;
3489 evaltree(&func->n, flags & EV_TESTED);
3490 funcnest--;
3491funcdone:
3492 INTOFF;
3493 freefunc(func);
3494 poplocalvars();
3495 localvars = savelocalvars;
3496 freeparam(&shellparam);
3497 shellparam = saveparam;
3498 handler = savehandler;
3499 INTON;
3500 if (evalskip == SKIPFUNC) {
3501 evalskip = 0;
3502 skipcount = 0;
3503 }
3504 return e;
3505}
3506
3507
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003508static inline int
3509goodname(const char *p)
3510{
3511 return !*endofname(p);
3512}
3513
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003514/*
3515 * Search for a command. This is called before we fork so that the
3516 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003517 * the child. The check for "goodname" is an overly conservative
3518 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003519 */
3520
Eric Andersenc470f442003-07-28 09:56:35 +00003521static void
3522prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003523{
3524 struct cmdentry entry;
3525
3526 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003527 if (goodname(n->ncmd.args->narg.text))
3528 find_command(n->ncmd.args->narg.text, &entry, 0,
3529 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003530}
3531
Eric Andersencb57d552001-06-28 07:25:16 +00003532
Eric Andersenc470f442003-07-28 09:56:35 +00003533
Eric Andersencb57d552001-06-28 07:25:16 +00003534/*
3535 * Builtin commands. Builtin commands whose functions are closely
3536 * tied to evaluation are implemented here.
3537 */
3538
3539/*
Eric Andersenc470f442003-07-28 09:56:35 +00003540 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003541 */
3542
Eric Andersenc470f442003-07-28 09:56:35 +00003543static int
3544bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003545{
3546 /*
3547 * Preserve exitstatus of a previous possible redirection
3548 * as POSIX mandates
3549 */
Eric Andersenc470f442003-07-28 09:56:35 +00003550 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003551}
3552
3553
3554/*
3555 * Handle break and continue commands. Break, continue, and return are
3556 * all handled by setting the evalskip flag. The evaluation routines
3557 * above all check this flag, and if it is set they start skipping
3558 * commands rather than executing them. The variable skipcount is
3559 * the number of loops to break/continue, or the number of function
3560 * levels to return. (The latter is always 1.) It should probably
3561 * be an error to break out of more loops than exist, but it isn't
3562 * in the standard shell so we don't make it one here.
3563 */
3564
Eric Andersenc470f442003-07-28 09:56:35 +00003565static int
3566breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003567{
3568 int n = argc > 1 ? number(argv[1]) : 1;
3569
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003570 if (n <= 0)
Eric Andersenc470f442003-07-28 09:56:35 +00003571 error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003572 if (n > loopnest)
3573 n = loopnest;
3574 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003575 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003576 skipcount = n;
3577 }
3578 return 0;
3579}
3580
3581
3582/*
3583 * The return command.
3584 */
3585
Eric Andersenc470f442003-07-28 09:56:35 +00003586static int
3587returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003588{
Eric Andersenc470f442003-07-28 09:56:35 +00003589 int ret = argc > 1 ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003590
3591 if (funcnest) {
3592 evalskip = SKIPFUNC;
3593 skipcount = 1;
3594 return ret;
Eric Andersenc470f442003-07-28 09:56:35 +00003595 }
3596 else {
Eric Andersencb57d552001-06-28 07:25:16 +00003597 /* Do what ksh does; skip the rest of the file */
3598 evalskip = SKIPFILE;
3599 skipcount = 1;
3600 return ret;
3601 }
3602}
3603
3604
Eric Andersenc470f442003-07-28 09:56:35 +00003605static int
3606falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003607{
3608 return 1;
3609}
3610
Eric Andersenc470f442003-07-28 09:56:35 +00003611
3612static int
3613truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003614{
3615 return 0;
3616}
Eric Andersen2870d962001-07-02 17:27:21 +00003617
Eric Andersencb57d552001-06-28 07:25:16 +00003618
Eric Andersenc470f442003-07-28 09:56:35 +00003619static int
3620execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003621{
3622 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003623 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003624 mflag = 0;
3625 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003626 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003627 }
3628 return 0;
3629}
3630
Eric Andersenc470f442003-07-28 09:56:35 +00003631
Eric Andersenc470f442003-07-28 09:56:35 +00003632/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3633
3634/*
3635 * When commands are first encountered, they are entered in a hash table.
3636 * This ensures that a full path search will not have to be done for them
3637 * on each invocation.
3638 *
3639 * We should investigate converting to a linear search, even though that
3640 * would make the command name "hash" a misnomer.
3641 */
3642
3643#define CMDTABLESIZE 31 /* should be prime */
3644#define ARB 1 /* actual size determined at run time */
3645
3646
3647
3648struct tblentry {
3649 struct tblentry *next; /* next entry in hash chain */
3650 union param param; /* definition of builtin function */
3651 short cmdtype; /* index identifying command */
3652 char rehash; /* if set, cd done since entry created */
3653 char cmdname[ARB]; /* name of command */
3654};
3655
3656
3657static struct tblentry *cmdtable[CMDTABLESIZE];
3658static int builtinloc = -1; /* index in path of %builtin, or -1 */
3659
3660
3661static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003662static void clearcmdentry(int);
3663static struct tblentry *cmdlookup(const char *, int);
3664static void delete_cmd_entry(void);
3665
Eric Andersencb57d552001-06-28 07:25:16 +00003666
3667/*
3668 * Exec a program. Never returns. If you change this routine, you may
3669 * have to change the find_command routine as well.
3670 */
3671
Eric Andersenc470f442003-07-28 09:56:35 +00003672static void
3673shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003674{
3675 char *cmdname;
3676 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003677 char **envp;
Eric Andersencb57d552001-06-28 07:25:16 +00003678
Eric Andersenc470f442003-07-28 09:56:35 +00003679 clearredir(1);
3680 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003681 if (strchr(argv[0], '/') != NULL
3682#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3683 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003684#endif
3685 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003686 tryexec(argv[0], argv, envp);
3687 e = errno;
3688 } else {
3689 e = ENOENT;
3690 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3691 if (--idx < 0 && pathopt == NULL) {
3692 tryexec(cmdname, argv, envp);
3693 if (errno != ENOENT && errno != ENOTDIR)
3694 e = errno;
3695 }
3696 stunalloc(cmdname);
3697 }
3698 }
3699
3700 /* Map to POSIX errors */
3701 switch (e) {
3702 case EACCES:
3703 exerrno = 126;
3704 break;
3705 case ENOENT:
3706 exerrno = 127;
3707 break;
3708 default:
3709 exerrno = 2;
3710 break;
3711 }
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
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003724 int flg_bb = 0;
Eric Andersen3102ac42001-07-06 04:26:23 +00003725 char *name = cmd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003726
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003727 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3728 flg_bb = 1;
3729 }
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003730 if(flg_bb) {
3731 char **ap;
3732 char **new;
3733
3734 *argv = name;
3735 if(strcmp(name, "busybox")) {
3736 for (ap = argv; *ap; ap++);
3737 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3738 *ap++ = cmd = "/bin/busybox";
3739 while ((*ap++ = *argv++));
3740 argv = new;
3741 repeated++;
3742 } else {
3743 cmd = "/bin/busybox";
3744 }
3745 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003746#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003747
3748repeat:
3749#ifdef SYSV
3750 do {
3751 execve(cmd, argv, envp);
3752 } while (errno == EINTR);
3753#else
Eric Andersencb57d552001-06-28 07:25:16 +00003754 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003755#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003756 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003757 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003758 } else if (errno == ENOEXEC) {
3759 char **ap;
3760 char **new;
3761
Eric Andersenc470f442003-07-28 09:56:35 +00003762 for (ap = argv; *ap; ap++)
3763 ;
3764 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003765 ap[1] = cmd;
3766 *ap = cmd = (char *)DEFAULT_SHELL;
3767 ap += 2;
3768 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003769 while ((*ap++ = *argv++))
3770 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003771 argv = new;
3772 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003773 }
Eric Andersencb57d552001-06-28 07:25:16 +00003774}
3775
Eric Andersenc470f442003-07-28 09:56:35 +00003776
Eric Andersencb57d552001-06-28 07:25:16 +00003777
3778/*
3779 * Do a path search. The variable path (passed by reference) should be
3780 * set to the start of the path before the first call; padvance will update
3781 * this value as it proceeds. Successive calls to padvance will return
3782 * the possible path expansions in sequence. If an option (indicated by
3783 * a percent sign) appears in the path entry then the global variable
3784 * pathopt will be set to point to it; otherwise pathopt will be set to
3785 * NULL.
3786 */
3787
Eric Andersenc470f442003-07-28 09:56:35 +00003788static char *
3789padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003790{
Eric Andersencb57d552001-06-28 07:25:16 +00003791 const char *p;
3792 char *q;
3793 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003794 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003795
3796 if (*path == NULL)
3797 return NULL;
3798 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003799 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3800 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003801 while (stackblocksize() < len)
3802 growstackblock();
3803 q = stackblock();
3804 if (p != start) {
3805 memcpy(q, start, p - start);
3806 q += p - start;
3807 *q++ = '/';
3808 }
3809 strcpy(q, name);
3810 pathopt = NULL;
3811 if (*p == '%') {
3812 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003813 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003814 }
3815 if (*p == ':')
3816 *path = p + 1;
3817 else
3818 *path = NULL;
3819 return stalloc(len);
3820}
3821
3822
Eric Andersencb57d552001-06-28 07:25:16 +00003823/*** Command hashing code ***/
3824
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003825static void
3826printentry(struct tblentry *cmdp)
3827{
3828 int idx;
3829 const char *path;
3830 char *name;
3831
3832 idx = cmdp->param.index;
3833 path = pathval();
3834 do {
3835 name = padvance(&path, cmdp->cmdname);
3836 stunalloc(name);
3837 } while (--idx >= 0);
3838 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3839}
3840
Eric Andersenc470f442003-07-28 09:56:35 +00003841
3842static int
3843hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003844{
3845 struct tblentry **pp;
3846 struct tblentry *cmdp;
3847 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003848 struct cmdentry entry;
3849 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003850
Eric Andersenc470f442003-07-28 09:56:35 +00003851 while ((c = nextopt("r")) != '\0') {
3852 clearcmdentry(0);
3853 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003854 }
3855 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003856 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3857 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3858 if (cmdp->cmdtype == CMDNORMAL)
3859 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003860 }
3861 }
3862 return 0;
3863 }
3864 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003865 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003866 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003867 && (cmdp->cmdtype == CMDNORMAL
3868 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003869 delete_cmd_entry();
3870 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003871 if (entry.cmdtype == CMDUNKNOWN)
3872 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003873 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003874 }
3875 return c;
3876}
3877
Eric Andersenc470f442003-07-28 09:56:35 +00003878
Eric Andersencb57d552001-06-28 07:25:16 +00003879/*
3880 * Resolve a command name. If you change this routine, you may have to
3881 * change the shellexec routine as well.
3882 */
3883
3884static void
Eric Andersenc470f442003-07-28 09:56:35 +00003885find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003886{
3887 struct tblentry *cmdp;
3888 int idx;
3889 int prev;
3890 char *fullname;
3891 struct stat statb;
3892 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003893 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003894 struct builtincmd *bcmd;
3895
Eric Andersenc470f442003-07-28 09:56:35 +00003896 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003897 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003898 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003899 if (act & DO_ABS) {
3900 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003901#ifdef SYSV
3902 if (errno == EINTR)
3903 continue;
3904#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003905 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003906 return;
3907 }
Eric Andersencb57d552001-06-28 07:25:16 +00003908 }
3909 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003910 return;
3911 }
3912
Eric Andersenbf8bf102002-09-17 08:41:08 +00003913#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3914 if (find_applet_by_name(name)) {
3915 entry->cmdtype = CMDNORMAL;
3916 entry->u.index = -1;
3917 return;
3918 }
3919#endif
3920
Eric Andersenc470f442003-07-28 09:56:35 +00003921 updatetbl = (path == pathval());
3922 if (!updatetbl) {
3923 act |= DO_ALTPATH;
3924 if (strstr(path, "%builtin") != NULL)
3925 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003926 }
3927
Eric Andersenc470f442003-07-28 09:56:35 +00003928 /* If name is in the table, check answer will be ok */
3929 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3930 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003931
Eric Andersenc470f442003-07-28 09:56:35 +00003932 switch (cmdp->cmdtype) {
3933 default:
3934#if DEBUG
3935 abort();
3936#endif
3937 case CMDNORMAL:
3938 bit = DO_ALTPATH;
3939 break;
3940 case CMDFUNCTION:
3941 bit = DO_NOFUNC;
3942 break;
3943 case CMDBUILTIN:
3944 bit = DO_ALTBLTIN;
3945 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003946 }
Eric Andersenc470f442003-07-28 09:56:35 +00003947 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003948 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003949 cmdp = NULL;
3950 } else if (cmdp->rehash == 0)
3951 /* if not invalidated by cd, we're done */
3952 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003953 }
3954
3955 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003956 bcmd = find_builtin(name);
3957 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3958 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3959 )))
3960 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003961
3962 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003963 prev = -1; /* where to start */
3964 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003965 if (cmdp->cmdtype == CMDBUILTIN)
3966 prev = builtinloc;
3967 else
3968 prev = cmdp->param.index;
3969 }
3970
3971 e = ENOENT;
3972 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003973loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003974 while ((fullname = padvance(&path, name)) != NULL) {
3975 stunalloc(fullname);
3976 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003977 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003978 if (prefix(pathopt, "builtin")) {
3979 if (bcmd)
3980 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003981 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003982 } else if (!(act & DO_NOFUNC) &&
3983 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003984 /* handled below */
3985 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003986 /* ignore unimplemented options */
3987 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003988 }
3989 }
3990 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003991 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003992 if (idx < prev)
3993 continue;
3994 TRACE(("searchexec \"%s\": no change\n", name));
3995 goto success;
3996 }
3997 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003998#ifdef SYSV
3999 if (errno == EINTR)
4000 continue;
4001#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004002 if (errno != ENOENT && errno != ENOTDIR)
4003 e = errno;
4004 goto loop;
4005 }
Eric Andersenc470f442003-07-28 09:56:35 +00004006 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004007 if (!S_ISREG(statb.st_mode))
4008 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004009 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004010 stalloc(strlen(fullname) + 1);
4011 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004012 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4013 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004014 error("%s not defined in %s", name, fullname);
4015 stunalloc(fullname);
4016 goto success;
4017 }
Eric Andersencb57d552001-06-28 07:25:16 +00004018 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004019 if (!updatetbl) {
4020 entry->cmdtype = CMDNORMAL;
4021 entry->u.index = idx;
4022 return;
4023 }
4024 INTOFF;
4025 cmdp = cmdlookup(name, 1);
4026 cmdp->cmdtype = CMDNORMAL;
4027 cmdp->param.index = idx;
4028 INTON;
4029 goto success;
4030 }
4031
4032 /* We failed. If there was an entry for this command, delete it */
4033 if (cmdp && updatetbl)
4034 delete_cmd_entry();
4035 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004036 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004037 entry->cmdtype = CMDUNKNOWN;
4038 return;
4039
Eric Andersenc470f442003-07-28 09:56:35 +00004040builtin_success:
4041 if (!updatetbl) {
4042 entry->cmdtype = CMDBUILTIN;
4043 entry->u.cmd = bcmd;
4044 return;
4045 }
4046 INTOFF;
4047 cmdp = cmdlookup(name, 1);
4048 cmdp->cmdtype = CMDBUILTIN;
4049 cmdp->param.cmd = bcmd;
4050 INTON;
4051success:
Eric Andersencb57d552001-06-28 07:25:16 +00004052 cmdp->rehash = 0;
4053 entry->cmdtype = cmdp->cmdtype;
4054 entry->u = cmdp->param;
4055}
4056
4057
Eric Andersenc470f442003-07-28 09:56:35 +00004058/*
4059 * Wrapper around strcmp for qsort/bsearch/...
4060 */
4061static int pstrcmp(const void *a, const void *b)
4062{
4063 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4064}
Eric Andersencb57d552001-06-28 07:25:16 +00004065
4066/*
4067 * Search the table of builtin commands.
4068 */
4069
Eric Andersenc470f442003-07-28 09:56:35 +00004070static struct builtincmd *
4071find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004072{
4073 struct builtincmd *bp;
4074
Eric Andersenc470f442003-07-28 09:56:35 +00004075 bp = bsearch(
4076 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4077 pstrcmp
4078 );
Eric Andersencb57d552001-06-28 07:25:16 +00004079 return bp;
4080}
4081
4082
Eric Andersenc470f442003-07-28 09:56:35 +00004083
Eric Andersencb57d552001-06-28 07:25:16 +00004084/*
4085 * Called when a cd is done. Marks all commands so the next time they
4086 * are executed they will be rehashed.
4087 */
4088
Eric Andersenc470f442003-07-28 09:56:35 +00004089static void
4090hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004091{
Eric Andersencb57d552001-06-28 07:25:16 +00004092 struct tblentry **pp;
4093 struct tblentry *cmdp;
4094
Eric Andersenc470f442003-07-28 09:56:35 +00004095 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4096 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4097 if (cmdp->cmdtype == CMDNORMAL || (
4098 cmdp->cmdtype == CMDBUILTIN &&
4099 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4100 builtinloc > 0
4101 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004102 cmdp->rehash = 1;
4103 }
4104 }
4105}
4106
4107
4108
4109/*
Eric Andersenc470f442003-07-28 09:56:35 +00004110 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004111 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004112 * pathval() still returns the old value at this point.
4113 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004114 */
4115
Eric Andersenc470f442003-07-28 09:56:35 +00004116static void
4117changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004118{
Eric Andersenc470f442003-07-28 09:56:35 +00004119 const char *old, *new;
4120 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004121 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004122 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004123
Eric Andersenc470f442003-07-28 09:56:35 +00004124 old = pathval();
4125 new = newval;
4126 firstchange = 9999; /* assume no change */
4127 idx = 0;
4128 idx_bltin = -1;
4129 for (;;) {
4130 if (*old != *new) {
4131 firstchange = idx;
4132 if ((*old == '\0' && *new == ':')
4133 || (*old == ':' && *new == '\0'))
4134 firstchange++;
4135 old = new; /* ignore subsequent differences */
4136 }
4137 if (*new == '\0')
4138 break;
4139 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4140 idx_bltin = idx;
4141 if (*new == ':') {
4142 idx++;
4143 }
4144 new++, old++;
4145 }
4146 if (builtinloc < 0 && idx_bltin >= 0)
4147 builtinloc = idx_bltin; /* zap builtins */
4148 if (builtinloc >= 0 && idx_bltin < 0)
4149 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004150 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004151 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004152}
4153
4154
4155/*
4156 * Clear out command entries. The argument specifies the first entry in
4157 * PATH which has changed.
4158 */
4159
Eric Andersenc470f442003-07-28 09:56:35 +00004160static void
4161clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004162{
4163 struct tblentry **tblp;
4164 struct tblentry **pp;
4165 struct tblentry *cmdp;
4166
4167 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004168 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004169 pp = tblp;
4170 while ((cmdp = *pp) != NULL) {
4171 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004172 cmdp->param.index >= firstchange)
4173 || (cmdp->cmdtype == CMDBUILTIN &&
4174 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004175 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004176 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004177 } else {
4178 pp = &cmdp->next;
4179 }
4180 }
4181 }
4182 INTON;
4183}
4184
4185
Eric Andersenc470f442003-07-28 09:56:35 +00004186
Eric Andersencb57d552001-06-28 07:25:16 +00004187/*
Eric Andersencb57d552001-06-28 07:25:16 +00004188 * Locate a command in the command hash table. If "add" is nonzero,
4189 * add the command to the table if it is not already present. The
4190 * variable "lastcmdentry" is set to point to the address of the link
4191 * pointing to the entry, so that delete_cmd_entry can delete the
4192 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004193 *
4194 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004195 */
4196
Eric Andersen2870d962001-07-02 17:27:21 +00004197static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004198
Eric Andersenc470f442003-07-28 09:56:35 +00004199
4200static struct tblentry *
4201cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004202{
Eric Andersenc470f442003-07-28 09:56:35 +00004203 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004204 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004205 struct tblentry *cmdp;
4206 struct tblentry **pp;
4207
4208 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004209 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004210 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004211 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004212 hashval &= 0x7FFF;
4213 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004214 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004215 if (equal(cmdp->cmdname, name))
4216 break;
4217 pp = &cmdp->next;
4218 }
4219 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004220 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4221 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004222 cmdp->next = NULL;
4223 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004224 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004225 }
4226 lastcmdentry = pp;
4227 return cmdp;
4228}
4229
4230/*
4231 * Delete the command entry returned on the last lookup.
4232 */
4233
Eric Andersenc470f442003-07-28 09:56:35 +00004234static void
4235delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004236{
Eric Andersencb57d552001-06-28 07:25:16 +00004237 struct tblentry *cmdp;
4238
4239 INTOFF;
4240 cmdp = *lastcmdentry;
4241 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004242 if (cmdp->cmdtype == CMDFUNCTION)
4243 freefunc(cmdp->param.func);
4244 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004245 INTON;
4246}
4247
4248
Eric Andersenc470f442003-07-28 09:56:35 +00004249/*
4250 * Add a new command entry, replacing any existing command entry for
4251 * the same name - except special builtins.
4252 */
Eric Andersencb57d552001-06-28 07:25:16 +00004253
Eric Andersenc470f442003-07-28 09:56:35 +00004254static inline void
4255addcmdentry(char *name, struct cmdentry *entry)
4256{
4257 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004258
Eric Andersenc470f442003-07-28 09:56:35 +00004259 cmdp = cmdlookup(name, 1);
4260 if (cmdp->cmdtype == CMDFUNCTION) {
4261 freefunc(cmdp->param.func);
4262 }
4263 cmdp->cmdtype = entry->cmdtype;
4264 cmdp->param = entry->u;
4265 cmdp->rehash = 0;
4266}
Eric Andersencb57d552001-06-28 07:25:16 +00004267
Eric Andersenc470f442003-07-28 09:56:35 +00004268/*
4269 * Make a copy of a parse tree.
4270 */
Eric Andersencb57d552001-06-28 07:25:16 +00004271
Eric Andersenc470f442003-07-28 09:56:35 +00004272static inline struct funcnode *
4273copyfunc(union node *n)
4274{
4275 struct funcnode *f;
4276 size_t blocksize;
4277
4278 funcblocksize = offsetof(struct funcnode, n);
4279 funcstringsize = 0;
4280 calcsize(n);
4281 blocksize = funcblocksize;
4282 f = ckmalloc(blocksize + funcstringsize);
4283 funcblock = (char *) f + offsetof(struct funcnode, n);
4284 funcstring = (char *) f + blocksize;
4285 copynode(n);
4286 f->count = 0;
4287 return f;
4288}
4289
4290/*
4291 * Define a shell function.
4292 */
4293
4294static void
4295defun(char *name, union node *func)
4296{
4297 struct cmdentry entry;
4298
4299 INTOFF;
4300 entry.cmdtype = CMDFUNCTION;
4301 entry.u.func = copyfunc(func);
4302 addcmdentry(name, &entry);
4303 INTON;
4304}
Eric Andersencb57d552001-06-28 07:25:16 +00004305
4306
4307/*
4308 * Delete a function if it exists.
4309 */
4310
Eric Andersenc470f442003-07-28 09:56:35 +00004311static void
4312unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004313{
Eric Andersencb57d552001-06-28 07:25:16 +00004314 struct tblentry *cmdp;
4315
Eric Andersenc470f442003-07-28 09:56:35 +00004316 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4317 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004318 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004319}
4320
Eric Andersen2870d962001-07-02 17:27:21 +00004321/*
Eric Andersencb57d552001-06-28 07:25:16 +00004322 * Locate and print what a word is...
4323 */
4324
Eric Andersenc470f442003-07-28 09:56:35 +00004325
4326#ifdef CONFIG_ASH_CMDCMD
4327static int
4328describe_command(char *command, int describe_command_verbose)
4329#else
4330#define describe_command_verbose 1
4331static int
4332describe_command(char *command)
4333#endif
4334{
4335 struct cmdentry entry;
4336 struct tblentry *cmdp;
4337#ifdef CONFIG_ASH_ALIAS
4338 const struct alias *ap;
4339#endif
4340 const char *path = pathval();
4341
4342 if (describe_command_verbose) {
4343 out1str(command);
4344 }
4345
4346 /* First look at the keywords */
4347 if (findkwd(command)) {
4348 out1str(describe_command_verbose ? " is a shell keyword" : command);
4349 goto out;
4350 }
4351
4352#ifdef CONFIG_ASH_ALIAS
4353 /* Then look at the aliases */
4354 if ((ap = lookupalias(command, 0)) != NULL) {
4355 if (describe_command_verbose) {
4356 out1fmt(" is an alias for %s", ap->val);
4357 } else {
4358 out1str("alias ");
4359 printalias(ap);
4360 return 0;
4361 }
4362 goto out;
4363 }
4364#endif
4365 /* Then check if it is a tracked alias */
4366 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4367 entry.cmdtype = cmdp->cmdtype;
4368 entry.u = cmdp->param;
4369 } else {
4370 /* Finally use brute force */
4371 find_command(command, &entry, DO_ABS, path);
4372 }
4373
4374 switch (entry.cmdtype) {
4375 case CMDNORMAL: {
4376 int j = entry.u.index;
4377 char *p;
4378 if (j == -1) {
4379 p = command;
4380 } else {
4381 do {
4382 p = padvance(&path, command);
4383 stunalloc(p);
4384 } while (--j >= 0);
4385 }
4386 if (describe_command_verbose) {
4387 out1fmt(" is%s %s",
4388 (cmdp ? " a tracked alias for" : nullstr), p
4389 );
4390 } else {
4391 out1str(p);
4392 }
4393 break;
4394 }
4395
4396 case CMDFUNCTION:
4397 if (describe_command_verbose) {
4398 out1str(" is a shell function");
4399 } else {
4400 out1str(command);
4401 }
4402 break;
4403
4404 case CMDBUILTIN:
4405 if (describe_command_verbose) {
4406 out1fmt(" is a %sshell builtin",
4407 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4408 "special " : nullstr
4409 );
4410 } else {
4411 out1str(command);
4412 }
4413 break;
4414
4415 default:
4416 if (describe_command_verbose) {
4417 out1str(": not found\n");
4418 }
4419 return 127;
4420 }
4421
4422out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004423 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004424 return 0;
4425}
4426
4427static int
4428typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004429{
4430 int i;
4431 int err = 0;
4432
4433 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004434#ifdef CONFIG_ASH_CMDCMD
4435 err |= describe_command(argv[i], 1);
4436#else
4437 err |= describe_command(argv[i]);
4438#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004439 }
4440 return err;
4441}
4442
Eric Andersend35c5df2002-01-09 15:37:36 +00004443#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004444static int
4445commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004446{
4447 int c;
4448 int default_path = 0;
4449 int verify_only = 0;
4450 int verbose_verify_only = 0;
4451
4452 while ((c = nextopt("pvV")) != '\0')
4453 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004454 default:
4455#ifdef DEBUG
4456 fprintf(stderr,
4457"command: nextopt returned character code 0%o\n", c);
4458 return EX_SOFTWARE;
4459#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004460 case 'p':
4461 default_path = 1;
4462 break;
4463 case 'v':
4464 verify_only = 1;
4465 break;
4466 case 'V':
4467 verbose_verify_only = 1;
4468 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004469 }
4470
Eric Andersenc470f442003-07-28 09:56:35 +00004471 if (default_path + verify_only + verbose_verify_only > 1 ||
4472 !*argptr) {
4473 fprintf(stderr,
4474 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004475 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004476 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004477 }
4478
Eric Andersencb57d552001-06-28 07:25:16 +00004479 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004480 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004481 }
Eric Andersencb57d552001-06-28 07:25:16 +00004482
4483 return 0;
4484}
Eric Andersen2870d962001-07-02 17:27:21 +00004485#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004486
Eric Andersenc470f442003-07-28 09:56:35 +00004487/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004488
Eric Andersencb57d552001-06-28 07:25:16 +00004489/*
4490 * Routines to expand arguments to commands. We have to deal with
4491 * backquotes, shell variables, and file metacharacters.
4492 */
Eric Andersenc470f442003-07-28 09:56:35 +00004493
Eric Andersencb57d552001-06-28 07:25:16 +00004494/*
4495 * _rmescape() flags
4496 */
Eric Andersenc470f442003-07-28 09:56:35 +00004497#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4498#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4499#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4500#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4501#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004502
4503/*
4504 * Structure specifying which parts of the string should be searched
4505 * for IFS characters.
4506 */
4507
4508struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004509 struct ifsregion *next; /* next region in list */
4510 int begoff; /* offset of start of region */
4511 int endoff; /* offset of end of region */
4512 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004513};
4514
Eric Andersenc470f442003-07-28 09:56:35 +00004515/* output of current string */
4516static char *expdest;
4517/* list of back quote expressions */
4518static struct nodelist *argbackq;
4519/* first struct in list of ifs regions */
4520static struct ifsregion ifsfirst;
4521/* last struct in list */
4522static struct ifsregion *ifslastp;
4523/* holds expanded arg list */
4524static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004525
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004526static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004527static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004528static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004529static const char *subevalvar(char *, char *, int, int, int, int, int);
4530static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004531static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004532static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004533static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004534static void recordregion(int, int, int);
4535static void removerecordregions(int);
4536static void ifsbreakup(char *, struct arglist *);
4537static void ifsfree(void);
4538static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004539static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004540
Eric Andersened9ecf72004-06-22 08:29:45 +00004541static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004542static size_t esclen(const char *, const char *);
4543static char *scanleft(char *, char *, char *, char *, int, int);
4544static char *scanright(char *, char *, char *, char *, int, int);
4545static void varunset(const char *, const char *, const char *, int)
4546 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004547
Eric Andersenc470f442003-07-28 09:56:35 +00004548
4549#define pmatch(a, b) !fnmatch((a), (b), 0)
4550/*
Eric Andersen90898442003-08-06 11:20:52 +00004551 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004552 *
4553 * Returns an stalloced string.
4554 */
4555
4556static inline char *
4557preglob(const char *pattern, int quoted, int flag) {
4558 flag |= RMESCAPE_GLOB;
4559 if (quoted) {
4560 flag |= RMESCAPE_QUOTED;
4561 }
4562 return _rmescapes((char *)pattern, flag);
4563}
4564
4565
4566static size_t
4567esclen(const char *start, const char *p) {
4568 size_t esc = 0;
4569
4570 while (p > start && *--p == CTLESC) {
4571 esc++;
4572 }
4573 return esc;
4574}
4575
Eric Andersencb57d552001-06-28 07:25:16 +00004576
4577/*
4578 * Expand shell variables and backquotes inside a here document.
4579 */
4580
Eric Andersenc470f442003-07-28 09:56:35 +00004581static inline void
4582expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004583{
Eric Andersencb57d552001-06-28 07:25:16 +00004584 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004585 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004586 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004587}
4588
4589
4590/*
4591 * Perform variable substitution and command substitution on an argument,
4592 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4593 * perform splitting and file name expansion. When arglist is NULL, perform
4594 * here document expansion.
4595 */
4596
Eric Andersenc470f442003-07-28 09:56:35 +00004597void
4598expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004599{
4600 struct strlist *sp;
4601 char *p;
4602
4603 argbackq = arg->narg.backquote;
4604 STARTSTACKSTR(expdest);
4605 ifsfirst.next = NULL;
4606 ifslastp = NULL;
4607 argstr(arg->narg.text, flag);
4608 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004609 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004610 }
4611 STPUTC('\0', expdest);
4612 p = grabstackstr(expdest);
4613 exparg.lastp = &exparg.list;
4614 /*
4615 * TODO - EXP_REDIR
4616 */
4617 if (flag & EXP_FULL) {
4618 ifsbreakup(p, &exparg);
4619 *exparg.lastp = NULL;
4620 exparg.lastp = &exparg.list;
4621 expandmeta(exparg.list, flag);
4622 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004623 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004624 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004625 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004626 sp->text = p;
4627 *exparg.lastp = sp;
4628 exparg.lastp = &sp->next;
4629 }
Eric Andersenc470f442003-07-28 09:56:35 +00004630 if (ifsfirst.next)
4631 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004632 *exparg.lastp = NULL;
4633 if (exparg.list) {
4634 *arglist->lastp = exparg.list;
4635 arglist->lastp = exparg.lastp;
4636 }
4637}
4638
4639
Eric Andersenc470f442003-07-28 09:56:35 +00004640/*
4641 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4642 * characters to allow for further processing. Otherwise treat
4643 * $@ like $* since no splitting will be performed.
4644 */
4645
4646static void
4647argstr(char *p, int flag)
4648{
4649 static const char spclchars[] = {
4650 '=',
4651 ':',
4652 CTLQUOTEMARK,
4653 CTLENDVAR,
4654 CTLESC,
4655 CTLVAR,
4656 CTLBACKQ,
4657 CTLBACKQ | CTLQUOTE,
4658#ifdef CONFIG_ASH_MATH_SUPPORT
4659 CTLENDARI,
4660#endif
4661 0
4662 };
4663 const char *reject = spclchars;
4664 int c;
4665 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4666 int breakall = flag & EXP_WORD;
4667 int inquotes;
4668 size_t length;
4669 int startloc;
4670
4671 if (!(flag & EXP_VARTILDE)) {
4672 reject += 2;
4673 } else if (flag & EXP_VARTILDE2) {
4674 reject++;
4675 }
4676 inquotes = 0;
4677 length = 0;
4678 if (flag & EXP_TILDE) {
4679 char *q;
4680
4681 flag &= ~EXP_TILDE;
4682tilde:
4683 q = p;
4684 if (*q == CTLESC && (flag & EXP_QWORD))
4685 q++;
4686 if (*q == '~')
4687 p = exptilde(p, q, flag);
4688 }
4689start:
4690 startloc = expdest - (char *)stackblock();
4691 for (;;) {
4692 length += strcspn(p + length, reject);
4693 c = p[length];
4694 if (c && (!(c & 0x80)
4695#ifdef CONFIG_ASH_MATH_SUPPORT
4696 || c == CTLENDARI
4697#endif
4698 )) {
4699 /* c == '=' || c == ':' || c == CTLENDARI */
4700 length++;
4701 }
4702 if (length > 0) {
4703 int newloc;
4704 expdest = stnputs(p, length, expdest);
4705 newloc = expdest - (char *)stackblock();
4706 if (breakall && !inquotes && newloc > startloc) {
4707 recordregion(startloc, newloc, 0);
4708 }
4709 startloc = newloc;
4710 }
4711 p += length + 1;
4712 length = 0;
4713
4714 switch (c) {
4715 case '\0':
4716 goto breakloop;
4717 case '=':
4718 if (flag & EXP_VARTILDE2) {
4719 p--;
4720 continue;
4721 }
4722 flag |= EXP_VARTILDE2;
4723 reject++;
4724 /* fall through */
4725 case ':':
4726 /*
4727 * sort of a hack - expand tildes in variable
4728 * assignments (after the first '=' and after ':'s).
4729 */
4730 if (*--p == '~') {
4731 goto tilde;
4732 }
4733 continue;
4734 }
4735
4736 switch (c) {
4737 case CTLENDVAR: /* ??? */
4738 goto breakloop;
4739 case CTLQUOTEMARK:
4740 /* "$@" syntax adherence hack */
4741 if (
4742 !inquotes &&
4743 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4744 (p[4] == CTLQUOTEMARK || (
4745 p[4] == CTLENDVAR &&
4746 p[5] == CTLQUOTEMARK
4747 ))
4748 ) {
4749 p = evalvar(p + 1, flag) + 1;
4750 goto start;
4751 }
4752 inquotes = !inquotes;
4753addquote:
4754 if (quotes) {
4755 p--;
4756 length++;
4757 startloc++;
4758 }
4759 break;
4760 case CTLESC:
4761 startloc++;
4762 length++;
4763 goto addquote;
4764 case CTLVAR:
4765 p = evalvar(p, flag);
4766 goto start;
4767 case CTLBACKQ:
4768 c = 0;
4769 case CTLBACKQ|CTLQUOTE:
4770 expbackq(argbackq->n, c, quotes);
4771 argbackq = argbackq->next;
4772 goto start;
4773#ifdef CONFIG_ASH_MATH_SUPPORT
4774 case CTLENDARI:
4775 p--;
4776 expari(quotes);
4777 goto start;
4778#endif
4779 }
4780 }
4781breakloop:
4782 ;
4783}
4784
4785static char *
4786exptilde(char *startp, char *p, int flag)
4787{
4788 char c;
4789 char *name;
4790 struct passwd *pw;
4791 const char *home;
4792 int quotes = flag & (EXP_FULL | EXP_CASE);
4793 int startloc;
4794
4795 name = p + 1;
4796
4797 while ((c = *++p) != '\0') {
4798 switch(c) {
4799 case CTLESC:
4800 return (startp);
4801 case CTLQUOTEMARK:
4802 return (startp);
4803 case ':':
4804 if (flag & EXP_VARTILDE)
4805 goto done;
4806 break;
4807 case '/':
4808 case CTLENDVAR:
4809 goto done;
4810 }
4811 }
4812done:
4813 *p = '\0';
4814 if (*name == '\0') {
4815 if ((home = lookupvar(homestr)) == NULL)
4816 goto lose;
4817 } else {
4818 if ((pw = getpwnam(name)) == NULL)
4819 goto lose;
4820 home = pw->pw_dir;
4821 }
4822 if (*home == '\0')
4823 goto lose;
4824 *p = c;
4825 startloc = expdest - (char *)stackblock();
4826 strtodest(home, SQSYNTAX, quotes);
4827 recordregion(startloc, expdest - (char *)stackblock(), 0);
4828 return (p);
4829lose:
4830 *p = c;
4831 return (startp);
4832}
4833
4834
4835static void
4836removerecordregions(int endoff)
4837{
4838 if (ifslastp == NULL)
4839 return;
4840
4841 if (ifsfirst.endoff > endoff) {
4842 while (ifsfirst.next != NULL) {
4843 struct ifsregion *ifsp;
4844 INTOFF;
4845 ifsp = ifsfirst.next->next;
4846 ckfree(ifsfirst.next);
4847 ifsfirst.next = ifsp;
4848 INTON;
4849 }
4850 if (ifsfirst.begoff > endoff)
4851 ifslastp = NULL;
4852 else {
4853 ifslastp = &ifsfirst;
4854 ifsfirst.endoff = endoff;
4855 }
4856 return;
4857 }
4858
4859 ifslastp = &ifsfirst;
4860 while (ifslastp->next && ifslastp->next->begoff < endoff)
4861 ifslastp=ifslastp->next;
4862 while (ifslastp->next != NULL) {
4863 struct ifsregion *ifsp;
4864 INTOFF;
4865 ifsp = ifslastp->next->next;
4866 ckfree(ifslastp->next);
4867 ifslastp->next = ifsp;
4868 INTON;
4869 }
4870 if (ifslastp->endoff > endoff)
4871 ifslastp->endoff = endoff;
4872}
4873
4874
4875#ifdef CONFIG_ASH_MATH_SUPPORT
4876/*
4877 * Expand arithmetic expression. Backup to start of expression,
4878 * evaluate, place result in (backed up) result, adjust string position.
4879 */
4880void
4881expari(int quotes)
4882{
4883 char *p, *start;
4884 int begoff;
4885 int flag;
4886 int len;
4887
4888 /* ifsfree(); */
4889
4890 /*
4891 * This routine is slightly over-complicated for
4892 * efficiency. Next we scan backwards looking for the
4893 * start of arithmetic.
4894 */
4895 start = stackblock();
4896 p = expdest - 1;
4897 *p = '\0';
4898 p--;
4899 do {
4900 int esc;
4901
4902 while (*p != CTLARI) {
4903 p--;
4904#ifdef DEBUG
4905 if (p < start) {
4906 error("missing CTLARI (shouldn't happen)");
4907 }
4908#endif
4909 }
4910
4911 esc = esclen(start, p);
4912 if (!(esc % 2)) {
4913 break;
4914 }
4915
4916 p -= esc + 1;
4917 } while (1);
4918
4919 begoff = p - start;
4920
4921 removerecordregions(begoff);
4922
4923 flag = p[1];
4924
4925 expdest = p;
4926
4927 if (quotes)
4928 rmescapes(p + 2);
4929
4930 len = cvtnum(dash_arith(p + 2));
4931
4932 if (flag != '"')
4933 recordregion(begoff, begoff + len, 0);
4934}
4935#endif
4936
4937/*
4938 * Expand stuff in backwards quotes.
4939 */
4940
4941static void
4942expbackq(union node *cmd, int quoted, int quotes)
4943{
4944 struct backcmd in;
4945 int i;
4946 char buf[128];
4947 char *p;
4948 char *dest;
4949 int startloc;
4950 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4951 struct stackmark smark;
4952
4953 INTOFF;
4954 setstackmark(&smark);
4955 dest = expdest;
4956 startloc = dest - (char *)stackblock();
4957 grabstackstr(dest);
4958 evalbackcmd(cmd, (struct backcmd *) &in);
4959 popstackmark(&smark);
4960
4961 p = in.buf;
4962 i = in.nleft;
4963 if (i == 0)
4964 goto read;
4965 for (;;) {
4966 memtodest(p, i, syntax, quotes);
4967read:
4968 if (in.fd < 0)
4969 break;
4970 i = safe_read(in.fd, buf, sizeof buf);
4971 TRACE(("expbackq: read returns %d\n", i));
4972 if (i <= 0)
4973 break;
4974 p = buf;
4975 }
4976
4977 if (in.buf)
4978 ckfree(in.buf);
4979 if (in.fd >= 0) {
4980 close(in.fd);
4981 back_exitstatus = waitforjob(in.jp);
4982 }
4983 INTON;
4984
4985 /* Eat all trailing newlines */
4986 dest = expdest;
4987 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4988 STUNPUTC(dest);
4989 expdest = dest;
4990
4991 if (quoted == 0)
4992 recordregion(startloc, dest - (char *)stackblock(), 0);
4993 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4994 (dest - (char *)stackblock()) - startloc,
4995 (dest - (char *)stackblock()) - startloc,
4996 stackblock() + startloc));
4997}
4998
4999
5000static char *
Eric Andersen90898442003-08-06 11:20:52 +00005001scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5002 int zero)
5003{
Eric Andersenc470f442003-07-28 09:56:35 +00005004 char *loc;
5005 char *loc2;
5006 char c;
5007
5008 loc = startp;
5009 loc2 = rmesc;
5010 do {
5011 int match;
5012 const char *s = loc2;
5013 c = *loc2;
5014 if (zero) {
5015 *loc2 = '\0';
5016 s = rmesc;
5017 }
5018 match = pmatch(str, s);
5019 *loc2 = c;
5020 if (match)
5021 return loc;
5022 if (quotes && *loc == CTLESC)
5023 loc++;
5024 loc++;
5025 loc2++;
5026 } while (c);
5027 return 0;
5028}
5029
5030
5031static char *
Eric Andersen90898442003-08-06 11:20:52 +00005032scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5033 int zero)
5034{
Eric Andersenc470f442003-07-28 09:56:35 +00005035 int esc = 0;
5036 char *loc;
5037 char *loc2;
5038
5039 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5040 int match;
5041 char c = *loc2;
5042 const char *s = loc2;
5043 if (zero) {
5044 *loc2 = '\0';
5045 s = rmesc;
5046 }
5047 match = pmatch(str, s);
5048 *loc2 = c;
5049 if (match)
5050 return loc;
5051 loc--;
5052 if (quotes) {
5053 if (--esc < 0) {
5054 esc = esclen(startp, loc);
5055 }
5056 if (esc % 2) {
5057 esc--;
5058 loc--;
5059 }
5060 }
5061 }
5062 return 0;
5063}
5064
5065static const char *
5066subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5067{
5068 char *startp;
5069 char *loc;
5070 int saveherefd = herefd;
5071 struct nodelist *saveargbackq = argbackq;
5072 int amount;
5073 char *rmesc, *rmescend;
5074 int zero;
5075 char *(*scan)(char *, char *, char *, char *, int , int);
5076
5077 herefd = -1;
5078 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5079 STPUTC('\0', expdest);
5080 herefd = saveherefd;
5081 argbackq = saveargbackq;
5082 startp = stackblock() + startloc;
5083
5084 switch (subtype) {
5085 case VSASSIGN:
5086 setvar(str, startp, 0);
5087 amount = startp - expdest;
5088 STADJUST(amount, expdest);
5089 return startp;
5090
5091 case VSQUESTION:
5092 varunset(p, str, startp, varflags);
5093 /* NOTREACHED */
5094 }
5095
5096 subtype -= VSTRIMRIGHT;
5097#ifdef DEBUG
5098 if (subtype < 0 || subtype > 3)
5099 abort();
5100#endif
5101
5102 rmesc = startp;
5103 rmescend = stackblock() + strloc;
5104 if (quotes) {
5105 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5106 if (rmesc != startp) {
5107 rmescend = expdest;
5108 startp = stackblock() + startloc;
5109 }
5110 }
5111 rmescend--;
5112 str = stackblock() + strloc;
5113 preglob(str, varflags & VSQUOTE, 0);
5114
5115 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5116 zero = subtype >> 1;
5117 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5118 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5119
5120 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5121 if (loc) {
5122 if (zero) {
5123 memmove(startp, loc, str - loc);
5124 loc = startp + (str - loc) - 1;
5125 }
5126 *loc = '\0';
5127 amount = loc - expdest;
5128 STADJUST(amount, expdest);
5129 }
5130 return loc;
5131}
5132
5133
Eric Andersen62483552001-07-10 06:09:16 +00005134/*
5135 * Expand a variable, and return a pointer to the next character in the
5136 * input string.
5137 */
Eric Andersenc470f442003-07-28 09:56:35 +00005138static char *
5139evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005140{
5141 int subtype;
5142 int varflags;
5143 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005144 int patloc;
5145 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005146 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005147 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005148 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005149 int quotes;
5150 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005151
Eric Andersenc470f442003-07-28 09:56:35 +00005152 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005153 varflags = *p++;
5154 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005155 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005156 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005157 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005158 startloc = expdest - (char *)stackblock();
5159 p = strchr(p, '=') + 1;
5160
Eric Andersenc470f442003-07-28 09:56:35 +00005161again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005162 varlen = varvalue(var, varflags, flag);
5163 if (varflags & VSNUL)
5164 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005165
Glenn L McGrath76620622004-01-13 10:19:37 +00005166 if (subtype == VSPLUS) {
5167 varlen = -1 - varlen;
5168 goto vsplus;
5169 }
Eric Andersen62483552001-07-10 06:09:16 +00005170
Eric Andersenc470f442003-07-28 09:56:35 +00005171 if (subtype == VSMINUS) {
5172vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005173 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005174 argstr(
5175 p, flag | EXP_TILDE |
5176 (quoted ? EXP_QWORD : EXP_WORD)
5177 );
5178 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005179 }
5180 if (easy)
5181 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005182 goto end;
5183 }
Eric Andersen62483552001-07-10 06:09:16 +00005184
Eric Andersenc470f442003-07-28 09:56:35 +00005185 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005186 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005187 if (subevalvar(p, var, 0, subtype, startloc,
5188 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005189 varflags &= ~VSNUL;
5190 /*
5191 * Remove any recorded regions beyond
5192 * start of variable
5193 */
5194 removerecordregions(startloc);
5195 goto again;
5196 }
Eric Andersenc470f442003-07-28 09:56:35 +00005197 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005198 }
5199 if (easy)
5200 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005201 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005202 }
5203
Glenn L McGrath76620622004-01-13 10:19:37 +00005204 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005205 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005206
Eric Andersenc470f442003-07-28 09:56:35 +00005207 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005208 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005209 goto record;
5210 }
5211
5212 if (subtype == VSNORMAL) {
5213 if (!easy)
5214 goto end;
5215record:
5216 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5217 goto end;
5218 }
5219
5220#ifdef DEBUG
5221 switch (subtype) {
5222 case VSTRIMLEFT:
5223 case VSTRIMLEFTMAX:
5224 case VSTRIMRIGHT:
5225 case VSTRIMRIGHTMAX:
5226 break;
5227 default:
5228 abort();
5229 }
5230#endif
5231
Glenn L McGrath76620622004-01-13 10:19:37 +00005232 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005233 /*
5234 * Terminate the string and start recording the pattern
5235 * right after it
5236 */
5237 STPUTC('\0', expdest);
5238 patloc = expdest - (char *)stackblock();
5239 if (subevalvar(p, NULL, patloc, subtype,
5240 startloc, varflags, quotes) == 0) {
5241 int amount = expdest - (
5242 (char *)stackblock() + patloc - 1
5243 );
5244 STADJUST(-amount, expdest);
5245 }
5246 /* Remove any recorded regions beyond start of variable */
5247 removerecordregions(startloc);
5248 goto record;
5249 }
5250
5251end:
5252 if (subtype != VSNORMAL) { /* skip to end of alternative */
5253 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005254 for (;;) {
5255 if ((c = *p++) == CTLESC)
5256 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005257 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005258 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005259 argbackq = argbackq->next;
5260 } else if (c == CTLVAR) {
5261 if ((*p++ & VSTYPE) != VSNORMAL)
5262 nesting++;
5263 } else if (c == CTLENDVAR) {
5264 if (--nesting == 0)
5265 break;
5266 }
5267 }
5268 }
5269 return p;
5270}
5271
Eric Andersencb57d552001-06-28 07:25:16 +00005272
Eric Andersencb57d552001-06-28 07:25:16 +00005273/*
5274 * Put a string on the stack.
5275 */
5276
Eric Andersenc470f442003-07-28 09:56:35 +00005277static void
5278memtodest(const char *p, size_t len, int syntax, int quotes) {
5279 char *q = expdest;
5280
5281 q = makestrspace(len * 2, q);
5282
5283 while (len--) {
5284 int c = *p++;
5285 if (!c)
5286 continue;
5287 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5288 USTPUTC(CTLESC, q);
5289 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005290 }
Eric Andersenc470f442003-07-28 09:56:35 +00005291
5292 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005293}
5294
Eric Andersenc470f442003-07-28 09:56:35 +00005295
5296static void
5297strtodest(const char *p, int syntax, int quotes)
5298{
5299 memtodest(p, strlen(p), syntax, quotes);
5300}
5301
5302
Eric Andersencb57d552001-06-28 07:25:16 +00005303/*
5304 * Add the value of a specialized variable to the stack string.
5305 */
5306
Glenn L McGrath76620622004-01-13 10:19:37 +00005307static ssize_t
5308varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005309{
5310 int num;
5311 char *p;
5312 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005313 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005314 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005315 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005316 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005317 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005318 int quoted = varflags & VSQUOTE;
5319 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005320 int quotes = flags & (EXP_FULL | EXP_CASE);
5321
Glenn L McGrath76620622004-01-13 10:19:37 +00005322 if (quoted && (flags & EXP_FULL))
5323 sep = 1 << CHAR_BIT;
5324
Eric Andersencb57d552001-06-28 07:25:16 +00005325 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5326 switch (*name) {
5327 case '$':
5328 num = rootpid;
5329 goto numvar;
5330 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005331 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005332 goto numvar;
5333 case '#':
5334 num = shellparam.nparam;
5335 goto numvar;
5336 case '!':
5337 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005338 if (num == 0)
5339 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005340numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005341 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005342 break;
5343 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005344 p = makestrspace(NOPTS, expdest);
5345 for (i = NOPTS - 1; i >= 0; i--) {
5346 if (optlist[i]) {
5347 USTPUTC(optletters(i), p);
5348 len++;
5349 }
Eric Andersencb57d552001-06-28 07:25:16 +00005350 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005351 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005352 break;
5353 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005354 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005355 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005356 /* fall through */
5357 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005358 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005359 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5360 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005361param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005362 if (!(ap = shellparam.p))
5363 return -1;
5364 while ((p = *ap++)) {
5365 size_t partlen;
5366
5367 partlen = strlen(p);
5368
5369 len += partlen;
5370 if (len > partlen && sep) {
5371 char *q;
5372
5373 len++;
5374 if (subtype == VSPLUS || subtype == VSLENGTH) {
5375 continue;
5376 }
5377 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005378 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005379 STPUTC(CTLESC, q);
5380 STPUTC(sep, q);
5381 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005382 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005383
5384 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5385 memtodest(p, partlen, syntax, quotes);
Eric Andersencb57d552001-06-28 07:25:16 +00005386 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005387 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005388 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005389 case '1':
5390 case '2':
5391 case '3':
5392 case '4':
5393 case '5':
5394 case '6':
5395 case '7':
5396 case '8':
5397 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005398 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005399 if (num < 0 || num > shellparam.nparam)
5400 return -1;
5401 p = num ? shellparam.p[num - 1] : arg0;
5402 goto value;
5403 default:
5404 p = lookupvar(name);
5405value:
5406 if (!p)
5407 return -1;
5408
5409 len = strlen(p);
5410 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5411 memtodest(p, len, syntax, quotes);
5412 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005413 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005414
5415 if (subtype == VSPLUS || subtype == VSLENGTH)
5416 STADJUST(-len, expdest);
5417 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005418}
5419
5420
Eric Andersencb57d552001-06-28 07:25:16 +00005421/*
5422 * Record the fact that we have to scan this region of the
5423 * string for IFS characters.
5424 */
5425
Eric Andersenc470f442003-07-28 09:56:35 +00005426static void
5427recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005428{
5429 struct ifsregion *ifsp;
5430
5431 if (ifslastp == NULL) {
5432 ifsp = &ifsfirst;
5433 } else {
5434 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005435 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005436 ifsp->next = NULL;
5437 ifslastp->next = ifsp;
5438 INTON;
5439 }
5440 ifslastp = ifsp;
5441 ifslastp->begoff = start;
5442 ifslastp->endoff = end;
5443 ifslastp->nulonly = nulonly;
5444}
5445
5446
Eric Andersencb57d552001-06-28 07:25:16 +00005447/*
5448 * Break the argument string into pieces based upon IFS and add the
5449 * strings to the argument list. The regions of the string to be
5450 * searched for IFS characters have been stored by recordregion.
5451 */
Eric Andersenc470f442003-07-28 09:56:35 +00005452static void
5453ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005454{
Eric Andersencb57d552001-06-28 07:25:16 +00005455 struct ifsregion *ifsp;
5456 struct strlist *sp;
5457 char *start;
5458 char *p;
5459 char *q;
5460 const char *ifs, *realifs;
5461 int ifsspc;
5462 int nulonly;
5463
5464
5465 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005466 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005467 ifsspc = 0;
5468 nulonly = 0;
5469 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005470 ifsp = &ifsfirst;
5471 do {
5472 p = string + ifsp->begoff;
5473 nulonly = ifsp->nulonly;
5474 ifs = nulonly ? nullstr : realifs;
5475 ifsspc = 0;
5476 while (p < string + ifsp->endoff) {
5477 q = p;
5478 if (*p == CTLESC)
5479 p++;
5480 if (strchr(ifs, *p)) {
5481 if (!nulonly)
5482 ifsspc = (strchr(defifs, *p) != NULL);
5483 /* Ignore IFS whitespace at start */
5484 if (q == start && ifsspc) {
5485 p++;
5486 start = p;
5487 continue;
5488 }
5489 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005490 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005491 sp->text = start;
5492 *arglist->lastp = sp;
5493 arglist->lastp = &sp->next;
5494 p++;
5495 if (!nulonly) {
5496 for (;;) {
5497 if (p >= string + ifsp->endoff) {
5498 break;
5499 }
5500 q = p;
5501 if (*p == CTLESC)
5502 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005503 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005504 p = q;
5505 break;
5506 } else if (strchr(defifs, *p) == NULL) {
5507 if (ifsspc) {
5508 p++;
5509 ifsspc = 0;
5510 } else {
5511 p = q;
5512 break;
5513 }
5514 } else
5515 p++;
5516 }
5517 }
5518 start = p;
5519 } else
5520 p++;
5521 }
5522 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005523 if (nulonly)
5524 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005525 }
5526
Eric Andersenc470f442003-07-28 09:56:35 +00005527 if (!*start)
5528 return;
5529
5530add:
5531 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005532 sp->text = start;
5533 *arglist->lastp = sp;
5534 arglist->lastp = &sp->next;
5535}
5536
Eric Andersenc470f442003-07-28 09:56:35 +00005537static void
5538ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005539{
Eric Andersenc470f442003-07-28 09:56:35 +00005540 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005541
Eric Andersenc470f442003-07-28 09:56:35 +00005542 INTOFF;
5543 p = ifsfirst.next;
5544 do {
5545 struct ifsregion *ifsp;
5546 ifsp = p->next;
5547 ckfree(p);
5548 p = ifsp;
5549 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005550 ifslastp = NULL;
5551 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005552 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005553}
5554
Eric Andersen90898442003-08-06 11:20:52 +00005555static void expmeta(char *, char *);
5556static struct strlist *expsort(struct strlist *);
5557static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005558
Eric Andersen90898442003-08-06 11:20:52 +00005559static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005560
Eric Andersencb57d552001-06-28 07:25:16 +00005561
Eric Andersenc470f442003-07-28 09:56:35 +00005562static void
Eric Andersen90898442003-08-06 11:20:52 +00005563expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005564{
Eric Andersen90898442003-08-06 11:20:52 +00005565 static const char metachars[] = {
5566 '*', '?', '[', 0
5567 };
Eric Andersencb57d552001-06-28 07:25:16 +00005568 /* TODO - EXP_REDIR */
5569
5570 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005571 struct strlist **savelastp;
5572 struct strlist *sp;
5573 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005574
Eric Andersencb57d552001-06-28 07:25:16 +00005575 if (fflag)
5576 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005577 if (!strpbrk(str->text, metachars))
5578 goto nometa;
5579 savelastp = exparg.lastp;
5580
Eric Andersencb57d552001-06-28 07:25:16 +00005581 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005582 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005583 {
5584 int i = strlen(str->text);
5585 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5586 }
5587
5588 expmeta(expdir, p);
5589 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005590 if (p != str->text)
5591 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005592 INTON;
5593 if (exparg.lastp == savelastp) {
5594 /*
5595 * no matches
5596 */
Eric Andersenc470f442003-07-28 09:56:35 +00005597nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005598 *exparg.lastp = str;
5599 rmescapes(str->text);
5600 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005601 } else {
5602 *exparg.lastp = NULL;
5603 *savelastp = sp = expsort(*savelastp);
5604 while (sp->next != NULL)
5605 sp = sp->next;
5606 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005607 }
5608 str = str->next;
5609 }
5610}
5611
Eric Andersencb57d552001-06-28 07:25:16 +00005612/*
Eric Andersenc470f442003-07-28 09:56:35 +00005613 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005614 */
5615
Eric Andersenc470f442003-07-28 09:56:35 +00005616static void
Eric Andersen90898442003-08-06 11:20:52 +00005617addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005618{
Eric Andersencb57d552001-06-28 07:25:16 +00005619 struct strlist *sp;
5620
Eric Andersenc470f442003-07-28 09:56:35 +00005621 sp = (struct strlist *)stalloc(sizeof *sp);
5622 sp->text = sstrdup(name);
5623 *exparg.lastp = sp;
5624 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005625}
5626
5627
Eric Andersencb57d552001-06-28 07:25:16 +00005628/*
Eric Andersen90898442003-08-06 11:20:52 +00005629 * Do metacharacter (i.e. *, ?, [...]) expansion.
5630 */
5631
5632static void
5633expmeta(char *enddir, char *name)
5634{
5635 char *p;
5636 const char *cp;
5637 char *start;
5638 char *endname;
5639 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005640 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005641 DIR *dirp;
5642 struct dirent *dp;
5643 int atend;
5644 int matchdot;
5645
5646 metaflag = 0;
5647 start = name;
5648 for (p = name; *p; p++) {
5649 if (*p == '*' || *p == '?')
5650 metaflag = 1;
5651 else if (*p == '[') {
5652 char *q = p + 1;
5653 if (*q == '!')
5654 q++;
5655 for (;;) {
5656 if (*q == '\\')
5657 q++;
5658 if (*q == '/' || *q == '\0')
5659 break;
5660 if (*++q == ']') {
5661 metaflag = 1;
5662 break;
5663 }
5664 }
5665 } else if (*p == '\\')
5666 p++;
5667 else if (*p == '/') {
5668 if (metaflag)
5669 goto out;
5670 start = p + 1;
5671 }
5672 }
5673out:
5674 if (metaflag == 0) { /* we've reached the end of the file name */
5675 if (enddir != expdir)
5676 metaflag++;
5677 p = name;
5678 do {
5679 if (*p == '\\')
5680 p++;
5681 *enddir++ = *p;
5682 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005683 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005684 addfname(expdir);
5685 return;
5686 }
5687 endname = p;
5688 if (name < start) {
5689 p = name;
5690 do {
5691 if (*p == '\\')
5692 p++;
5693 *enddir++ = *p++;
5694 } while (p < start);
5695 }
5696 if (enddir == expdir) {
5697 cp = ".";
5698 } else if (enddir == expdir + 1 && *expdir == '/') {
5699 cp = "/";
5700 } else {
5701 cp = expdir;
5702 enddir[-1] = '\0';
5703 }
5704 if ((dirp = opendir(cp)) == NULL)
5705 return;
5706 if (enddir != expdir)
5707 enddir[-1] = '/';
5708 if (*endname == 0) {
5709 atend = 1;
5710 } else {
5711 atend = 0;
5712 *endname++ = '\0';
5713 }
5714 matchdot = 0;
5715 p = start;
5716 if (*p == '\\')
5717 p++;
5718 if (*p == '.')
5719 matchdot++;
5720 while (! intpending && (dp = readdir(dirp)) != NULL) {
5721 if (dp->d_name[0] == '.' && ! matchdot)
5722 continue;
5723 if (pmatch(start, dp->d_name)) {
5724 if (atend) {
5725 scopy(dp->d_name, enddir);
5726 addfname(expdir);
5727 } else {
5728 for (p = enddir, cp = dp->d_name;
5729 (*p++ = *cp++) != '\0';)
5730 continue;
5731 p[-1] = '/';
5732 expmeta(p, endname);
5733 }
5734 }
5735 }
5736 closedir(dirp);
5737 if (! atend)
5738 endname[-1] = '/';
5739}
5740
5741/*
5742 * Sort the results of file name expansion. It calculates the number of
5743 * strings to sort and then calls msort (short for merge sort) to do the
5744 * work.
5745 */
5746
5747static struct strlist *
5748expsort(struct strlist *str)
5749{
5750 int len;
5751 struct strlist *sp;
5752
5753 len = 0;
5754 for (sp = str ; sp ; sp = sp->next)
5755 len++;
5756 return msort(str, len);
5757}
5758
5759
5760static struct strlist *
5761msort(struct strlist *list, int len)
5762{
5763 struct strlist *p, *q = NULL;
5764 struct strlist **lpp;
5765 int half;
5766 int n;
5767
5768 if (len <= 1)
5769 return list;
5770 half = len >> 1;
5771 p = list;
5772 for (n = half ; --n >= 0 ; ) {
5773 q = p;
5774 p = p->next;
5775 }
5776 q->next = NULL; /* terminate first half of list */
5777 q = msort(list, half); /* sort first half of list */
5778 p = msort(p, len - half); /* sort second half */
5779 lpp = &list;
5780 for (;;) {
5781#ifdef CONFIG_LOCALE_SUPPORT
5782 if (strcoll(p->text, q->text) < 0)
5783#else
5784 if (strcmp(p->text, q->text) < 0)
5785#endif
5786 {
5787 *lpp = p;
5788 lpp = &p->next;
5789 if ((p = *lpp) == NULL) {
5790 *lpp = q;
5791 break;
5792 }
5793 } else {
5794 *lpp = q;
5795 lpp = &q->next;
5796 if ((q = *lpp) == NULL) {
5797 *lpp = p;
5798 break;
5799 }
5800 }
5801 }
5802 return list;
5803}
5804
5805
5806/*
Eric Andersencb57d552001-06-28 07:25:16 +00005807 * Returns true if the pattern matches the string.
5808 */
5809
Eric Andersenc470f442003-07-28 09:56:35 +00005810static inline int
5811patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005812{
Eric Andersenc470f442003-07-28 09:56:35 +00005813 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005814}
5815
5816
Eric Andersencb57d552001-06-28 07:25:16 +00005817/*
5818 * Remove any CTLESC characters from a string.
5819 */
5820
Eric Andersenc470f442003-07-28 09:56:35 +00005821static char *
5822_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005823{
5824 char *p, *q, *r;
5825 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005826 unsigned inquotes;
5827 int notescaped;
5828 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005829
5830 p = strpbrk(str, qchars);
5831 if (!p) {
5832 return str;
5833 }
5834 q = p;
5835 r = str;
5836 if (flag & RMESCAPE_ALLOC) {
5837 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005838 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005839
Eric Andersenc470f442003-07-28 09:56:35 +00005840 if (flag & RMESCAPE_GROW) {
5841 r = makestrspace(fulllen, expdest);
5842 } else if (flag & RMESCAPE_HEAP) {
5843 r = ckmalloc(fulllen);
5844 } else {
5845 r = stalloc(fulllen);
5846 }
5847 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005848 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005849 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005850 }
5851 }
Eric Andersenc470f442003-07-28 09:56:35 +00005852 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5853 globbing = flag & RMESCAPE_GLOB;
5854 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005855 while (*p) {
5856 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005857 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005858 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005859 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005860 continue;
5861 }
Eric Andersenc470f442003-07-28 09:56:35 +00005862 if (*p == '\\') {
5863 /* naked back slash */
5864 notescaped = 0;
5865 goto copy;
5866 }
Eric Andersencb57d552001-06-28 07:25:16 +00005867 if (*p == CTLESC) {
5868 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005869 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005870 *q++ = '\\';
5871 }
5872 }
Eric Andersenc470f442003-07-28 09:56:35 +00005873 notescaped = globbing;
5874copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005875 *q++ = *p++;
5876 }
5877 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005878 if (flag & RMESCAPE_GROW) {
5879 expdest = r;
5880 STADJUST(q - r + 1, expdest);
5881 }
Eric Andersencb57d552001-06-28 07:25:16 +00005882 return r;
5883}
Eric Andersencb57d552001-06-28 07:25:16 +00005884
5885
Eric Andersencb57d552001-06-28 07:25:16 +00005886/*
5887 * See if a pattern matches in a case statement.
5888 */
5889
Eric Andersenc470f442003-07-28 09:56:35 +00005890int
5891casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005892{
Eric Andersencb57d552001-06-28 07:25:16 +00005893 struct stackmark smark;
5894 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005895
5896 setstackmark(&smark);
5897 argbackq = pattern->narg.backquote;
5898 STARTSTACKSTR(expdest);
5899 ifslastp = NULL;
5900 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005901 STACKSTRNUL(expdest);
5902 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005903 popstackmark(&smark);
5904 return result;
5905}
5906
5907/*
5908 * Our own itoa().
5909 */
5910
Eric Andersenc470f442003-07-28 09:56:35 +00005911static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005912cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005913{
Eric Andersencb57d552001-06-28 07:25:16 +00005914 int len;
5915
Eric Andersenc470f442003-07-28 09:56:35 +00005916 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005917#ifdef CONFIG_ASH_MATH_SUPPORT_64
5918 len = fmtstr(expdest, 32, "%lld", (long long) num);
5919#else
Eric Andersenc470f442003-07-28 09:56:35 +00005920 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005921#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005922 STADJUST(len, expdest);
5923 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005924}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005925
Eric Andersenc470f442003-07-28 09:56:35 +00005926static void
5927varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005928{
Eric Andersenc470f442003-07-28 09:56:35 +00005929 const char *msg;
5930 const char *tail;
5931
5932 tail = nullstr;
5933 msg = "parameter not set";
5934 if (umsg) {
5935 if (*end == CTLENDVAR) {
5936 if (varflags & VSNUL)
5937 tail = " or null";
5938 } else
5939 msg = umsg;
5940 }
5941 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005942}
Eric Andersen90898442003-08-06 11:20:52 +00005943
5944
Eric Andersenc470f442003-07-28 09:56:35 +00005945/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005946
Eric Andersencb57d552001-06-28 07:25:16 +00005947/*
Eric Andersen90898442003-08-06 11:20:52 +00005948 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005949 */
5950
Eric Andersenc470f442003-07-28 09:56:35 +00005951#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5952#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005953
Eric Andersenc470f442003-07-28 09:56:35 +00005954static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005955
Eric Andersencb57d552001-06-28 07:25:16 +00005956/*
Eric Andersenc470f442003-07-28 09:56:35 +00005957 * Read a character from the script, returning PEOF on end of file.
5958 * Nul characters in the input are silently discarded.
5959 */
5960
5961#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5962
5963#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5964#define pgetc_macro() pgetc()
5965static int
5966pgetc(void)
5967{
5968 return pgetc_as_macro();
5969}
5970#else
5971#define pgetc_macro() pgetc_as_macro()
5972static int
5973pgetc(void)
5974{
5975 return pgetc_macro();
5976}
5977#endif
5978
5979
5980/*
5981 * Same as pgetc(), but ignores PEOA.
5982 */
5983#ifdef CONFIG_ASH_ALIAS
5984static int pgetc2(void)
5985{
5986 int c;
5987
5988 do {
5989 c = pgetc_macro();
5990 } while (c == PEOA);
5991 return c;
5992}
5993#else
5994static inline int pgetc2(void)
5995{
5996 return pgetc_macro();
5997}
5998#endif
5999
Glenn L McGrath28939ad2004-07-21 10:20:19 +00006000/*
6001 * Read a line from the script.
6002 */
6003
6004static inline char *
6005pfgets(char *line, int len)
6006{
6007 char *p = line;
6008 int nleft = len;
6009 int c;
6010
6011 while (--nleft > 0) {
6012 c = pgetc2();
6013 if (c == PEOF) {
6014 if (p == line)
6015 return NULL;
6016 break;
6017 }
6018 *p++ = c;
6019 if (c == '\n')
6020 break;
6021 }
6022 *p = '\0';
6023 return line;
6024}
6025
6026
Eric Andersenc470f442003-07-28 09:56:35 +00006027
6028#ifdef CONFIG_FEATURE_COMMAND_EDITING
6029static const char *cmdedit_prompt;
6030static inline void putprompt(const char *s)
6031{
6032 cmdedit_prompt = s;
6033}
6034#else
6035static inline void putprompt(const char *s)
6036{
6037 out2str(s);
6038}
6039#endif
6040
6041static inline int
6042preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006043{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006044 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006045 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006046 parsenextc = buf;
6047
Eric Andersenc470f442003-07-28 09:56:35 +00006048retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006049#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006050 if (!iflag || parsefile->fd)
6051 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6052 else {
Eric Andersenfa06a772004-02-06 10:33:19 +00006053 cmdedit_path_lookup = pathval();
Eric Andersenc470f442003-07-28 09:56:35 +00006054 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6055 if(nr == 0) {
6056 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006057 if(trap[SIGINT]) {
6058 buf[0] = '\n';
6059 buf[1] = 0;
6060 raise(SIGINT);
6061 return 1;
6062 }
Eric Andersenc470f442003-07-28 09:56:35 +00006063 goto retry;
6064 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006065 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006066 /* Ctrl+D presend */
6067 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006068 }
Eric Andersencb57d552001-06-28 07:25:16 +00006069 }
6070#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006071 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006072#endif
6073
6074 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006075 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6076 int flags = fcntl(0, F_GETFL, 0);
6077 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006078 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006079 if (fcntl(0, F_SETFL, flags) >= 0) {
6080 out2str("sh: turning off NDELAY mode\n");
6081 goto retry;
6082 }
6083 }
6084 }
6085 }
6086 return nr;
6087}
6088
6089/*
6090 * Refill the input buffer and return the next input character:
6091 *
6092 * 1) If a string was pushed back on the input, pop it;
6093 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6094 * from a string so we can't refill the buffer, return EOF.
6095 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6096 * 4) Process input up to the next newline, deleting nul characters.
6097 */
6098
Eric Andersenc470f442003-07-28 09:56:35 +00006099int
6100preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006101{
6102 char *p, *q;
6103 int more;
6104 char savec;
6105
6106 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006107#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006108 if (parsenleft == -1 && parsefile->strpush->ap &&
6109 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006110 return PEOA;
6111 }
Eric Andersen2870d962001-07-02 17:27:21 +00006112#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006113 popstring();
6114 if (--parsenleft >= 0)
6115 return (*parsenextc++);
6116 }
6117 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6118 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006119 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006120
Eric Andersenc470f442003-07-28 09:56:35 +00006121again:
Eric Andersencb57d552001-06-28 07:25:16 +00006122 if (parselleft <= 0) {
6123 if ((parselleft = preadfd()) <= 0) {
6124 parselleft = parsenleft = EOF_NLEFT;
6125 return PEOF;
6126 }
6127 }
6128
6129 q = p = parsenextc;
6130
6131 /* delete nul characters */
6132 for (more = 1; more;) {
6133 switch (*p) {
6134 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006135 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006136 goto check;
6137
Eric Andersencb57d552001-06-28 07:25:16 +00006138 case '\n':
6139 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006140 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006141 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006142
Eric Andersencb57d552001-06-28 07:25:16 +00006143 }
6144
6145 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006146check:
Eric Andersencb57d552001-06-28 07:25:16 +00006147 if (--parselleft <= 0 && more) {
6148 parsenleft = q - parsenextc - 1;
6149 if (parsenleft < 0)
6150 goto again;
6151 more = 0;
6152 }
6153 }
6154
6155 savec = *q;
6156 *q = '\0';
6157
6158 if (vflag) {
6159 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006160 }
6161
6162 *q = savec;
6163
6164 return *parsenextc++;
6165}
6166
Eric Andersenc470f442003-07-28 09:56:35 +00006167/*
6168 * Undo the last call to pgetc. Only one character may be pushed back.
6169 * PEOF may be pushed back.
6170 */
6171
6172void
6173pungetc(void)
6174{
6175 parsenleft++;
6176 parsenextc--;
6177}
Eric Andersencb57d552001-06-28 07:25:16 +00006178
6179/*
6180 * Push a string back onto the input at this current parsefile level.
6181 * We handle aliases this way.
6182 */
Eric Andersenc470f442003-07-28 09:56:35 +00006183void
6184pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006185{
Eric Andersencb57d552001-06-28 07:25:16 +00006186 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006187 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006188
Eric Andersenc470f442003-07-28 09:56:35 +00006189 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006190 INTOFF;
6191/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6192 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006193 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006194 sp->prev = parsefile->strpush;
6195 parsefile->strpush = sp;
6196 } else
6197 sp = parsefile->strpush = &(parsefile->basestrpush);
6198 sp->prevstring = parsenextc;
6199 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006200#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006201 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006202 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006203 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006204 sp->string = s;
6205 }
Eric Andersen2870d962001-07-02 17:27:21 +00006206#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006207 parsenextc = s;
6208 parsenleft = len;
6209 INTON;
6210}
6211
Eric Andersenc470f442003-07-28 09:56:35 +00006212void
6213popstring(void)
6214{
6215 struct strpush *sp = parsefile->strpush;
6216
6217 INTOFF;
6218#ifdef CONFIG_ASH_ALIAS
6219 if (sp->ap) {
6220 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6221 checkkwd |= CHKALIAS;
6222 }
6223 if (sp->string != sp->ap->val) {
6224 ckfree(sp->string);
6225 }
6226 sp->ap->flag &= ~ALIASINUSE;
6227 if (sp->ap->flag & ALIASDEAD) {
6228 unalias(sp->ap->name);
6229 }
6230 }
6231#endif
6232 parsenextc = sp->prevstring;
6233 parsenleft = sp->prevnleft;
6234/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6235 parsefile->strpush = sp->prev;
6236 if (sp != &(parsefile->basestrpush))
6237 ckfree(sp);
6238 INTON;
6239}
6240
6241/*
6242 * Set the input to take input from a file. If push is set, push the
6243 * old input onto the stack first.
6244 */
6245
6246void
6247setinputfile(const char *fname, int push)
6248{
6249 int fd;
6250 int fd2;
6251
6252 INTOFF;
6253 if ((fd = open(fname, O_RDONLY)) < 0)
6254 error("Can't open %s", fname);
6255 if (fd < 10) {
6256 fd2 = copyfd(fd, 10);
6257 close(fd);
6258 if (fd2 < 0)
6259 error("Out of file descriptors");
6260 fd = fd2;
6261 }
6262 setinputfd(fd, push);
6263 INTON;
6264}
6265
6266
6267/*
6268 * Like setinputfile, but takes an open file descriptor. Call this with
6269 * interrupts off.
6270 */
6271
6272static void
6273setinputfd(int fd, int push)
6274{
6275 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6276 if (push) {
6277 pushfile();
6278 parsefile->buf = 0;
6279 }
6280 parsefile->fd = fd;
6281 if (parsefile->buf == NULL)
6282 parsefile->buf = ckmalloc(IBUFSIZ);
6283 parselleft = parsenleft = 0;
6284 plinno = 1;
6285}
6286
Eric Andersencb57d552001-06-28 07:25:16 +00006287
Eric Andersencb57d552001-06-28 07:25:16 +00006288/*
6289 * Like setinputfile, but takes input from a string.
6290 */
6291
Eric Andersenc470f442003-07-28 09:56:35 +00006292static void
6293setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006294{
Eric Andersencb57d552001-06-28 07:25:16 +00006295 INTOFF;
6296 pushfile();
6297 parsenextc = string;
6298 parsenleft = strlen(string);
6299 parsefile->buf = NULL;
6300 plinno = 1;
6301 INTON;
6302}
6303
6304
Eric Andersencb57d552001-06-28 07:25:16 +00006305/*
6306 * To handle the "." command, a stack of input files is used. Pushfile
6307 * adds a new entry to the stack and popfile restores the previous level.
6308 */
6309
Eric Andersenc470f442003-07-28 09:56:35 +00006310static void
6311pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006312{
Eric Andersencb57d552001-06-28 07:25:16 +00006313 struct parsefile *pf;
6314
6315 parsefile->nleft = parsenleft;
6316 parsefile->lleft = parselleft;
6317 parsefile->nextc = parsenextc;
6318 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006319 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006320 pf->prev = parsefile;
6321 pf->fd = -1;
6322 pf->strpush = NULL;
6323 pf->basestrpush.prev = NULL;
6324 parsefile = pf;
6325}
6326
Eric Andersenc470f442003-07-28 09:56:35 +00006327
6328static void
6329popfile(void)
6330{
6331 struct parsefile *pf = parsefile;
6332
6333 INTOFF;
6334 if (pf->fd >= 0)
6335 close(pf->fd);
6336 if (pf->buf)
6337 ckfree(pf->buf);
6338 while (pf->strpush)
6339 popstring();
6340 parsefile = pf->prev;
6341 ckfree(pf);
6342 parsenleft = parsefile->nleft;
6343 parselleft = parsefile->lleft;
6344 parsenextc = parsefile->nextc;
6345 plinno = parsefile->linno;
6346 INTON;
6347}
Eric Andersencb57d552001-06-28 07:25:16 +00006348
6349
Eric Andersen2870d962001-07-02 17:27:21 +00006350/*
Eric Andersenc470f442003-07-28 09:56:35 +00006351 * Return to top level.
6352 */
Eric Andersen2870d962001-07-02 17:27:21 +00006353
Eric Andersenc470f442003-07-28 09:56:35 +00006354static void
6355popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006356{
Eric Andersenc470f442003-07-28 09:56:35 +00006357 while (parsefile != &basepf)
6358 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006359}
6360
Eric Andersen2870d962001-07-02 17:27:21 +00006361
Eric Andersenc470f442003-07-28 09:56:35 +00006362/*
6363 * Close the file(s) that the shell is reading commands from. Called
6364 * after a fork is done.
6365 */
6366
6367static void
6368closescript(void)
6369{
6370 popallfiles();
6371 if (parsefile->fd > 0) {
6372 close(parsefile->fd);
6373 parsefile->fd = 0;
6374 }
6375}
Eric Andersenc470f442003-07-28 09:56:35 +00006376
Eric Andersen90898442003-08-06 11:20:52 +00006377/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006378
6379/* mode flags for set_curjob */
6380#define CUR_DELETE 2
6381#define CUR_RUNNING 1
6382#define CUR_STOPPED 0
6383
6384/* mode flags for dowait */
6385#define DOWAIT_NORMAL 0
6386#define DOWAIT_BLOCK 1
6387
6388/* array of jobs */
6389static struct job *jobtab;
6390/* size of array */
6391static unsigned njobs;
6392#if JOBS
6393/* pgrp of shell on invocation */
6394static int initialpgrp;
6395static int ttyfd = -1;
6396#endif
6397/* current job */
6398static struct job *curjob;
6399/* number of presumed living untracked jobs */
6400static int jobless;
6401
6402static void set_curjob(struct job *, unsigned);
6403#if JOBS
6404static int restartjob(struct job *, int);
6405static void xtcsetpgrp(int, pid_t);
6406static char *commandtext(union node *);
6407static void cmdlist(union node *, int);
6408static void cmdtxt(union node *);
6409static void cmdputs(const char *);
6410static void showpipe(struct job *, FILE *);
6411#endif
6412static int sprint_status(char *, int, int);
6413static void freejob(struct job *);
6414static struct job *getjob(const char *, int);
6415static struct job *growjobtab(void);
6416static void forkchild(struct job *, union node *, int);
6417static void forkparent(struct job *, union node *, int, pid_t);
6418static int dowait(int, struct job *);
6419static int getstatus(struct job *);
6420
6421static void
6422set_curjob(struct job *jp, unsigned mode)
6423{
6424 struct job *jp1;
6425 struct job **jpp, **curp;
6426
6427 /* first remove from list */
6428 jpp = curp = &curjob;
6429 do {
6430 jp1 = *jpp;
6431 if (jp1 == jp)
6432 break;
6433 jpp = &jp1->prev_job;
6434 } while (1);
6435 *jpp = jp1->prev_job;
6436
6437 /* Then re-insert in correct position */
6438 jpp = curp;
6439 switch (mode) {
6440 default:
6441#ifdef DEBUG
6442 abort();
6443#endif
6444 case CUR_DELETE:
6445 /* job being deleted */
6446 break;
6447 case CUR_RUNNING:
6448 /* newly created job or backgrounded job,
6449 put after all stopped jobs. */
6450 do {
6451 jp1 = *jpp;
6452#ifdef JOBS
6453 if (!jp1 || jp1->state != JOBSTOPPED)
6454#endif
6455 break;
6456 jpp = &jp1->prev_job;
6457 } while (1);
6458 /* FALLTHROUGH */
6459#ifdef JOBS
6460 case CUR_STOPPED:
6461#endif
6462 /* newly stopped job - becomes curjob */
6463 jp->prev_job = *jpp;
6464 *jpp = jp;
6465 break;
6466 }
6467}
6468
6469#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006470/*
6471 * Turn job control on and off.
6472 *
6473 * Note: This code assumes that the third arg to ioctl is a character
6474 * pointer, which is true on Berkeley systems but not System V. Since
6475 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006476 *
6477 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006478 */
6479
Eric Andersenc470f442003-07-28 09:56:35 +00006480void
6481setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006482{
Eric Andersenc470f442003-07-28 09:56:35 +00006483 int fd;
6484 int pgrp;
6485
6486 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006487 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006488 if (on) {
6489 int ofd;
6490 ofd = fd = open(_PATH_TTY, O_RDWR);
6491 if (fd < 0) {
6492 fd += 3;
6493 while (!isatty(fd) && --fd >= 0)
6494 ;
6495 }
6496 fd = fcntl(fd, F_DUPFD, 10);
6497 close(ofd);
6498 if (fd < 0)
6499 goto out;
6500 fcntl(fd, F_SETFD, FD_CLOEXEC);
6501 do { /* while we are in the background */
6502 if ((pgrp = tcgetpgrp(fd)) < 0) {
6503out:
6504 sh_warnx("can't access tty; job control turned off");
6505 mflag = on = 0;
6506 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006507 }
Eric Andersenc470f442003-07-28 09:56:35 +00006508 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006509 break;
6510 killpg(0, SIGTTIN);
6511 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006512 initialpgrp = pgrp;
6513
Eric Andersencb57d552001-06-28 07:25:16 +00006514 setsignal(SIGTSTP);
6515 setsignal(SIGTTOU);
6516 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006517 pgrp = rootpid;
6518 setpgid(0, pgrp);
6519 xtcsetpgrp(fd, pgrp);
6520 } else {
6521 /* turning job control off */
6522 fd = ttyfd;
6523 pgrp = initialpgrp;
6524 xtcsetpgrp(fd, pgrp);
6525 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006526 setsignal(SIGTSTP);
6527 setsignal(SIGTTOU);
6528 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006529close:
6530 close(fd);
6531 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006532 }
Eric Andersenc470f442003-07-28 09:56:35 +00006533 ttyfd = fd;
6534 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006535}
Eric Andersencb57d552001-06-28 07:25:16 +00006536
Eric Andersenc470f442003-07-28 09:56:35 +00006537static int
Eric Andersen90898442003-08-06 11:20:52 +00006538killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006539{
6540 int signo = -1;
6541 int list = 0;
6542 int i;
6543 pid_t pid;
6544 struct job *jp;
6545
6546 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006547usage:
6548 error(
6549"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6550"kill -l [exitstatus]"
6551 );
Eric Andersencb57d552001-06-28 07:25:16 +00006552 }
6553
Eric Andersenc470f442003-07-28 09:56:35 +00006554 if (**++argv == '-') {
6555 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006556 if (signo < 0) {
6557 int c;
6558
6559 while ((c = nextopt("ls:")) != '\0')
6560 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006561 default:
6562#ifdef DEBUG
6563 abort();
6564#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006565 case 'l':
6566 list = 1;
6567 break;
6568 case 's':
6569 signo = decode_signal(optionarg, 1);
6570 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006571 error(
6572 "invalid signal number or name: %s",
6573 optionarg
6574 );
Eric Andersencb57d552001-06-28 07:25:16 +00006575 }
Eric Andersen2870d962001-07-02 17:27:21 +00006576 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006577 }
Eric Andersenc470f442003-07-28 09:56:35 +00006578 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006579 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006580 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006581 }
6582
6583 if (!list && signo < 0)
6584 signo = SIGTERM;
6585
Eric Andersenc470f442003-07-28 09:56:35 +00006586 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006587 goto usage;
6588 }
6589
6590 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006591 const char *name;
6592
Eric Andersenc470f442003-07-28 09:56:35 +00006593 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006594 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006595 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006596 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006597 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006598 }
6599 return 0;
6600 }
Eric Andersen34506362001-08-02 05:02:46 +00006601 name = u_signal_names(*argptr, &signo, -1);
6602 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006603 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006604 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006605 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006606 return 0;
6607 }
6608
Eric Andersenc470f442003-07-28 09:56:35 +00006609 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006610 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006611 if (**argv == '%') {
6612 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006613 pid = -jp->ps[0].pid;
6614 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006615 pid = number(*argv);
6616 if (kill(pid, signo) != 0) {
6617 sh_warnx("%m\n");
6618 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006619 }
Eric Andersenc470f442003-07-28 09:56:35 +00006620 } while (*++argv);
6621
6622 return i;
6623}
6624#endif /* JOBS */
6625
6626#if defined(JOBS) || defined(DEBUG)
6627static int
6628jobno(const struct job *jp)
6629{
6630 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006631}
6632#endif
6633
Eric Andersenc470f442003-07-28 09:56:35 +00006634#ifdef JOBS
6635static int
6636fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006637{
Eric Andersenc470f442003-07-28 09:56:35 +00006638 struct job *jp;
6639 FILE *out;
6640 int mode;
6641 int retval;
6642
6643 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6644 nextopt(nullstr);
6645 argv = argptr;
6646 out = stdout;
6647 do {
6648 jp = getjob(*argv, 1);
6649 if (mode == FORK_BG) {
6650 set_curjob(jp, CUR_RUNNING);
6651 fprintf(out, "[%d] ", jobno(jp));
6652 }
6653 outstr(jp->ps->cmd, out);
6654 showpipe(jp, out);
6655 retval = restartjob(jp, mode);
6656 } while (*argv && *++argv);
6657 return retval;
6658}
6659
6660static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6661
6662
6663static int
6664restartjob(struct job *jp, int mode)
6665{
6666 struct procstat *ps;
6667 int i;
6668 int status;
6669 pid_t pgid;
6670
6671 INTOFF;
6672 if (jp->state == JOBDONE)
6673 goto out;
6674 jp->state = JOBRUNNING;
6675 pgid = jp->ps->pid;
6676 if (mode == FORK_FG)
6677 xtcsetpgrp(ttyfd, pgid);
6678 killpg(pgid, SIGCONT);
6679 ps = jp->ps;
6680 i = jp->nprocs;
6681 do {
6682 if (WIFSTOPPED(ps->status)) {
6683 ps->status = -1;
6684 }
6685 } while (ps++, --i);
6686out:
6687 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6688 INTON;
6689 return status;
6690}
6691#endif
6692
6693static int
6694sprint_status(char *s, int status, int sigonly)
6695{
6696 int col;
6697 int st;
6698
6699 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006700 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006701#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006702 if (WIFSTOPPED(status))
6703 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006704 else
Eric Andersenc470f442003-07-28 09:56:35 +00006705#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006706 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006707 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006708 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006709 goto out;
6710#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006711 if (WIFSTOPPED(status))
6712 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006713#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006714 }
6715 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006716 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006717 if (WCOREDUMP(status)) {
6718 col += fmtstr(s + col, 16, " (core dumped)");
6719 }
6720 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006721 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006722 if (st)
6723 col = fmtstr(s, 16, "Done(%d)", st);
6724 else
6725 col = fmtstr(s, 16, "Done");
6726 }
6727
6728out:
6729 return col;
6730}
6731
6732#if JOBS
6733static void
6734showjob(FILE *out, struct job *jp, int mode)
6735{
6736 struct procstat *ps;
6737 struct procstat *psend;
6738 int col;
6739 int indent;
6740 char s[80];
6741
6742 ps = jp->ps;
6743
6744 if (mode & SHOW_PGID) {
6745 /* just output process (group) id of pipeline */
6746 fprintf(out, "%d\n", ps->pid);
6747 return;
6748 }
6749
6750 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6751 indent = col;
6752
6753 if (jp == curjob)
6754 s[col - 2] = '+';
6755 else if (curjob && jp == curjob->prev_job)
6756 s[col - 2] = '-';
6757
6758 if (mode & SHOW_PID)
6759 col += fmtstr(s + col, 16, "%d ", ps->pid);
6760
6761 psend = ps + jp->nprocs;
6762
6763 if (jp->state == JOBRUNNING) {
6764 scopy("Running", s + col);
6765 col += strlen("Running");
6766 } else {
6767 int status = psend[-1].status;
6768#if JOBS
6769 if (jp->state == JOBSTOPPED)
6770 status = jp->stopstatus;
6771#endif
6772 col += sprint_status(s + col, status, 0);
6773 }
6774
6775 goto start;
6776
6777 do {
6778 /* for each process */
6779 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6780
6781start:
Eric Andersen90898442003-08-06 11:20:52 +00006782 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006783 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6784 );
6785 if (!(mode & SHOW_PID)) {
6786 showpipe(jp, out);
6787 break;
6788 }
6789 if (++ps == psend) {
6790 outcslow('\n', out);
6791 break;
6792 }
6793 } while (1);
6794
6795 jp->changed = 0;
6796
6797 if (jp->state == JOBDONE) {
6798 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6799 freejob(jp);
6800 }
6801}
6802
6803
6804static int
6805jobscmd(int argc, char **argv)
6806{
6807 int mode, m;
6808 FILE *out;
6809
6810 mode = 0;
6811 while ((m = nextopt("lp")))
6812 if (m == 'l')
6813 mode = SHOW_PID;
6814 else
6815 mode = SHOW_PGID;
6816
6817 out = stdout;
6818 argv = argptr;
6819 if (*argv)
6820 do
6821 showjob(out, getjob(*argv,0), mode);
6822 while (*++argv);
6823 else
6824 showjobs(out, mode);
6825
Eric Andersencb57d552001-06-28 07:25:16 +00006826 return 0;
6827}
6828
6829
6830/*
6831 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6832 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006833 */
6834
Eric Andersenc470f442003-07-28 09:56:35 +00006835static void
6836showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006837{
Eric Andersencb57d552001-06-28 07:25:16 +00006838 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006839
Eric Andersenc470f442003-07-28 09:56:35 +00006840 TRACE(("showjobs(%x) called\n", mode));
6841
6842 /* If not even one one job changed, there is nothing to do */
6843 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6844 continue;
6845
6846 for (jp = curjob; jp; jp = jp->prev_job) {
6847 if (!(mode & SHOW_CHANGED) || jp->changed)
6848 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006849 }
6850}
Eric Andersenc470f442003-07-28 09:56:35 +00006851#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006852
6853/*
6854 * Mark a job structure as unused.
6855 */
6856
Eric Andersenc470f442003-07-28 09:56:35 +00006857static void
6858freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006859{
Eric Andersenc470f442003-07-28 09:56:35 +00006860 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006861 int i;
6862
6863 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006864 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006865 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006866 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006867 }
6868 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006869 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006870 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006871 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006872 INTON;
6873}
6874
6875
Eric Andersenc470f442003-07-28 09:56:35 +00006876static int
6877waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006878{
6879 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006880 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006881 struct job *jp;
6882
Eric Andersenc470f442003-07-28 09:56:35 +00006883 EXSIGON();
6884
6885 nextopt(nullstr);
6886 retval = 0;
6887
6888 argv = argptr;
6889 if (!*argv) {
6890 /* wait for all jobs */
6891 for (;;) {
6892 jp = curjob;
6893 while (1) {
6894 if (!jp) {
6895 /* no running procs */
6896 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006897 }
Eric Andersenc470f442003-07-28 09:56:35 +00006898 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006899 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006900 jp->waited = 1;
6901 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006902 }
Eric Andersenc470f442003-07-28 09:56:35 +00006903 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006904 }
6905 }
Eric Andersenc470f442003-07-28 09:56:35 +00006906
6907 retval = 127;
6908 do {
6909 if (**argv != '%') {
6910 pid_t pid = number(*argv);
6911 job = curjob;
6912 goto start;
6913 do {
6914 if (job->ps[job->nprocs - 1].pid == pid)
6915 break;
6916 job = job->prev_job;
6917start:
6918 if (!job)
6919 goto repeat;
6920 } while (1);
6921 } else
6922 job = getjob(*argv, 0);
6923 /* loop until process terminated or stopped */
6924 while (job->state == JOBRUNNING)
6925 dowait(DOWAIT_BLOCK, 0);
6926 job->waited = 1;
6927 retval = getstatus(job);
6928repeat:
6929 ;
6930 } while (*++argv);
6931
6932out:
6933 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006934}
6935
6936
Eric Andersencb57d552001-06-28 07:25:16 +00006937/*
6938 * Convert a job name to a job structure.
6939 */
6940
Eric Andersenc470f442003-07-28 09:56:35 +00006941static struct job *
6942getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006943{
Eric Andersencb57d552001-06-28 07:25:16 +00006944 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006945 struct job *found;
6946 const char *err_msg = "No such job: %s";
6947 unsigned num;
6948 int c;
6949 const char *p;
6950 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006951
Eric Andersenc470f442003-07-28 09:56:35 +00006952 jp = curjob;
6953 p = name;
6954 if (!p)
6955 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006956
Eric Andersenc470f442003-07-28 09:56:35 +00006957 if (*p != '%')
6958 goto err;
6959
6960 c = *++p;
6961 if (!c)
6962 goto currentjob;
6963
6964 if (!p[1]) {
6965 if (c == '+' || c == '%') {
6966currentjob:
6967 err_msg = "No current job";
6968 goto check;
6969 } else if (c == '-') {
6970 if (jp)
6971 jp = jp->prev_job;
6972 err_msg = "No previous job";
6973check:
6974 if (!jp)
6975 goto err;
6976 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006977 }
6978 }
Eric Andersenc470f442003-07-28 09:56:35 +00006979
6980 if (is_number(p)) {
6981 num = atoi(p);
6982 if (num < njobs) {
6983 jp = jobtab + num - 1;
6984 if (jp->used)
6985 goto gotit;
6986 goto err;
6987 }
6988 }
6989
6990 match = prefix;
6991 if (*p == '?') {
6992 match = strstr;
6993 p++;
6994 }
6995
6996 found = 0;
6997 while (1) {
6998 if (!jp)
6999 goto err;
7000 if (match(jp->ps[0].cmd, p)) {
7001 if (found)
7002 goto err;
7003 found = jp;
7004 err_msg = "%s: ambiguous";
7005 }
7006 jp = jp->prev_job;
7007 }
7008
7009gotit:
7010#if JOBS
7011 err_msg = "job %s not created under job control";
7012 if (getctl && jp->jobctl == 0)
7013 goto err;
7014#endif
7015 return jp;
7016err:
7017 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007018}
7019
7020
Eric Andersencb57d552001-06-28 07:25:16 +00007021/*
Eric Andersenc470f442003-07-28 09:56:35 +00007022 * Return a new job structure.
7023 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007024 */
7025
Eric Andersenc470f442003-07-28 09:56:35 +00007026static struct job *
7027makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007028{
7029 int i;
7030 struct job *jp;
7031
Eric Andersenc470f442003-07-28 09:56:35 +00007032 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007033 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007034 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007035 break;
7036 }
7037 if (jp->used == 0)
7038 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007039 if (jp->state != JOBDONE || !jp->waited)
7040 continue;
7041#if JOBS
7042 if (jobctl)
7043 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007044#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007045 freejob(jp);
7046 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007047 }
Eric Andersenc470f442003-07-28 09:56:35 +00007048 memset(jp, 0, sizeof(*jp));
7049#if JOBS
7050 if (jobctl)
7051 jp->jobctl = 1;
7052#endif
7053 jp->prev_job = curjob;
7054 curjob = jp;
7055 jp->used = 1;
7056 jp->ps = &jp->ps0;
7057 if (nprocs > 1) {
7058 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7059 }
7060 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7061 jobno(jp)));
7062 return jp;
7063}
7064
7065static struct job *
7066growjobtab(void)
7067{
7068 size_t len;
7069 ptrdiff_t offset;
7070 struct job *jp, *jq;
7071
7072 len = njobs * sizeof(*jp);
7073 jq = jobtab;
7074 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7075
7076 offset = (char *)jp - (char *)jq;
7077 if (offset) {
7078 /* Relocate pointers */
7079 size_t l = len;
7080
7081 jq = (struct job *)((char *)jq + l);
7082 while (l) {
7083 l -= sizeof(*jp);
7084 jq--;
7085#define joff(p) ((struct job *)((char *)(p) + l))
7086#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007087 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007088 jmove(joff(jp)->ps);
7089 if (joff(jp)->prev_job)
7090 jmove(joff(jp)->prev_job);
7091 }
7092 if (curjob)
7093 jmove(curjob);
7094#undef joff
7095#undef jmove
7096 }
7097
7098 njobs += 4;
7099 jobtab = jp;
7100 jp = (struct job *)((char *)jp + len);
7101 jq = jp + 3;
7102 do {
7103 jq->used = 0;
7104 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007105 return jp;
7106}
7107
7108
7109/*
Eric Andersenc470f442003-07-28 09:56:35 +00007110 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007111 * own process group. Jp is a job structure that the job is to be added to.
7112 * N is the command that will be evaluated by the child. Both jp and n may
7113 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007114 * FORK_FG - Fork off a foreground process.
7115 * FORK_BG - Fork off a background process.
7116 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7117 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007118 *
7119 * When job control is turned off, background processes have their standard
7120 * input redirected to /dev/null (except for the second and later processes
7121 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007122 *
7123 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007124 */
7125
Eric Andersenc470f442003-07-28 09:56:35 +00007126static inline void
7127forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007128{
Eric Andersenc470f442003-07-28 09:56:35 +00007129 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007130
Eric Andersenc470f442003-07-28 09:56:35 +00007131 TRACE(("Child shell %d\n", getpid()));
7132 wasroot = rootshell;
7133 rootshell = 0;
7134
7135 closescript();
7136 clear_traps();
7137#if JOBS
7138 /* do job control only in root shell */
7139 jobctl = 0;
7140 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7141 pid_t pgrp;
7142
7143 if (jp->nprocs == 0)
7144 pgrp = getpid();
7145 else
7146 pgrp = jp->ps[0].pid;
7147 /* This can fail because we are doing it in the parent also */
7148 (void)setpgid(0, pgrp);
7149 if (mode == FORK_FG)
7150 xtcsetpgrp(ttyfd, pgrp);
7151 setsignal(SIGTSTP);
7152 setsignal(SIGTTOU);
7153 } else
Eric Andersen62483552001-07-10 06:09:16 +00007154#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007155 if (mode == FORK_BG) {
7156 ignoresig(SIGINT);
7157 ignoresig(SIGQUIT);
7158 if (jp->nprocs == 0) {
7159 close(0);
7160 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7161 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007162 }
Eric Andersencb57d552001-06-28 07:25:16 +00007163 }
Eric Andersenc470f442003-07-28 09:56:35 +00007164 if (wasroot && iflag) {
7165 setsignal(SIGINT);
7166 setsignal(SIGQUIT);
7167 setsignal(SIGTERM);
7168 }
7169 for (jp = curjob; jp; jp = jp->prev_job)
7170 freejob(jp);
7171 jobless = 0;
7172}
7173
7174static inline void
7175forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7176{
7177 TRACE(("In parent shell: child = %d\n", pid));
7178 if (!jp) {
7179 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7180 jobless++;
7181 return;
7182 }
7183#if JOBS
7184 if (mode != FORK_NOJOB && jp->jobctl) {
7185 int pgrp;
7186
7187 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007188 pgrp = pid;
7189 else
7190 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007191 /* This can fail because we are doing it in the child also */
7192 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007193 }
Eric Andersen62483552001-07-10 06:09:16 +00007194#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007195 if (mode == FORK_BG) {
7196 backgndpid = pid; /* set $! */
7197 set_curjob(jp, CUR_RUNNING);
7198 }
Eric Andersencb57d552001-06-28 07:25:16 +00007199 if (jp) {
7200 struct procstat *ps = &jp->ps[jp->nprocs++];
7201 ps->pid = pid;
7202 ps->status = -1;
7203 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007204#if JOBS
7205 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007206 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007207#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007208 }
Eric Andersencb57d552001-06-28 07:25:16 +00007209}
7210
Eric Andersenc470f442003-07-28 09:56:35 +00007211static int
7212forkshell(struct job *jp, union node *n, int mode)
7213{
7214 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007215
Eric Andersenc470f442003-07-28 09:56:35 +00007216 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7217 pid = fork();
7218 if (pid < 0) {
7219 TRACE(("Fork failed, errno=%d", errno));
7220 if (jp)
7221 freejob(jp);
7222 error("Cannot fork");
7223 }
7224 if (pid == 0)
7225 forkchild(jp, n, mode);
7226 else
7227 forkparent(jp, n, mode, pid);
7228 return pid;
7229}
Eric Andersencb57d552001-06-28 07:25:16 +00007230
7231/*
7232 * Wait for job to finish.
7233 *
7234 * Under job control we have the problem that while a child process is
7235 * running interrupts generated by the user are sent to the child but not
7236 * to the shell. This means that an infinite loop started by an inter-
7237 * active user may be hard to kill. With job control turned off, an
7238 * interactive user may place an interactive program inside a loop. If
7239 * the interactive program catches interrupts, the user doesn't want
7240 * these interrupts to also abort the loop. The approach we take here
7241 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007242 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007243 * signal if the child process was terminated by an interrupt signal.
7244 * Unfortunately, some programs want to do a bit of cleanup and then
7245 * exit on interrupt; unless these processes terminate themselves by
7246 * sending a signal to themselves (instead of calling exit) they will
7247 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007248 *
7249 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007250 */
7251
Eric Andersenc470f442003-07-28 09:56:35 +00007252int
7253waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007254{
Eric Andersencb57d552001-06-28 07:25:16 +00007255 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007256
Eric Andersenc470f442003-07-28 09:56:35 +00007257 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7258 while (jp->state == JOBRUNNING) {
7259 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007260 }
Eric Andersenc470f442003-07-28 09:56:35 +00007261 st = getstatus(jp);
7262#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007263 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007264 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007265 /*
7266 * This is truly gross.
7267 * If we're doing job control, then we did a TIOCSPGRP which
7268 * caused us (the shell) to no longer be in the controlling
7269 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7270 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007271 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007272 */
Eric Andersenc470f442003-07-28 09:56:35 +00007273 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007274 raise(SIGINT);
7275 }
Eric Andersen2870d962001-07-02 17:27:21 +00007276 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007277#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007278 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007279 return st;
7280}
7281
7282
Eric Andersen62483552001-07-10 06:09:16 +00007283/*
7284 * Do a wait system call. If job control is compiled in, we accept
7285 * stopped processes. If block is zero, we return a value of zero
7286 * rather than blocking.
7287 *
7288 * System V doesn't have a non-blocking wait system call. It does
7289 * have a SIGCLD signal that is sent to a process when one of it's
7290 * children dies. The obvious way to use SIGCLD would be to install
7291 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7292 * was received, and have waitproc bump another counter when it got
7293 * the status of a process. Waitproc would then know that a wait
7294 * system call would not block if the two counters were different.
7295 * This approach doesn't work because if a process has children that
7296 * have not been waited for, System V will send it a SIGCLD when it
7297 * installs a signal handler for SIGCLD. What this means is that when
7298 * a child exits, the shell will be sent SIGCLD signals continuously
7299 * until is runs out of stack space, unless it does a wait call before
7300 * restoring the signal handler. The code below takes advantage of
7301 * this (mis)feature by installing a signal handler for SIGCLD and
7302 * then checking to see whether it was called. If there are any
7303 * children to be waited for, it will be.
7304 *
Eric Andersenc470f442003-07-28 09:56:35 +00007305 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7306 * waits at all. In this case, the user will not be informed when
7307 * a background process until the next time she runs a real program
7308 * (as opposed to running a builtin command or just typing return),
7309 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007310 */
7311
Eric Andersenc470f442003-07-28 09:56:35 +00007312static inline int
7313waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007314{
Eric Andersenc470f442003-07-28 09:56:35 +00007315 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007316
Eric Andersenc470f442003-07-28 09:56:35 +00007317#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007318 if (jobctl)
7319 flags |= WUNTRACED;
7320#endif
7321 if (block == 0)
7322 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007323 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007324}
7325
Eric Andersenc470f442003-07-28 09:56:35 +00007326/*
7327 * Wait for a process to terminate.
7328 */
7329
7330static int
7331dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007332{
7333 int pid;
7334 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007335 struct job *jp;
7336 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007337 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007338
7339 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007340 pid = waitproc(block, &status);
7341 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007342 if (pid <= 0)
7343 return pid;
7344 INTOFF;
7345 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007346 for (jp = curjob; jp; jp = jp->prev_job) {
7347 struct procstat *sp;
7348 struct procstat *spend;
7349 if (jp->state == JOBDONE)
7350 continue;
7351 state = JOBDONE;
7352 spend = jp->ps + jp->nprocs;
7353 sp = jp->ps;
7354 do {
7355 if (sp->pid == pid) {
7356 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7357 sp->status = status;
7358 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007359 }
Eric Andersenc470f442003-07-28 09:56:35 +00007360 if (sp->status == -1)
7361 state = JOBRUNNING;
7362#ifdef JOBS
7363 if (state == JOBRUNNING)
7364 continue;
7365 if (WIFSTOPPED(sp->status)) {
7366 jp->stopstatus = sp->status;
7367 state = JOBSTOPPED;
7368 }
Eric Andersencb57d552001-06-28 07:25:16 +00007369#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007370 } while (++sp < spend);
7371 if (thisjob)
7372 goto gotjob;
7373 }
7374#ifdef JOBS
7375 if (!WIFSTOPPED(status))
7376#endif
7377
7378 jobless--;
7379 goto out;
7380
7381gotjob:
7382 if (state != JOBRUNNING) {
7383 thisjob->changed = 1;
7384
7385 if (thisjob->state != state) {
7386 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7387 thisjob->state = state;
7388#ifdef JOBS
7389 if (state == JOBSTOPPED) {
7390 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007391 }
Eric Andersenc470f442003-07-28 09:56:35 +00007392#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007393 }
7394 }
Eric Andersencb57d552001-06-28 07:25:16 +00007395
Eric Andersenc470f442003-07-28 09:56:35 +00007396out:
7397 INTON;
7398
7399 if (thisjob && thisjob == job) {
7400 char s[48 + 1];
7401 int len;
7402
7403 len = sprint_status(s, status, 1);
7404 if (len) {
7405 s[len] = '\n';
7406 s[len + 1] = 0;
7407 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007408 }
Eric Andersencb57d552001-06-28 07:25:16 +00007409 }
7410 return pid;
7411}
7412
7413
Eric Andersencb57d552001-06-28 07:25:16 +00007414/*
7415 * return 1 if there are stopped jobs, otherwise 0
7416 */
Eric Andersen90898442003-08-06 11:20:52 +00007417
Eric Andersenc470f442003-07-28 09:56:35 +00007418int
7419stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007420{
Eric Andersencb57d552001-06-28 07:25:16 +00007421 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007422 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007423
Eric Andersenc470f442003-07-28 09:56:35 +00007424 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007425 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007426 goto out;
7427 jp = curjob;
7428 if (jp && jp->state == JOBSTOPPED) {
7429 out2str("You have stopped jobs.\n");
7430 job_warning = 2;
7431 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007432 }
7433
Eric Andersenc470f442003-07-28 09:56:35 +00007434out:
7435 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007436}
7437
7438/*
7439 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007440 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007441 */
7442
Eric Andersenc470f442003-07-28 09:56:35 +00007443#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007444static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007445
Eric Andersenc470f442003-07-28 09:56:35 +00007446static char *
7447commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007448{
Eric Andersenc470f442003-07-28 09:56:35 +00007449 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007450
Eric Andersenc470f442003-07-28 09:56:35 +00007451 STARTSTACKSTR(cmdnextc);
7452 cmdtxt(n);
7453 name = stackblock();
7454 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7455 name, cmdnextc, cmdnextc));
7456 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007457}
7458
Eric Andersenc470f442003-07-28 09:56:35 +00007459static void
7460cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007461{
Eric Andersencb57d552001-06-28 07:25:16 +00007462 union node *np;
7463 struct nodelist *lp;
7464 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007465 char s[2];
7466
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007467 if (!n)
7468 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007469 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007470 default:
7471#if DEBUG
7472 abort();
7473#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007474 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007475 lp = n->npipe.cmdlist;
7476 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007477 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007478 lp = lp->next;
7479 if (!lp)
7480 break;
7481 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007482 }
7483 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007484 case NSEMI:
7485 p = "; ";
7486 goto binop;
7487 case NAND:
7488 p = " && ";
7489 goto binop;
7490 case NOR:
7491 p = " || ";
7492binop:
7493 cmdtxt(n->nbinary.ch1);
7494 cmdputs(p);
7495 n = n->nbinary.ch2;
7496 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007497 case NREDIR:
7498 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007499 n = n->nredir.n;
7500 goto donode;
7501 case NNOT:
7502 cmdputs("!");
7503 n = n->nnot.com;
7504donode:
7505 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007506 break;
7507 case NIF:
7508 cmdputs("if ");
7509 cmdtxt(n->nif.test);
7510 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007511 n = n->nif.ifpart;
7512 if (n->nif.elsepart) {
7513 cmdtxt(n);
7514 cmdputs("; else ");
7515 n = n->nif.elsepart;
7516 }
7517 p = "; fi";
7518 goto dotail;
7519 case NSUBSHELL:
7520 cmdputs("(");
7521 n = n->nredir.n;
7522 p = ")";
7523 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007524 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007525 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007526 goto until;
7527 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007528 p = "until ";
7529until:
7530 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007531 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007532 n = n->nbinary.ch2;
7533 p = "; done";
7534dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007535 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007536dotail:
7537 cmdtxt(n);
7538 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007539 case NFOR:
7540 cmdputs("for ");
7541 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007542 cmdputs(" in ");
7543 cmdlist(n->nfor.args, 1);
7544 n = n->nfor.body;
7545 p = "; done";
7546 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007547 case NDEFUN:
7548 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007549 p = "() { ... }";
7550 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007551 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007552 cmdlist(n->ncmd.args, 1);
7553 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007554 break;
7555 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007556 p = n->narg.text;
7557dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007558 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007559 break;
7560 case NHERE:
7561 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007562 p = "<<...";
7563 goto dotail2;
7564 case NCASE:
7565 cmdputs("case ");
7566 cmdputs(n->ncase.expr->narg.text);
7567 cmdputs(" in ");
7568 for (np = n->ncase.cases; np; np = np->nclist.next) {
7569 cmdtxt(np->nclist.pattern);
7570 cmdputs(") ");
7571 cmdtxt(np->nclist.body);
7572 cmdputs(";; ");
7573 }
7574 p = "esac";
7575 goto dotail2;
7576 case NTO:
7577 p = ">";
7578 goto redir;
7579 case NCLOBBER:
7580 p = ">|";
7581 goto redir;
7582 case NAPPEND:
7583 p = ">>";
7584 goto redir;
7585 case NTOFD:
7586 p = ">&";
7587 goto redir;
7588 case NFROM:
7589 p = "<";
7590 goto redir;
7591 case NFROMFD:
7592 p = "<&";
7593 goto redir;
7594 case NFROMTO:
7595 p = "<>";
7596redir:
7597 s[0] = n->nfile.fd + '0';
7598 s[1] = '\0';
7599 cmdputs(s);
7600 cmdputs(p);
7601 if (n->type == NTOFD || n->type == NFROMFD) {
7602 s[0] = n->ndup.dupfd + '0';
7603 p = s;
7604 goto dotail2;
7605 } else {
7606 n = n->nfile.fname;
7607 goto donode;
7608 }
Eric Andersencb57d552001-06-28 07:25:16 +00007609 }
7610}
Eric Andersencb57d552001-06-28 07:25:16 +00007611
Eric Andersenc470f442003-07-28 09:56:35 +00007612static void
7613cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007614{
Eric Andersenc470f442003-07-28 09:56:35 +00007615 for (; np; np = np->narg.next) {
7616 if (!sep)
7617 cmdputs(spcstr);
7618 cmdtxt(np);
7619 if (sep && np->narg.next)
7620 cmdputs(spcstr);
7621 }
Eric Andersencb57d552001-06-28 07:25:16 +00007622}
7623
Eric Andersenc470f442003-07-28 09:56:35 +00007624static void
7625cmdputs(const char *s)
7626{
7627 const char *p, *str;
7628 char c, cc[2] = " ";
7629 char *nextc;
7630 int subtype = 0;
7631 int quoted = 0;
7632 static const char *const vstype[16] = {
7633 nullstr, "}", "-", "+", "?", "=",
Eric Andersenc7bda1c2004-03-15 08:29:22 +00007634 "%", "%%", "#", "##", nullstr
Eric Andersenc470f442003-07-28 09:56:35 +00007635 };
7636
7637 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7638 p = s;
7639 while ((c = *p++) != 0) {
7640 str = 0;
7641 switch (c) {
7642 case CTLESC:
7643 c = *p++;
7644 break;
7645 case CTLVAR:
7646 subtype = *p++;
7647 if ((subtype & VSTYPE) == VSLENGTH)
7648 str = "${#";
7649 else
7650 str = "${";
7651 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7652 quoted ^= 1;
7653 c = '"';
7654 } else
7655 goto dostr;
7656 break;
7657 case CTLENDVAR:
7658 quoted >>= 1;
7659 subtype = 0;
7660 if (quoted & 1) {
7661 str = "\"}";
7662 goto dostr;
7663 }
7664 c = '}';
7665 break;
7666 case CTLBACKQ:
7667 str = "$(...)";
7668 goto dostr;
7669 case CTLBACKQ+CTLQUOTE:
7670 str = "\"$(...)\"";
7671 goto dostr;
7672#ifdef CONFIG_ASH_MATH_SUPPORT
7673 case CTLARI:
7674 str = "$((";
7675 goto dostr;
7676 case CTLENDARI:
7677 str = "))";
7678 goto dostr;
7679#endif
7680 case CTLQUOTEMARK:
7681 quoted ^= 1;
7682 c = '"';
7683 break;
7684 case '=':
7685 if (subtype == 0)
7686 break;
7687 str = vstype[subtype & VSTYPE];
7688 if (subtype & VSNUL)
7689 c = ':';
7690 else
7691 c = *str++;
7692 if (c != '}')
7693 quoted <<= 1;
7694 break;
7695 case '\'':
7696 case '\\':
7697 case '"':
7698 case '$':
7699 /* These can only happen inside quotes */
7700 cc[0] = c;
7701 str = cc;
7702 c = '\\';
7703 break;
7704 default:
7705 break;
7706 }
7707 USTPUTC(c, nextc);
7708 if (!str)
7709 continue;
7710dostr:
7711 while ((c = *str++)) {
7712 USTPUTC(c, nextc);
7713 }
7714 }
7715 if (quoted & 1) {
7716 USTPUTC('"', nextc);
7717 }
7718 *nextc = 0;
7719 cmdnextc = nextc;
7720}
7721
7722
7723static void
7724showpipe(struct job *jp, FILE *out)
7725{
7726 struct procstat *sp;
7727 struct procstat *spend;
7728
7729 spend = jp->ps + jp->nprocs;
7730 for (sp = jp->ps + 1; sp < spend; sp++)
7731 fprintf(out, " | %s", sp->cmd);
7732 outcslow('\n', out);
7733 flushall();
7734}
7735
7736static void
7737xtcsetpgrp(int fd, pid_t pgrp)
7738{
7739 if (tcsetpgrp(fd, pgrp))
7740 error("Cannot set tty process group (%m)");
7741}
7742#endif /* JOBS */
7743
7744static int
7745getstatus(struct job *job) {
7746 int status;
7747 int retval;
7748
7749 status = job->ps[job->nprocs - 1].status;
7750 retval = WEXITSTATUS(status);
7751 if (!WIFEXITED(status)) {
7752#if JOBS
7753 retval = WSTOPSIG(status);
7754 if (!WIFSTOPPED(status))
7755#endif
7756 {
7757 /* XXX: limits number of signals */
7758 retval = WTERMSIG(status);
7759#if JOBS
7760 if (retval == SIGINT)
7761 job->sigint = 1;
7762#endif
7763 }
7764 retval += 128;
7765 }
7766 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7767 jobno(job), job->nprocs, status, retval));
7768 return retval;
7769}
7770
Eric Andersend35c5df2002-01-09 15:37:36 +00007771#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007772/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007773
Eric Andersencb57d552001-06-28 07:25:16 +00007774/*
Eric Andersenc470f442003-07-28 09:56:35 +00007775 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007776 */
7777
Eric Andersencb57d552001-06-28 07:25:16 +00007778#define MAXMBOXES 10
7779
Eric Andersenc470f442003-07-28 09:56:35 +00007780/* times of mailboxes */
7781static time_t mailtime[MAXMBOXES];
7782/* Set if MAIL or MAILPATH is changed. */
7783static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007784
7785
7786
7787/*
Eric Andersenc470f442003-07-28 09:56:35 +00007788 * Print appropriate message(s) if mail has arrived.
7789 * If mail_var_path_changed is set,
7790 * then the value of MAIL has mail_var_path_changed,
7791 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007792 */
7793
Eric Andersenc470f442003-07-28 09:56:35 +00007794static void
7795chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007796{
Eric Andersencb57d552001-06-28 07:25:16 +00007797 const char *mpath;
7798 char *p;
7799 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007800 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007801 struct stackmark smark;
7802 struct stat statb;
7803
Eric Andersencb57d552001-06-28 07:25:16 +00007804 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007805 mpath = mpathset() ? mpathval() : mailval();
7806 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007807 p = padvance(&mpath, nullstr);
7808 if (p == NULL)
7809 break;
7810 if (*p == '\0')
7811 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007812 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007813#ifdef DEBUG
7814 if (q[-1] != '/')
7815 abort();
7816#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007817 q[-1] = '\0'; /* delete trailing '/' */
7818 if (stat(p, &statb) < 0) {
7819 *mtp = 0;
7820 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007821 }
Eric Andersenc470f442003-07-28 09:56:35 +00007822 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7823 fprintf(
7824 stderr, snlfmt,
7825 pathopt ? pathopt : "you have mail"
7826 );
7827 }
7828 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007829 }
Eric Andersenc470f442003-07-28 09:56:35 +00007830 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007831 popstackmark(&smark);
7832}
Eric Andersencb57d552001-06-28 07:25:16 +00007833
Eric Andersenec074692001-10-31 11:05:49 +00007834
Eric Andersenc470f442003-07-28 09:56:35 +00007835static void
7836changemail(const char *val)
7837{
7838 mail_var_path_changed++;
7839}
7840
7841#endif /* CONFIG_ASH_MAIL */
7842
7843/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7844
Eric Andersencb57d552001-06-28 07:25:16 +00007845
Eric Andersencb57d552001-06-28 07:25:16 +00007846#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007847static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007848extern int etext();
7849#endif
7850
Eric Andersenc470f442003-07-28 09:56:35 +00007851static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007852
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007853static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007854
Eric Andersencb57d552001-06-28 07:25:16 +00007855/*
7856 * Main routine. We initialize things, parse the arguments, execute
7857 * profiles if we're a login shell, and then call cmdloop to execute
7858 * commands. The setjmp call sets up the location to jump to when an
7859 * exception occurs. When an exception occurs the variable "state"
7860 * is used to figure out how far we had gotten.
7861 */
7862
Eric Andersenc470f442003-07-28 09:56:35 +00007863int
7864ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007865{
Eric Andersenc470f442003-07-28 09:56:35 +00007866 char *shinit;
7867 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007868 struct jmploc jmploc;
7869 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007870
Eric Andersenc470f442003-07-28 09:56:35 +00007871#ifdef __GLIBC__
7872 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007873#endif
7874
Eric Andersencb57d552001-06-28 07:25:16 +00007875#if PROFILE
7876 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7877#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007878 state = 0;
7879 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007880 int status;
7881 int e;
7882
Eric Andersencb57d552001-06-28 07:25:16 +00007883 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007884
7885 e = exception;
7886 switch (exception) {
7887 case EXEXEC:
7888 status = exerrno;
7889 break;
7890
7891 case EXERROR:
7892 status = 2;
7893 break;
7894
7895 default:
7896 status = exitstatus;
7897 break;
7898 }
7899 exitstatus = status;
7900
7901 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7902 exitshell();
7903
Eric Andersen90898442003-08-06 11:20:52 +00007904 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007905 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007906 }
7907 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007908 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007909 if (state == 1)
7910 goto state1;
7911 else if (state == 2)
7912 goto state2;
7913 else if (state == 3)
7914 goto state3;
7915 else
7916 goto state4;
7917 }
7918 handler = &jmploc;
7919#ifdef DEBUG
7920 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007921 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007922#endif
7923 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007924
7925#ifdef CONFIG_ASH_RANDOM_SUPPORT
7926 rseed = rootpid + ((time_t)time((time_t *)0));
7927#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007928 rootshell = 1;
7929 init();
7930 setstackmark(&smark);
7931 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007932#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7933 if ( iflag ) {
7934 const char *hp = lookupvar("HISTFILE");
7935
7936 if(hp == NULL ) {
7937 hp = lookupvar("HOME");
7938 if(hp != NULL) {
7939 char *defhp = concat_path_file(hp, ".ash_history");
7940 setvar("HISTFILE", defhp, 0);
7941 free(defhp);
7942 }
7943 }
7944 }
7945#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007946 if (argv[0] && argv[0][0] == '-')
7947 isloginsh = 1;
7948 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007949 state = 1;
7950 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007951state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007952 state = 2;
7953 read_profile(".profile");
7954 }
Eric Andersenc470f442003-07-28 09:56:35 +00007955state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007956 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007957 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007958#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007959 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007960#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007961 iflag
7962 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007963 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007964 read_profile(shinit);
7965 }
Eric Andersencb57d552001-06-28 07:25:16 +00007966 }
Eric Andersenc470f442003-07-28 09:56:35 +00007967state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007968 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007969 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007970 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007971
7972 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007973#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007974 if ( iflag ) {
7975 const char *hp = lookupvar("HISTFILE");
7976
7977 if(hp != NULL )
7978 load_history ( hp );
7979 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007980#endif
Eric Andersen90898442003-08-06 11:20:52 +00007981state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007982 cmdloop(1);
7983 }
7984#if PROFILE
7985 monitor(0);
7986#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007987#if GPROF
7988 {
7989 extern void _mcleanup(void);
7990 _mcleanup();
7991 }
7992#endif
7993 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007994 /* NOTREACHED */
7995}
7996
7997
7998/*
7999 * Read and execute commands. "Top" is nonzero for the top level command
8000 * loop; it turns on prompting if the shell is interactive.
8001 */
8002
Eric Andersenc470f442003-07-28 09:56:35 +00008003static void
8004cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008005{
8006 union node *n;
8007 struct stackmark smark;
8008 int inter;
8009 int numeof = 0;
8010
8011 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008012 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00008013 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00008014 if (pendingsigs)
8015 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00008016#if JOBS
8017 if (jobctl)
8018 showjobs(stderr, SHOW_CHANGED);
8019#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008020 inter = 0;
8021 if (iflag && top) {
8022 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008023#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008024 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008025#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008026 }
8027 n = parsecmd(inter);
8028 /* showtree(n); DEBUG */
8029 if (n == NEOF) {
8030 if (!top || numeof >= 50)
8031 break;
8032 if (!stoppedjobs()) {
8033 if (!Iflag)
8034 break;
8035 out2str("\nUse \"exit\" to leave shell.\n");
8036 }
8037 numeof++;
8038 } else if (n != NULL && nflag == 0) {
8039 job_warning = (job_warning == 2) ? 1 : 0;
8040 numeof = 0;
8041 evaltree(n, 0);
8042 }
8043 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008044 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008045 evalskip = 0;
8046 break;
8047 }
8048 }
Eric Andersencb57d552001-06-28 07:25:16 +00008049}
8050
8051
Eric Andersencb57d552001-06-28 07:25:16 +00008052/*
8053 * Read /etc/profile or .profile. Return on error.
8054 */
8055
Eric Andersenc470f442003-07-28 09:56:35 +00008056static void
8057read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008058{
8059 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008060 int xflag_set = 0;
8061 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008062
8063 INTOFF;
8064 if ((fd = open(name, O_RDONLY)) >= 0)
8065 setinputfd(fd, 1);
8066 INTON;
8067 if (fd < 0)
8068 return;
8069 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008070 if (qflag) {
8071 if (xflag)
8072 xflag = 0, xflag_set = 1;
8073 if (vflag)
8074 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008075 }
8076 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008077 if (qflag) {
8078 if (xflag_set)
8079 xflag = 1;
8080 if (vflag_set)
8081 vflag = 1;
8082 }
Eric Andersencb57d552001-06-28 07:25:16 +00008083 popfile();
8084}
8085
8086
Eric Andersencb57d552001-06-28 07:25:16 +00008087/*
8088 * Read a file containing shell functions.
8089 */
8090
Eric Andersenc470f442003-07-28 09:56:35 +00008091static void
8092readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008093{
8094 int fd;
8095
8096 INTOFF;
8097 if ((fd = open(name, O_RDONLY)) >= 0)
8098 setinputfd(fd, 1);
8099 else
8100 error("Can't open %s", name);
8101 INTON;
8102 cmdloop(0);
8103 popfile();
8104}
8105
8106
Eric Andersencb57d552001-06-28 07:25:16 +00008107/*
Eric Andersenc470f442003-07-28 09:56:35 +00008108 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008109 * search for the file, which is necessary to find sub-commands.
8110 */
8111
Eric Andersenc470f442003-07-28 09:56:35 +00008112static inline char *
8113find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008114{
8115 char *fullname;
8116 const char *path = pathval();
8117 struct stat statb;
8118
8119 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008120 if (strchr(name, '/'))
8121 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008122
Eric Andersenc470f442003-07-28 09:56:35 +00008123 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008124 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8125 /*
8126 * Don't bother freeing here, since it will
8127 * be freed by the caller.
8128 */
8129 return fullname;
8130 }
8131 stunalloc(fullname);
8132 }
8133
8134 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008135 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008136 /* NOTREACHED */
8137}
8138
Eric Andersen1e6aba92004-04-12 19:12:13 +00008139static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008140{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008141 struct strlist *sp;
8142 volatile struct shparam saveparam;
8143
Eric Andersencb57d552001-06-28 07:25:16 +00008144 exitstatus = 0;
8145
Eric Andersen1e6aba92004-04-12 19:12:13 +00008146 for (sp = cmdenviron; sp; sp = sp->next)
8147 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8148
8149 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008150 char *fullname;
8151 struct stackmark smark;
8152
8153 setstackmark(&smark);
8154 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008155
8156 if (argc > 2) {
8157 saveparam = shellparam;
8158 shellparam.malloc = 0;
8159 shellparam.nparam = argc - 2;
8160 shellparam.p = argv + 2;
8161 };
8162
Eric Andersencb57d552001-06-28 07:25:16 +00008163 setinputfile(fullname, 1);
8164 commandname = fullname;
8165 cmdloop(0);
8166 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008167
8168 if (argc > 2) {
8169 freeparam(&shellparam);
8170 shellparam = saveparam;
8171 };
8172
Eric Andersencb57d552001-06-28 07:25:16 +00008173 popstackmark(&smark);
8174 }
8175 return exitstatus;
8176}
8177
8178
Eric Andersenc470f442003-07-28 09:56:35 +00008179static int
8180exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008181{
8182 if (stoppedjobs())
8183 return 0;
8184 if (argc > 1)
8185 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008186 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008187 /* NOTREACHED */
8188}
Eric Andersen62483552001-07-10 06:09:16 +00008189
Eric Andersenc470f442003-07-28 09:56:35 +00008190/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8191
8192/*
Eric Andersen90898442003-08-06 11:20:52 +00008193 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008194 */
8195
8196static pointer
8197ckrealloc(pointer p, size_t nbytes)
8198{
8199 p = realloc(p, nbytes);
8200 if (p == NULL)
8201 error(bb_msg_memory_exhausted);
8202 return p;
8203}
8204
Eric Andersen90898442003-08-06 11:20:52 +00008205static pointer
8206ckmalloc(size_t nbytes)
8207{
8208 return ckrealloc(NULL, nbytes);
8209}
Eric Andersenc470f442003-07-28 09:56:35 +00008210
8211/*
8212 * Make a copy of a string in safe storage.
8213 */
8214
8215static char *
8216savestr(const char *s)
8217{
8218 char *p = strdup(s);
8219 if (!p)
8220 error(bb_msg_memory_exhausted);
8221 return p;
8222}
8223
8224
8225/*
8226 * Parse trees for commands are allocated in lifo order, so we use a stack
8227 * to make this more efficient, and also to avoid all sorts of exception
8228 * handling code to handle interrupts in the middle of a parse.
8229 *
8230 * The size 504 was chosen because the Ultrix malloc handles that size
8231 * well.
8232 */
8233
8234
8235static pointer
8236stalloc(size_t nbytes)
8237{
8238 char *p;
8239 size_t aligned;
8240
8241 aligned = SHELL_ALIGN(nbytes);
8242 if (aligned > stacknleft) {
8243 size_t len;
8244 size_t blocksize;
8245 struct stack_block *sp;
8246
8247 blocksize = aligned;
8248 if (blocksize < MINSIZE)
8249 blocksize = MINSIZE;
8250 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8251 if (len < blocksize)
8252 error(bb_msg_memory_exhausted);
8253 INTOFF;
8254 sp = ckmalloc(len);
8255 sp->prev = stackp;
8256 stacknxt = sp->space;
8257 stacknleft = blocksize;
8258 sstrend = stacknxt + blocksize;
8259 stackp = sp;
8260 INTON;
8261 }
8262 p = stacknxt;
8263 stacknxt += aligned;
8264 stacknleft -= aligned;
8265 return p;
8266}
8267
8268
8269void
8270stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008271{
Eric Andersencb57d552001-06-28 07:25:16 +00008272#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008273 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008274 write(2, "stunalloc\n", 10);
8275 abort();
8276 }
8277#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008278 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008279 stacknxt = p;
8280}
8281
8282
Eric Andersenc470f442003-07-28 09:56:35 +00008283void
8284setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008285{
Eric Andersencb57d552001-06-28 07:25:16 +00008286 mark->stackp = stackp;
8287 mark->stacknxt = stacknxt;
8288 mark->stacknleft = stacknleft;
8289 mark->marknext = markp;
8290 markp = mark;
8291}
8292
8293
Eric Andersenc470f442003-07-28 09:56:35 +00008294void
8295popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008296{
Eric Andersencb57d552001-06-28 07:25:16 +00008297 struct stack_block *sp;
8298
8299 INTOFF;
8300 markp = mark->marknext;
8301 while (stackp != mark->stackp) {
8302 sp = stackp;
8303 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008304 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008305 }
8306 stacknxt = mark->stacknxt;
8307 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008308 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008309 INTON;
8310}
8311
8312
8313/*
8314 * When the parser reads in a string, it wants to stick the string on the
8315 * stack and only adjust the stack pointer when it knows how big the
8316 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8317 * of space on top of the stack and stackblocklen returns the length of
8318 * this block. Growstackblock will grow this space by at least one byte,
8319 * possibly moving it (like realloc). Grabstackblock actually allocates the
8320 * part of the block that has been used.
8321 */
8322
Eric Andersenc470f442003-07-28 09:56:35 +00008323void
8324growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008325{
Eric Andersenc470f442003-07-28 09:56:35 +00008326 size_t newlen;
8327
8328 newlen = stacknleft * 2;
8329 if (newlen < stacknleft)
8330 error(bb_msg_memory_exhausted);
8331 if (newlen < 128)
8332 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008333
8334 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008335 struct stack_block *oldstackp;
8336 struct stackmark *xmark;
8337 struct stack_block *sp;
8338 struct stack_block *prevstackp;
8339 size_t grosslen;
8340
Eric Andersencb57d552001-06-28 07:25:16 +00008341 INTOFF;
8342 oldstackp = stackp;
8343 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008344 prevstackp = sp->prev;
8345 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8346 sp = ckrealloc((pointer)sp, grosslen);
8347 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008348 stackp = sp;
8349 stacknxt = sp->space;
8350 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008351 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008352
Eric Andersenc470f442003-07-28 09:56:35 +00008353 /*
8354 * Stack marks pointing to the start of the old block
8355 * must be relocated to point to the new block
8356 */
8357 xmark = markp;
8358 while (xmark != NULL && xmark->stackp == oldstackp) {
8359 xmark->stackp = stackp;
8360 xmark->stacknxt = stacknxt;
8361 xmark->stacknleft = stacknleft;
8362 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008363 }
8364 INTON;
8365 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008366 char *oldspace = stacknxt;
8367 int oldlen = stacknleft;
8368 char *p = stalloc(newlen);
8369
8370 /* free the space we just allocated */
8371 stacknxt = memcpy(p, oldspace, oldlen);
8372 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008373 }
8374}
8375
Eric Andersenc470f442003-07-28 09:56:35 +00008376static inline void
8377grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008378{
Eric Andersenc470f442003-07-28 09:56:35 +00008379 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008380 stacknxt += len;
8381 stacknleft -= len;
8382}
8383
Eric Andersencb57d552001-06-28 07:25:16 +00008384/*
Eric Andersenc470f442003-07-28 09:56:35 +00008385 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008386 * The user declares a variable of type STACKSTR, which may be declared
8387 * to be a register. The macro STARTSTACKSTR initializes things. Then
8388 * the user uses the macro STPUTC to add characters to the string. In
8389 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8390 * grown as necessary. When the user is done, she can just leave the
8391 * string there and refer to it using stackblock(). Or she can allocate
8392 * the space for it using grabstackstr(). If it is necessary to allow
8393 * someone else to use the stack temporarily and then continue to grow
8394 * the string, the user should use grabstack to allocate the space, and
8395 * then call ungrabstr(p) to return to the previous mode of operation.
8396 *
8397 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8398 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8399 * is space for at least one character.
8400 */
8401
Eric Andersenc470f442003-07-28 09:56:35 +00008402void *
8403growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008404{
Eric Andersenc470f442003-07-28 09:56:35 +00008405 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008406 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008407 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008408 return stackblock();
8409 }
8410 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008411 return stackblock() + len;
8412}
8413
Eric Andersencb57d552001-06-28 07:25:16 +00008414/*
8415 * Called from CHECKSTRSPACE.
8416 */
8417
Eric Andersenc470f442003-07-28 09:56:35 +00008418char *
8419makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008420{
Eric Andersenc470f442003-07-28 09:56:35 +00008421 size_t len = p - stacknxt;
8422 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008423
Eric Andersenc470f442003-07-28 09:56:35 +00008424 for (;;) {
8425 size_t nleft;
8426
8427 size = stackblocksize();
8428 nleft = size - len;
8429 if (nleft >= newlen)
8430 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008431 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008432 }
Eric Andersencb57d552001-06-28 07:25:16 +00008433 return stackblock() + len;
8434}
8435
Eric Andersenc470f442003-07-28 09:56:35 +00008436char *
8437stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008438{
Eric Andersenc470f442003-07-28 09:56:35 +00008439 p = makestrspace(n, p);
8440 p = mempcpy(p, s, n);
8441 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008442}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008443
Eric Andersenc470f442003-07-28 09:56:35 +00008444char *
8445stputs(const char *s, char *p)
8446{
8447 return stnputs(s, strlen(s), p);
8448}
8449
8450/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8451
Eric Andersencb57d552001-06-28 07:25:16 +00008452/*
Eric Andersenc470f442003-07-28 09:56:35 +00008453 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008454 *
Eric Andersenc470f442003-07-28 09:56:35 +00008455 * number(s) Convert a string of digits to an integer.
8456 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008457 */
8458
Eric Andersencb57d552001-06-28 07:25:16 +00008459/*
8460 * prefix -- see if pfx is a prefix of string.
8461 */
8462
Eric Andersenc470f442003-07-28 09:56:35 +00008463char *
8464prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008465{
Eric Andersencb57d552001-06-28 07:25:16 +00008466 while (*pfx) {
8467 if (*pfx++ != *string++)
8468 return 0;
8469 }
Eric Andersenc470f442003-07-28 09:56:35 +00008470 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008471}
8472
8473
8474/*
8475 * Convert a string of digits to an integer, printing an error message on
8476 * failure.
8477 */
8478
Eric Andersenc470f442003-07-28 09:56:35 +00008479int
8480number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008481{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008482
Eric Andersenc470f442003-07-28 09:56:35 +00008483 if (! is_number(s))
8484 error(illnum, s);
8485 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008486}
8487
Eric Andersenc470f442003-07-28 09:56:35 +00008488
Eric Andersenc470f442003-07-28 09:56:35 +00008489/*
8490 * Check for a valid number. This should be elsewhere.
8491 */
8492
8493int
8494is_number(const char *p)
8495{
8496 do {
8497 if (! is_digit(*p))
8498 return 0;
8499 } while (*++p != '\0');
8500 return 1;
8501}
8502
8503
Eric Andersencb57d552001-06-28 07:25:16 +00008504/*
8505 * Produce a possibly single quoted string suitable as input to the shell.
8506 * The return string is allocated on the stack.
8507 */
8508
Eric Andersenc470f442003-07-28 09:56:35 +00008509char *
8510single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008511 char *p;
8512
8513 STARTSTACKSTR(p);
8514
8515 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008516 char *q;
8517 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008518
Eric Andersenc470f442003-07-28 09:56:35 +00008519 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008520
Eric Andersenc470f442003-07-28 09:56:35 +00008521 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008522
Eric Andersenc470f442003-07-28 09:56:35 +00008523 *q++ = '\'';
8524 q = mempcpy(q, s, len);
8525 *q++ = '\'';
8526 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008527
Eric Andersenc470f442003-07-28 09:56:35 +00008528 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008529
Eric Andersenc470f442003-07-28 09:56:35 +00008530 len = strspn(s, "'");
8531 if (!len)
8532 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008533
Eric Andersenc470f442003-07-28 09:56:35 +00008534 q = p = makestrspace(len + 3, p);
8535
8536 *q++ = '"';
8537 q = mempcpy(q, s, len);
8538 *q++ = '"';
8539 s += len;
8540
8541 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008542 } while (*s);
8543
8544 USTPUTC(0, p);
8545
Eric Andersenc470f442003-07-28 09:56:35 +00008546 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008547}
8548
8549/*
Eric Andersenc470f442003-07-28 09:56:35 +00008550 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008551 */
8552
Eric Andersenc470f442003-07-28 09:56:35 +00008553char *
8554sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008555{
Eric Andersenc470f442003-07-28 09:56:35 +00008556 size_t len = strlen(p) + 1;
8557 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008558}
Eric Andersenc470f442003-07-28 09:56:35 +00008559
8560
8561static void
8562calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008563{
Eric Andersenc470f442003-07-28 09:56:35 +00008564 if (n == NULL)
8565 return;
8566 funcblocksize += nodesize[n->type];
8567 switch (n->type) {
8568 case NCMD:
8569 calcsize(n->ncmd.redirect);
8570 calcsize(n->ncmd.args);
8571 calcsize(n->ncmd.assign);
8572 break;
8573 case NPIPE:
8574 sizenodelist(n->npipe.cmdlist);
8575 break;
8576 case NREDIR:
8577 case NBACKGND:
8578 case NSUBSHELL:
8579 calcsize(n->nredir.redirect);
8580 calcsize(n->nredir.n);
8581 break;
8582 case NAND:
8583 case NOR:
8584 case NSEMI:
8585 case NWHILE:
8586 case NUNTIL:
8587 calcsize(n->nbinary.ch2);
8588 calcsize(n->nbinary.ch1);
8589 break;
8590 case NIF:
8591 calcsize(n->nif.elsepart);
8592 calcsize(n->nif.ifpart);
8593 calcsize(n->nif.test);
8594 break;
8595 case NFOR:
8596 funcstringsize += strlen(n->nfor.var) + 1;
8597 calcsize(n->nfor.body);
8598 calcsize(n->nfor.args);
8599 break;
8600 case NCASE:
8601 calcsize(n->ncase.cases);
8602 calcsize(n->ncase.expr);
8603 break;
8604 case NCLIST:
8605 calcsize(n->nclist.body);
8606 calcsize(n->nclist.pattern);
8607 calcsize(n->nclist.next);
8608 break;
8609 case NDEFUN:
8610 case NARG:
8611 sizenodelist(n->narg.backquote);
8612 funcstringsize += strlen(n->narg.text) + 1;
8613 calcsize(n->narg.next);
8614 break;
8615 case NTO:
8616 case NCLOBBER:
8617 case NFROM:
8618 case NFROMTO:
8619 case NAPPEND:
8620 calcsize(n->nfile.fname);
8621 calcsize(n->nfile.next);
8622 break;
8623 case NTOFD:
8624 case NFROMFD:
8625 calcsize(n->ndup.vname);
8626 calcsize(n->ndup.next);
8627 break;
8628 case NHERE:
8629 case NXHERE:
8630 calcsize(n->nhere.doc);
8631 calcsize(n->nhere.next);
8632 break;
8633 case NNOT:
8634 calcsize(n->nnot.com);
8635 break;
8636 };
Eric Andersencb57d552001-06-28 07:25:16 +00008637}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008638
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008639
Eric Andersenc470f442003-07-28 09:56:35 +00008640static void
8641sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008642{
8643 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008644 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008645 calcsize(lp->n);
8646 lp = lp->next;
8647 }
8648}
Eric Andersencb57d552001-06-28 07:25:16 +00008649
8650
Eric Andersenc470f442003-07-28 09:56:35 +00008651static union node *
8652copynode(union node *n)
8653{
8654 union node *new;
8655
8656 if (n == NULL)
8657 return NULL;
8658 new = funcblock;
8659 funcblock = (char *) funcblock + nodesize[n->type];
8660 switch (n->type) {
8661 case NCMD:
8662 new->ncmd.redirect = copynode(n->ncmd.redirect);
8663 new->ncmd.args = copynode(n->ncmd.args);
8664 new->ncmd.assign = copynode(n->ncmd.assign);
8665 break;
8666 case NPIPE:
8667 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8668 new->npipe.backgnd = n->npipe.backgnd;
8669 break;
8670 case NREDIR:
8671 case NBACKGND:
8672 case NSUBSHELL:
8673 new->nredir.redirect = copynode(n->nredir.redirect);
8674 new->nredir.n = copynode(n->nredir.n);
8675 break;
8676 case NAND:
8677 case NOR:
8678 case NSEMI:
8679 case NWHILE:
8680 case NUNTIL:
8681 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8682 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8683 break;
8684 case NIF:
8685 new->nif.elsepart = copynode(n->nif.elsepart);
8686 new->nif.ifpart = copynode(n->nif.ifpart);
8687 new->nif.test = copynode(n->nif.test);
8688 break;
8689 case NFOR:
8690 new->nfor.var = nodesavestr(n->nfor.var);
8691 new->nfor.body = copynode(n->nfor.body);
8692 new->nfor.args = copynode(n->nfor.args);
8693 break;
8694 case NCASE:
8695 new->ncase.cases = copynode(n->ncase.cases);
8696 new->ncase.expr = copynode(n->ncase.expr);
8697 break;
8698 case NCLIST:
8699 new->nclist.body = copynode(n->nclist.body);
8700 new->nclist.pattern = copynode(n->nclist.pattern);
8701 new->nclist.next = copynode(n->nclist.next);
8702 break;
8703 case NDEFUN:
8704 case NARG:
8705 new->narg.backquote = copynodelist(n->narg.backquote);
8706 new->narg.text = nodesavestr(n->narg.text);
8707 new->narg.next = copynode(n->narg.next);
8708 break;
8709 case NTO:
8710 case NCLOBBER:
8711 case NFROM:
8712 case NFROMTO:
8713 case NAPPEND:
8714 new->nfile.fname = copynode(n->nfile.fname);
8715 new->nfile.fd = n->nfile.fd;
8716 new->nfile.next = copynode(n->nfile.next);
8717 break;
8718 case NTOFD:
8719 case NFROMFD:
8720 new->ndup.vname = copynode(n->ndup.vname);
8721 new->ndup.dupfd = n->ndup.dupfd;
8722 new->ndup.fd = n->ndup.fd;
8723 new->ndup.next = copynode(n->ndup.next);
8724 break;
8725 case NHERE:
8726 case NXHERE:
8727 new->nhere.doc = copynode(n->nhere.doc);
8728 new->nhere.fd = n->nhere.fd;
8729 new->nhere.next = copynode(n->nhere.next);
8730 break;
8731 case NNOT:
8732 new->nnot.com = copynode(n->nnot.com);
8733 break;
8734 };
8735 new->type = n->type;
8736 return new;
8737}
8738
8739
8740static struct nodelist *
8741copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008742{
8743 struct nodelist *start;
8744 struct nodelist **lpp;
8745
8746 lpp = &start;
8747 while (lp) {
8748 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008749 funcblock = (char *) funcblock +
8750 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008751 (*lpp)->n = copynode(lp->n);
8752 lp = lp->next;
8753 lpp = &(*lpp)->next;
8754 }
8755 *lpp = NULL;
8756 return start;
8757}
8758
8759
Eric Andersenc470f442003-07-28 09:56:35 +00008760static char *
8761nodesavestr(char *s)
8762{
8763 char *rtn = funcstring;
8764
8765 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008766 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008767}
8768
Eric Andersenc470f442003-07-28 09:56:35 +00008769
Eric Andersenc470f442003-07-28 09:56:35 +00008770/*
8771 * Free a parse tree.
8772 */
8773
8774static void
8775freefunc(struct funcnode *f)
8776{
8777 if (f && --f->count < 0)
8778 ckfree(f);
8779}
8780
8781
8782static void options(int);
8783static void setoption(int, int);
8784
Eric Andersencb57d552001-06-28 07:25:16 +00008785
Eric Andersencb57d552001-06-28 07:25:16 +00008786/*
8787 * Process the shell command line arguments.
8788 */
8789
Eric Andersenc470f442003-07-28 09:56:35 +00008790void
8791procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008792{
8793 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008794 const char *xminusc;
8795 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008796
Eric Andersenc470f442003-07-28 09:56:35 +00008797 xargv = argv;
8798 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008799 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008800 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008801 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008802 optlist[i] = 2;
8803 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008804 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008805 xargv = argptr;
8806 xminusc = minusc;
8807 if (*xargv == NULL) {
8808 if (xminusc)
8809 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008810 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008811 }
Eric Andersencb57d552001-06-28 07:25:16 +00008812 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8813 iflag = 1;
8814 if (mflag == 2)
8815 mflag = iflag;
8816 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008817 if (optlist[i] == 2)
8818 optlist[i] = 0;
8819#if DEBUG == 2
8820 debug = 1;
8821#endif
8822 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8823 if (xminusc) {
8824 minusc = *xargv++;
8825 if (*xargv)
8826 goto setarg0;
8827 } else if (!sflag) {
8828 setinputfile(*xargv, 0);
8829setarg0:
8830 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008831 commandname = arg0;
8832 }
Eric Andersencb57d552001-06-28 07:25:16 +00008833
Eric Andersenc470f442003-07-28 09:56:35 +00008834 shellparam.p = xargv;
8835#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008836 shellparam.optind = 1;
8837 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008838#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008839 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008840 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008841 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008842 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008843 }
8844 optschanged();
8845}
8846
8847
Eric Andersenc470f442003-07-28 09:56:35 +00008848void
8849optschanged(void)
8850{
8851#ifdef DEBUG
8852 opentrace();
8853#endif
8854 setinteractive(iflag);
8855 setjobctl(mflag);
8856}
Eric Andersencb57d552001-06-28 07:25:16 +00008857
Eric Andersenc470f442003-07-28 09:56:35 +00008858static inline void
8859minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008860{
8861 int i;
8862
8863 if (name == NULL) {
8864 out1str("Current option settings\n");
8865 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008866 out1fmt("%-16s%s\n", optnames(i),
8867 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008868 } else {
8869 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008870 if (equal(name, optnames(i))) {
8871 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008872 return;
8873 }
8874 error("Illegal option -o %s", name);
8875 }
8876}
8877
Eric Andersenc470f442003-07-28 09:56:35 +00008878/*
8879 * Process shell options. The global variable argptr contains a pointer
8880 * to the argument list; we advance it past the options.
8881 */
Eric Andersen62483552001-07-10 06:09:16 +00008882
Eric Andersenc470f442003-07-28 09:56:35 +00008883static void
8884options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008885{
8886 char *p;
8887 int val;
8888 int c;
8889
8890 if (cmdline)
8891 minusc = NULL;
8892 while ((p = *argptr) != NULL) {
8893 argptr++;
8894 if ((c = *p++) == '-') {
8895 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008896 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8897 if (!cmdline) {
8898 /* "-" means turn off -x and -v */
8899 if (p[0] == '\0')
8900 xflag = vflag = 0;
8901 /* "--" means reset params */
8902 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008903 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008904 }
Eric Andersenc470f442003-07-28 09:56:35 +00008905 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008906 }
8907 } else if (c == '+') {
8908 val = 0;
8909 } else {
8910 argptr--;
8911 break;
8912 }
8913 while ((c = *p++) != '\0') {
8914 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008915 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008916 } else if (c == 'o') {
8917 minus_o(*argptr, val);
8918 if (*argptr)
8919 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008920 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008921 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008922 isloginsh = 1;
8923 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008924 } else {
8925 setoption(c, val);
8926 }
8927 }
8928 }
8929}
8930
Eric Andersencb57d552001-06-28 07:25:16 +00008931
Eric Andersenc470f442003-07-28 09:56:35 +00008932static void
8933setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008934{
Eric Andersencb57d552001-06-28 07:25:16 +00008935 int i;
8936
8937 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008938 if (optletters(i) == flag) {
8939 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008940 return;
8941 }
8942 error("Illegal option -%c", flag);
8943 /* NOTREACHED */
8944}
8945
8946
8947
Eric Andersencb57d552001-06-28 07:25:16 +00008948/*
8949 * Set the shell parameters.
8950 */
8951
Eric Andersenc470f442003-07-28 09:56:35 +00008952void
8953setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008954{
Eric Andersencb57d552001-06-28 07:25:16 +00008955 char **newparam;
8956 char **ap;
8957 int nparam;
8958
Eric Andersenc470f442003-07-28 09:56:35 +00008959 for (nparam = 0 ; argv[nparam] ; nparam++);
8960 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008961 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008962 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008963 }
8964 *ap = NULL;
8965 freeparam(&shellparam);
8966 shellparam.malloc = 1;
8967 shellparam.nparam = nparam;
8968 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008969#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008970 shellparam.optind = 1;
8971 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008972#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008973}
8974
8975
8976/*
8977 * Free the list of positional parameters.
8978 */
8979
Eric Andersenc470f442003-07-28 09:56:35 +00008980void
8981freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008982{
Eric Andersencb57d552001-06-28 07:25:16 +00008983 char **ap;
8984
8985 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008986 for (ap = param->p ; *ap ; ap++)
8987 ckfree(*ap);
8988 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008989 }
8990}
8991
8992
8993
8994/*
8995 * The shift builtin command.
8996 */
8997
Eric Andersenc470f442003-07-28 09:56:35 +00008998int
8999shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009000{
9001 int n;
9002 char **ap1, **ap2;
9003
9004 n = 1;
9005 if (argc > 1)
9006 n = number(argv[1]);
9007 if (n > shellparam.nparam)
9008 error("can't shift that many");
9009 INTOFF;
9010 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009011 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009012 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009013 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009014 }
9015 ap2 = shellparam.p;
9016 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009017#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009018 shellparam.optind = 1;
9019 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009020#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009021 INTON;
9022 return 0;
9023}
9024
9025
9026
9027/*
9028 * The set command builtin.
9029 */
9030
Eric Andersenc470f442003-07-28 09:56:35 +00009031int
9032setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009033{
9034 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009035 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009036 INTOFF;
9037 options(0);
9038 optschanged();
9039 if (*argptr != NULL) {
9040 setparam(argptr);
9041 }
9042 INTON;
9043 return 0;
9044}
9045
9046
Eric Andersenc470f442003-07-28 09:56:35 +00009047#ifdef CONFIG_ASH_GETOPTS
9048static void
9049getoptsreset(value)
9050 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009051{
9052 shellparam.optind = number(value);
9053 shellparam.optoff = -1;
9054}
Eric Andersenc470f442003-07-28 09:56:35 +00009055#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009056
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009057#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009058static void change_lc_all(const char *value)
9059{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009060 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009061 setlocale(LC_ALL, value);
9062}
9063
9064static void change_lc_ctype(const char *value)
9065{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009066 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009067 setlocale(LC_CTYPE, value);
9068}
9069
9070#endif
9071
Eric Andersen16767e22004-03-16 05:14:10 +00009072#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009073/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009074static void change_random(const char *value)
9075{
Eric Andersen16767e22004-03-16 05:14:10 +00009076 if(value == NULL) {
9077 /* "get", generate */
9078 char buf[16];
9079
9080 rseed = rseed * 1103515245 + 12345;
9081 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9082 /* set without recursion */
9083 setvar(vrandom.text, buf, VNOFUNC);
9084 vrandom.flags &= ~VNOFUNC;
9085 } else {
9086 /* set/reset */
9087 rseed = strtoul(value, (char **)NULL, 10);
9088 }
Eric Andersenef02f822004-03-11 13:34:24 +00009089}
Eric Andersen16767e22004-03-16 05:14:10 +00009090#endif
9091
Eric Andersenef02f822004-03-11 13:34:24 +00009092
Eric Andersend35c5df2002-01-09 15:37:36 +00009093#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009094static int
Eric Andersenc470f442003-07-28 09:56:35 +00009095getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009096{
9097 char *p, *q;
9098 char c = '?';
9099 int done = 0;
9100 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009101 char s[12];
9102 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009103
Eric Andersena48b0a32003-10-22 10:56:47 +00009104 if(*param_optind < 1)
9105 return 1;
9106 optnext = optfirst + *param_optind - 1;
9107
9108 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009109 p = NULL;
9110 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009111 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009112 if (p == NULL || *p == '\0') {
9113 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009114 p = *optnext;
9115 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009116atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009117 p = NULL;
9118 done = 1;
9119 goto out;
9120 }
9121 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009122 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009123 goto atend;
9124 }
9125
9126 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009127 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009128 if (*q == '\0') {
9129 if (optstr[0] == ':') {
9130 s[0] = c;
9131 s[1] = '\0';
9132 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009133 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009134 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009135 (void) unsetvar("OPTARG");
9136 }
9137 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009138 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009139 }
9140 if (*++q == ':')
9141 q++;
9142 }
9143
9144 if (*++q == ':') {
9145 if (*p == '\0' && (p = *optnext) == NULL) {
9146 if (optstr[0] == ':') {
9147 s[0] = c;
9148 s[1] = '\0';
9149 err |= setvarsafe("OPTARG", s, 0);
9150 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009151 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009152 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009153 (void) unsetvar("OPTARG");
9154 c = '?';
9155 }
Eric Andersenc470f442003-07-28 09:56:35 +00009156 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009157 }
9158
9159 if (p == *optnext)
9160 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009161 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009162 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009163 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009164 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009165
Eric Andersenc470f442003-07-28 09:56:35 +00009166out:
Eric Andersencb57d552001-06-28 07:25:16 +00009167 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009168 *param_optind = optnext - optfirst + 1;
9169 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009170 err |= setvarsafe("OPTIND", s, VNOFUNC);
9171 s[0] = c;
9172 s[1] = '\0';
9173 err |= setvarsafe(optvar, s, 0);
9174 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009175 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009176 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009177 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009178 exraise(EXERROR);
9179 }
9180 return done;
9181}
Eric Andersenc470f442003-07-28 09:56:35 +00009182
9183/*
9184 * The getopts builtin. Shellparam.optnext points to the next argument
9185 * to be processed. Shellparam.optptr points to the next character to
9186 * be processed in the current argument. If shellparam.optnext is NULL,
9187 * then it's the first time getopts has been called.
9188 */
9189
9190int
9191getoptscmd(int argc, char **argv)
9192{
9193 char **optbase;
9194
9195 if (argc < 3)
9196 error("Usage: getopts optstring var [arg]");
9197 else if (argc == 3) {
9198 optbase = shellparam.p;
9199 if (shellparam.optind > shellparam.nparam + 1) {
9200 shellparam.optind = 1;
9201 shellparam.optoff = -1;
9202 }
9203 }
9204 else {
9205 optbase = &argv[3];
9206 if (shellparam.optind > argc - 2) {
9207 shellparam.optind = 1;
9208 shellparam.optoff = -1;
9209 }
9210 }
9211
9212 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9213 &shellparam.optoff);
9214}
9215#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009216
9217/*
9218 * XXX - should get rid of. have all builtins use getopt(3). the
9219 * library getopt must have the BSD extension static variable "optreset"
9220 * otherwise it can't be used within the shell safely.
9221 *
9222 * Standard option processing (a la getopt) for builtin routines. The
9223 * only argument that is passed to nextopt is the option string; the
9224 * other arguments are unnecessary. It return the character, or '\0' on
9225 * end of input.
9226 */
9227
Eric Andersenc470f442003-07-28 09:56:35 +00009228static int
9229nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009230{
Eric Andersencb57d552001-06-28 07:25:16 +00009231 char *p;
9232 const char *q;
9233 char c;
9234
9235 if ((p = optptr) == NULL || *p == '\0') {
9236 p = *argptr;
9237 if (p == NULL || *p != '-' || *++p == '\0')
9238 return '\0';
9239 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009240 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009241 return '\0';
9242 }
9243 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009244 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009245 if (*q == '\0')
9246 error("Illegal option -%c", c);
9247 if (*++q == ':')
9248 q++;
9249 }
9250 if (*++q == ':') {
9251 if (*p == '\0' && (p = *argptr++) == NULL)
9252 error("No arg for -%c option", c);
9253 optionarg = p;
9254 p = NULL;
9255 }
9256 optptr = p;
9257 return c;
9258}
9259
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009260
Eric Andersenc470f442003-07-28 09:56:35 +00009261/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9262
Eric Andersenc470f442003-07-28 09:56:35 +00009263void
9264outstr(const char *p, FILE *file)
9265{
9266 INTOFF;
9267 fputs(p, file);
9268 INTON;
9269}
9270
9271void
9272flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009273{
Eric Andersencb57d552001-06-28 07:25:16 +00009274 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009275 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009276 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009277 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009278}
9279
Eric Andersenc470f442003-07-28 09:56:35 +00009280void
Eric Andersen16767e22004-03-16 05:14:10 +00009281flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009282{
9283 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009284 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009285 INTON;
9286}
9287
9288static void
9289outcslow(int c, FILE *dest)
9290{
9291 INTOFF;
9292 putc(c, dest);
9293 fflush(dest);
9294 INTON;
9295}
9296
9297
9298static int
9299out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009300{
9301 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009302 int r;
9303
9304 INTOFF;
9305 va_start(ap, fmt);
9306 r = vprintf(fmt, ap);
9307 va_end(ap);
9308 INTON;
9309 return r;
9310}
9311
9312
9313int
9314fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9315{
9316 va_list ap;
9317 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009318
Eric Andersencb57d552001-06-28 07:25:16 +00009319 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009320 INTOFF;
9321 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009322 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009323 INTON;
9324 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009325}
9326
Eric Andersenc470f442003-07-28 09:56:35 +00009327
Eric Andersencb57d552001-06-28 07:25:16 +00009328
Eric Andersenc470f442003-07-28 09:56:35 +00009329/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9330
9331
Eric Andersencb57d552001-06-28 07:25:16 +00009332/*
9333 * Shell command parser.
9334 */
9335
9336#define EOFMARKLEN 79
9337
9338
Eric Andersencb57d552001-06-28 07:25:16 +00009339struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009340 struct heredoc *next; /* next here document in list */
9341 union node *here; /* redirection node */
9342 char *eofmark; /* string indicating end of input */
9343 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009344};
9345
9346
9347
Eric Andersenc470f442003-07-28 09:56:35 +00009348static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009349
9350
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009351static union node *list(int);
9352static union node *andor(void);
9353static union node *pipeline(void);
9354static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009355static union node *simplecmd(void);
9356static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009357static void parsefname(void);
9358static void parseheredoc(void);
9359static char peektoken(void);
9360static int readtoken(void);
9361static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009362static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009363static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009364static void synexpect(int) __attribute__((__noreturn__));
9365static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009366static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009367
9368
Eric Andersenc470f442003-07-28 09:56:35 +00009369
9370static inline int
9371isassignment(const char *p)
9372{
9373 const char *q = endofname(p);
9374 if (p == q)
9375 return 0;
9376 return *q == '=';
9377}
9378
9379
Eric Andersencb57d552001-06-28 07:25:16 +00009380/*
9381 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9382 * valid parse tree indicating a blank line.)
9383 */
9384
Eric Andersenc470f442003-07-28 09:56:35 +00009385union node *
9386parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009387{
9388 int t;
9389
9390 tokpushback = 0;
9391 doprompt = interact;
9392 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009393 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009394 needprompt = 0;
9395 t = readtoken();
9396 if (t == TEOF)
9397 return NEOF;
9398 if (t == TNL)
9399 return NULL;
9400 tokpushback++;
9401 return list(1);
9402}
9403
9404
Eric Andersenc470f442003-07-28 09:56:35 +00009405static union node *
9406list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009407{
9408 union node *n1, *n2, *n3;
9409 int tok;
9410
Eric Andersenc470f442003-07-28 09:56:35 +00009411 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9412 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009413 return NULL;
9414 n1 = NULL;
9415 for (;;) {
9416 n2 = andor();
9417 tok = readtoken();
9418 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009419 if (n2->type == NPIPE) {
9420 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009421 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009422 if (n2->type != NREDIR) {
9423 n3 = stalloc(sizeof(struct nredir));
9424 n3->nredir.n = n2;
9425 n3->nredir.redirect = NULL;
9426 n2 = n3;
9427 }
9428 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009429 }
9430 }
9431 if (n1 == NULL) {
9432 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009433 }
9434 else {
9435 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009436 n3->type = NSEMI;
9437 n3->nbinary.ch1 = n1;
9438 n3->nbinary.ch2 = n2;
9439 n1 = n3;
9440 }
9441 switch (tok) {
9442 case TBACKGND:
9443 case TSEMI:
9444 tok = readtoken();
9445 /* fall through */
9446 case TNL:
9447 if (tok == TNL) {
9448 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009449 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009450 return n1;
9451 } else {
9452 tokpushback++;
9453 }
Eric Andersenc470f442003-07-28 09:56:35 +00009454 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009455 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009456 return n1;
9457 break;
9458 case TEOF:
9459 if (heredoclist)
9460 parseheredoc();
9461 else
Eric Andersenc470f442003-07-28 09:56:35 +00009462 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009463 return n1;
9464 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009465 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009466 synexpect(-1);
9467 tokpushback++;
9468 return n1;
9469 }
9470 }
9471}
9472
9473
9474
Eric Andersenc470f442003-07-28 09:56:35 +00009475static union node *
9476andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009477{
Eric Andersencb57d552001-06-28 07:25:16 +00009478 union node *n1, *n2, *n3;
9479 int t;
9480
Eric Andersencb57d552001-06-28 07:25:16 +00009481 n1 = pipeline();
9482 for (;;) {
9483 if ((t = readtoken()) == TAND) {
9484 t = NAND;
9485 } else if (t == TOR) {
9486 t = NOR;
9487 } else {
9488 tokpushback++;
9489 return n1;
9490 }
Eric Andersenc470f442003-07-28 09:56:35 +00009491 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009492 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009493 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009494 n3->type = t;
9495 n3->nbinary.ch1 = n1;
9496 n3->nbinary.ch2 = n2;
9497 n1 = n3;
9498 }
9499}
9500
9501
9502
Eric Andersenc470f442003-07-28 09:56:35 +00009503static union node *
9504pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009505{
Eric Andersencb57d552001-06-28 07:25:16 +00009506 union node *n1, *n2, *pipenode;
9507 struct nodelist *lp, *prev;
9508 int negate;
9509
9510 negate = 0;
9511 TRACE(("pipeline: entered\n"));
9512 if (readtoken() == TNOT) {
9513 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009514 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009515 } else
9516 tokpushback++;
9517 n1 = command();
9518 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009519 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009520 pipenode->type = NPIPE;
9521 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009522 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009523 pipenode->npipe.cmdlist = lp;
9524 lp->n = n1;
9525 do {
9526 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009527 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9528 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009529 lp->n = command();
9530 prev->next = lp;
9531 } while (readtoken() == TPIPE);
9532 lp->next = NULL;
9533 n1 = pipenode;
9534 }
9535 tokpushback++;
9536 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009537 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009538 n2->type = NNOT;
9539 n2->nnot.com = n1;
9540 return n2;
9541 } else
9542 return n1;
9543}
9544
9545
9546
Eric Andersenc470f442003-07-28 09:56:35 +00009547static union node *
9548command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009549{
Eric Andersencb57d552001-06-28 07:25:16 +00009550 union node *n1, *n2;
9551 union node *ap, **app;
9552 union node *cp, **cpp;
9553 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009554 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009555 int t;
9556
9557 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009558 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009559
Eric Andersencb57d552001-06-28 07:25:16 +00009560 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009561 default:
9562 synexpect(-1);
9563 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009564 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009565 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009566 n1->type = NIF;
9567 n1->nif.test = list(0);
9568 if (readtoken() != TTHEN)
9569 synexpect(TTHEN);
9570 n1->nif.ifpart = list(0);
9571 n2 = n1;
9572 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009573 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009574 n2 = n2->nif.elsepart;
9575 n2->type = NIF;
9576 n2->nif.test = list(0);
9577 if (readtoken() != TTHEN)
9578 synexpect(TTHEN);
9579 n2->nif.ifpart = list(0);
9580 }
9581 if (lasttoken == TELSE)
9582 n2->nif.elsepart = list(0);
9583 else {
9584 n2->nif.elsepart = NULL;
9585 tokpushback++;
9586 }
Eric Andersenc470f442003-07-28 09:56:35 +00009587 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009588 break;
9589 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009590 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009591 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009592 n1 = (union node *)stalloc(sizeof (struct nbinary));
9593 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009594 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009595 if ((got=readtoken()) != TDO) {
9596TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009597 synexpect(TDO);
9598 }
9599 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009600 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009601 break;
9602 }
9603 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009604 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009605 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009606 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009607 n1->type = NFOR;
9608 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009609 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009610 if (readtoken() == TIN) {
9611 app = &ap;
9612 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009613 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009614 n2->type = NARG;
9615 n2->narg.text = wordtext;
9616 n2->narg.backquote = backquotelist;
9617 *app = n2;
9618 app = &n2->narg.next;
9619 }
9620 *app = NULL;
9621 n1->nfor.args = ap;
9622 if (lasttoken != TNL && lasttoken != TSEMI)
9623 synexpect(-1);
9624 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009625 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009626 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009627 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009628 n2->narg.backquote = NULL;
9629 n2->narg.next = NULL;
9630 n1->nfor.args = n2;
9631 /*
9632 * Newline or semicolon here is optional (but note
9633 * that the original Bourne shell only allowed NL).
9634 */
9635 if (lasttoken != TNL && lasttoken != TSEMI)
9636 tokpushback++;
9637 }
Eric Andersenc470f442003-07-28 09:56:35 +00009638 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009639 if (readtoken() != TDO)
9640 synexpect(TDO);
9641 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009642 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009643 break;
9644 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009645 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009646 n1->type = NCASE;
9647 if (readtoken() != TWORD)
9648 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009649 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009650 n2->type = NARG;
9651 n2->narg.text = wordtext;
9652 n2->narg.backquote = backquotelist;
9653 n2->narg.next = NULL;
9654 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009655 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009656 } while (readtoken() == TNL);
9657 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009658 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009659 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009660next_case:
9661 checkkwd = CHKNL | CHKKWD;
9662 t = readtoken();
9663 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009664 if (lasttoken == TLP)
9665 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009666 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009667 cp->type = NCLIST;
9668 app = &cp->nclist.pattern;
9669 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009670 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009671 ap->type = NARG;
9672 ap->narg.text = wordtext;
9673 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009674 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009675 break;
9676 app = &ap->narg.next;
9677 readtoken();
9678 }
9679 ap->narg.next = NULL;
9680 if (lasttoken != TRP)
9681 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009682 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009683
Eric Andersenc470f442003-07-28 09:56:35 +00009684 cpp = &cp->nclist.next;
9685
9686 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009687 if ((t = readtoken()) != TESAC) {
9688 if (t != TENDCASE)
9689 synexpect(TENDCASE);
9690 else
Eric Andersenc470f442003-07-28 09:56:35 +00009691 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009692 }
Eric Andersenc470f442003-07-28 09:56:35 +00009693 }
Eric Andersencb57d552001-06-28 07:25:16 +00009694 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009695 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009696 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009697 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009698 n1->type = NSUBSHELL;
9699 n1->nredir.n = list(0);
9700 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009701 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009702 break;
9703 case TBEGIN:
9704 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009705 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009706 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009707 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009708 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009709 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009710 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009711 }
9712
Eric Andersenc470f442003-07-28 09:56:35 +00009713 if (readtoken() != t)
9714 synexpect(t);
9715
9716redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009717 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009718 checkkwd = CHKKWD | CHKALIAS;
9719 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009720 while (readtoken() == TREDIR) {
9721 *rpp = n2 = redirnode;
9722 rpp = &n2->nfile.next;
9723 parsefname();
9724 }
9725 tokpushback++;
9726 *rpp = NULL;
9727 if (redir) {
9728 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009729 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009730 n2->type = NREDIR;
9731 n2->nredir.n = n1;
9732 n1 = n2;
9733 }
9734 n1->nredir.redirect = redir;
9735 }
9736
9737 return n1;
9738}
9739
9740
Eric Andersenc470f442003-07-28 09:56:35 +00009741static union node *
9742simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009743 union node *args, **app;
9744 union node *n = NULL;
9745 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009746 union node **rpp, *redir;
9747 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009748
9749 args = NULL;
9750 app = &args;
9751 vars = NULL;
9752 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009753 redir = NULL;
9754 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009755
Eric Andersenc470f442003-07-28 09:56:35 +00009756 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009757 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009758 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009759 switch (readtoken()) {
9760 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009761 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009762 n->type = NARG;
9763 n->narg.text = wordtext;
9764 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009765 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009766 *vpp = n;
9767 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009768 } else {
9769 *app = n;
9770 app = &n->narg.next;
9771 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009772 }
9773 break;
9774 case TREDIR:
9775 *rpp = n = redirnode;
9776 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009777 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009778 break;
9779 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009780 if (
9781 args && app == &args->narg.next &&
9782 !vars && !redir
9783 ) {
9784 struct builtincmd *bcmd;
9785 const char *name;
9786
Eric Andersencb57d552001-06-28 07:25:16 +00009787 /* We have a function */
9788 if (readtoken() != TRP)
9789 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009790 name = n->narg.text;
9791 if (
9792 !goodname(name) || (
9793 (bcmd = find_builtin(name)) &&
9794 IS_BUILTIN_SPECIAL(bcmd)
9795 )
9796 )
9797 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009798 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009799 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009800 n->narg.next = command();
9801 return n;
9802 }
9803 /* fall through */
9804 default:
9805 tokpushback++;
9806 goto out;
9807 }
9808 }
Eric Andersenc470f442003-07-28 09:56:35 +00009809out:
Eric Andersencb57d552001-06-28 07:25:16 +00009810 *app = NULL;
9811 *vpp = NULL;
9812 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009813 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009814 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009815 n->ncmd.args = args;
9816 n->ncmd.assign = vars;
9817 n->ncmd.redirect = redir;
9818 return n;
9819}
9820
Eric Andersenc470f442003-07-28 09:56:35 +00009821static union node *
9822makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009823{
Eric Andersencb57d552001-06-28 07:25:16 +00009824 union node *n;
9825
Eric Andersenc470f442003-07-28 09:56:35 +00009826 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009827 n->type = NARG;
9828 n->narg.next = NULL;
9829 n->narg.text = wordtext;
9830 n->narg.backquote = backquotelist;
9831 return n;
9832}
9833
Eric Andersenc470f442003-07-28 09:56:35 +00009834void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009835{
Eric Andersencb57d552001-06-28 07:25:16 +00009836 TRACE(("Fix redir %s %d\n", text, err));
9837 if (!err)
9838 n->ndup.vname = NULL;
9839
9840 if (is_digit(text[0]) && text[1] == '\0')
9841 n->ndup.dupfd = digit_val(text[0]);
9842 else if (text[0] == '-' && text[1] == '\0')
9843 n->ndup.dupfd = -1;
9844 else {
9845
9846 if (err)
9847 synerror("Bad fd number");
9848 else
9849 n->ndup.vname = makename();
9850 }
9851}
9852
9853
Eric Andersenc470f442003-07-28 09:56:35 +00009854static void
9855parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009856{
Eric Andersencb57d552001-06-28 07:25:16 +00009857 union node *n = redirnode;
9858
9859 if (readtoken() != TWORD)
9860 synexpect(-1);
9861 if (n->type == NHERE) {
9862 struct heredoc *here = heredoc;
9863 struct heredoc *p;
9864 int i;
9865
9866 if (quoteflag == 0)
9867 n->type = NXHERE;
9868 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009869 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009870 synerror("Illegal eof marker for << redirection");
9871 rmescapes(wordtext);
9872 here->eofmark = wordtext;
9873 here->next = NULL;
9874 if (heredoclist == NULL)
9875 heredoclist = here;
9876 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009877 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009878 p->next = here;
9879 }
9880 } else if (n->type == NTOFD || n->type == NFROMFD) {
9881 fixredir(n, wordtext, 0);
9882 } else {
9883 n->nfile.fname = makename();
9884 }
9885}
9886
9887
9888/*
9889 * Input any here documents.
9890 */
9891
Eric Andersenc470f442003-07-28 09:56:35 +00009892static void
9893parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009894{
Eric Andersencb57d552001-06-28 07:25:16 +00009895 struct heredoc *here;
9896 union node *n;
9897
Eric Andersenc470f442003-07-28 09:56:35 +00009898 here = heredoclist;
9899 heredoclist = 0;
9900
9901 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009902 if (needprompt) {
9903 setprompt(2);
9904 needprompt = 0;
9905 }
Eric Andersenc470f442003-07-28 09:56:35 +00009906 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9907 here->eofmark, here->striptabs);
9908 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009909 n->narg.type = NARG;
9910 n->narg.next = NULL;
9911 n->narg.text = wordtext;
9912 n->narg.backquote = backquotelist;
9913 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009914 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009915 }
9916}
9917
Eric Andersenc470f442003-07-28 09:56:35 +00009918static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009919{
Eric Andersencb57d552001-06-28 07:25:16 +00009920 int t;
9921
9922 t = readtoken();
9923 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009924 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009925}
9926
Eric Andersenc470f442003-07-28 09:56:35 +00009927static int
9928readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009929{
Eric Andersencb57d552001-06-28 07:25:16 +00009930 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009931#ifdef DEBUG
9932 int alreadyseen = tokpushback;
9933#endif
9934
Eric Andersend35c5df2002-01-09 15:37:36 +00009935#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009936top:
Eric Andersen2870d962001-07-02 17:27:21 +00009937#endif
9938
Eric Andersencb57d552001-06-28 07:25:16 +00009939 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009940
Eric Andersenc470f442003-07-28 09:56:35 +00009941 /*
9942 * eat newlines
9943 */
9944 if (checkkwd & CHKNL) {
9945 while (t == TNL) {
9946 parseheredoc();
9947 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009948 }
9949 }
9950
Eric Andersenc470f442003-07-28 09:56:35 +00009951 if (t != TWORD || quoteflag) {
9952 goto out;
9953 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009954
Eric Andersenc470f442003-07-28 09:56:35 +00009955 /*
9956 * check for keywords
9957 */
9958 if (checkkwd & CHKKWD) {
9959 const char *const *pp;
9960
9961 if ((pp = findkwd(wordtext))) {
9962 lasttoken = t = pp - tokname_array;
9963 TRACE(("keyword %s recognized\n", tokname(t)));
9964 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009965 }
Eric Andersenc470f442003-07-28 09:56:35 +00009966 }
9967
9968 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009969#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009970 struct alias *ap;
9971 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009972 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009973 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009974 }
Eric Andersencb57d552001-06-28 07:25:16 +00009975 goto top;
9976 }
Eric Andersen2870d962001-07-02 17:27:21 +00009977#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009978 }
Eric Andersenc470f442003-07-28 09:56:35 +00009979out:
9980 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009981#ifdef DEBUG
9982 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009983 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009984 else
Eric Andersenc470f442003-07-28 09:56:35 +00009985 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009986#endif
9987 return (t);
9988}
9989
9990
9991/*
9992 * Read the next input token.
9993 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009994 * backquotes. We set quoteflag to true if any part of the word was
9995 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009996 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009997 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009998 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009999 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010000 *
10001 * [Change comment: here documents and internal procedures]
10002 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10003 * word parsing code into a separate routine. In this case, readtoken
10004 * doesn't need to have any internal procedures, but parseword does.
10005 * We could also make parseoperator in essence the main routine, and
10006 * have parseword (readtoken1?) handle both words and redirection.]
10007 */
10008
Eric Andersen81fe1232003-07-29 06:38:40 +000010009#define NEW_xxreadtoken
10010#ifdef NEW_xxreadtoken
10011
10012/* singles must be first! */
10013static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10014
10015static const char xxreadtoken_tokens[] = {
10016 TNL, TLP, TRP, /* only single occurrence allowed */
10017 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10018 TEOF, /* corresponds to trailing nul */
10019 TAND, TOR, TENDCASE, /* if double occurrence */
10020};
10021
10022#define xxreadtoken_doubles \
10023 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10024#define xxreadtoken_singles \
10025 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10026
10027static int xxreadtoken()
10028{
10029 int c;
10030
10031 if (tokpushback) {
10032 tokpushback = 0;
10033 return lasttoken;
10034 }
10035 if (needprompt) {
10036 setprompt(2);
10037 needprompt = 0;
10038 }
10039 startlinno = plinno;
10040 for (;;) { /* until token or start of word found */
10041 c = pgetc_macro();
10042
10043 if ((c != ' ') && (c != '\t')
10044#ifdef CONFIG_ASH_ALIAS
10045 && (c != PEOA)
10046#endif
10047 ) {
10048 if (c == '#') {
10049 while ((c = pgetc()) != '\n' && c != PEOF);
10050 pungetc();
10051 } else if (c == '\\') {
10052 if (pgetc() != '\n') {
10053 pungetc();
10054 goto READTOKEN1;
10055 }
10056 startlinno = ++plinno;
10057 if (doprompt)
10058 setprompt(2);
10059 } else {
10060 const char *p
10061 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10062
10063 if (c != PEOF) {
10064 if (c == '\n') {
10065 plinno++;
10066 needprompt = doprompt;
10067 }
10068
10069 p = strchr(xxreadtoken_chars, c);
10070 if (p == NULL) {
10071 READTOKEN1:
10072 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10073 }
10074
10075 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10076 if (pgetc() == *p) { /* double occurrence? */
10077 p += xxreadtoken_doubles + 1;
10078 } else {
10079 pungetc();
10080 }
10081 }
10082 }
10083
10084 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10085 }
10086 }
10087 }
10088}
10089
10090
10091#else
Eric Andersen2870d962001-07-02 17:27:21 +000010092#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010093
Eric Andersenc470f442003-07-28 09:56:35 +000010094static int
10095xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010096{
Eric Andersencb57d552001-06-28 07:25:16 +000010097 int c;
10098
10099 if (tokpushback) {
10100 tokpushback = 0;
10101 return lasttoken;
10102 }
10103 if (needprompt) {
10104 setprompt(2);
10105 needprompt = 0;
10106 }
10107 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010108 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010109 c = pgetc_macro();
10110 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010111 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010112#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010113 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010114#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010115 continue;
10116 case '#':
10117 while ((c = pgetc()) != '\n' && c != PEOF);
10118 pungetc();
10119 continue;
10120 case '\\':
10121 if (pgetc() == '\n') {
10122 startlinno = ++plinno;
10123 if (doprompt)
10124 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010125 continue;
10126 }
10127 pungetc();
10128 goto breakloop;
10129 case '\n':
10130 plinno++;
10131 needprompt = doprompt;
10132 RETURN(TNL);
10133 case PEOF:
10134 RETURN(TEOF);
10135 case '&':
10136 if (pgetc() == '&')
10137 RETURN(TAND);
10138 pungetc();
10139 RETURN(TBACKGND);
10140 case '|':
10141 if (pgetc() == '|')
10142 RETURN(TOR);
10143 pungetc();
10144 RETURN(TPIPE);
10145 case ';':
10146 if (pgetc() == ';')
10147 RETURN(TENDCASE);
10148 pungetc();
10149 RETURN(TSEMI);
10150 case '(':
10151 RETURN(TLP);
10152 case ')':
10153 RETURN(TRP);
10154 default:
10155 goto breakloop;
10156 }
10157 }
Eric Andersenc470f442003-07-28 09:56:35 +000010158breakloop:
10159 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010160#undef RETURN
10161}
Eric Andersen81fe1232003-07-29 06:38:40 +000010162#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010163
Eric Andersencb57d552001-06-28 07:25:16 +000010164
Eric Andersencb57d552001-06-28 07:25:16 +000010165/*
10166 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10167 * is not NULL, read a here document. In the latter case, eofmark is the
10168 * word which marks the end of the document and striptabs is true if
10169 * leading tabs should be stripped from the document. The argument firstc
10170 * is the first character of the input token or document.
10171 *
10172 * Because C does not have internal subroutines, I have simulated them
10173 * using goto's to implement the subroutine linkage. The following macros
10174 * will run code that appears at the end of readtoken1.
10175 */
10176
Eric Andersen2870d962001-07-02 17:27:21 +000010177#define CHECKEND() {goto checkend; checkend_return:;}
10178#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10179#define PARSESUB() {goto parsesub; parsesub_return:;}
10180#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10181#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10182#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010183
10184static int
Eric Andersenc470f442003-07-28 09:56:35 +000010185readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010186{
Eric Andersencb57d552001-06-28 07:25:16 +000010187 int c = firstc;
10188 char *out;
10189 int len;
10190 char line[EOFMARKLEN + 1];
10191 struct nodelist *bqlist;
10192 int quotef;
10193 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010194 int varnest; /* levels of variables expansion */
10195 int arinest; /* levels of arithmetic expansion */
10196 int parenlevel; /* levels of parens in arithmetic */
10197 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010198 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010199 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010200#if __GNUC__
10201 /* Avoid longjmp clobbering */
10202 (void) &out;
10203 (void) &quotef;
10204 (void) &dblquote;
10205 (void) &varnest;
10206 (void) &arinest;
10207 (void) &parenlevel;
10208 (void) &dqvarnest;
10209 (void) &oldstyle;
10210 (void) &prevsyntax;
10211 (void) &syntax;
10212#endif
10213
10214 startlinno = plinno;
10215 dblquote = 0;
10216 if (syntax == DQSYNTAX)
10217 dblquote = 1;
10218 quotef = 0;
10219 bqlist = NULL;
10220 varnest = 0;
10221 arinest = 0;
10222 parenlevel = 0;
10223 dqvarnest = 0;
10224
10225 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010226 loop: { /* for each line, until end of word */
10227 CHECKEND(); /* set c to PEOF if at end of here document */
10228 for (;;) { /* until end of line or end of word */
10229 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10230 switch(SIT(c, syntax)) {
10231 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010232 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010233 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010234 USTPUTC(c, out);
10235 plinno++;
10236 if (doprompt)
10237 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010238 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010239 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010240 case CWORD:
10241 USTPUTC(c, out);
10242 break;
10243 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010244 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010245 USTPUTC(CTLESC, out);
10246 USTPUTC(c, out);
10247 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010248 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010249 c = pgetc2();
10250 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010251 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010252 USTPUTC('\\', out);
10253 pungetc();
10254 } else if (c == '\n') {
10255 if (doprompt)
10256 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010257 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010258 if (
10259 dblquote &&
10260 c != '\\' && c != '`' &&
10261 c != '$' && (
10262 c != '"' ||
10263 eofmark != NULL
10264 )
10265 ) {
10266 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010267 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010268 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010269 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010270 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010271 USTPUTC(c, out);
10272 quotef++;
10273 }
10274 break;
10275 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010276 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010277quotemark:
10278 if (eofmark == NULL) {
10279 USTPUTC(CTLQUOTEMARK, out);
10280 }
Eric Andersencb57d552001-06-28 07:25:16 +000010281 break;
10282 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010283 syntax = DQSYNTAX;
10284 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010285 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010286 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010287 if (eofmark != NULL && arinest == 0 &&
10288 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010289 USTPUTC(c, out);
10290 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010291 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010292 syntax = BASESYNTAX;
10293 dblquote = 0;
10294 }
10295 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010296 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010297 }
10298 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010299 case CVAR: /* '$' */
10300 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010301 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010302 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010303 if (varnest > 0) {
10304 varnest--;
10305 if (dqvarnest > 0) {
10306 dqvarnest--;
10307 }
10308 USTPUTC(CTLENDVAR, out);
10309 } else {
10310 USTPUTC(c, out);
10311 }
10312 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010313#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010314 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010315 parenlevel++;
10316 USTPUTC(c, out);
10317 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010318 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010319 if (parenlevel > 0) {
10320 USTPUTC(c, out);
10321 --parenlevel;
10322 } else {
10323 if (pgetc() == ')') {
10324 if (--arinest == 0) {
10325 USTPUTC(CTLENDARI, out);
10326 syntax = prevsyntax;
10327 if (syntax == DQSYNTAX)
10328 dblquote = 1;
10329 else
10330 dblquote = 0;
10331 } else
10332 USTPUTC(')', out);
10333 } else {
10334 /*
10335 * unbalanced parens
10336 * (don't 2nd guess - no error)
10337 */
10338 pungetc();
10339 USTPUTC(')', out);
10340 }
10341 }
10342 break;
10343#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010344 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010345 PARSEBACKQOLD();
10346 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010347 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010348 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010349 case CIGN:
10350 break;
10351 default:
10352 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010353 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010354#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010355 if (c != PEOA)
10356#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010357 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010358
Eric Andersencb57d552001-06-28 07:25:16 +000010359 }
10360 c = pgetc_macro();
10361 }
10362 }
Eric Andersenc470f442003-07-28 09:56:35 +000010363endword:
10364#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010365 if (syntax == ARISYNTAX)
10366 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010367#endif
10368 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010369 synerror("Unterminated quoted string");
10370 if (varnest != 0) {
10371 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010372 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010373 synerror("Missing '}'");
10374 }
10375 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010376 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010377 out = stackblock();
10378 if (eofmark == NULL) {
10379 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010380 && quotef == 0
10381 && len <= 2
10382 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010383 PARSEREDIR();
10384 return lasttoken = TREDIR;
10385 } else {
10386 pungetc();
10387 }
10388 }
10389 quoteflag = quotef;
10390 backquotelist = bqlist;
10391 grabstackblock(len);
10392 wordtext = out;
10393 return lasttoken = TWORD;
10394/* end of readtoken routine */
10395
10396
10397
10398/*
10399 * Check to see whether we are at the end of the here document. When this
10400 * is called, c is set to the first character of the next input line. If
10401 * we are at the end of the here document, this routine sets the c to PEOF.
10402 */
10403
Eric Andersenc470f442003-07-28 09:56:35 +000010404checkend: {
10405 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010406#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010407 if (c == PEOA) {
10408 c = pgetc2();
10409 }
10410#endif
10411 if (striptabs) {
10412 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010413 c = pgetc2();
10414 }
Eric Andersenc470f442003-07-28 09:56:35 +000010415 }
10416 if (c == *eofmark) {
10417 if (pfgets(line, sizeof line) != NULL) {
10418 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010419
Eric Andersenc470f442003-07-28 09:56:35 +000010420 p = line;
10421 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10422 if (*p == '\n' && *q == '\0') {
10423 c = PEOF;
10424 plinno++;
10425 needprompt = doprompt;
10426 } else {
10427 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010428 }
10429 }
10430 }
10431 }
Eric Andersenc470f442003-07-28 09:56:35 +000010432 goto checkend_return;
10433}
Eric Andersencb57d552001-06-28 07:25:16 +000010434
10435
10436/*
10437 * Parse a redirection operator. The variable "out" points to a string
10438 * specifying the fd to be redirected. The variable "c" contains the
10439 * first character of the redirection operator.
10440 */
10441
Eric Andersenc470f442003-07-28 09:56:35 +000010442parseredir: {
10443 char fd = *out;
10444 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010445
Eric Andersenc470f442003-07-28 09:56:35 +000010446 np = (union node *)stalloc(sizeof (struct nfile));
10447 if (c == '>') {
10448 np->nfile.fd = 1;
10449 c = pgetc();
10450 if (c == '>')
10451 np->type = NAPPEND;
10452 else if (c == '|')
10453 np->type = NCLOBBER;
10454 else if (c == '&')
10455 np->type = NTOFD;
10456 else {
10457 np->type = NTO;
10458 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010459 }
Eric Andersenc470f442003-07-28 09:56:35 +000010460 } else { /* c == '<' */
10461 np->nfile.fd = 0;
10462 switch (c = pgetc()) {
10463 case '<':
10464 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10465 np = (union node *)stalloc(sizeof (struct nhere));
10466 np->nfile.fd = 0;
10467 }
10468 np->type = NHERE;
10469 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10470 heredoc->here = np;
10471 if ((c = pgetc()) == '-') {
10472 heredoc->striptabs = 1;
10473 } else {
10474 heredoc->striptabs = 0;
10475 pungetc();
10476 }
10477 break;
10478
10479 case '&':
10480 np->type = NFROMFD;
10481 break;
10482
10483 case '>':
10484 np->type = NFROMTO;
10485 break;
10486
10487 default:
10488 np->type = NFROM;
10489 pungetc();
10490 break;
10491 }
Eric Andersencb57d552001-06-28 07:25:16 +000010492 }
Eric Andersenc470f442003-07-28 09:56:35 +000010493 if (fd != '\0')
10494 np->nfile.fd = digit_val(fd);
10495 redirnode = np;
10496 goto parseredir_return;
10497}
Eric Andersencb57d552001-06-28 07:25:16 +000010498
10499
10500/*
10501 * Parse a substitution. At this point, we have read the dollar sign
10502 * and nothing else.
10503 */
10504
Eric Andersenc470f442003-07-28 09:56:35 +000010505parsesub: {
10506 int subtype;
10507 int typeloc;
10508 int flags;
10509 char *p;
10510 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010511
Eric Andersenc470f442003-07-28 09:56:35 +000010512 c = pgetc();
10513 if (
10514 c <= PEOA_OR_PEOF ||
10515 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10516 ) {
10517 USTPUTC('$', out);
10518 pungetc();
10519 } else if (c == '(') { /* $(command) or $((arith)) */
10520 if (pgetc() == '(') {
10521#ifdef CONFIG_ASH_MATH_SUPPORT
10522 PARSEARITH();
10523#else
10524 synerror("We unsupport $((arith))");
10525#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010526 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010527 pungetc();
10528 PARSEBACKQNEW();
10529 }
10530 } else {
10531 USTPUTC(CTLVAR, out);
10532 typeloc = out - (char *)stackblock();
10533 USTPUTC(VSNORMAL, out);
10534 subtype = VSNORMAL;
10535 if (c == '{') {
10536 c = pgetc();
10537 if (c == '#') {
10538 if ((c = pgetc()) == '}')
10539 c = '#';
10540 else
10541 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010542 }
Eric Andersenc470f442003-07-28 09:56:35 +000010543 else
10544 subtype = 0;
10545 }
10546 if (c > PEOA_OR_PEOF && is_name(c)) {
10547 do {
10548 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010549 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010550 } while (c > PEOA_OR_PEOF && is_in_name(c));
10551 } else if (is_digit(c)) {
10552 do {
10553 STPUTC(c, out);
10554 c = pgetc();
10555 } while (is_digit(c));
10556 }
10557 else if (is_special(c)) {
10558 USTPUTC(c, out);
10559 c = pgetc();
10560 }
10561 else
10562badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010563
Eric Andersenc470f442003-07-28 09:56:35 +000010564 STPUTC('=', out);
10565 flags = 0;
10566 if (subtype == 0) {
10567 switch (c) {
10568 case ':':
10569 flags = VSNUL;
10570 c = pgetc();
10571 /*FALLTHROUGH*/
10572 default:
10573 p = strchr(types, c);
10574 if (p == NULL)
10575 goto badsub;
10576 subtype = p - types + VSNORMAL;
10577 break;
10578 case '%':
10579 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010580 {
10581 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010582 subtype = c == '#' ? VSTRIMLEFT :
10583 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010584 c = pgetc();
10585 if (c == cc)
10586 subtype++;
10587 else
10588 pungetc();
10589 break;
10590 }
10591 }
Eric Andersenc470f442003-07-28 09:56:35 +000010592 } else {
10593 pungetc();
10594 }
10595 if (dblquote || arinest)
10596 flags |= VSQUOTE;
10597 *((char *)stackblock() + typeloc) = subtype | flags;
10598 if (subtype != VSNORMAL) {
10599 varnest++;
10600 if (dblquote || arinest) {
10601 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010602 }
10603 }
10604 }
Eric Andersenc470f442003-07-28 09:56:35 +000010605 goto parsesub_return;
10606}
Eric Andersencb57d552001-06-28 07:25:16 +000010607
10608
10609/*
10610 * Called to parse command substitutions. Newstyle is set if the command
10611 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10612 * list of commands (passed by reference), and savelen is the number of
10613 * characters on the top of the stack which must be preserved.
10614 */
10615
Eric Andersenc470f442003-07-28 09:56:35 +000010616parsebackq: {
10617 struct nodelist **nlpp;
10618 int savepbq;
10619 union node *n;
10620 char *volatile str;
10621 struct jmploc jmploc;
10622 struct jmploc *volatile savehandler;
10623 size_t savelen;
10624 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010625#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010626 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010627#endif
10628
Eric Andersenc470f442003-07-28 09:56:35 +000010629 savepbq = parsebackquote;
10630 if (setjmp(jmploc.loc)) {
10631 if (str)
10632 ckfree(str);
10633 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010634 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010635 longjmp(handler->loc, 1);
10636 }
10637 INTOFF;
10638 str = NULL;
10639 savelen = out - (char *)stackblock();
10640 if (savelen > 0) {
10641 str = ckmalloc(savelen);
10642 memcpy(str, stackblock(), savelen);
10643 }
10644 savehandler = handler;
10645 handler = &jmploc;
10646 INTON;
10647 if (oldstyle) {
10648 /* We must read until the closing backquote, giving special
10649 treatment to some slashes, and then push the string and
10650 reread it as input, interpreting it normally. */
10651 char *pout;
10652 int pc;
10653 size_t psavelen;
10654 char *pstr;
10655
10656
10657 STARTSTACKSTR(pout);
10658 for (;;) {
10659 if (needprompt) {
10660 setprompt(2);
10661 needprompt = 0;
10662 }
10663 switch (pc = pgetc()) {
10664 case '`':
10665 goto done;
10666
10667 case '\\':
10668 if ((pc = pgetc()) == '\n') {
10669 plinno++;
10670 if (doprompt)
10671 setprompt(2);
10672 /*
10673 * If eating a newline, avoid putting
10674 * the newline into the new character
10675 * stream (via the STPUTC after the
10676 * switch).
10677 */
10678 continue;
10679 }
10680 if (pc != '\\' && pc != '`' && pc != '$'
10681 && (!dblquote || pc != '"'))
10682 STPUTC('\\', pout);
10683 if (pc > PEOA_OR_PEOF) {
10684 break;
10685 }
10686 /* fall through */
10687
10688 case PEOF:
10689#ifdef CONFIG_ASH_ALIAS
10690 case PEOA:
10691#endif
10692 startlinno = plinno;
10693 synerror("EOF in backquote substitution");
10694
10695 case '\n':
10696 plinno++;
10697 needprompt = doprompt;
10698 break;
10699
10700 default:
10701 break;
10702 }
10703 STPUTC(pc, pout);
10704 }
10705done:
10706 STPUTC('\0', pout);
10707 psavelen = pout - (char *)stackblock();
10708 if (psavelen > 0) {
10709 pstr = grabstackstr(pout);
10710 setinputstring(pstr);
10711 }
10712 }
10713 nlpp = &bqlist;
10714 while (*nlpp)
10715 nlpp = &(*nlpp)->next;
10716 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10717 (*nlpp)->next = NULL;
10718 parsebackquote = oldstyle;
10719
10720 if (oldstyle) {
10721 saveprompt = doprompt;
10722 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010723 }
10724
Eric Andersenc470f442003-07-28 09:56:35 +000010725 n = list(2);
10726
10727 if (oldstyle)
10728 doprompt = saveprompt;
10729 else {
10730 if (readtoken() != TRP)
10731 synexpect(TRP);
10732 }
10733
10734 (*nlpp)->n = n;
10735 if (oldstyle) {
10736 /*
10737 * Start reading from old file again, ignoring any pushed back
10738 * tokens left from the backquote parsing
10739 */
10740 popfile();
10741 tokpushback = 0;
10742 }
10743 while (stackblocksize() <= savelen)
10744 growstackblock();
10745 STARTSTACKSTR(out);
10746 if (str) {
10747 memcpy(out, str, savelen);
10748 STADJUST(savelen, out);
10749 INTOFF;
10750 ckfree(str);
10751 str = NULL;
10752 INTON;
10753 }
10754 parsebackquote = savepbq;
10755 handler = savehandler;
10756 if (arinest || dblquote)
10757 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10758 else
10759 USTPUTC(CTLBACKQ, out);
10760 if (oldstyle)
10761 goto parsebackq_oldreturn;
10762 else
10763 goto parsebackq_newreturn;
10764}
10765
10766#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010767/*
10768 * Parse an arithmetic expansion (indicate start of one and set state)
10769 */
Eric Andersenc470f442003-07-28 09:56:35 +000010770parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010771
Eric Andersenc470f442003-07-28 09:56:35 +000010772 if (++arinest == 1) {
10773 prevsyntax = syntax;
10774 syntax = ARISYNTAX;
10775 USTPUTC(CTLARI, out);
10776 if (dblquote)
10777 USTPUTC('"',out);
10778 else
10779 USTPUTC(' ',out);
10780 } else {
10781 /*
10782 * we collapse embedded arithmetic expansion to
10783 * parenthesis, which should be equivalent
10784 */
10785 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010786 }
Eric Andersenc470f442003-07-28 09:56:35 +000010787 goto parsearith_return;
10788}
10789#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010790
Eric Andersenc470f442003-07-28 09:56:35 +000010791} /* end of readtoken */
10792
Eric Andersencb57d552001-06-28 07:25:16 +000010793
10794
Eric Andersencb57d552001-06-28 07:25:16 +000010795/*
10796 * Returns true if the text contains nothing to expand (no dollar signs
10797 * or backquotes).
10798 */
10799
Eric Andersenc470f442003-07-28 09:56:35 +000010800static int
10801noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010802{
Eric Andersencb57d552001-06-28 07:25:16 +000010803 char *p;
10804 char c;
10805
10806 p = text;
10807 while ((c = *p++) != '\0') {
10808 if (c == CTLQUOTEMARK)
10809 continue;
10810 if (c == CTLESC)
10811 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010812 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010813 return 0;
10814 }
10815 return 1;
10816}
10817
10818
10819/*
Eric Andersenc470f442003-07-28 09:56:35 +000010820 * Return of a legal variable name (a letter or underscore followed by zero or
10821 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010822 */
10823
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010824static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010825endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010826{
Eric Andersenc470f442003-07-28 09:56:35 +000010827 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010828
Eric Andersenc470f442003-07-28 09:56:35 +000010829 p = (char *) name;
10830 if (! is_name(*p))
10831 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010832 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010833 if (! is_in_name(*p))
10834 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010835 }
Eric Andersenc470f442003-07-28 09:56:35 +000010836 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010837}
10838
10839
10840/*
10841 * Called when an unexpected token is read during the parse. The argument
10842 * is the token that is expected, or -1 if more than one type of token can
10843 * occur at this point.
10844 */
10845
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010846static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010847{
10848 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010849 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010850
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010851 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10852 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010853 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010854 synerror(msg);
10855 /* NOTREACHED */
10856}
10857
Eric Andersenc470f442003-07-28 09:56:35 +000010858static void
10859synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010860{
Eric Andersenc470f442003-07-28 09:56:35 +000010861 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010862 /* NOTREACHED */
10863}
10864
Eric Andersencb57d552001-06-28 07:25:16 +000010865
10866/*
10867 * called by editline -- any expansions to the prompt
10868 * should be added here.
10869 */
Eric Andersenc470f442003-07-28 09:56:35 +000010870
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010871static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010872{
Eric Andersenc470f442003-07-28 09:56:35 +000010873 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010874
10875 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010876 case 1:
10877 prompt = ps1val();
10878 break;
10879 case 2:
10880 prompt = ps2val();
10881 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010882 default: /* 0 */
10883 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010884 }
10885 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010886}
10887
Eric Andersencb57d552001-06-28 07:25:16 +000010888
Eric Andersenc470f442003-07-28 09:56:35 +000010889static const char *const *findkwd(const char *s)
10890{
10891 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010892 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010893 sizeof(const char *), pstrcmp);
10894}
10895
10896/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10897
Eric Andersencb57d552001-06-28 07:25:16 +000010898/*
10899 * Code for dealing with input/output redirection.
10900 */
10901
Eric Andersenc470f442003-07-28 09:56:35 +000010902#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010903#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010904# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010905#else
10906# define PIPESIZE PIPE_BUF
10907#endif
10908
Eric Andersen62483552001-07-10 06:09:16 +000010909/*
10910 * Open a file in noclobber mode.
10911 * The code was copied from bash.
10912 */
Eric Andersenc470f442003-07-28 09:56:35 +000010913static inline int
10914noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010915{
10916 int r, fd;
10917 struct stat finfo, finfo2;
10918
10919 /*
10920 * If the file exists and is a regular file, return an error
10921 * immediately.
10922 */
10923 r = stat(fname, &finfo);
10924 if (r == 0 && S_ISREG(finfo.st_mode)) {
10925 errno = EEXIST;
10926 return -1;
10927 }
10928
10929 /*
10930 * If the file was not present (r != 0), make sure we open it
10931 * exclusively so that if it is created before we open it, our open
10932 * will fail. Make sure that we do not truncate an existing file.
10933 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10934 * file was not a regular file, we leave O_EXCL off.
10935 */
10936 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010937 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10938 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010939
10940 /* If the open failed, return the file descriptor right away. */
10941 if (fd < 0)
10942 return fd;
10943
10944 /*
10945 * OK, the open succeeded, but the file may have been changed from a
10946 * non-regular file to a regular file between the stat and the open.
10947 * We are assuming that the O_EXCL open handles the case where FILENAME
10948 * did not exist and is symlinked to an existing file between the stat
10949 * and open.
10950 */
10951
10952 /*
10953 * If we can open it and fstat the file descriptor, and neither check
10954 * revealed that it was a regular file, and the file has not been
10955 * replaced, return the file descriptor.
10956 */
Eric Andersenc470f442003-07-28 09:56:35 +000010957 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10958 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010959 return fd;
10960
10961 /* The file has been replaced. badness. */
10962 close(fd);
10963 errno = EEXIST;
10964 return -1;
10965}
Eric Andersencb57d552001-06-28 07:25:16 +000010966
10967/*
Eric Andersen62483552001-07-10 06:09:16 +000010968 * Handle here documents. Normally we fork off a process to write the
10969 * data to a pipe. If the document is short, we can stuff the data in
10970 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010971 */
10972
Eric Andersenc470f442003-07-28 09:56:35 +000010973static inline int
10974openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010975{
10976 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010977 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010978
Eric Andersen62483552001-07-10 06:09:16 +000010979 if (pipe(pip) < 0)
10980 error("Pipe call failed");
10981 if (redir->type == NHERE) {
10982 len = strlen(redir->nhere.doc->narg.text);
10983 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010984 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010985 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010986 }
Eric Andersencb57d552001-06-28 07:25:16 +000010987 }
Eric Andersenc470f442003-07-28 09:56:35 +000010988 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010989 close(pip[0]);
10990 signal(SIGINT, SIG_IGN);
10991 signal(SIGQUIT, SIG_IGN);
10992 signal(SIGHUP, SIG_IGN);
10993#ifdef SIGTSTP
10994 signal(SIGTSTP, SIG_IGN);
10995#endif
10996 signal(SIGPIPE, SIG_DFL);
10997 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000010998 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010999 else
11000 expandhere(redir->nhere.doc, pip[1]);
11001 _exit(0);
11002 }
Eric Andersenc470f442003-07-28 09:56:35 +000011003out:
Eric Andersen62483552001-07-10 06:09:16 +000011004 close(pip[1]);
11005 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011006}
11007
Eric Andersenc470f442003-07-28 09:56:35 +000011008static int
11009openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011010{
Eric Andersencb57d552001-06-28 07:25:16 +000011011 char *fname;
11012 int f;
11013
11014 switch (redir->nfile.type) {
11015 case NFROM:
11016 fname = redir->nfile.expfname;
11017 if ((f = open(fname, O_RDONLY)) < 0)
11018 goto eopen;
11019 break;
11020 case NFROMTO:
11021 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011022 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011023 goto ecreate;
11024 break;
11025 case NTO:
11026 /* Take care of noclobber mode. */
11027 if (Cflag) {
11028 fname = redir->nfile.expfname;
11029 if ((f = noclobberopen(fname)) < 0)
11030 goto ecreate;
11031 break;
11032 }
Eric Andersenc470f442003-07-28 09:56:35 +000011033 /* FALLTHROUGH */
11034 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011035 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011036 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011037 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011038 break;
11039 case NAPPEND:
11040 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011041 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011042 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011043 break;
11044 default:
11045#ifdef DEBUG
11046 abort();
11047#endif
11048 /* Fall through to eliminate warning. */
11049 case NTOFD:
11050 case NFROMFD:
11051 f = -1;
11052 break;
11053 case NHERE:
11054 case NXHERE:
11055 f = openhere(redir);
11056 break;
11057 }
11058
11059 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011060ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011061 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011062eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011063 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11064}
11065
Eric Andersenc470f442003-07-28 09:56:35 +000011066static inline void
11067dupredirect(union node *redir, int f)
11068{
11069 int fd = redir->nfile.fd;
11070
11071 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11072 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11073 copyfd(redir->ndup.dupfd, fd);
11074 }
11075 return;
11076 }
11077
11078 if (f != fd) {
11079 copyfd(f, fd);
11080 close(f);
11081 }
11082 return;
11083}
Eric Andersencb57d552001-06-28 07:25:16 +000011084
Eric Andersen62483552001-07-10 06:09:16 +000011085/*
11086 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11087 * old file descriptors are stashed away so that the redirection can be
11088 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11089 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011090 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011091 */
11092
Eric Andersenc470f442003-07-28 09:56:35 +000011093static void
11094redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011095{
11096 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011097 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011098 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011099 int fd;
11100 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011101 int *p;
11102 nullredirs++;
11103 if (!redir) {
11104 return;
Eric Andersen62483552001-07-10 06:09:16 +000011105 }
Eric Andersenc470f442003-07-28 09:56:35 +000011106 sv = NULL;
11107 INTOFF;
11108 if (flags & REDIR_PUSH) {
11109 struct redirtab *q;
11110 q = ckmalloc(sizeof (struct redirtab));
11111 q->next = redirlist;
11112 redirlist = q;
11113 q->nullredirs = nullredirs - 1;
11114 for (i = 0 ; i < 10 ; i++)
11115 q->renamed[i] = EMPTY;
11116 nullredirs = 0;
11117 sv = q;
11118 }
11119 n = redir;
11120 do {
Eric Andersen62483552001-07-10 06:09:16 +000011121 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011122 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011123 n->ndup.dupfd == fd)
11124 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011125
Eric Andersen62483552001-07-10 06:09:16 +000011126 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011127 if (fd == newfd)
11128 continue;
11129 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11130 i = fcntl(fd, F_DUPFD, 10);
11131
11132 if (i == -1) {
11133 i = errno;
11134 if (i != EBADF) {
11135 close(newfd);
11136 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011137 error("%d: %m", fd);
11138 /* NOTREACHED */
11139 }
Eric Andersenc470f442003-07-28 09:56:35 +000011140 } else {
11141 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011142 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011143 }
Eric Andersenc470f442003-07-28 09:56:35 +000011144 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011145 close(fd);
11146 }
Eric Andersenc470f442003-07-28 09:56:35 +000011147 dupredirect(n, newfd);
11148 } while ((n = n->nfile.next));
11149 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011150 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11151 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011152}
11153
11154
Eric Andersencb57d552001-06-28 07:25:16 +000011155/*
11156 * Undo the effects of the last redirection.
11157 */
11158
Eric Andersenc470f442003-07-28 09:56:35 +000011159void
11160popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011161{
Eric Andersenc470f442003-07-28 09:56:35 +000011162 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011163 int i;
11164
Eric Andersenc470f442003-07-28 09:56:35 +000011165 if (--nullredirs >= 0)
11166 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011167 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011168 rp = redirlist;
11169 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011170 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011171 if (!drop) {
11172 close(i);
11173 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011174 }
Eric Andersenc470f442003-07-28 09:56:35 +000011175 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011176 }
11177 }
11178 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011179 nullredirs = rp->nullredirs;
11180 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011181 INTON;
11182}
11183
11184/*
Eric Andersenc470f442003-07-28 09:56:35 +000011185 * Undo all redirections. Called on error or interrupt.
11186 */
11187
11188/*
Eric Andersencb57d552001-06-28 07:25:16 +000011189 * Discard all saved file descriptors.
11190 */
11191
Eric Andersenc470f442003-07-28 09:56:35 +000011192void
11193clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011194{
Eric Andersenc470f442003-07-28 09:56:35 +000011195 for (;;) {
11196 nullredirs = 0;
11197 if (!redirlist)
11198 break;
11199 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011200 }
Eric Andersencb57d552001-06-28 07:25:16 +000011201}
11202
11203
Eric Andersencb57d552001-06-28 07:25:16 +000011204/*
11205 * Copy a file descriptor to be >= to. Returns -1
11206 * if the source file descriptor is closed, EMPTY if there are no unused
11207 * file descriptors left.
11208 */
11209
Eric Andersenc470f442003-07-28 09:56:35 +000011210int
11211copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011212{
11213 int newfd;
11214
11215 newfd = fcntl(from, F_DUPFD, to);
11216 if (newfd < 0) {
11217 if (errno == EMFILE)
11218 return EMPTY;
11219 else
Eric Andersen2870d962001-07-02 17:27:21 +000011220 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011221 }
11222 return newfd;
11223}
11224
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011225
Eric Andersenc470f442003-07-28 09:56:35 +000011226int
11227redirectsafe(union node *redir, int flags)
11228{
11229 int err;
11230 volatile int saveint;
11231 struct jmploc *volatile savehandler = handler;
11232 struct jmploc jmploc;
11233
11234 SAVEINT(saveint);
11235 if (!(err = setjmp(jmploc.loc) * 2)) {
11236 handler = &jmploc;
11237 redirect(redir, flags);
11238 }
11239 handler = savehandler;
11240 if (err && exception != EXERROR)
11241 longjmp(handler->loc, 1);
11242 RESTOREINT(saveint);
11243 return err;
11244}
11245
11246/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11247
11248#ifdef DEBUG
11249static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011250static void shcmd(union node *, FILE *);
11251static void sharg(union node *, FILE *);
11252static void indent(int, char *, FILE *);
11253static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011254
11255
Eric Andersenc470f442003-07-28 09:56:35 +000011256void
11257showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011258{
11259 trputs("showtree called\n");
11260 shtree(n, 1, NULL, stdout);
11261}
Eric Andersencb57d552001-06-28 07:25:16 +000011262
Eric Andersenc470f442003-07-28 09:56:35 +000011263
11264static void
11265shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011266{
11267 struct nodelist *lp;
11268 const char *s;
11269
11270 if (n == NULL)
11271 return;
11272
11273 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011274 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011275 case NSEMI:
11276 s = "; ";
11277 goto binop;
11278 case NAND:
11279 s = " && ";
11280 goto binop;
11281 case NOR:
11282 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011283binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011284 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011285 /* if (ind < 0) */
11286 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011287 shtree(n->nbinary.ch2, ind, NULL, fp);
11288 break;
11289 case NCMD:
11290 shcmd(n, fp);
11291 if (ind >= 0)
11292 putc('\n', fp);
11293 break;
11294 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011295 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011296 shcmd(lp->n, fp);
11297 if (lp->next)
11298 fputs(" | ", fp);
11299 }
11300 if (n->npipe.backgnd)
11301 fputs(" &", fp);
11302 if (ind >= 0)
11303 putc('\n', fp);
11304 break;
11305 default:
11306 fprintf(fp, "<node type %d>", n->type);
11307 if (ind >= 0)
11308 putc('\n', fp);
11309 break;
11310 }
11311}
11312
11313
Eric Andersenc470f442003-07-28 09:56:35 +000011314static void
11315shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011316{
11317 union node *np;
11318 int first;
11319 const char *s;
11320 int dftfd;
11321
11322 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011323 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11324 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011325 putchar(' ');
11326 sharg(np, fp);
11327 first = 0;
11328 }
Eric Andersenc470f442003-07-28 09:56:35 +000011329 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11330 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011331 putchar(' ');
11332 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011333 case NTO: s = ">"; dftfd = 1; break;
11334 case NCLOBBER: s = ">|"; dftfd = 1; break;
11335 case NAPPEND: s = ">>"; dftfd = 1; break;
11336 case NTOFD: s = ">&"; dftfd = 1; break;
11337 case NFROM: s = "<"; dftfd = 0; break;
11338 case NFROMFD: s = "<&"; dftfd = 0; break;
11339 case NFROMTO: s = "<>"; dftfd = 0; break;
11340 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011341 }
11342 if (np->nfile.fd != dftfd)
11343 fprintf(fp, "%d", np->nfile.fd);
11344 fputs(s, fp);
11345 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11346 fprintf(fp, "%d", np->ndup.dupfd);
11347 } else {
11348 sharg(np->nfile.fname, fp);
11349 }
11350 first = 0;
11351 }
11352}
11353
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011354
Eric Andersenc470f442003-07-28 09:56:35 +000011355
11356static void
11357sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011358{
Eric Andersencb57d552001-06-28 07:25:16 +000011359 char *p;
11360 struct nodelist *bqlist;
11361 int subtype;
11362
11363 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011364 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011365 abort();
11366 }
11367 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011368 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011369 switch (*p) {
11370 case CTLESC:
11371 putc(*++p, fp);
11372 break;
11373 case CTLVAR:
11374 putc('$', fp);
11375 putc('{', fp);
11376 subtype = *++p;
11377 if (subtype == VSLENGTH)
11378 putc('#', fp);
11379
11380 while (*p != '=')
11381 putc(*p++, fp);
11382
11383 if (subtype & VSNUL)
11384 putc(':', fp);
11385
11386 switch (subtype & VSTYPE) {
11387 case VSNORMAL:
11388 putc('}', fp);
11389 break;
11390 case VSMINUS:
11391 putc('-', fp);
11392 break;
11393 case VSPLUS:
11394 putc('+', fp);
11395 break;
11396 case VSQUESTION:
11397 putc('?', fp);
11398 break;
11399 case VSASSIGN:
11400 putc('=', fp);
11401 break;
11402 case VSTRIMLEFT:
11403 putc('#', fp);
11404 break;
11405 case VSTRIMLEFTMAX:
11406 putc('#', fp);
11407 putc('#', fp);
11408 break;
11409 case VSTRIMRIGHT:
11410 putc('%', fp);
11411 break;
11412 case VSTRIMRIGHTMAX:
11413 putc('%', fp);
11414 putc('%', fp);
11415 break;
11416 case VSLENGTH:
11417 break;
11418 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011419 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011420 }
11421 break;
11422 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011423 putc('}', fp);
11424 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011425 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011426 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011427 putc('$', fp);
11428 putc('(', fp);
11429 shtree(bqlist->n, -1, NULL, fp);
11430 putc(')', fp);
11431 break;
11432 default:
11433 putc(*p, fp);
11434 break;
11435 }
11436 }
11437}
11438
11439
Eric Andersenc470f442003-07-28 09:56:35 +000011440static void
11441indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011442{
11443 int i;
11444
Eric Andersenc470f442003-07-28 09:56:35 +000011445 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011446 if (pfx && i == amount - 1)
11447 fputs(pfx, fp);
11448 putc('\t', fp);
11449 }
11450}
Eric Andersencb57d552001-06-28 07:25:16 +000011451
Eric Andersenc470f442003-07-28 09:56:35 +000011452
11453
11454/*
11455 * Debugging stuff.
11456 */
11457
11458
Eric Andersencb57d552001-06-28 07:25:16 +000011459FILE *tracefile;
11460
Eric Andersencb57d552001-06-28 07:25:16 +000011461
Eric Andersenc470f442003-07-28 09:56:35 +000011462void
11463trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011464{
Eric Andersenc470f442003-07-28 09:56:35 +000011465 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011466 return;
11467 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011468}
11469
Eric Andersenc470f442003-07-28 09:56:35 +000011470void
11471trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011472{
11473 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011474
Eric Andersenc470f442003-07-28 09:56:35 +000011475 if (debug != 1)
11476 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011477 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011478 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011479 va_end(va);
11480}
11481
Eric Andersenc470f442003-07-28 09:56:35 +000011482void
11483tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011484{
Eric Andersenc470f442003-07-28 09:56:35 +000011485 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011486 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011487 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011488}
11489
11490
Eric Andersenc470f442003-07-28 09:56:35 +000011491void
11492trputs(const char *s)
11493{
11494 if (debug != 1)
11495 return;
11496 fputs(s, tracefile);
11497}
11498
11499
11500static void
11501trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011502{
11503 char *p;
11504 char c;
11505
Eric Andersenc470f442003-07-28 09:56:35 +000011506 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011507 return;
11508 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011509 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011510 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011511 case '\n': c = 'n'; goto backslash;
11512 case '\t': c = 't'; goto backslash;
11513 case '\r': c = 'r'; goto backslash;
11514 case '"': c = '"'; goto backslash;
11515 case '\\': c = '\\'; goto backslash;
11516 case CTLESC: c = 'e'; goto backslash;
11517 case CTLVAR: c = 'v'; goto backslash;
11518 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11519 case CTLBACKQ: c = 'q'; goto backslash;
11520 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11521backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011522 putc(c, tracefile);
11523 break;
11524 default:
11525 if (*p >= ' ' && *p <= '~')
11526 putc(*p, tracefile);
11527 else {
11528 putc('\\', tracefile);
11529 putc(*p >> 6 & 03, tracefile);
11530 putc(*p >> 3 & 07, tracefile);
11531 putc(*p & 07, tracefile);
11532 }
11533 break;
11534 }
11535 }
11536 putc('"', tracefile);
11537}
11538
11539
Eric Andersenc470f442003-07-28 09:56:35 +000011540void
11541trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011542{
Eric Andersenc470f442003-07-28 09:56:35 +000011543 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011544 return;
11545 while (*ap) {
11546 trstring(*ap++);
11547 if (*ap)
11548 putc(' ', tracefile);
11549 else
11550 putc('\n', tracefile);
11551 }
Eric Andersencb57d552001-06-28 07:25:16 +000011552}
11553
11554
Eric Andersenc470f442003-07-28 09:56:35 +000011555void
11556opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011557{
Eric Andersencb57d552001-06-28 07:25:16 +000011558 char s[100];
11559#ifdef O_APPEND
11560 int flags;
11561#endif
11562
Eric Andersenc470f442003-07-28 09:56:35 +000011563 if (debug != 1) {
11564 if (tracefile)
11565 fflush(tracefile);
11566 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011567 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011568 }
Eric Andersenc470f442003-07-28 09:56:35 +000011569 scopy("./trace", s);
11570 if (tracefile) {
11571 if (!freopen(s, "a", tracefile)) {
11572 fprintf(stderr, "Can't re-open %s\n", s);
11573 debug = 0;
11574 return;
11575 }
11576 } else {
11577 if ((tracefile = fopen(s, "a")) == NULL) {
11578 fprintf(stderr, "Can't open %s\n", s);
11579 debug = 0;
11580 return;
11581 }
11582 }
Eric Andersencb57d552001-06-28 07:25:16 +000011583#ifdef O_APPEND
11584 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11585 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11586#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011587 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011588 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011589}
Eric Andersenc470f442003-07-28 09:56:35 +000011590#endif /* DEBUG */
11591
11592
11593/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11594
11595/*
11596 * Sigmode records the current value of the signal handlers for the various
11597 * modes. A value of zero means that the current handler is not known.
11598 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11599 */
11600
11601#define S_DFL 1 /* default signal handling (SIG_DFL) */
11602#define S_CATCH 2 /* signal is caught */
11603#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11604#define S_HARD_IGN 4 /* signal is ignored permenantly */
11605#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11606
Eric Andersencb57d552001-06-28 07:25:16 +000011607
11608
11609/*
Eric Andersencb57d552001-06-28 07:25:16 +000011610 * The trap builtin.
11611 */
11612
Eric Andersenc470f442003-07-28 09:56:35 +000011613int
11614trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011615{
11616 char *action;
11617 char **ap;
11618 int signo;
11619
Eric Andersenc470f442003-07-28 09:56:35 +000011620 nextopt(nullstr);
11621 ap = argptr;
11622 if (!*ap) {
11623 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011624 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011625 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011626
Eric Andersenc470f442003-07-28 09:56:35 +000011627 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011628 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011629 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011630 out1fmt("trap -- %s %s\n",
11631 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011632 }
11633 }
11634 return 0;
11635 }
Eric Andersenc470f442003-07-28 09:56:35 +000011636 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011637 action = NULL;
11638 else
11639 action = *ap++;
11640 while (*ap) {
11641 if ((signo = decode_signal(*ap, 0)) < 0)
11642 error("%s: bad trap", *ap);
11643 INTOFF;
11644 if (action) {
11645 if (action[0] == '-' && action[1] == '\0')
11646 action = NULL;
11647 else
Eric Andersenc470f442003-07-28 09:56:35 +000011648 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011649 }
Eric Andersenc470f442003-07-28 09:56:35 +000011650 if (trap[signo])
11651 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011652 trap[signo] = action;
11653 if (signo != 0)
11654 setsignal(signo);
11655 INTON;
11656 ap++;
11657 }
11658 return 0;
11659}
11660
11661
Eric Andersenc470f442003-07-28 09:56:35 +000011662/*
11663 * Clear traps on a fork.
11664 */
11665
11666void
11667clear_traps(void)
11668{
11669 char **tp;
11670
11671 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11672 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11673 INTOFF;
11674 ckfree(*tp);
11675 *tp = NULL;
11676 if (tp != &trap[0])
11677 setsignal(tp - trap);
11678 INTON;
11679 }
11680 }
11681}
11682
11683
Eric Andersencb57d552001-06-28 07:25:16 +000011684/*
11685 * Set the signal handler for the specified signal. The routine figures
11686 * out what it should be set to.
11687 */
11688
Eric Andersenc470f442003-07-28 09:56:35 +000011689void
11690setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011691{
11692 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011693 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011694 struct sigaction act;
11695
11696 if ((t = trap[signo]) == NULL)
11697 action = S_DFL;
11698 else if (*t != '\0')
11699 action = S_CATCH;
11700 else
11701 action = S_IGN;
11702 if (rootshell && action == S_DFL) {
11703 switch (signo) {
11704 case SIGINT:
11705 if (iflag || minusc || sflag == 0)
11706 action = S_CATCH;
11707 break;
11708 case SIGQUIT:
11709#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011710 if (debug)
11711 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011712#endif
11713 /* FALLTHROUGH */
11714 case SIGTERM:
11715 if (iflag)
11716 action = S_IGN;
11717 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011718#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011719 case SIGTSTP:
11720 case SIGTTOU:
11721 if (mflag)
11722 action = S_IGN;
11723 break;
11724#endif
11725 }
11726 }
11727
11728 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011729 tsig = *t;
11730 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011731 /*
11732 * current setting unknown
11733 */
11734 if (sigaction(signo, 0, &act) == -1) {
11735 /*
11736 * Pretend it worked; maybe we should give a warning
11737 * here, but other shells don't. We don't alter
11738 * sigmode, so that we retry every time.
11739 */
11740 return;
11741 }
11742 if (act.sa_handler == SIG_IGN) {
11743 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011744 signo == SIGTTIN || signo == SIGTTOU)) {
11745 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011746 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011747 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011748 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011749 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011750 }
11751 }
Eric Andersenc470f442003-07-28 09:56:35 +000011752 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011753 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011754 switch (action) {
11755 case S_CATCH:
11756 act.sa_handler = onsig;
11757 break;
11758 case S_IGN:
11759 act.sa_handler = SIG_IGN;
11760 break;
11761 default:
11762 act.sa_handler = SIG_DFL;
11763 }
Eric Andersencb57d552001-06-28 07:25:16 +000011764 *t = action;
11765 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011766 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011767 sigaction(signo, &act, 0);
11768}
11769
11770/*
11771 * Ignore a signal.
11772 */
11773
Eric Andersenc470f442003-07-28 09:56:35 +000011774void
11775ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011776{
11777 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11778 signal(signo, SIG_IGN);
11779 }
11780 sigmode[signo - 1] = S_HARD_IGN;
11781}
11782
11783
Eric Andersencb57d552001-06-28 07:25:16 +000011784/*
11785 * Signal handler.
11786 */
11787
Eric Andersenc470f442003-07-28 09:56:35 +000011788void
11789onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011790{
Eric Andersencb57d552001-06-28 07:25:16 +000011791 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011792 pendingsigs = signo;
11793
11794 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11795 if (!suppressint)
11796 onint();
11797 intpending = 1;
11798 }
Eric Andersencb57d552001-06-28 07:25:16 +000011799}
11800
11801
Eric Andersencb57d552001-06-28 07:25:16 +000011802/*
11803 * Called to execute a trap. Perhaps we should avoid entering new trap
11804 * handlers while we are executing a trap handler.
11805 */
11806
Eric Andersenc470f442003-07-28 09:56:35 +000011807void
11808dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011809{
Eric Andersenc470f442003-07-28 09:56:35 +000011810 char *p;
11811 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011812 int savestatus;
11813
Eric Andersenc470f442003-07-28 09:56:35 +000011814 savestatus = exitstatus;
11815 q = gotsig;
Glenn L McGrath2f325a02004-08-06 01:49:04 +000011816 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
Eric Andersenc470f442003-07-28 09:56:35 +000011817 *p = 0;
11818 p = trap[p - q + 1];
11819 if (!p)
11820 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011821 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011822 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011823 }
Eric Andersencb57d552001-06-28 07:25:16 +000011824}
11825
Eric Andersenc470f442003-07-28 09:56:35 +000011826
Eric Andersenc470f442003-07-28 09:56:35 +000011827/*
11828 * Controls whether the shell is interactive or not.
11829 */
11830
Eric Andersenc470f442003-07-28 09:56:35 +000011831void
11832setinteractive(int on)
11833{
11834 static int is_interactive;
11835
11836 if (++on == is_interactive)
11837 return;
11838 is_interactive = on;
11839 setsignal(SIGINT);
11840 setsignal(SIGQUIT);
11841 setsignal(SIGTERM);
11842#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11843 if(is_interactive > 1) {
11844 /* Looks like they want an interactive shell */
11845 static int do_banner;
11846
11847 if(!do_banner) {
11848 out1fmt(
11849 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11850 "Enter 'help' for a list of built-in commands.\n\n");
11851 do_banner++;
11852 }
11853 }
11854#endif
11855}
11856
11857
11858#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11859/*** List the available builtins ***/
11860
11861static int helpcmd(int argc, char **argv)
11862{
11863 int col, i;
11864
11865 out1fmt("\nBuilt-in commands:\n-------------------\n");
11866 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11867 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11868 builtincmd[i].name + 1);
11869 if (col > 60) {
11870 out1fmt("\n");
11871 col = 0;
11872 }
11873 }
11874#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11875 {
11876 extern const struct BB_applet applets[];
11877 extern const size_t NUM_APPLETS;
11878
11879 for (i = 0; i < NUM_APPLETS; i++) {
11880
11881 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11882 if (col > 60) {
11883 out1fmt("\n");
11884 col = 0;
11885 }
11886 }
11887 }
11888#endif
11889 out1fmt("\n\n");
11890 return EXIT_SUCCESS;
11891}
11892#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11893
Eric Andersencb57d552001-06-28 07:25:16 +000011894/*
11895 * Called to exit the shell.
11896 */
11897
Eric Andersenc470f442003-07-28 09:56:35 +000011898void
11899exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011900{
Eric Andersenc470f442003-07-28 09:56:35 +000011901 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011902 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011903 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011904 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011905
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011906 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011907 status = exitstatus;
11908 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011909 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011910 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011911 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011912 if ((p = trap[0]) != NULL && *p != '\0') {
11913 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011914 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011915 }
Eric Andersencb57d552001-06-28 07:25:16 +000011916 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011917 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011918#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11919 if (iflag && rootshell) {
11920 const char *hp = lookupvar("HISTFILE");
11921
11922 if(hp != NULL )
11923 save_history ( hp );
11924 }
11925#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011926out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011927 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011928 /* NOTREACHED */
11929}
11930
11931static int decode_signal(const char *string, int minsig)
11932{
11933 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011934 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011935
Eric Andersen34506362001-08-02 05:02:46 +000011936 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011937}
Eric Andersen34506362001-08-02 05:02:46 +000011938
Eric Andersenc470f442003-07-28 09:56:35 +000011939/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11940
11941static struct var *vartab[VTABSIZE];
11942
11943static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011944static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011945
11946/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011947 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011948 */
11949
Eric Andersenc470f442003-07-28 09:56:35 +000011950
11951#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011952/*
Eric Andersenc470f442003-07-28 09:56:35 +000011953 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011954 */
11955
Eric Andersenc470f442003-07-28 09:56:35 +000011956int
11957setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011958{
Eric Andersenc470f442003-07-28 09:56:35 +000011959 int err;
11960 volatile int saveint;
11961 struct jmploc *volatile savehandler = handler;
11962 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011963
Eric Andersenc470f442003-07-28 09:56:35 +000011964 SAVEINT(saveint);
11965 if (setjmp(jmploc.loc))
11966 err = 1;
11967 else {
11968 handler = &jmploc;
11969 setvar(name, val, flags);
11970 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011971 }
Eric Andersenc470f442003-07-28 09:56:35 +000011972 handler = savehandler;
11973 RESTOREINT(saveint);
11974 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011975}
Eric Andersenc470f442003-07-28 09:56:35 +000011976#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011977
11978/*
11979 * Set the value of a variable. The flags argument is ored with the
11980 * flags of the variable. If val is NULL, the variable is unset.
11981 */
11982
Eric Andersenc470f442003-07-28 09:56:35 +000011983static void
11984setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011985{
Eric Andersenc470f442003-07-28 09:56:35 +000011986 char *p, *q;
11987 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011988 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011989 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011990
Eric Andersenc470f442003-07-28 09:56:35 +000011991 q = endofname(name);
11992 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011993 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011994 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011995 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011996 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011997 if (val == NULL) {
11998 flags |= VUNSET;
11999 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012000 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000012001 }
12002 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012003 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12004 *p++ = '\0';
12005 if (vallen) {
12006 p[-1] = '=';
12007 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000012008 }
Eric Andersenc470f442003-07-28 09:56:35 +000012009 *p = '\0';
12010 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012011 INTON;
12012}
12013
12014
Eric Andersencb57d552001-06-28 07:25:16 +000012015/*
12016 * Same as setvar except that the variable and value are passed in
12017 * the first argument as name=value. Since the first argument will
12018 * be actually stored in the table, it should not be a string that
12019 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012020 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012021 */
12022
Eric Andersenc470f442003-07-28 09:56:35 +000012023void
12024setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012025{
12026 struct var *vp, **vpp;
12027
12028 vpp = hashvar(s);
12029 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012030 vp = *findvar(vpp, s);
12031 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012032 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12033 const char *n;
12034
Eric Andersenc470f442003-07-28 09:56:35 +000012035 if (flags & VNOSAVE)
12036 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012037 n = vp->text;
12038 error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012039 }
Eric Andersenc470f442003-07-28 09:56:35 +000012040
12041 if (flags & VNOSET)
12042 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012043
12044 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012045 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012046
Eric Andersenc470f442003-07-28 09:56:35 +000012047 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12048 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012049
Eric Andersenc470f442003-07-28 09:56:35 +000012050 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12051 } else {
12052 if (flags & VNOSET)
12053 return;
12054 /* not found */
12055 vp = ckmalloc(sizeof (*vp));
12056 vp->next = *vpp;
12057 vp->func = NULL;
12058 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012059 }
Eric Andersenc470f442003-07-28 09:56:35 +000012060 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12061 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012062 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012063 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012064}
12065
12066
Eric Andersencb57d552001-06-28 07:25:16 +000012067/*
12068 * Process a linked list of variable assignments.
12069 */
12070
Eric Andersenc470f442003-07-28 09:56:35 +000012071static void
12072listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012073{
Eric Andersenc470f442003-07-28 09:56:35 +000012074 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012075
Eric Andersenc470f442003-07-28 09:56:35 +000012076 if (!lp)
12077 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012078 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012079 do {
12080 setvareq(lp->text, flags);
12081 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012082 INTON;
12083}
12084
12085
Eric Andersencb57d552001-06-28 07:25:16 +000012086/*
12087 * Find the value of a variable. Returns NULL if not set.
12088 */
12089
Eric Andersenc470f442003-07-28 09:56:35 +000012090static char *
12091lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012092{
Eric Andersencb57d552001-06-28 07:25:16 +000012093 struct var *v;
12094
Eric Andersen16767e22004-03-16 05:14:10 +000012095 if ((v = *findvar(hashvar(name), name))) {
12096#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012097 /*
12098 * Dynamic variables are implemented roughly the same way they are
12099 * in bash. Namely, they're "special" so long as they aren't unset.
12100 * As soon as they're unset, they're no longer dynamic, and dynamic
12101 * lookup will no longer happen at that point. -- PFM.
12102 */
Eric Andersen16767e22004-03-16 05:14:10 +000012103 if((v->flags & VDYNAMIC))
12104 (*v->func)(NULL);
12105#endif
12106 if(!(v->flags & VUNSET))
12107 return strchrnul(v->text, '=') + 1;
12108 }
Eric Andersenef02f822004-03-11 13:34:24 +000012109
Eric Andersencb57d552001-06-28 07:25:16 +000012110 return NULL;
12111}
12112
12113
Eric Andersencb57d552001-06-28 07:25:16 +000012114/*
12115 * Search the environment of a builtin command.
12116 */
12117
Eric Andersenc470f442003-07-28 09:56:35 +000012118static char *
12119bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012120{
Eric Andersenc470f442003-07-28 09:56:35 +000012121 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012122
Eric Andersenc470f442003-07-28 09:56:35 +000012123 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012124 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012125 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012126 }
12127 return lookupvar(name);
12128}
12129
12130
Eric Andersencb57d552001-06-28 07:25:16 +000012131/*
Eric Andersenc470f442003-07-28 09:56:35 +000012132 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012133 */
12134
Eric Andersenc470f442003-07-28 09:56:35 +000012135static char **
12136listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012137{
Eric Andersencb57d552001-06-28 07:25:16 +000012138 struct var **vpp;
12139 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012140 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012141 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012142
Eric Andersenc470f442003-07-28 09:56:35 +000012143 STARTSTACKSTR(ep);
12144 vpp = vartab;
12145 mask = on | off;
12146 do {
12147 for (vp = *vpp ; vp ; vp = vp->next)
12148 if ((vp->flags & mask) == on) {
12149 if (ep == stackstrend())
12150 ep = growstackstr();
12151 *ep++ = (char *) vp->text;
12152 }
12153 } while (++vpp < vartab + VTABSIZE);
12154 if (ep == stackstrend())
12155 ep = growstackstr();
12156 if (end)
12157 *end = ep;
12158 *ep++ = NULL;
12159 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012160}
12161
12162
12163/*
Eric Andersenc470f442003-07-28 09:56:35 +000012164 * POSIX requires that 'set' (but not export or readonly) output the
12165 * variables in lexicographic order - by the locale's collating order (sigh).
12166 * Maybe we could keep them in an ordered balanced binary tree
12167 * instead of hashed lists.
12168 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012169 */
12170
Eric Andersenc470f442003-07-28 09:56:35 +000012171static int
12172showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012173{
Eric Andersenc470f442003-07-28 09:56:35 +000012174 const char *sep;
12175 char **ep, **epend;
12176
12177 ep = listvars(on, off, &epend);
12178 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12179
12180 sep = *sep_prefix ? spcstr : sep_prefix;
12181
12182 for (; ep < epend; ep++) {
12183 const char *p;
12184 const char *q;
12185
12186 p = strchrnul(*ep, '=');
12187 q = nullstr;
12188 if (*p)
12189 q = single_quote(++p);
12190
12191 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12192 }
12193
Eric Andersencb57d552001-06-28 07:25:16 +000012194 return 0;
12195}
12196
12197
12198
12199/*
12200 * The export and readonly commands.
12201 */
12202
Eric Andersenc470f442003-07-28 09:56:35 +000012203static int
12204exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012205{
12206 struct var *vp;
12207 char *name;
12208 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012209 char **aptr;
12210 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12211 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012212
Eric Andersenc470f442003-07-28 09:56:35 +000012213 notp = nextopt("p") - 'p';
12214 if (notp && ((name = *(aptr = argptr)))) {
12215 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012216 if ((p = strchr(name, '=')) != NULL) {
12217 p++;
12218 } else {
12219 if ((vp = *findvar(hashvar(name), name))) {
12220 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012221 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012222 }
12223 }
12224 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012225 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012226 } else {
12227 showvars(argv[0], flag, 0);
12228 }
12229 return 0;
12230}
12231
Eric Andersen34506362001-08-02 05:02:46 +000012232
Eric Andersencb57d552001-06-28 07:25:16 +000012233/*
Eric Andersencb57d552001-06-28 07:25:16 +000012234 * Make a variable a local variable. When a variable is made local, it's
12235 * value and flags are saved in a localvar structure. The saved values
12236 * will be restored when the shell function returns. We handle the name
12237 * "-" as a special case.
12238 */
12239
Eric Andersenc470f442003-07-28 09:56:35 +000012240static inline void
12241mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012242{
Eric Andersencb57d552001-06-28 07:25:16 +000012243 struct localvar *lvp;
12244 struct var **vpp;
12245 struct var *vp;
12246
12247 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012248 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012249 if (name[0] == '-' && name[1] == '\0') {
12250 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012251 p = ckmalloc(sizeof(optlist));
12252 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012253 vp = NULL;
12254 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012255 char *eq;
12256
Eric Andersencb57d552001-06-28 07:25:16 +000012257 vpp = hashvar(name);
12258 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012259 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012260 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012261 if (eq)
12262 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012263 else
12264 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012265 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012266 lvp->flags = VUNSET;
12267 } else {
12268 lvp->text = vp->text;
12269 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012270 vp->flags |= VSTRFIXED|VTEXTFIXED;
12271 if (eq)
12272 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012273 }
12274 }
12275 lvp->vp = vp;
12276 lvp->next = localvars;
12277 localvars = lvp;
12278 INTON;
12279}
12280
Eric Andersenc470f442003-07-28 09:56:35 +000012281/*
12282 * The "local" command.
12283 */
12284
12285static int
12286localcmd(int argc, char **argv)
12287{
12288 char *name;
12289
12290 argv = argptr;
12291 while ((name = *argv++) != NULL) {
12292 mklocal(name);
12293 }
12294 return 0;
12295}
12296
12297
Eric Andersencb57d552001-06-28 07:25:16 +000012298/*
12299 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012300 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012301 */
12302
Eric Andersenc470f442003-07-28 09:56:35 +000012303static void
12304poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012305{
Eric Andersencb57d552001-06-28 07:25:16 +000012306 struct localvar *lvp;
12307 struct var *vp;
12308
12309 while ((lvp = localvars) != NULL) {
12310 localvars = lvp->next;
12311 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012312 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12313 if (vp == NULL) { /* $- saved */
12314 memcpy(optlist, lvp->text, sizeof(optlist));
12315 ckfree(lvp->text);
12316 optschanged();
12317 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12318 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012319 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012320 if (vp->func)
12321 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12322 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12323 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012324 vp->flags = lvp->flags;
12325 vp->text = lvp->text;
12326 }
Eric Andersenc470f442003-07-28 09:56:35 +000012327 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012328 }
12329}
12330
12331
Eric Andersencb57d552001-06-28 07:25:16 +000012332/*
12333 * The unset builtin command. We unset the function before we unset the
12334 * variable to allow a function to be unset when there is a readonly variable
12335 * with the same name.
12336 */
12337
Eric Andersenc470f442003-07-28 09:56:35 +000012338int
12339unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012340{
12341 char **ap;
12342 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012343 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012344 int ret = 0;
12345
12346 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012347 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012348 }
Eric Andersencb57d552001-06-28 07:25:16 +000012349
Eric Andersenc470f442003-07-28 09:56:35 +000012350 for (ap = argptr; *ap ; ap++) {
12351 if (flag != 'f') {
12352 i = unsetvar(*ap);
12353 ret |= i;
12354 if (!(i & 2))
12355 continue;
12356 }
12357 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012358 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012359 }
Eric Andersenc470f442003-07-28 09:56:35 +000012360 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012361}
12362
12363
12364/*
12365 * Unset the specified variable.
12366 */
12367
Eric Andersenc470f442003-07-28 09:56:35 +000012368int
12369unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012370{
Eric Andersencb57d552001-06-28 07:25:16 +000012371 struct var **vpp;
12372 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012373 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012374
12375 vpp = findvar(hashvar(s), s);
12376 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012377 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012378 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012379 int flags = vp->flags;
12380
12381 retval = 1;
12382 if (flags & VREADONLY)
12383 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012384#ifdef DYNAMIC_VAR
12385 vp->flags &= ~VDYNAMIC;
12386#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012387 if (flags & VUNSET)
12388 goto ok;
12389 if ((flags & VSTRFIXED) == 0) {
12390 INTOFF;
12391 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12392 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012393 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012394 ckfree(vp);
12395 INTON;
12396 } else {
12397 setvar(s, 0, 0);
12398 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012399 }
Eric Andersenc470f442003-07-28 09:56:35 +000012400ok:
12401 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012402 }
12403
Eric Andersenc470f442003-07-28 09:56:35 +000012404out:
12405 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012406}
12407
12408
12409
12410/*
12411 * Find the appropriate entry in the hash table from the name.
12412 */
12413
Eric Andersenc470f442003-07-28 09:56:35 +000012414static struct var **
12415hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012416{
Eric Andersencb57d552001-06-28 07:25:16 +000012417 unsigned int hashval;
12418
12419 hashval = ((unsigned char) *p) << 4;
12420 while (*p && *p != '=')
12421 hashval += (unsigned char) *p++;
12422 return &vartab[hashval % VTABSIZE];
12423}
12424
12425
12426
12427/*
Eric Andersenc470f442003-07-28 09:56:35 +000012428 * Compares two strings up to the first = or '\0'. The first
12429 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012430 * either '=' or '\0'.
12431 */
12432
Eric Andersenc470f442003-07-28 09:56:35 +000012433int
12434varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012435{
Eric Andersenc470f442003-07-28 09:56:35 +000012436 int c, d;
12437
12438 while ((c = *p) == (d = *q)) {
12439 if (!c || c == '=')
12440 goto out;
12441 p++;
12442 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012443 }
Eric Andersenc470f442003-07-28 09:56:35 +000012444 if (c == '=')
12445 c = 0;
12446 if (d == '=')
12447 d = 0;
12448out:
12449 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012450}
12451
Eric Andersenc470f442003-07-28 09:56:35 +000012452static int
12453vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012454{
Eric Andersenc470f442003-07-28 09:56:35 +000012455 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012456}
12457
Eric Andersenc470f442003-07-28 09:56:35 +000012458static struct var **
12459findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012460{
12461 for (; *vpp; vpp = &(*vpp)->next) {
12462 if (varequal((*vpp)->text, name)) {
12463 break;
12464 }
12465 }
12466 return vpp;
12467}
Eric Andersenc470f442003-07-28 09:56:35 +000012468/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012469
Eric Andersenc470f442003-07-28 09:56:35 +000012470#include <sys/times.h>
12471
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012472static const unsigned char timescmd_str[] = {
12473 ' ', offsetof(struct tms, tms_utime),
12474 '\n', offsetof(struct tms, tms_stime),
12475 ' ', offsetof(struct tms, tms_cutime),
12476 '\n', offsetof(struct tms, tms_cstime),
12477 0
12478};
Eric Andersencb57d552001-06-28 07:25:16 +000012479
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012480static int timescmd(int ac, char **av)
12481{
12482 long int clk_tck, s, t;
12483 const unsigned char *p;
12484 struct tms buf;
12485
12486 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012487 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012488
12489 p = timescmd_str;
12490 do {
12491 t = *(clock_t *)(((char *) &buf) + p[1]);
12492 s = t / clk_tck;
12493 out1fmt("%ldm%ld.%.3lds%c",
12494 s/60, s%60,
12495 ((t - s * clk_tck) * 1000) / clk_tck,
12496 p[0]);
12497 } while (*(p += 2));
12498
Eric Andersencb57d552001-06-28 07:25:16 +000012499 return 0;
12500}
12501
Eric Andersend35c5df2002-01-09 15:37:36 +000012502#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012503static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012504dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012505{
Eric Andersened9ecf72004-06-22 08:29:45 +000012506 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012507 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012508
Eric Andersenc470f442003-07-28 09:56:35 +000012509 INTOFF;
12510 result = arith(s, &errcode);
12511 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012512 if (errcode == -3)
12513 error("exponent less than 0");
12514 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012515 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012516 else if (errcode == -5)
12517 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012518 else
12519 synerror(s);
12520 }
12521 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012522
Eric Andersenc470f442003-07-28 09:56:35 +000012523 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012524}
Eric Andersenc470f442003-07-28 09:56:35 +000012525
12526
12527/*
Eric Andersen90898442003-08-06 11:20:52 +000012528 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12529 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12530 *
12531 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012532 */
Eric Andersen90898442003-08-06 11:20:52 +000012533
Eric Andersenc470f442003-07-28 09:56:35 +000012534static int
Eric Andersen90898442003-08-06 11:20:52 +000012535letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012536{
Eric Andersenc470f442003-07-28 09:56:35 +000012537 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012538 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012539
Eric Andersen90898442003-08-06 11:20:52 +000012540 ap = argv + 1;
12541 if(!*ap)
12542 error("expression expected");
12543 for (ap = argv + 1; *ap; ap++) {
12544 i = dash_arith(*ap);
12545 }
Eric Andersenc470f442003-07-28 09:56:35 +000012546
Eric Andersen90898442003-08-06 11:20:52 +000012547 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012548}
12549#endif /* CONFIG_ASH_MATH_SUPPORT */
12550
12551/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12552
12553/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012554 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012555 */
12556
12557#undef rflag
12558
12559#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012560#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012561typedef enum __rlimit_resource rlim_t;
12562#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012563#endif
12564
12565
Eric Andersenc470f442003-07-28 09:56:35 +000012566/*
12567 * The read builtin. The -e option causes backslashes to escape the
12568 * following character.
12569 *
12570 * This uses unbuffered input, which may be avoidable in some cases.
12571 */
12572
12573static int
12574readcmd(int argc, char **argv)
12575{
12576 char **ap;
12577 int backslash;
12578 char c;
12579 int rflag;
12580 char *prompt;
12581 const char *ifs;
12582 char *p;
12583 int startword;
12584 int status;
12585 int i;
12586
12587 rflag = 0;
12588 prompt = NULL;
12589 while ((i = nextopt("p:r")) != '\0') {
12590 if (i == 'p')
12591 prompt = optionarg;
12592 else
12593 rflag = 1;
12594 }
12595 if (prompt && isatty(0)) {
12596 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012597 }
12598 if (*(ap = argptr) == NULL)
12599 error("arg count");
12600 if ((ifs = bltinlookup("IFS")) == NULL)
12601 ifs = defifs;
12602 status = 0;
12603 startword = 1;
12604 backslash = 0;
12605 STARTSTACKSTR(p);
12606 for (;;) {
12607 if (read(0, &c, 1) != 1) {
12608 status = 1;
12609 break;
12610 }
12611 if (c == '\0')
12612 continue;
12613 if (backslash) {
12614 backslash = 0;
12615 if (c != '\n')
12616 goto put;
12617 continue;
12618 }
12619 if (!rflag && c == '\\') {
12620 backslash++;
12621 continue;
12622 }
12623 if (c == '\n')
12624 break;
12625 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12626 continue;
12627 }
12628 startword = 0;
12629 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12630 STACKSTRNUL(p);
12631 setvar(*ap, stackblock(), 0);
12632 ap++;
12633 startword = 1;
12634 STARTSTACKSTR(p);
12635 } else {
12636put:
12637 STPUTC(c, p);
12638 }
12639 }
12640 STACKSTRNUL(p);
12641 /* Remove trailing blanks */
12642 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12643 *p = '\0';
12644 setvar(*ap, stackblock(), 0);
12645 while (*++ap != NULL)
12646 setvar(*ap, nullstr, 0);
12647 return status;
12648}
12649
12650
12651static int umaskcmd(int argc, char **argv)
12652{
12653 static const char permuser[3] = "ugo";
12654 static const char permmode[3] = "rwx";
12655 static const short int permmask[] = {
12656 S_IRUSR, S_IWUSR, S_IXUSR,
12657 S_IRGRP, S_IWGRP, S_IXGRP,
12658 S_IROTH, S_IWOTH, S_IXOTH
12659 };
12660
12661 char *ap;
12662 mode_t mask;
12663 int i;
12664 int symbolic_mode = 0;
12665
12666 while (nextopt("S") != '\0') {
12667 symbolic_mode = 1;
12668 }
12669
12670 INTOFF;
12671 mask = umask(0);
12672 umask(mask);
12673 INTON;
12674
12675 if ((ap = *argptr) == NULL) {
12676 if (symbolic_mode) {
12677 char buf[18];
12678 char *p = buf;
12679
12680 for (i = 0; i < 3; i++) {
12681 int j;
12682
12683 *p++ = permuser[i];
12684 *p++ = '=';
12685 for (j = 0; j < 3; j++) {
12686 if ((mask & permmask[3 * i + j]) == 0) {
12687 *p++ = permmode[j];
12688 }
12689 }
12690 *p++ = ',';
12691 }
12692 *--p = 0;
12693 puts(buf);
12694 } else {
12695 out1fmt("%.4o\n", mask);
12696 }
12697 } else {
12698 if (is_digit((unsigned char) *ap)) {
12699 mask = 0;
12700 do {
12701 if (*ap >= '8' || *ap < '0')
12702 error(illnum, argv[1]);
12703 mask = (mask << 3) + (*ap - '0');
12704 } while (*++ap != '\0');
12705 umask(mask);
12706 } else {
12707 mask = ~mask & 0777;
12708 if (!bb_parse_mode(ap, &mask)) {
12709 error("Illegal mode: %s", ap);
12710 }
12711 umask(~mask & 0777);
12712 }
12713 }
12714 return 0;
12715}
12716
12717/*
12718 * ulimit builtin
12719 *
12720 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12721 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12722 * ash by J.T. Conklin.
12723 *
12724 * Public domain.
12725 */
12726
12727struct limits {
12728 const char *name;
12729 int cmd;
12730 int factor; /* multiply by to get rlim_{cur,max} values */
12731 char option;
12732};
12733
12734static const struct limits limits[] = {
12735#ifdef RLIMIT_CPU
12736 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12737#endif
12738#ifdef RLIMIT_FSIZE
12739 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12740#endif
12741#ifdef RLIMIT_DATA
12742 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12743#endif
12744#ifdef RLIMIT_STACK
12745 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12746#endif
12747#ifdef RLIMIT_CORE
12748 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12749#endif
12750#ifdef RLIMIT_RSS
12751 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12752#endif
12753#ifdef RLIMIT_MEMLOCK
12754 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12755#endif
12756#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012757 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012758#endif
12759#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012760 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012761#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012762#ifdef RLIMIT_AS
12763 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012764#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012765#ifdef RLIMIT_LOCKS
12766 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012767#endif
12768 { (char *) 0, 0, 0, '\0' }
12769};
12770
Glenn L McGrath76620622004-01-13 10:19:37 +000012771enum limtype { SOFT = 0x1, HARD = 0x2 };
12772
12773static void printlim(enum limtype how, const struct rlimit *limit,
12774 const struct limits *l)
12775{
12776 rlim_t val;
12777
12778 val = limit->rlim_max;
12779 if (how & SOFT)
12780 val = limit->rlim_cur;
12781
12782 if (val == RLIM_INFINITY)
12783 out1fmt("unlimited\n");
12784 else {
12785 val /= l->factor;
12786 out1fmt("%lld\n", (long long) val);
12787 }
12788}
12789
Eric Andersenc470f442003-07-28 09:56:35 +000012790int
12791ulimitcmd(int argc, char **argv)
12792{
12793 int c;
12794 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012795 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012796 const struct limits *l;
12797 int set, all = 0;
12798 int optc, what;
12799 struct rlimit limit;
12800
12801 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012802 while ((optc = nextopt("HSa"
12803#ifdef RLIMIT_CPU
12804 "t"
12805#endif
12806#ifdef RLIMIT_FSIZE
12807 "f"
12808#endif
12809#ifdef RLIMIT_DATA
12810 "d"
12811#endif
12812#ifdef RLIMIT_STACK
12813 "s"
12814#endif
12815#ifdef RLIMIT_CORE
12816 "c"
12817#endif
12818#ifdef RLIMIT_RSS
12819 "m"
12820#endif
12821#ifdef RLIMIT_MEMLOCK
12822 "l"
12823#endif
12824#ifdef RLIMIT_NPROC
12825 "p"
12826#endif
12827#ifdef RLIMIT_NOFILE
12828 "n"
12829#endif
12830#ifdef RLIMIT_AS
12831 "v"
12832#endif
12833#ifdef RLIMIT_LOCKS
12834 "w"
12835#endif
12836 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012837 switch (optc) {
12838 case 'H':
12839 how = HARD;
12840 break;
12841 case 'S':
12842 how = SOFT;
12843 break;
12844 case 'a':
12845 all = 1;
12846 break;
12847 default:
12848 what = optc;
12849 }
12850
Glenn L McGrath76620622004-01-13 10:19:37 +000012851 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012852 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012853
12854 set = *argptr ? 1 : 0;
12855 if (set) {
12856 char *p = *argptr;
12857
12858 if (all || argptr[1])
12859 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012860 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012861 val = RLIM_INFINITY;
12862 else {
12863 val = (rlim_t) 0;
12864
12865 while ((c = *p++) >= '0' && c <= '9')
12866 {
12867 val = (val * 10) + (long)(c - '0');
12868 if (val < (rlim_t) 0)
12869 break;
12870 }
12871 if (c)
12872 error("bad number");
12873 val *= l->factor;
12874 }
12875 }
12876 if (all) {
12877 for (l = limits; l->name; l++) {
12878 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012879 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012880 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012881 }
12882 return 0;
12883 }
12884
12885 getrlimit(l->cmd, &limit);
12886 if (set) {
12887 if (how & HARD)
12888 limit.rlim_max = val;
12889 if (how & SOFT)
12890 limit.rlim_cur = val;
12891 if (setrlimit(l->cmd, &limit) < 0)
12892 error("error setting limit (%m)");
12893 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012894 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012895 }
12896 return 0;
12897}
12898
Eric Andersen90898442003-08-06 11:20:52 +000012899
12900#ifdef CONFIG_ASH_MATH_SUPPORT
12901
12902/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12903
12904 Permission is hereby granted, free of charge, to any person obtaining
12905 a copy of this software and associated documentation files (the
12906 "Software"), to deal in the Software without restriction, including
12907 without limitation the rights to use, copy, modify, merge, publish,
12908 distribute, sublicense, and/or sell copies of the Software, and to
12909 permit persons to whom the Software is furnished to do so, subject to
12910 the following conditions:
12911
12912 The above copyright notice and this permission notice shall be
12913 included in all copies or substantial portions of the Software.
12914
12915 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12916 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12917 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12918 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12919 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12920 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12921 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12922*/
12923
12924/* This is my infix parser/evaluator. It is optimized for size, intended
12925 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000012926 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000012927 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000012928 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000012929 * be that which POSIX specifies for shells. */
12930
12931/* The code uses a simple two-stack algorithm. See
12932 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000012933 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000012934 * this is based (this code differs in that it applies operators immediately
12935 * to the stack instead of adding them to a queue to end up with an
12936 * expression). */
12937
12938/* To use the routine, call it with an expression string and error return
12939 * pointer */
12940
12941/*
12942 * Aug 24, 2001 Manuel Novoa III
12943 *
12944 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12945 *
12946 * 1) In arith_apply():
12947 * a) Cached values of *numptr and &(numptr[-1]).
12948 * b) Removed redundant test for zero denominator.
12949 *
12950 * 2) In arith():
12951 * a) Eliminated redundant code for processing operator tokens by moving
12952 * to a table-based implementation. Also folded handling of parens
12953 * into the table.
12954 * b) Combined all 3 loops which called arith_apply to reduce generated
12955 * code size at the cost of speed.
12956 *
12957 * 3) The following expressions were treated as valid by the original code:
12958 * 1() , 0! , 1 ( *3 ) .
12959 * These bugs have been fixed by internally enclosing the expression in
12960 * parens and then checking that all binary ops and right parens are
12961 * preceded by a valid expression (NUM_TOKEN).
12962 *
Eric Andersenaff114c2004-04-14 17:51:38 +000012963 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000012964 * ctype's isspace() if it is used by another busybox applet or if additional
12965 * whitespace chars should be considered. Look below the "#include"s for a
12966 * precompiler test.
12967 */
12968
12969/*
12970 * Aug 26, 2001 Manuel Novoa III
12971 *
12972 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12973 *
12974 * Merge in Aaron's comments previously posted to the busybox list,
12975 * modified slightly to take account of my changes to the code.
12976 *
12977 */
12978
12979/*
12980 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12981 *
12982 * - allow access to variable,
12983 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12984 * - realize assign syntax (VAR=expr, +=, *= etc)
12985 * - realize exponentiation (** operator)
12986 * - realize comma separated - expr, expr
12987 * - realise ++expr --expr expr++ expr--
12988 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000012989 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000012990 * - was restored loses XOR operator
12991 * - remove one goto label, added three ;-)
12992 * - protect $((num num)) as true zero expr (Manuel`s error)
12993 * - always use special isspace(), see comment from bash ;-)
12994 */
12995
12996
12997#define arith_isspace(arithval) \
12998 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12999
13000
13001typedef unsigned char operator;
13002
13003/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013004 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013005 * precedence. The ID portion is so that multiple operators can have the
13006 * same precedence, ensuring that the leftmost one is evaluated first.
13007 * Consider * and /. */
13008
13009#define tok_decl(prec,id) (((id)<<5)|(prec))
13010#define PREC(op) ((op) & 0x1F)
13011
13012#define TOK_LPAREN tok_decl(0,0)
13013
13014#define TOK_COMMA tok_decl(1,0)
13015
13016#define TOK_ASSIGN tok_decl(2,0)
13017#define TOK_AND_ASSIGN tok_decl(2,1)
13018#define TOK_OR_ASSIGN tok_decl(2,2)
13019#define TOK_XOR_ASSIGN tok_decl(2,3)
13020#define TOK_PLUS_ASSIGN tok_decl(2,4)
13021#define TOK_MINUS_ASSIGN tok_decl(2,5)
13022#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13023#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13024
13025#define TOK_MUL_ASSIGN tok_decl(3,0)
13026#define TOK_DIV_ASSIGN tok_decl(3,1)
13027#define TOK_REM_ASSIGN tok_decl(3,2)
13028
13029/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13030#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13031
13032/* conditional is right associativity too */
13033#define TOK_CONDITIONAL tok_decl(4,0)
13034#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13035
13036#define TOK_OR tok_decl(5,0)
13037
13038#define TOK_AND tok_decl(6,0)
13039
13040#define TOK_BOR tok_decl(7,0)
13041
13042#define TOK_BXOR tok_decl(8,0)
13043
13044#define TOK_BAND tok_decl(9,0)
13045
13046#define TOK_EQ tok_decl(10,0)
13047#define TOK_NE tok_decl(10,1)
13048
13049#define TOK_LT tok_decl(11,0)
13050#define TOK_GT tok_decl(11,1)
13051#define TOK_GE tok_decl(11,2)
13052#define TOK_LE tok_decl(11,3)
13053
13054#define TOK_LSHIFT tok_decl(12,0)
13055#define TOK_RSHIFT tok_decl(12,1)
13056
13057#define TOK_ADD tok_decl(13,0)
13058#define TOK_SUB tok_decl(13,1)
13059
13060#define TOK_MUL tok_decl(14,0)
13061#define TOK_DIV tok_decl(14,1)
13062#define TOK_REM tok_decl(14,2)
13063
13064/* exponent is right associativity */
13065#define TOK_EXPONENT tok_decl(15,1)
13066
13067/* For now unary operators. */
13068#define UNARYPREC 16
13069#define TOK_BNOT tok_decl(UNARYPREC,0)
13070#define TOK_NOT tok_decl(UNARYPREC,1)
13071
13072#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13073#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13074
13075#define PREC_PRE (UNARYPREC+2)
13076
13077#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13078#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13079
13080#define PREC_POST (UNARYPREC+3)
13081
13082#define TOK_POST_INC tok_decl(PREC_POST, 0)
13083#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13084
13085#define SPEC_PREC (UNARYPREC+4)
13086
13087#define TOK_NUM tok_decl(SPEC_PREC, 0)
13088#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13089
13090#define NUMPTR (*numstackptr)
13091
13092static inline int tok_have_assign(operator op)
13093{
13094 operator prec = PREC(op);
13095
13096 convert_prec_is_assing(prec);
13097 return (prec == PREC(TOK_ASSIGN) ||
13098 prec == PREC_PRE || prec == PREC_POST);
13099}
13100
13101static inline int is_right_associativity(operator prec)
13102{
13103 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13104 prec == PREC(TOK_CONDITIONAL));
13105}
13106
13107
13108typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013109 arith_t val;
13110 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013111 char contidional_second_val_initialized;
13112 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013113 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013114} v_n_t;
13115
13116
13117typedef struct CHK_VAR_RECURSIVE_LOOPED {
13118 const char *var;
13119 struct CHK_VAR_RECURSIVE_LOOPED *next;
13120} chk_var_recursive_looped_t;
13121
13122static chk_var_recursive_looped_t *prev_chk_var_recursive;
13123
13124
13125static int arith_lookup_val(v_n_t *t)
13126{
13127 if(t->var) {
13128 const char * p = lookupvar(t->var);
13129
13130 if(p) {
13131 int errcode;
13132
13133 /* recursive try as expression */
13134 chk_var_recursive_looped_t *cur;
13135 chk_var_recursive_looped_t cur_save;
13136
13137 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13138 if(strcmp(cur->var, t->var) == 0) {
13139 /* expression recursion loop detected */
13140 return -5;
13141 }
13142 }
13143 /* save current lookuped var name */
13144 cur = prev_chk_var_recursive;
13145 cur_save.var = t->var;
13146 cur_save.next = cur;
13147 prev_chk_var_recursive = &cur_save;
13148
13149 t->val = arith (p, &errcode);
13150 /* restore previous ptr after recursiving */
13151 prev_chk_var_recursive = cur;
13152 return errcode;
13153 } else {
13154 /* allow undefined var as 0 */
13155 t->val = 0;
13156 }
13157 }
13158 return 0;
13159}
13160
13161/* "applying" a token means performing it on the top elements on the integer
13162 * stack. For a unary operator it will only change the top element, but a
13163 * binary operator will pop two arguments and push a result */
13164static inline int
13165arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13166{
Eric Andersen90898442003-08-06 11:20:52 +000013167 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013168 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013169 int ret_arith_lookup_val;
13170
13171 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13172 without arguments */
13173 numptr_m1 = NUMPTR - 1;
13174
13175 /* check operand is var with noninteger value */
13176 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13177 if(ret_arith_lookup_val)
13178 return ret_arith_lookup_val;
13179
13180 rez = numptr_m1->val;
13181 if (op == TOK_UMINUS)
13182 rez *= -1;
13183 else if (op == TOK_NOT)
13184 rez = !rez;
13185 else if (op == TOK_BNOT)
13186 rez = ~rez;
13187 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13188 rez++;
13189 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13190 rez--;
13191 else if (op != TOK_UPLUS) {
13192 /* Binary operators */
13193
13194 /* check and binary operators need two arguments */
13195 if (numptr_m1 == numstack) goto err;
13196
13197 /* ... and they pop one */
13198 --NUMPTR;
13199 numptr_val = rez;
13200 if (op == TOK_CONDITIONAL) {
13201 if(! numptr_m1->contidional_second_val_initialized) {
13202 /* protect $((expr1 ? expr2)) without ": expr" */
13203 goto err;
13204 }
13205 rez = numptr_m1->contidional_second_val;
13206 } else if(numptr_m1->contidional_second_val_initialized) {
13207 /* protect $((expr1 : expr2)) without "expr ? " */
13208 goto err;
13209 }
13210 numptr_m1 = NUMPTR - 1;
13211 if(op != TOK_ASSIGN) {
13212 /* check operand is var with noninteger value for not '=' */
13213 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13214 if(ret_arith_lookup_val)
13215 return ret_arith_lookup_val;
13216 }
13217 if (op == TOK_CONDITIONAL) {
13218 numptr_m1->contidional_second_val = rez;
13219 }
13220 rez = numptr_m1->val;
13221 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13222 rez |= numptr_val;
13223 else if (op == TOK_OR)
13224 rez = numptr_val || rez;
13225 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13226 rez &= numptr_val;
13227 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13228 rez ^= numptr_val;
13229 else if (op == TOK_AND)
13230 rez = rez && numptr_val;
13231 else if (op == TOK_EQ)
13232 rez = (rez == numptr_val);
13233 else if (op == TOK_NE)
13234 rez = (rez != numptr_val);
13235 else if (op == TOK_GE)
13236 rez = (rez >= numptr_val);
13237 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13238 rez >>= numptr_val;
13239 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13240 rez <<= numptr_val;
13241 else if (op == TOK_GT)
13242 rez = (rez > numptr_val);
13243 else if (op == TOK_LT)
13244 rez = (rez < numptr_val);
13245 else if (op == TOK_LE)
13246 rez = (rez <= numptr_val);
13247 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13248 rez *= numptr_val;
13249 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13250 rez += numptr_val;
13251 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13252 rez -= numptr_val;
13253 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13254 rez = numptr_val;
13255 else if (op == TOK_CONDITIONAL_SEP) {
13256 if (numptr_m1 == numstack) {
13257 /* protect $((expr : expr)) without "expr ? " */
13258 goto err;
13259 }
13260 numptr_m1->contidional_second_val_initialized = op;
13261 numptr_m1->contidional_second_val = numptr_val;
13262 }
13263 else if (op == TOK_CONDITIONAL) {
13264 rez = rez ?
13265 numptr_val : numptr_m1->contidional_second_val;
13266 }
13267 else if(op == TOK_EXPONENT) {
13268 if(numptr_val < 0)
13269 return -3; /* exponent less than 0 */
13270 else {
13271 long c = 1;
13272
13273 if(numptr_val)
13274 while(numptr_val--)
13275 c *= rez;
13276 rez = c;
13277 }
13278 }
13279 else if(numptr_val==0) /* zero divisor check */
13280 return -2;
13281 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13282 rez /= numptr_val;
13283 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13284 rez %= numptr_val;
13285 }
13286 if(tok_have_assign(op)) {
13287 char buf[32];
13288
13289 if(numptr_m1->var == NULL) {
13290 /* Hmm, 1=2 ? */
13291 goto err;
13292 }
13293 /* save to shell variable */
Eric Andersened9ecf72004-06-22 08:29:45 +000013294 sprintf(buf, "%lld", (long long) rez);
Eric Andersen90898442003-08-06 11:20:52 +000013295 setvar(numptr_m1->var, buf, 0);
13296 /* after saving, make previous value for v++ or v-- */
13297 if(op == TOK_POST_INC)
13298 rez--;
13299 else if(op == TOK_POST_DEC)
13300 rez++;
13301 }
13302 numptr_m1->val = rez;
13303 /* protect geting var value, is number now */
13304 numptr_m1->var = NULL;
13305 return 0;
13306err: return(-1);
13307}
13308
13309/* longest must first */
13310static const char op_tokens[] = {
13311 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13312 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13313 '<','<', 0, TOK_LSHIFT,
13314 '>','>', 0, TOK_RSHIFT,
13315 '|','|', 0, TOK_OR,
13316 '&','&', 0, TOK_AND,
13317 '!','=', 0, TOK_NE,
13318 '<','=', 0, TOK_LE,
13319 '>','=', 0, TOK_GE,
13320 '=','=', 0, TOK_EQ,
13321 '|','=', 0, TOK_OR_ASSIGN,
13322 '&','=', 0, TOK_AND_ASSIGN,
13323 '*','=', 0, TOK_MUL_ASSIGN,
13324 '/','=', 0, TOK_DIV_ASSIGN,
13325 '%','=', 0, TOK_REM_ASSIGN,
13326 '+','=', 0, TOK_PLUS_ASSIGN,
13327 '-','=', 0, TOK_MINUS_ASSIGN,
13328 '-','-', 0, TOK_POST_DEC,
13329 '^','=', 0, TOK_XOR_ASSIGN,
13330 '+','+', 0, TOK_POST_INC,
13331 '*','*', 0, TOK_EXPONENT,
13332 '!', 0, TOK_NOT,
13333 '<', 0, TOK_LT,
13334 '>', 0, TOK_GT,
13335 '=', 0, TOK_ASSIGN,
13336 '|', 0, TOK_BOR,
13337 '&', 0, TOK_BAND,
13338 '*', 0, TOK_MUL,
13339 '/', 0, TOK_DIV,
13340 '%', 0, TOK_REM,
13341 '+', 0, TOK_ADD,
13342 '-', 0, TOK_SUB,
13343 '^', 0, TOK_BXOR,
13344 /* uniq */
13345 '~', 0, TOK_BNOT,
13346 ',', 0, TOK_COMMA,
13347 '?', 0, TOK_CONDITIONAL,
13348 ':', 0, TOK_CONDITIONAL_SEP,
13349 ')', 0, TOK_RPAREN,
13350 '(', 0, TOK_LPAREN,
13351 0
13352};
13353/* ptr to ")" */
13354#define endexpression &op_tokens[sizeof(op_tokens)-7]
13355
13356
Eric Andersened9ecf72004-06-22 08:29:45 +000013357static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013358{
13359 register char arithval; /* Current character under analysis */
13360 operator lasttok, op;
13361 operator prec;
13362
13363 const char *p = endexpression;
13364 int errcode;
13365
13366 size_t datasizes = strlen(expr) + 2;
13367
13368 /* Stack of integers */
13369 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013370 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013371 * the reader. */
13372 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13373 *numstackptr = numstack;
13374 /* Stack of operator tokens */
13375 operator *stack = alloca((datasizes) * sizeof(operator)),
13376 *stackptr = stack;
13377
13378 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13379 *perrcode = errcode = 0;
13380
13381 while(1) {
13382 if ((arithval = *expr) == 0) {
13383 if (p == endexpression) {
13384 /* Null expression. */
13385 return 0;
13386 }
13387
13388 /* This is only reached after all tokens have been extracted from the
13389 * input stream. If there are still tokens on the operator stack, they
13390 * are to be applied in order. At the end, there should be a final
13391 * result on the integer stack */
13392
13393 if (expr != endexpression + 1) {
13394 /* If we haven't done so already, */
13395 /* append a closing right paren */
13396 expr = endexpression;
13397 /* and let the loop process it. */
13398 continue;
13399 }
13400 /* At this point, we're done with the expression. */
13401 if (numstackptr != numstack+1) {
13402 /* ... but if there isn't, it's bad */
13403 err:
13404 return (*perrcode = -1);
13405 }
13406 if(numstack->var) {
13407 /* expression is $((var)) only, lookup now */
13408 errcode = arith_lookup_val(numstack);
13409 }
13410 ret:
13411 *perrcode = errcode;
13412 return numstack->val;
13413 } else {
13414 /* Continue processing the expression. */
13415 if (arith_isspace(arithval)) {
13416 /* Skip whitespace */
13417 goto prologue;
13418 }
13419 if((p = endofname(expr)) != expr) {
13420 int var_name_size = (p-expr) + 1; /* trailing zero */
13421
13422 numstackptr->var = alloca(var_name_size);
13423 safe_strncpy(numstackptr->var, expr, var_name_size);
13424 expr = p;
13425 num:
13426 numstackptr->contidional_second_val_initialized = 0;
13427 numstackptr++;
13428 lasttok = TOK_NUM;
13429 continue;
13430 } else if (is_digit(arithval)) {
13431 numstackptr->var = NULL;
13432 numstackptr->val = strtol(expr, (char **) &expr, 0);
13433 goto num;
13434 }
13435 for(p = op_tokens; ; p++) {
13436 const char *o;
13437
13438 if(*p == 0) {
13439 /* strange operator not found */
13440 goto err;
13441 }
13442 for(o = expr; *p && *o == *p; p++)
13443 o++;
13444 if(! *p) {
13445 /* found */
13446 expr = o - 1;
13447 break;
13448 }
13449 /* skip tail uncompared token */
13450 while(*p)
13451 p++;
13452 /* skip zero delim */
13453 p++;
13454 }
13455 op = p[1];
13456
13457 /* post grammar: a++ reduce to num */
13458 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13459 lasttok = TOK_NUM;
13460
13461 /* Plus and minus are binary (not unary) _only_ if the last
13462 * token was as number, or a right paren (which pretends to be
13463 * a number, since it evaluates to one). Think about it.
13464 * It makes sense. */
13465 if (lasttok != TOK_NUM) {
13466 switch(op) {
13467 case TOK_ADD:
13468 op = TOK_UPLUS;
13469 break;
13470 case TOK_SUB:
13471 op = TOK_UMINUS;
13472 break;
13473 case TOK_POST_INC:
13474 op = TOK_PRE_INC;
13475 break;
13476 case TOK_POST_DEC:
13477 op = TOK_PRE_DEC;
13478 break;
13479 }
13480 }
13481 /* We don't want a unary operator to cause recursive descent on the
13482 * stack, because there can be many in a row and it could cause an
13483 * operator to be evaluated before its argument is pushed onto the
13484 * integer stack. */
13485 /* But for binary operators, "apply" everything on the operator
13486 * stack until we find an operator with a lesser priority than the
13487 * one we have just extracted. */
13488 /* Left paren is given the lowest priority so it will never be
13489 * "applied" in this way.
13490 * if associativity is right and priority eq, applied also skip
13491 */
13492 prec = PREC(op);
13493 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13494 /* not left paren or unary */
13495 if (lasttok != TOK_NUM) {
13496 /* binary op must be preceded by a num */
13497 goto err;
13498 }
13499 while (stackptr != stack) {
13500 if (op == TOK_RPAREN) {
13501 /* The algorithm employed here is simple: while we don't
13502 * hit an open paren nor the bottom of the stack, pop
13503 * tokens and apply them */
13504 if (stackptr[-1] == TOK_LPAREN) {
13505 --stackptr;
13506 /* Any operator directly after a */
13507 lasttok = TOK_NUM;
13508 /* close paren should consider itself binary */
13509 goto prologue;
13510 }
13511 } else {
13512 operator prev_prec = PREC(stackptr[-1]);
13513
13514 convert_prec_is_assing(prec);
13515 convert_prec_is_assing(prev_prec);
13516 if (prev_prec < prec)
13517 break;
13518 /* check right assoc */
13519 if(prev_prec == prec && is_right_associativity(prec))
13520 break;
13521 }
13522 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13523 if(errcode) goto ret;
13524 }
13525 if (op == TOK_RPAREN) {
13526 goto err;
13527 }
13528 }
13529
13530 /* Push this operator to the stack and remember it. */
13531 *stackptr++ = lasttok = op;
13532
13533 prologue:
13534 ++expr;
13535 }
13536 }
13537}
13538#endif /* CONFIG_ASH_MATH_SUPPORT */
13539
13540
Eric Andersenc470f442003-07-28 09:56:35 +000013541#ifdef DEBUG
13542const char *bb_applet_name = "debug stuff usage";
13543int main(int argc, char **argv)
13544{
13545 return ash_main(argc, argv);
13546}
13547#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013548
Eric Andersendf82f612001-06-28 07:46:40 +000013549/*-
13550 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013551 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013552 *
13553 * This code is derived from software contributed to Berkeley by
13554 * Kenneth Almquist.
13555 *
13556 * Redistribution and use in source and binary forms, with or without
13557 * modification, are permitted provided that the following conditions
13558 * are met:
13559 * 1. Redistributions of source code must retain the above copyright
13560 * notice, this list of conditions and the following disclaimer.
13561 * 2. Redistributions in binary form must reproduce the above copyright
13562 * notice, this list of conditions and the following disclaimer in the
13563 * documentation and/or other materials provided with the distribution.
13564 *
Eric Andersen2870d962001-07-02 17:27:21 +000013565 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13566 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013567 *
13568 * 4. Neither the name of the University nor the names of its contributors
13569 * may be used to endorse or promote products derived from this software
13570 * without specific prior written permission.
13571 *
13572 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13573 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13574 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13575 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13576 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13577 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13578 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13579 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13580 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13581 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13582 * SUCH DAMAGE.
13583 */