blob: f82a77258632ccc5b34fa68f888ddf8a45dabec3 [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 Andersen4a79c0e2004-09-08 10:01:07 +00006053#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006054 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006055#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006056 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6057 if(nr == 0) {
6058 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006059 if(trap[SIGINT]) {
6060 buf[0] = '\n';
6061 buf[1] = 0;
6062 raise(SIGINT);
6063 return 1;
6064 }
Eric Andersenc470f442003-07-28 09:56:35 +00006065 goto retry;
6066 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006067 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006068 /* Ctrl+D presend */
6069 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006070 }
Eric Andersencb57d552001-06-28 07:25:16 +00006071 }
6072#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006073 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006074#endif
6075
6076 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006077 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6078 int flags = fcntl(0, F_GETFL, 0);
6079 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006080 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006081 if (fcntl(0, F_SETFL, flags) >= 0) {
6082 out2str("sh: turning off NDELAY mode\n");
6083 goto retry;
6084 }
6085 }
6086 }
6087 }
6088 return nr;
6089}
6090
6091/*
6092 * Refill the input buffer and return the next input character:
6093 *
6094 * 1) If a string was pushed back on the input, pop it;
6095 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6096 * from a string so we can't refill the buffer, return EOF.
6097 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6098 * 4) Process input up to the next newline, deleting nul characters.
6099 */
6100
Eric Andersenc470f442003-07-28 09:56:35 +00006101int
6102preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006103{
6104 char *p, *q;
6105 int more;
6106 char savec;
6107
6108 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006109#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006110 if (parsenleft == -1 && parsefile->strpush->ap &&
6111 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006112 return PEOA;
6113 }
Eric Andersen2870d962001-07-02 17:27:21 +00006114#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006115 popstring();
6116 if (--parsenleft >= 0)
6117 return (*parsenextc++);
6118 }
6119 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6120 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006121 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006122
Eric Andersenc470f442003-07-28 09:56:35 +00006123again:
Eric Andersencb57d552001-06-28 07:25:16 +00006124 if (parselleft <= 0) {
6125 if ((parselleft = preadfd()) <= 0) {
6126 parselleft = parsenleft = EOF_NLEFT;
6127 return PEOF;
6128 }
6129 }
6130
6131 q = p = parsenextc;
6132
6133 /* delete nul characters */
6134 for (more = 1; more;) {
6135 switch (*p) {
6136 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006137 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006138 goto check;
6139
Eric Andersencb57d552001-06-28 07:25:16 +00006140 case '\n':
6141 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006142 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006143 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006144
Eric Andersencb57d552001-06-28 07:25:16 +00006145 }
6146
6147 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006148check:
Eric Andersencb57d552001-06-28 07:25:16 +00006149 if (--parselleft <= 0 && more) {
6150 parsenleft = q - parsenextc - 1;
6151 if (parsenleft < 0)
6152 goto again;
6153 more = 0;
6154 }
6155 }
6156
6157 savec = *q;
6158 *q = '\0';
6159
6160 if (vflag) {
6161 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006162 }
6163
6164 *q = savec;
6165
6166 return *parsenextc++;
6167}
6168
Eric Andersenc470f442003-07-28 09:56:35 +00006169/*
6170 * Undo the last call to pgetc. Only one character may be pushed back.
6171 * PEOF may be pushed back.
6172 */
6173
6174void
6175pungetc(void)
6176{
6177 parsenleft++;
6178 parsenextc--;
6179}
Eric Andersencb57d552001-06-28 07:25:16 +00006180
6181/*
6182 * Push a string back onto the input at this current parsefile level.
6183 * We handle aliases this way.
6184 */
Eric Andersenc470f442003-07-28 09:56:35 +00006185void
6186pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006187{
Eric Andersencb57d552001-06-28 07:25:16 +00006188 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006189 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006190
Eric Andersenc470f442003-07-28 09:56:35 +00006191 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006192 INTOFF;
6193/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6194 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006195 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006196 sp->prev = parsefile->strpush;
6197 parsefile->strpush = sp;
6198 } else
6199 sp = parsefile->strpush = &(parsefile->basestrpush);
6200 sp->prevstring = parsenextc;
6201 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006202#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006203 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006204 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006205 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006206 sp->string = s;
6207 }
Eric Andersen2870d962001-07-02 17:27:21 +00006208#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006209 parsenextc = s;
6210 parsenleft = len;
6211 INTON;
6212}
6213
Eric Andersenc470f442003-07-28 09:56:35 +00006214void
6215popstring(void)
6216{
6217 struct strpush *sp = parsefile->strpush;
6218
6219 INTOFF;
6220#ifdef CONFIG_ASH_ALIAS
6221 if (sp->ap) {
6222 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6223 checkkwd |= CHKALIAS;
6224 }
6225 if (sp->string != sp->ap->val) {
6226 ckfree(sp->string);
6227 }
6228 sp->ap->flag &= ~ALIASINUSE;
6229 if (sp->ap->flag & ALIASDEAD) {
6230 unalias(sp->ap->name);
6231 }
6232 }
6233#endif
6234 parsenextc = sp->prevstring;
6235 parsenleft = sp->prevnleft;
6236/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6237 parsefile->strpush = sp->prev;
6238 if (sp != &(parsefile->basestrpush))
6239 ckfree(sp);
6240 INTON;
6241}
6242
6243/*
6244 * Set the input to take input from a file. If push is set, push the
6245 * old input onto the stack first.
6246 */
6247
6248void
6249setinputfile(const char *fname, int push)
6250{
6251 int fd;
6252 int fd2;
6253
6254 INTOFF;
6255 if ((fd = open(fname, O_RDONLY)) < 0)
6256 error("Can't open %s", fname);
6257 if (fd < 10) {
6258 fd2 = copyfd(fd, 10);
6259 close(fd);
6260 if (fd2 < 0)
6261 error("Out of file descriptors");
6262 fd = fd2;
6263 }
6264 setinputfd(fd, push);
6265 INTON;
6266}
6267
6268
6269/*
6270 * Like setinputfile, but takes an open file descriptor. Call this with
6271 * interrupts off.
6272 */
6273
6274static void
6275setinputfd(int fd, int push)
6276{
6277 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6278 if (push) {
6279 pushfile();
6280 parsefile->buf = 0;
6281 }
6282 parsefile->fd = fd;
6283 if (parsefile->buf == NULL)
6284 parsefile->buf = ckmalloc(IBUFSIZ);
6285 parselleft = parsenleft = 0;
6286 plinno = 1;
6287}
6288
Eric Andersencb57d552001-06-28 07:25:16 +00006289
Eric Andersencb57d552001-06-28 07:25:16 +00006290/*
6291 * Like setinputfile, but takes input from a string.
6292 */
6293
Eric Andersenc470f442003-07-28 09:56:35 +00006294static void
6295setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006296{
Eric Andersencb57d552001-06-28 07:25:16 +00006297 INTOFF;
6298 pushfile();
6299 parsenextc = string;
6300 parsenleft = strlen(string);
6301 parsefile->buf = NULL;
6302 plinno = 1;
6303 INTON;
6304}
6305
6306
Eric Andersencb57d552001-06-28 07:25:16 +00006307/*
6308 * To handle the "." command, a stack of input files is used. Pushfile
6309 * adds a new entry to the stack and popfile restores the previous level.
6310 */
6311
Eric Andersenc470f442003-07-28 09:56:35 +00006312static void
6313pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006314{
Eric Andersencb57d552001-06-28 07:25:16 +00006315 struct parsefile *pf;
6316
6317 parsefile->nleft = parsenleft;
6318 parsefile->lleft = parselleft;
6319 parsefile->nextc = parsenextc;
6320 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006321 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006322 pf->prev = parsefile;
6323 pf->fd = -1;
6324 pf->strpush = NULL;
6325 pf->basestrpush.prev = NULL;
6326 parsefile = pf;
6327}
6328
Eric Andersenc470f442003-07-28 09:56:35 +00006329
6330static void
6331popfile(void)
6332{
6333 struct parsefile *pf = parsefile;
6334
6335 INTOFF;
6336 if (pf->fd >= 0)
6337 close(pf->fd);
6338 if (pf->buf)
6339 ckfree(pf->buf);
6340 while (pf->strpush)
6341 popstring();
6342 parsefile = pf->prev;
6343 ckfree(pf);
6344 parsenleft = parsefile->nleft;
6345 parselleft = parsefile->lleft;
6346 parsenextc = parsefile->nextc;
6347 plinno = parsefile->linno;
6348 INTON;
6349}
Eric Andersencb57d552001-06-28 07:25:16 +00006350
6351
Eric Andersen2870d962001-07-02 17:27:21 +00006352/*
Eric Andersenc470f442003-07-28 09:56:35 +00006353 * Return to top level.
6354 */
Eric Andersen2870d962001-07-02 17:27:21 +00006355
Eric Andersenc470f442003-07-28 09:56:35 +00006356static void
6357popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006358{
Eric Andersenc470f442003-07-28 09:56:35 +00006359 while (parsefile != &basepf)
6360 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006361}
6362
Eric Andersen2870d962001-07-02 17:27:21 +00006363
Eric Andersenc470f442003-07-28 09:56:35 +00006364/*
6365 * Close the file(s) that the shell is reading commands from. Called
6366 * after a fork is done.
6367 */
6368
6369static void
6370closescript(void)
6371{
6372 popallfiles();
6373 if (parsefile->fd > 0) {
6374 close(parsefile->fd);
6375 parsefile->fd = 0;
6376 }
6377}
Eric Andersenc470f442003-07-28 09:56:35 +00006378
Eric Andersen90898442003-08-06 11:20:52 +00006379/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006380
6381/* mode flags for set_curjob */
6382#define CUR_DELETE 2
6383#define CUR_RUNNING 1
6384#define CUR_STOPPED 0
6385
6386/* mode flags for dowait */
6387#define DOWAIT_NORMAL 0
6388#define DOWAIT_BLOCK 1
6389
6390/* array of jobs */
6391static struct job *jobtab;
6392/* size of array */
6393static unsigned njobs;
6394#if JOBS
6395/* pgrp of shell on invocation */
6396static int initialpgrp;
6397static int ttyfd = -1;
6398#endif
6399/* current job */
6400static struct job *curjob;
6401/* number of presumed living untracked jobs */
6402static int jobless;
6403
6404static void set_curjob(struct job *, unsigned);
6405#if JOBS
6406static int restartjob(struct job *, int);
6407static void xtcsetpgrp(int, pid_t);
6408static char *commandtext(union node *);
6409static void cmdlist(union node *, int);
6410static void cmdtxt(union node *);
6411static void cmdputs(const char *);
6412static void showpipe(struct job *, FILE *);
6413#endif
6414static int sprint_status(char *, int, int);
6415static void freejob(struct job *);
6416static struct job *getjob(const char *, int);
6417static struct job *growjobtab(void);
6418static void forkchild(struct job *, union node *, int);
6419static void forkparent(struct job *, union node *, int, pid_t);
6420static int dowait(int, struct job *);
6421static int getstatus(struct job *);
6422
6423static void
6424set_curjob(struct job *jp, unsigned mode)
6425{
6426 struct job *jp1;
6427 struct job **jpp, **curp;
6428
6429 /* first remove from list */
6430 jpp = curp = &curjob;
6431 do {
6432 jp1 = *jpp;
6433 if (jp1 == jp)
6434 break;
6435 jpp = &jp1->prev_job;
6436 } while (1);
6437 *jpp = jp1->prev_job;
6438
6439 /* Then re-insert in correct position */
6440 jpp = curp;
6441 switch (mode) {
6442 default:
6443#ifdef DEBUG
6444 abort();
6445#endif
6446 case CUR_DELETE:
6447 /* job being deleted */
6448 break;
6449 case CUR_RUNNING:
6450 /* newly created job or backgrounded job,
6451 put after all stopped jobs. */
6452 do {
6453 jp1 = *jpp;
6454#ifdef JOBS
6455 if (!jp1 || jp1->state != JOBSTOPPED)
6456#endif
6457 break;
6458 jpp = &jp1->prev_job;
6459 } while (1);
6460 /* FALLTHROUGH */
6461#ifdef JOBS
6462 case CUR_STOPPED:
6463#endif
6464 /* newly stopped job - becomes curjob */
6465 jp->prev_job = *jpp;
6466 *jpp = jp;
6467 break;
6468 }
6469}
6470
6471#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006472/*
6473 * Turn job control on and off.
6474 *
6475 * Note: This code assumes that the third arg to ioctl is a character
6476 * pointer, which is true on Berkeley systems but not System V. Since
6477 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006478 *
6479 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006480 */
6481
Eric Andersenc470f442003-07-28 09:56:35 +00006482void
6483setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006484{
Eric Andersenc470f442003-07-28 09:56:35 +00006485 int fd;
6486 int pgrp;
6487
6488 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006489 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006490 if (on) {
6491 int ofd;
6492 ofd = fd = open(_PATH_TTY, O_RDWR);
6493 if (fd < 0) {
6494 fd += 3;
6495 while (!isatty(fd) && --fd >= 0)
6496 ;
6497 }
6498 fd = fcntl(fd, F_DUPFD, 10);
6499 close(ofd);
6500 if (fd < 0)
6501 goto out;
6502 fcntl(fd, F_SETFD, FD_CLOEXEC);
6503 do { /* while we are in the background */
6504 if ((pgrp = tcgetpgrp(fd)) < 0) {
6505out:
6506 sh_warnx("can't access tty; job control turned off");
6507 mflag = on = 0;
6508 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006509 }
Eric Andersenc470f442003-07-28 09:56:35 +00006510 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006511 break;
6512 killpg(0, SIGTTIN);
6513 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006514 initialpgrp = pgrp;
6515
Eric Andersencb57d552001-06-28 07:25:16 +00006516 setsignal(SIGTSTP);
6517 setsignal(SIGTTOU);
6518 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006519 pgrp = rootpid;
6520 setpgid(0, pgrp);
6521 xtcsetpgrp(fd, pgrp);
6522 } else {
6523 /* turning job control off */
6524 fd = ttyfd;
6525 pgrp = initialpgrp;
6526 xtcsetpgrp(fd, pgrp);
6527 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006528 setsignal(SIGTSTP);
6529 setsignal(SIGTTOU);
6530 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006531close:
6532 close(fd);
6533 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006534 }
Eric Andersenc470f442003-07-28 09:56:35 +00006535 ttyfd = fd;
6536 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006537}
Eric Andersencb57d552001-06-28 07:25:16 +00006538
Eric Andersenc470f442003-07-28 09:56:35 +00006539static int
Eric Andersen90898442003-08-06 11:20:52 +00006540killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006541{
6542 int signo = -1;
6543 int list = 0;
6544 int i;
6545 pid_t pid;
6546 struct job *jp;
6547
6548 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006549usage:
6550 error(
6551"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6552"kill -l [exitstatus]"
6553 );
Eric Andersencb57d552001-06-28 07:25:16 +00006554 }
6555
Eric Andersenc470f442003-07-28 09:56:35 +00006556 if (**++argv == '-') {
6557 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006558 if (signo < 0) {
6559 int c;
6560
6561 while ((c = nextopt("ls:")) != '\0')
6562 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006563 default:
6564#ifdef DEBUG
6565 abort();
6566#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006567 case 'l':
6568 list = 1;
6569 break;
6570 case 's':
6571 signo = decode_signal(optionarg, 1);
6572 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006573 error(
6574 "invalid signal number or name: %s",
6575 optionarg
6576 );
Eric Andersencb57d552001-06-28 07:25:16 +00006577 }
Eric Andersen2870d962001-07-02 17:27:21 +00006578 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006579 }
Eric Andersenc470f442003-07-28 09:56:35 +00006580 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006581 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006582 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006583 }
6584
6585 if (!list && signo < 0)
6586 signo = SIGTERM;
6587
Eric Andersenc470f442003-07-28 09:56:35 +00006588 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006589 goto usage;
6590 }
6591
6592 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006593 const char *name;
6594
Eric Andersenc470f442003-07-28 09:56:35 +00006595 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006596 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006597 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006598 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006599 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006600 }
6601 return 0;
6602 }
Eric Andersen34506362001-08-02 05:02:46 +00006603 name = u_signal_names(*argptr, &signo, -1);
6604 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006605 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006606 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006607 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006608 return 0;
6609 }
6610
Eric Andersenc470f442003-07-28 09:56:35 +00006611 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006612 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006613 if (**argv == '%') {
6614 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006615 pid = -jp->ps[0].pid;
6616 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006617 pid = number(*argv);
6618 if (kill(pid, signo) != 0) {
6619 sh_warnx("%m\n");
6620 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006621 }
Eric Andersenc470f442003-07-28 09:56:35 +00006622 } while (*++argv);
6623
6624 return i;
6625}
6626#endif /* JOBS */
6627
6628#if defined(JOBS) || defined(DEBUG)
6629static int
6630jobno(const struct job *jp)
6631{
6632 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006633}
6634#endif
6635
Eric Andersenc470f442003-07-28 09:56:35 +00006636#ifdef JOBS
6637static int
6638fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006639{
Eric Andersenc470f442003-07-28 09:56:35 +00006640 struct job *jp;
6641 FILE *out;
6642 int mode;
6643 int retval;
6644
6645 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6646 nextopt(nullstr);
6647 argv = argptr;
6648 out = stdout;
6649 do {
6650 jp = getjob(*argv, 1);
6651 if (mode == FORK_BG) {
6652 set_curjob(jp, CUR_RUNNING);
6653 fprintf(out, "[%d] ", jobno(jp));
6654 }
6655 outstr(jp->ps->cmd, out);
6656 showpipe(jp, out);
6657 retval = restartjob(jp, mode);
6658 } while (*argv && *++argv);
6659 return retval;
6660}
6661
6662static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6663
6664
6665static int
6666restartjob(struct job *jp, int mode)
6667{
6668 struct procstat *ps;
6669 int i;
6670 int status;
6671 pid_t pgid;
6672
6673 INTOFF;
6674 if (jp->state == JOBDONE)
6675 goto out;
6676 jp->state = JOBRUNNING;
6677 pgid = jp->ps->pid;
6678 if (mode == FORK_FG)
6679 xtcsetpgrp(ttyfd, pgid);
6680 killpg(pgid, SIGCONT);
6681 ps = jp->ps;
6682 i = jp->nprocs;
6683 do {
6684 if (WIFSTOPPED(ps->status)) {
6685 ps->status = -1;
6686 }
6687 } while (ps++, --i);
6688out:
6689 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6690 INTON;
6691 return status;
6692}
6693#endif
6694
6695static int
6696sprint_status(char *s, int status, int sigonly)
6697{
6698 int col;
6699 int st;
6700
6701 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006702 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006703#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006704 if (WIFSTOPPED(status))
6705 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006706 else
Eric Andersenc470f442003-07-28 09:56:35 +00006707#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006708 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006709 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006710 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006711 goto out;
6712#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006713 if (WIFSTOPPED(status))
6714 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006715#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006716 }
6717 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006718 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006719 if (WCOREDUMP(status)) {
6720 col += fmtstr(s + col, 16, " (core dumped)");
6721 }
6722 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006723 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006724 if (st)
6725 col = fmtstr(s, 16, "Done(%d)", st);
6726 else
6727 col = fmtstr(s, 16, "Done");
6728 }
6729
6730out:
6731 return col;
6732}
6733
6734#if JOBS
6735static void
6736showjob(FILE *out, struct job *jp, int mode)
6737{
6738 struct procstat *ps;
6739 struct procstat *psend;
6740 int col;
6741 int indent;
6742 char s[80];
6743
6744 ps = jp->ps;
6745
6746 if (mode & SHOW_PGID) {
6747 /* just output process (group) id of pipeline */
6748 fprintf(out, "%d\n", ps->pid);
6749 return;
6750 }
6751
6752 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6753 indent = col;
6754
6755 if (jp == curjob)
6756 s[col - 2] = '+';
6757 else if (curjob && jp == curjob->prev_job)
6758 s[col - 2] = '-';
6759
6760 if (mode & SHOW_PID)
6761 col += fmtstr(s + col, 16, "%d ", ps->pid);
6762
6763 psend = ps + jp->nprocs;
6764
6765 if (jp->state == JOBRUNNING) {
6766 scopy("Running", s + col);
6767 col += strlen("Running");
6768 } else {
6769 int status = psend[-1].status;
6770#if JOBS
6771 if (jp->state == JOBSTOPPED)
6772 status = jp->stopstatus;
6773#endif
6774 col += sprint_status(s + col, status, 0);
6775 }
6776
6777 goto start;
6778
6779 do {
6780 /* for each process */
6781 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6782
6783start:
Eric Andersen90898442003-08-06 11:20:52 +00006784 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006785 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6786 );
6787 if (!(mode & SHOW_PID)) {
6788 showpipe(jp, out);
6789 break;
6790 }
6791 if (++ps == psend) {
6792 outcslow('\n', out);
6793 break;
6794 }
6795 } while (1);
6796
6797 jp->changed = 0;
6798
6799 if (jp->state == JOBDONE) {
6800 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6801 freejob(jp);
6802 }
6803}
6804
6805
6806static int
6807jobscmd(int argc, char **argv)
6808{
6809 int mode, m;
6810 FILE *out;
6811
6812 mode = 0;
6813 while ((m = nextopt("lp")))
6814 if (m == 'l')
6815 mode = SHOW_PID;
6816 else
6817 mode = SHOW_PGID;
6818
6819 out = stdout;
6820 argv = argptr;
6821 if (*argv)
6822 do
6823 showjob(out, getjob(*argv,0), mode);
6824 while (*++argv);
6825 else
6826 showjobs(out, mode);
6827
Eric Andersencb57d552001-06-28 07:25:16 +00006828 return 0;
6829}
6830
6831
6832/*
6833 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6834 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006835 */
6836
Eric Andersenc470f442003-07-28 09:56:35 +00006837static void
6838showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006839{
Eric Andersencb57d552001-06-28 07:25:16 +00006840 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006841
Eric Andersenc470f442003-07-28 09:56:35 +00006842 TRACE(("showjobs(%x) called\n", mode));
6843
6844 /* If not even one one job changed, there is nothing to do */
6845 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6846 continue;
6847
6848 for (jp = curjob; jp; jp = jp->prev_job) {
6849 if (!(mode & SHOW_CHANGED) || jp->changed)
6850 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006851 }
6852}
Eric Andersenc470f442003-07-28 09:56:35 +00006853#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006854
6855/*
6856 * Mark a job structure as unused.
6857 */
6858
Eric Andersenc470f442003-07-28 09:56:35 +00006859static void
6860freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006861{
Eric Andersenc470f442003-07-28 09:56:35 +00006862 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006863 int i;
6864
6865 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006866 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006867 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006868 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006869 }
6870 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006871 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006872 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006873 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006874 INTON;
6875}
6876
6877
Eric Andersenc470f442003-07-28 09:56:35 +00006878static int
6879waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006880{
6881 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006882 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006883 struct job *jp;
6884
Eric Andersenc470f442003-07-28 09:56:35 +00006885 EXSIGON();
6886
6887 nextopt(nullstr);
6888 retval = 0;
6889
6890 argv = argptr;
6891 if (!*argv) {
6892 /* wait for all jobs */
6893 for (;;) {
6894 jp = curjob;
6895 while (1) {
6896 if (!jp) {
6897 /* no running procs */
6898 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006899 }
Eric Andersenc470f442003-07-28 09:56:35 +00006900 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006901 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006902 jp->waited = 1;
6903 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006904 }
Eric Andersenc470f442003-07-28 09:56:35 +00006905 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006906 }
6907 }
Eric Andersenc470f442003-07-28 09:56:35 +00006908
6909 retval = 127;
6910 do {
6911 if (**argv != '%') {
6912 pid_t pid = number(*argv);
6913 job = curjob;
6914 goto start;
6915 do {
6916 if (job->ps[job->nprocs - 1].pid == pid)
6917 break;
6918 job = job->prev_job;
6919start:
6920 if (!job)
6921 goto repeat;
6922 } while (1);
6923 } else
6924 job = getjob(*argv, 0);
6925 /* loop until process terminated or stopped */
6926 while (job->state == JOBRUNNING)
6927 dowait(DOWAIT_BLOCK, 0);
6928 job->waited = 1;
6929 retval = getstatus(job);
6930repeat:
6931 ;
6932 } while (*++argv);
6933
6934out:
6935 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006936}
6937
6938
Eric Andersencb57d552001-06-28 07:25:16 +00006939/*
6940 * Convert a job name to a job structure.
6941 */
6942
Eric Andersenc470f442003-07-28 09:56:35 +00006943static struct job *
6944getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006945{
Eric Andersencb57d552001-06-28 07:25:16 +00006946 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006947 struct job *found;
6948 const char *err_msg = "No such job: %s";
6949 unsigned num;
6950 int c;
6951 const char *p;
6952 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006953
Eric Andersenc470f442003-07-28 09:56:35 +00006954 jp = curjob;
6955 p = name;
6956 if (!p)
6957 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006958
Eric Andersenc470f442003-07-28 09:56:35 +00006959 if (*p != '%')
6960 goto err;
6961
6962 c = *++p;
6963 if (!c)
6964 goto currentjob;
6965
6966 if (!p[1]) {
6967 if (c == '+' || c == '%') {
6968currentjob:
6969 err_msg = "No current job";
6970 goto check;
6971 } else if (c == '-') {
6972 if (jp)
6973 jp = jp->prev_job;
6974 err_msg = "No previous job";
6975check:
6976 if (!jp)
6977 goto err;
6978 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006979 }
6980 }
Eric Andersenc470f442003-07-28 09:56:35 +00006981
6982 if (is_number(p)) {
6983 num = atoi(p);
6984 if (num < njobs) {
6985 jp = jobtab + num - 1;
6986 if (jp->used)
6987 goto gotit;
6988 goto err;
6989 }
6990 }
6991
6992 match = prefix;
6993 if (*p == '?') {
6994 match = strstr;
6995 p++;
6996 }
6997
6998 found = 0;
6999 while (1) {
7000 if (!jp)
7001 goto err;
7002 if (match(jp->ps[0].cmd, p)) {
7003 if (found)
7004 goto err;
7005 found = jp;
7006 err_msg = "%s: ambiguous";
7007 }
7008 jp = jp->prev_job;
7009 }
7010
7011gotit:
7012#if JOBS
7013 err_msg = "job %s not created under job control";
7014 if (getctl && jp->jobctl == 0)
7015 goto err;
7016#endif
7017 return jp;
7018err:
7019 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007020}
7021
7022
Eric Andersencb57d552001-06-28 07:25:16 +00007023/*
Eric Andersenc470f442003-07-28 09:56:35 +00007024 * Return a new job structure.
7025 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007026 */
7027
Eric Andersenc470f442003-07-28 09:56:35 +00007028static struct job *
7029makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007030{
7031 int i;
7032 struct job *jp;
7033
Eric Andersenc470f442003-07-28 09:56:35 +00007034 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007035 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007036 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007037 break;
7038 }
7039 if (jp->used == 0)
7040 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007041 if (jp->state != JOBDONE || !jp->waited)
7042 continue;
7043#if JOBS
7044 if (jobctl)
7045 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007046#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007047 freejob(jp);
7048 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007049 }
Eric Andersenc470f442003-07-28 09:56:35 +00007050 memset(jp, 0, sizeof(*jp));
7051#if JOBS
7052 if (jobctl)
7053 jp->jobctl = 1;
7054#endif
7055 jp->prev_job = curjob;
7056 curjob = jp;
7057 jp->used = 1;
7058 jp->ps = &jp->ps0;
7059 if (nprocs > 1) {
7060 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7061 }
7062 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7063 jobno(jp)));
7064 return jp;
7065}
7066
7067static struct job *
7068growjobtab(void)
7069{
7070 size_t len;
7071 ptrdiff_t offset;
7072 struct job *jp, *jq;
7073
7074 len = njobs * sizeof(*jp);
7075 jq = jobtab;
7076 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7077
7078 offset = (char *)jp - (char *)jq;
7079 if (offset) {
7080 /* Relocate pointers */
7081 size_t l = len;
7082
7083 jq = (struct job *)((char *)jq + l);
7084 while (l) {
7085 l -= sizeof(*jp);
7086 jq--;
7087#define joff(p) ((struct job *)((char *)(p) + l))
7088#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007089 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007090 jmove(joff(jp)->ps);
7091 if (joff(jp)->prev_job)
7092 jmove(joff(jp)->prev_job);
7093 }
7094 if (curjob)
7095 jmove(curjob);
7096#undef joff
7097#undef jmove
7098 }
7099
7100 njobs += 4;
7101 jobtab = jp;
7102 jp = (struct job *)((char *)jp + len);
7103 jq = jp + 3;
7104 do {
7105 jq->used = 0;
7106 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007107 return jp;
7108}
7109
7110
7111/*
Eric Andersenc470f442003-07-28 09:56:35 +00007112 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007113 * own process group. Jp is a job structure that the job is to be added to.
7114 * N is the command that will be evaluated by the child. Both jp and n may
7115 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007116 * FORK_FG - Fork off a foreground process.
7117 * FORK_BG - Fork off a background process.
7118 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7119 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007120 *
7121 * When job control is turned off, background processes have their standard
7122 * input redirected to /dev/null (except for the second and later processes
7123 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007124 *
7125 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007126 */
7127
Eric Andersenc470f442003-07-28 09:56:35 +00007128static inline void
7129forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007130{
Eric Andersenc470f442003-07-28 09:56:35 +00007131 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007132
Eric Andersenc470f442003-07-28 09:56:35 +00007133 TRACE(("Child shell %d\n", getpid()));
7134 wasroot = rootshell;
7135 rootshell = 0;
7136
7137 closescript();
7138 clear_traps();
7139#if JOBS
7140 /* do job control only in root shell */
7141 jobctl = 0;
7142 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7143 pid_t pgrp;
7144
7145 if (jp->nprocs == 0)
7146 pgrp = getpid();
7147 else
7148 pgrp = jp->ps[0].pid;
7149 /* This can fail because we are doing it in the parent also */
7150 (void)setpgid(0, pgrp);
7151 if (mode == FORK_FG)
7152 xtcsetpgrp(ttyfd, pgrp);
7153 setsignal(SIGTSTP);
7154 setsignal(SIGTTOU);
7155 } else
Eric Andersen62483552001-07-10 06:09:16 +00007156#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007157 if (mode == FORK_BG) {
7158 ignoresig(SIGINT);
7159 ignoresig(SIGQUIT);
7160 if (jp->nprocs == 0) {
7161 close(0);
7162 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7163 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007164 }
Eric Andersencb57d552001-06-28 07:25:16 +00007165 }
Eric Andersenc470f442003-07-28 09:56:35 +00007166 if (wasroot && iflag) {
7167 setsignal(SIGINT);
7168 setsignal(SIGQUIT);
7169 setsignal(SIGTERM);
7170 }
7171 for (jp = curjob; jp; jp = jp->prev_job)
7172 freejob(jp);
7173 jobless = 0;
7174}
7175
7176static inline void
7177forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7178{
7179 TRACE(("In parent shell: child = %d\n", pid));
7180 if (!jp) {
7181 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7182 jobless++;
7183 return;
7184 }
7185#if JOBS
7186 if (mode != FORK_NOJOB && jp->jobctl) {
7187 int pgrp;
7188
7189 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007190 pgrp = pid;
7191 else
7192 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007193 /* This can fail because we are doing it in the child also */
7194 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007195 }
Eric Andersen62483552001-07-10 06:09:16 +00007196#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007197 if (mode == FORK_BG) {
7198 backgndpid = pid; /* set $! */
7199 set_curjob(jp, CUR_RUNNING);
7200 }
Eric Andersencb57d552001-06-28 07:25:16 +00007201 if (jp) {
7202 struct procstat *ps = &jp->ps[jp->nprocs++];
7203 ps->pid = pid;
7204 ps->status = -1;
7205 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007206#if JOBS
7207 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007208 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007209#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007210 }
Eric Andersencb57d552001-06-28 07:25:16 +00007211}
7212
Eric Andersenc470f442003-07-28 09:56:35 +00007213static int
7214forkshell(struct job *jp, union node *n, int mode)
7215{
7216 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007217
Eric Andersenc470f442003-07-28 09:56:35 +00007218 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7219 pid = fork();
7220 if (pid < 0) {
7221 TRACE(("Fork failed, errno=%d", errno));
7222 if (jp)
7223 freejob(jp);
7224 error("Cannot fork");
7225 }
7226 if (pid == 0)
7227 forkchild(jp, n, mode);
7228 else
7229 forkparent(jp, n, mode, pid);
7230 return pid;
7231}
Eric Andersencb57d552001-06-28 07:25:16 +00007232
7233/*
7234 * Wait for job to finish.
7235 *
7236 * Under job control we have the problem that while a child process is
7237 * running interrupts generated by the user are sent to the child but not
7238 * to the shell. This means that an infinite loop started by an inter-
7239 * active user may be hard to kill. With job control turned off, an
7240 * interactive user may place an interactive program inside a loop. If
7241 * the interactive program catches interrupts, the user doesn't want
7242 * these interrupts to also abort the loop. The approach we take here
7243 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007244 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007245 * signal if the child process was terminated by an interrupt signal.
7246 * Unfortunately, some programs want to do a bit of cleanup and then
7247 * exit on interrupt; unless these processes terminate themselves by
7248 * sending a signal to themselves (instead of calling exit) they will
7249 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007250 *
7251 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007252 */
7253
Eric Andersenc470f442003-07-28 09:56:35 +00007254int
7255waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007256{
Eric Andersencb57d552001-06-28 07:25:16 +00007257 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007258
Eric Andersenc470f442003-07-28 09:56:35 +00007259 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7260 while (jp->state == JOBRUNNING) {
7261 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007262 }
Eric Andersenc470f442003-07-28 09:56:35 +00007263 st = getstatus(jp);
7264#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007265 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007266 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007267 /*
7268 * This is truly gross.
7269 * If we're doing job control, then we did a TIOCSPGRP which
7270 * caused us (the shell) to no longer be in the controlling
7271 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7272 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007273 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007274 */
Eric Andersenc470f442003-07-28 09:56:35 +00007275 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007276 raise(SIGINT);
7277 }
Eric Andersen2870d962001-07-02 17:27:21 +00007278 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007279#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007280 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007281 return st;
7282}
7283
7284
Eric Andersen62483552001-07-10 06:09:16 +00007285/*
7286 * Do a wait system call. If job control is compiled in, we accept
7287 * stopped processes. If block is zero, we return a value of zero
7288 * rather than blocking.
7289 *
7290 * System V doesn't have a non-blocking wait system call. It does
7291 * have a SIGCLD signal that is sent to a process when one of it's
7292 * children dies. The obvious way to use SIGCLD would be to install
7293 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7294 * was received, and have waitproc bump another counter when it got
7295 * the status of a process. Waitproc would then know that a wait
7296 * system call would not block if the two counters were different.
7297 * This approach doesn't work because if a process has children that
7298 * have not been waited for, System V will send it a SIGCLD when it
7299 * installs a signal handler for SIGCLD. What this means is that when
7300 * a child exits, the shell will be sent SIGCLD signals continuously
7301 * until is runs out of stack space, unless it does a wait call before
7302 * restoring the signal handler. The code below takes advantage of
7303 * this (mis)feature by installing a signal handler for SIGCLD and
7304 * then checking to see whether it was called. If there are any
7305 * children to be waited for, it will be.
7306 *
Eric Andersenc470f442003-07-28 09:56:35 +00007307 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7308 * waits at all. In this case, the user will not be informed when
7309 * a background process until the next time she runs a real program
7310 * (as opposed to running a builtin command or just typing return),
7311 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007312 */
7313
Eric Andersenc470f442003-07-28 09:56:35 +00007314static inline int
7315waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007316{
Eric Andersenc470f442003-07-28 09:56:35 +00007317 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007318
Eric Andersenc470f442003-07-28 09:56:35 +00007319#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007320 if (jobctl)
7321 flags |= WUNTRACED;
7322#endif
7323 if (block == 0)
7324 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007325 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007326}
7327
Eric Andersenc470f442003-07-28 09:56:35 +00007328/*
7329 * Wait for a process to terminate.
7330 */
7331
7332static int
7333dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007334{
7335 int pid;
7336 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007337 struct job *jp;
7338 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007339 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007340
7341 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007342 pid = waitproc(block, &status);
7343 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007344 if (pid <= 0)
7345 return pid;
7346 INTOFF;
7347 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007348 for (jp = curjob; jp; jp = jp->prev_job) {
7349 struct procstat *sp;
7350 struct procstat *spend;
7351 if (jp->state == JOBDONE)
7352 continue;
7353 state = JOBDONE;
7354 spend = jp->ps + jp->nprocs;
7355 sp = jp->ps;
7356 do {
7357 if (sp->pid == pid) {
7358 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7359 sp->status = status;
7360 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007361 }
Eric Andersenc470f442003-07-28 09:56:35 +00007362 if (sp->status == -1)
7363 state = JOBRUNNING;
7364#ifdef JOBS
7365 if (state == JOBRUNNING)
7366 continue;
7367 if (WIFSTOPPED(sp->status)) {
7368 jp->stopstatus = sp->status;
7369 state = JOBSTOPPED;
7370 }
Eric Andersencb57d552001-06-28 07:25:16 +00007371#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007372 } while (++sp < spend);
7373 if (thisjob)
7374 goto gotjob;
7375 }
7376#ifdef JOBS
7377 if (!WIFSTOPPED(status))
7378#endif
7379
7380 jobless--;
7381 goto out;
7382
7383gotjob:
7384 if (state != JOBRUNNING) {
7385 thisjob->changed = 1;
7386
7387 if (thisjob->state != state) {
7388 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7389 thisjob->state = state;
7390#ifdef JOBS
7391 if (state == JOBSTOPPED) {
7392 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007393 }
Eric Andersenc470f442003-07-28 09:56:35 +00007394#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007395 }
7396 }
Eric Andersencb57d552001-06-28 07:25:16 +00007397
Eric Andersenc470f442003-07-28 09:56:35 +00007398out:
7399 INTON;
7400
7401 if (thisjob && thisjob == job) {
7402 char s[48 + 1];
7403 int len;
7404
7405 len = sprint_status(s, status, 1);
7406 if (len) {
7407 s[len] = '\n';
7408 s[len + 1] = 0;
7409 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007410 }
Eric Andersencb57d552001-06-28 07:25:16 +00007411 }
7412 return pid;
7413}
7414
7415
Eric Andersencb57d552001-06-28 07:25:16 +00007416/*
7417 * return 1 if there are stopped jobs, otherwise 0
7418 */
Eric Andersen90898442003-08-06 11:20:52 +00007419
Eric Andersenc470f442003-07-28 09:56:35 +00007420int
7421stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007422{
Eric Andersencb57d552001-06-28 07:25:16 +00007423 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007424 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007425
Eric Andersenc470f442003-07-28 09:56:35 +00007426 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007427 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007428 goto out;
7429 jp = curjob;
7430 if (jp && jp->state == JOBSTOPPED) {
7431 out2str("You have stopped jobs.\n");
7432 job_warning = 2;
7433 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007434 }
7435
Eric Andersenc470f442003-07-28 09:56:35 +00007436out:
7437 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007438}
7439
7440/*
7441 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007442 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007443 */
7444
Eric Andersenc470f442003-07-28 09:56:35 +00007445#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007446static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007447
Eric Andersenc470f442003-07-28 09:56:35 +00007448static char *
7449commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007450{
Eric Andersenc470f442003-07-28 09:56:35 +00007451 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007452
Eric Andersenc470f442003-07-28 09:56:35 +00007453 STARTSTACKSTR(cmdnextc);
7454 cmdtxt(n);
7455 name = stackblock();
7456 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7457 name, cmdnextc, cmdnextc));
7458 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007459}
7460
Eric Andersenc470f442003-07-28 09:56:35 +00007461static void
7462cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007463{
Eric Andersencb57d552001-06-28 07:25:16 +00007464 union node *np;
7465 struct nodelist *lp;
7466 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007467 char s[2];
7468
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007469 if (!n)
7470 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007471 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007472 default:
7473#if DEBUG
7474 abort();
7475#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007476 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007477 lp = n->npipe.cmdlist;
7478 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007479 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007480 lp = lp->next;
7481 if (!lp)
7482 break;
7483 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007484 }
7485 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007486 case NSEMI:
7487 p = "; ";
7488 goto binop;
7489 case NAND:
7490 p = " && ";
7491 goto binop;
7492 case NOR:
7493 p = " || ";
7494binop:
7495 cmdtxt(n->nbinary.ch1);
7496 cmdputs(p);
7497 n = n->nbinary.ch2;
7498 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007499 case NREDIR:
7500 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007501 n = n->nredir.n;
7502 goto donode;
7503 case NNOT:
7504 cmdputs("!");
7505 n = n->nnot.com;
7506donode:
7507 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007508 break;
7509 case NIF:
7510 cmdputs("if ");
7511 cmdtxt(n->nif.test);
7512 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007513 n = n->nif.ifpart;
7514 if (n->nif.elsepart) {
7515 cmdtxt(n);
7516 cmdputs("; else ");
7517 n = n->nif.elsepart;
7518 }
7519 p = "; fi";
7520 goto dotail;
7521 case NSUBSHELL:
7522 cmdputs("(");
7523 n = n->nredir.n;
7524 p = ")";
7525 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007526 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007527 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007528 goto until;
7529 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007530 p = "until ";
7531until:
7532 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007533 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007534 n = n->nbinary.ch2;
7535 p = "; done";
7536dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007537 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007538dotail:
7539 cmdtxt(n);
7540 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007541 case NFOR:
7542 cmdputs("for ");
7543 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007544 cmdputs(" in ");
7545 cmdlist(n->nfor.args, 1);
7546 n = n->nfor.body;
7547 p = "; done";
7548 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007549 case NDEFUN:
7550 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007551 p = "() { ... }";
7552 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007553 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007554 cmdlist(n->ncmd.args, 1);
7555 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007556 break;
7557 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007558 p = n->narg.text;
7559dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007560 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007561 break;
7562 case NHERE:
7563 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007564 p = "<<...";
7565 goto dotail2;
7566 case NCASE:
7567 cmdputs("case ");
7568 cmdputs(n->ncase.expr->narg.text);
7569 cmdputs(" in ");
7570 for (np = n->ncase.cases; np; np = np->nclist.next) {
7571 cmdtxt(np->nclist.pattern);
7572 cmdputs(") ");
7573 cmdtxt(np->nclist.body);
7574 cmdputs(";; ");
7575 }
7576 p = "esac";
7577 goto dotail2;
7578 case NTO:
7579 p = ">";
7580 goto redir;
7581 case NCLOBBER:
7582 p = ">|";
7583 goto redir;
7584 case NAPPEND:
7585 p = ">>";
7586 goto redir;
7587 case NTOFD:
7588 p = ">&";
7589 goto redir;
7590 case NFROM:
7591 p = "<";
7592 goto redir;
7593 case NFROMFD:
7594 p = "<&";
7595 goto redir;
7596 case NFROMTO:
7597 p = "<>";
7598redir:
7599 s[0] = n->nfile.fd + '0';
7600 s[1] = '\0';
7601 cmdputs(s);
7602 cmdputs(p);
7603 if (n->type == NTOFD || n->type == NFROMFD) {
7604 s[0] = n->ndup.dupfd + '0';
7605 p = s;
7606 goto dotail2;
7607 } else {
7608 n = n->nfile.fname;
7609 goto donode;
7610 }
Eric Andersencb57d552001-06-28 07:25:16 +00007611 }
7612}
Eric Andersencb57d552001-06-28 07:25:16 +00007613
Eric Andersenc470f442003-07-28 09:56:35 +00007614static void
7615cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007616{
Eric Andersenc470f442003-07-28 09:56:35 +00007617 for (; np; np = np->narg.next) {
7618 if (!sep)
7619 cmdputs(spcstr);
7620 cmdtxt(np);
7621 if (sep && np->narg.next)
7622 cmdputs(spcstr);
7623 }
Eric Andersencb57d552001-06-28 07:25:16 +00007624}
7625
Eric Andersenc470f442003-07-28 09:56:35 +00007626static void
7627cmdputs(const char *s)
7628{
7629 const char *p, *str;
7630 char c, cc[2] = " ";
7631 char *nextc;
7632 int subtype = 0;
7633 int quoted = 0;
7634 static const char *const vstype[16] = {
7635 nullstr, "}", "-", "+", "?", "=",
Eric Andersenc7bda1c2004-03-15 08:29:22 +00007636 "%", "%%", "#", "##", nullstr
Eric Andersenc470f442003-07-28 09:56:35 +00007637 };
7638
7639 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7640 p = s;
7641 while ((c = *p++) != 0) {
7642 str = 0;
7643 switch (c) {
7644 case CTLESC:
7645 c = *p++;
7646 break;
7647 case CTLVAR:
7648 subtype = *p++;
7649 if ((subtype & VSTYPE) == VSLENGTH)
7650 str = "${#";
7651 else
7652 str = "${";
7653 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7654 quoted ^= 1;
7655 c = '"';
7656 } else
7657 goto dostr;
7658 break;
7659 case CTLENDVAR:
7660 quoted >>= 1;
7661 subtype = 0;
7662 if (quoted & 1) {
7663 str = "\"}";
7664 goto dostr;
7665 }
7666 c = '}';
7667 break;
7668 case CTLBACKQ:
7669 str = "$(...)";
7670 goto dostr;
7671 case CTLBACKQ+CTLQUOTE:
7672 str = "\"$(...)\"";
7673 goto dostr;
7674#ifdef CONFIG_ASH_MATH_SUPPORT
7675 case CTLARI:
7676 str = "$((";
7677 goto dostr;
7678 case CTLENDARI:
7679 str = "))";
7680 goto dostr;
7681#endif
7682 case CTLQUOTEMARK:
7683 quoted ^= 1;
7684 c = '"';
7685 break;
7686 case '=':
7687 if (subtype == 0)
7688 break;
7689 str = vstype[subtype & VSTYPE];
7690 if (subtype & VSNUL)
7691 c = ':';
7692 else
7693 c = *str++;
7694 if (c != '}')
7695 quoted <<= 1;
7696 break;
7697 case '\'':
7698 case '\\':
7699 case '"':
7700 case '$':
7701 /* These can only happen inside quotes */
7702 cc[0] = c;
7703 str = cc;
7704 c = '\\';
7705 break;
7706 default:
7707 break;
7708 }
7709 USTPUTC(c, nextc);
7710 if (!str)
7711 continue;
7712dostr:
7713 while ((c = *str++)) {
7714 USTPUTC(c, nextc);
7715 }
7716 }
7717 if (quoted & 1) {
7718 USTPUTC('"', nextc);
7719 }
7720 *nextc = 0;
7721 cmdnextc = nextc;
7722}
7723
7724
7725static void
7726showpipe(struct job *jp, FILE *out)
7727{
7728 struct procstat *sp;
7729 struct procstat *spend;
7730
7731 spend = jp->ps + jp->nprocs;
7732 for (sp = jp->ps + 1; sp < spend; sp++)
7733 fprintf(out, " | %s", sp->cmd);
7734 outcslow('\n', out);
7735 flushall();
7736}
7737
7738static void
7739xtcsetpgrp(int fd, pid_t pgrp)
7740{
7741 if (tcsetpgrp(fd, pgrp))
7742 error("Cannot set tty process group (%m)");
7743}
7744#endif /* JOBS */
7745
7746static int
7747getstatus(struct job *job) {
7748 int status;
7749 int retval;
7750
7751 status = job->ps[job->nprocs - 1].status;
7752 retval = WEXITSTATUS(status);
7753 if (!WIFEXITED(status)) {
7754#if JOBS
7755 retval = WSTOPSIG(status);
7756 if (!WIFSTOPPED(status))
7757#endif
7758 {
7759 /* XXX: limits number of signals */
7760 retval = WTERMSIG(status);
7761#if JOBS
7762 if (retval == SIGINT)
7763 job->sigint = 1;
7764#endif
7765 }
7766 retval += 128;
7767 }
7768 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7769 jobno(job), job->nprocs, status, retval));
7770 return retval;
7771}
7772
Eric Andersend35c5df2002-01-09 15:37:36 +00007773#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007774/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007775
Eric Andersencb57d552001-06-28 07:25:16 +00007776/*
Eric Andersenc470f442003-07-28 09:56:35 +00007777 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007778 */
7779
Eric Andersencb57d552001-06-28 07:25:16 +00007780#define MAXMBOXES 10
7781
Eric Andersenc470f442003-07-28 09:56:35 +00007782/* times of mailboxes */
7783static time_t mailtime[MAXMBOXES];
7784/* Set if MAIL or MAILPATH is changed. */
7785static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007786
7787
7788
7789/*
Eric Andersenc470f442003-07-28 09:56:35 +00007790 * Print appropriate message(s) if mail has arrived.
7791 * If mail_var_path_changed is set,
7792 * then the value of MAIL has mail_var_path_changed,
7793 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007794 */
7795
Eric Andersenc470f442003-07-28 09:56:35 +00007796static void
7797chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007798{
Eric Andersencb57d552001-06-28 07:25:16 +00007799 const char *mpath;
7800 char *p;
7801 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007802 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007803 struct stackmark smark;
7804 struct stat statb;
7805
Eric Andersencb57d552001-06-28 07:25:16 +00007806 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007807 mpath = mpathset() ? mpathval() : mailval();
7808 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007809 p = padvance(&mpath, nullstr);
7810 if (p == NULL)
7811 break;
7812 if (*p == '\0')
7813 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007814 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007815#ifdef DEBUG
7816 if (q[-1] != '/')
7817 abort();
7818#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007819 q[-1] = '\0'; /* delete trailing '/' */
7820 if (stat(p, &statb) < 0) {
7821 *mtp = 0;
7822 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007823 }
Eric Andersenc470f442003-07-28 09:56:35 +00007824 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7825 fprintf(
7826 stderr, snlfmt,
7827 pathopt ? pathopt : "you have mail"
7828 );
7829 }
7830 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007831 }
Eric Andersenc470f442003-07-28 09:56:35 +00007832 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007833 popstackmark(&smark);
7834}
Eric Andersencb57d552001-06-28 07:25:16 +00007835
Eric Andersenec074692001-10-31 11:05:49 +00007836
Eric Andersenc470f442003-07-28 09:56:35 +00007837static void
7838changemail(const char *val)
7839{
7840 mail_var_path_changed++;
7841}
7842
7843#endif /* CONFIG_ASH_MAIL */
7844
7845/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7846
Eric Andersencb57d552001-06-28 07:25:16 +00007847
Eric Andersencb57d552001-06-28 07:25:16 +00007848#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007849static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007850extern int etext();
7851#endif
7852
Eric Andersenc470f442003-07-28 09:56:35 +00007853static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007854
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007855static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007856
Eric Andersencb57d552001-06-28 07:25:16 +00007857/*
7858 * Main routine. We initialize things, parse the arguments, execute
7859 * profiles if we're a login shell, and then call cmdloop to execute
7860 * commands. The setjmp call sets up the location to jump to when an
7861 * exception occurs. When an exception occurs the variable "state"
7862 * is used to figure out how far we had gotten.
7863 */
7864
Eric Andersenc470f442003-07-28 09:56:35 +00007865int
7866ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007867{
Eric Andersenc470f442003-07-28 09:56:35 +00007868 char *shinit;
7869 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007870 struct jmploc jmploc;
7871 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007872
Eric Andersenc470f442003-07-28 09:56:35 +00007873#ifdef __GLIBC__
7874 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007875#endif
7876
Eric Andersencb57d552001-06-28 07:25:16 +00007877#if PROFILE
7878 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7879#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007880 state = 0;
7881 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007882 int status;
7883 int e;
7884
Eric Andersencb57d552001-06-28 07:25:16 +00007885 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007886
7887 e = exception;
7888 switch (exception) {
7889 case EXEXEC:
7890 status = exerrno;
7891 break;
7892
7893 case EXERROR:
7894 status = 2;
7895 break;
7896
7897 default:
7898 status = exitstatus;
7899 break;
7900 }
7901 exitstatus = status;
7902
7903 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7904 exitshell();
7905
Eric Andersen90898442003-08-06 11:20:52 +00007906 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007907 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007908 }
7909 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007910 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007911 if (state == 1)
7912 goto state1;
7913 else if (state == 2)
7914 goto state2;
7915 else if (state == 3)
7916 goto state3;
7917 else
7918 goto state4;
7919 }
7920 handler = &jmploc;
7921#ifdef DEBUG
7922 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007923 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007924#endif
7925 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007926
7927#ifdef CONFIG_ASH_RANDOM_SUPPORT
7928 rseed = rootpid + ((time_t)time((time_t *)0));
7929#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007930 rootshell = 1;
7931 init();
7932 setstackmark(&smark);
7933 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007934#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7935 if ( iflag ) {
7936 const char *hp = lookupvar("HISTFILE");
7937
7938 if(hp == NULL ) {
7939 hp = lookupvar("HOME");
7940 if(hp != NULL) {
7941 char *defhp = concat_path_file(hp, ".ash_history");
7942 setvar("HISTFILE", defhp, 0);
7943 free(defhp);
7944 }
7945 }
7946 }
7947#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007948 if (argv[0] && argv[0][0] == '-')
7949 isloginsh = 1;
7950 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007951 state = 1;
7952 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007953state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007954 state = 2;
7955 read_profile(".profile");
7956 }
Eric Andersenc470f442003-07-28 09:56:35 +00007957state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007958 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007959 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007960#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007961 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007962#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007963 iflag
7964 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007965 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007966 read_profile(shinit);
7967 }
Eric Andersencb57d552001-06-28 07:25:16 +00007968 }
Eric Andersenc470f442003-07-28 09:56:35 +00007969state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007970 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007971 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007972 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007973
7974 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007975#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007976 if ( iflag ) {
7977 const char *hp = lookupvar("HISTFILE");
7978
7979 if(hp != NULL )
7980 load_history ( hp );
7981 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007982#endif
Eric Andersen90898442003-08-06 11:20:52 +00007983state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007984 cmdloop(1);
7985 }
7986#if PROFILE
7987 monitor(0);
7988#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007989#if GPROF
7990 {
7991 extern void _mcleanup(void);
7992 _mcleanup();
7993 }
7994#endif
7995 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007996 /* NOTREACHED */
7997}
7998
7999
8000/*
8001 * Read and execute commands. "Top" is nonzero for the top level command
8002 * loop; it turns on prompting if the shell is interactive.
8003 */
8004
Eric Andersenc470f442003-07-28 09:56:35 +00008005static void
8006cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008007{
8008 union node *n;
8009 struct stackmark smark;
8010 int inter;
8011 int numeof = 0;
8012
8013 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008014 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00008015 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00008016 if (pendingsigs)
8017 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00008018#if JOBS
8019 if (jobctl)
8020 showjobs(stderr, SHOW_CHANGED);
8021#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008022 inter = 0;
8023 if (iflag && top) {
8024 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008025#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008026 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008027#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008028 }
8029 n = parsecmd(inter);
8030 /* showtree(n); DEBUG */
8031 if (n == NEOF) {
8032 if (!top || numeof >= 50)
8033 break;
8034 if (!stoppedjobs()) {
8035 if (!Iflag)
8036 break;
8037 out2str("\nUse \"exit\" to leave shell.\n");
8038 }
8039 numeof++;
8040 } else if (n != NULL && nflag == 0) {
8041 job_warning = (job_warning == 2) ? 1 : 0;
8042 numeof = 0;
8043 evaltree(n, 0);
8044 }
8045 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008046 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008047 evalskip = 0;
8048 break;
8049 }
8050 }
Eric Andersencb57d552001-06-28 07:25:16 +00008051}
8052
8053
Eric Andersencb57d552001-06-28 07:25:16 +00008054/*
8055 * Read /etc/profile or .profile. Return on error.
8056 */
8057
Eric Andersenc470f442003-07-28 09:56:35 +00008058static void
8059read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008060{
8061 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008062 int xflag_set = 0;
8063 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008064
8065 INTOFF;
8066 if ((fd = open(name, O_RDONLY)) >= 0)
8067 setinputfd(fd, 1);
8068 INTON;
8069 if (fd < 0)
8070 return;
8071 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008072 if (qflag) {
8073 if (xflag)
8074 xflag = 0, xflag_set = 1;
8075 if (vflag)
8076 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008077 }
8078 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008079 if (qflag) {
8080 if (xflag_set)
8081 xflag = 1;
8082 if (vflag_set)
8083 vflag = 1;
8084 }
Eric Andersencb57d552001-06-28 07:25:16 +00008085 popfile();
8086}
8087
8088
Eric Andersencb57d552001-06-28 07:25:16 +00008089/*
8090 * Read a file containing shell functions.
8091 */
8092
Eric Andersenc470f442003-07-28 09:56:35 +00008093static void
8094readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008095{
8096 int fd;
8097
8098 INTOFF;
8099 if ((fd = open(name, O_RDONLY)) >= 0)
8100 setinputfd(fd, 1);
8101 else
8102 error("Can't open %s", name);
8103 INTON;
8104 cmdloop(0);
8105 popfile();
8106}
8107
8108
Eric Andersencb57d552001-06-28 07:25:16 +00008109/*
Eric Andersenc470f442003-07-28 09:56:35 +00008110 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008111 * search for the file, which is necessary to find sub-commands.
8112 */
8113
Eric Andersenc470f442003-07-28 09:56:35 +00008114static inline char *
8115find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008116{
8117 char *fullname;
8118 const char *path = pathval();
8119 struct stat statb;
8120
8121 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008122 if (strchr(name, '/'))
8123 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008124
Eric Andersenc470f442003-07-28 09:56:35 +00008125 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008126 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8127 /*
8128 * Don't bother freeing here, since it will
8129 * be freed by the caller.
8130 */
8131 return fullname;
8132 }
8133 stunalloc(fullname);
8134 }
8135
8136 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008137 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008138 /* NOTREACHED */
8139}
8140
Eric Andersen1e6aba92004-04-12 19:12:13 +00008141static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008142{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008143 struct strlist *sp;
8144 volatile struct shparam saveparam;
8145
Eric Andersencb57d552001-06-28 07:25:16 +00008146 exitstatus = 0;
8147
Eric Andersen1e6aba92004-04-12 19:12:13 +00008148 for (sp = cmdenviron; sp; sp = sp->next)
8149 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8150
8151 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008152 char *fullname;
8153 struct stackmark smark;
8154
8155 setstackmark(&smark);
8156 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008157
8158 if (argc > 2) {
8159 saveparam = shellparam;
8160 shellparam.malloc = 0;
8161 shellparam.nparam = argc - 2;
8162 shellparam.p = argv + 2;
8163 };
8164
Eric Andersencb57d552001-06-28 07:25:16 +00008165 setinputfile(fullname, 1);
8166 commandname = fullname;
8167 cmdloop(0);
8168 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008169
8170 if (argc > 2) {
8171 freeparam(&shellparam);
8172 shellparam = saveparam;
8173 };
8174
Eric Andersencb57d552001-06-28 07:25:16 +00008175 popstackmark(&smark);
8176 }
8177 return exitstatus;
8178}
8179
8180
Eric Andersenc470f442003-07-28 09:56:35 +00008181static int
8182exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008183{
8184 if (stoppedjobs())
8185 return 0;
8186 if (argc > 1)
8187 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008188 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008189 /* NOTREACHED */
8190}
Eric Andersen62483552001-07-10 06:09:16 +00008191
Eric Andersenc470f442003-07-28 09:56:35 +00008192/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8193
8194/*
Eric Andersen90898442003-08-06 11:20:52 +00008195 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008196 */
8197
8198static pointer
8199ckrealloc(pointer p, size_t nbytes)
8200{
8201 p = realloc(p, nbytes);
8202 if (p == NULL)
8203 error(bb_msg_memory_exhausted);
8204 return p;
8205}
8206
Eric Andersen90898442003-08-06 11:20:52 +00008207static pointer
8208ckmalloc(size_t nbytes)
8209{
8210 return ckrealloc(NULL, nbytes);
8211}
Eric Andersenc470f442003-07-28 09:56:35 +00008212
8213/*
8214 * Make a copy of a string in safe storage.
8215 */
8216
8217static char *
8218savestr(const char *s)
8219{
8220 char *p = strdup(s);
8221 if (!p)
8222 error(bb_msg_memory_exhausted);
8223 return p;
8224}
8225
8226
8227/*
8228 * Parse trees for commands are allocated in lifo order, so we use a stack
8229 * to make this more efficient, and also to avoid all sorts of exception
8230 * handling code to handle interrupts in the middle of a parse.
8231 *
8232 * The size 504 was chosen because the Ultrix malloc handles that size
8233 * well.
8234 */
8235
8236
8237static pointer
8238stalloc(size_t nbytes)
8239{
8240 char *p;
8241 size_t aligned;
8242
8243 aligned = SHELL_ALIGN(nbytes);
8244 if (aligned > stacknleft) {
8245 size_t len;
8246 size_t blocksize;
8247 struct stack_block *sp;
8248
8249 blocksize = aligned;
8250 if (blocksize < MINSIZE)
8251 blocksize = MINSIZE;
8252 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8253 if (len < blocksize)
8254 error(bb_msg_memory_exhausted);
8255 INTOFF;
8256 sp = ckmalloc(len);
8257 sp->prev = stackp;
8258 stacknxt = sp->space;
8259 stacknleft = blocksize;
8260 sstrend = stacknxt + blocksize;
8261 stackp = sp;
8262 INTON;
8263 }
8264 p = stacknxt;
8265 stacknxt += aligned;
8266 stacknleft -= aligned;
8267 return p;
8268}
8269
8270
8271void
8272stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008273{
Eric Andersencb57d552001-06-28 07:25:16 +00008274#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008275 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008276 write(2, "stunalloc\n", 10);
8277 abort();
8278 }
8279#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008280 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008281 stacknxt = p;
8282}
8283
8284
Eric Andersenc470f442003-07-28 09:56:35 +00008285void
8286setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008287{
Eric Andersencb57d552001-06-28 07:25:16 +00008288 mark->stackp = stackp;
8289 mark->stacknxt = stacknxt;
8290 mark->stacknleft = stacknleft;
8291 mark->marknext = markp;
8292 markp = mark;
8293}
8294
8295
Eric Andersenc470f442003-07-28 09:56:35 +00008296void
8297popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008298{
Eric Andersencb57d552001-06-28 07:25:16 +00008299 struct stack_block *sp;
8300
8301 INTOFF;
8302 markp = mark->marknext;
8303 while (stackp != mark->stackp) {
8304 sp = stackp;
8305 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008306 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008307 }
8308 stacknxt = mark->stacknxt;
8309 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008310 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008311 INTON;
8312}
8313
8314
8315/*
8316 * When the parser reads in a string, it wants to stick the string on the
8317 * stack and only adjust the stack pointer when it knows how big the
8318 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8319 * of space on top of the stack and stackblocklen returns the length of
8320 * this block. Growstackblock will grow this space by at least one byte,
8321 * possibly moving it (like realloc). Grabstackblock actually allocates the
8322 * part of the block that has been used.
8323 */
8324
Eric Andersenc470f442003-07-28 09:56:35 +00008325void
8326growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008327{
Eric Andersenc470f442003-07-28 09:56:35 +00008328 size_t newlen;
8329
8330 newlen = stacknleft * 2;
8331 if (newlen < stacknleft)
8332 error(bb_msg_memory_exhausted);
8333 if (newlen < 128)
8334 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008335
8336 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008337 struct stack_block *oldstackp;
8338 struct stackmark *xmark;
8339 struct stack_block *sp;
8340 struct stack_block *prevstackp;
8341 size_t grosslen;
8342
Eric Andersencb57d552001-06-28 07:25:16 +00008343 INTOFF;
8344 oldstackp = stackp;
8345 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008346 prevstackp = sp->prev;
8347 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8348 sp = ckrealloc((pointer)sp, grosslen);
8349 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008350 stackp = sp;
8351 stacknxt = sp->space;
8352 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008353 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008354
Eric Andersenc470f442003-07-28 09:56:35 +00008355 /*
8356 * Stack marks pointing to the start of the old block
8357 * must be relocated to point to the new block
8358 */
8359 xmark = markp;
8360 while (xmark != NULL && xmark->stackp == oldstackp) {
8361 xmark->stackp = stackp;
8362 xmark->stacknxt = stacknxt;
8363 xmark->stacknleft = stacknleft;
8364 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008365 }
8366 INTON;
8367 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008368 char *oldspace = stacknxt;
8369 int oldlen = stacknleft;
8370 char *p = stalloc(newlen);
8371
8372 /* free the space we just allocated */
8373 stacknxt = memcpy(p, oldspace, oldlen);
8374 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008375 }
8376}
8377
Eric Andersenc470f442003-07-28 09:56:35 +00008378static inline void
8379grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008380{
Eric Andersenc470f442003-07-28 09:56:35 +00008381 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008382 stacknxt += len;
8383 stacknleft -= len;
8384}
8385
Eric Andersencb57d552001-06-28 07:25:16 +00008386/*
Eric Andersenc470f442003-07-28 09:56:35 +00008387 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008388 * The user declares a variable of type STACKSTR, which may be declared
8389 * to be a register. The macro STARTSTACKSTR initializes things. Then
8390 * the user uses the macro STPUTC to add characters to the string. In
8391 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8392 * grown as necessary. When the user is done, she can just leave the
8393 * string there and refer to it using stackblock(). Or she can allocate
8394 * the space for it using grabstackstr(). If it is necessary to allow
8395 * someone else to use the stack temporarily and then continue to grow
8396 * the string, the user should use grabstack to allocate the space, and
8397 * then call ungrabstr(p) to return to the previous mode of operation.
8398 *
8399 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8400 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8401 * is space for at least one character.
8402 */
8403
Eric Andersenc470f442003-07-28 09:56:35 +00008404void *
8405growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008406{
Eric Andersenc470f442003-07-28 09:56:35 +00008407 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008408 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008409 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008410 return stackblock();
8411 }
8412 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008413 return stackblock() + len;
8414}
8415
Eric Andersencb57d552001-06-28 07:25:16 +00008416/*
8417 * Called from CHECKSTRSPACE.
8418 */
8419
Eric Andersenc470f442003-07-28 09:56:35 +00008420char *
8421makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008422{
Eric Andersenc470f442003-07-28 09:56:35 +00008423 size_t len = p - stacknxt;
8424 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008425
Eric Andersenc470f442003-07-28 09:56:35 +00008426 for (;;) {
8427 size_t nleft;
8428
8429 size = stackblocksize();
8430 nleft = size - len;
8431 if (nleft >= newlen)
8432 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008433 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008434 }
Eric Andersencb57d552001-06-28 07:25:16 +00008435 return stackblock() + len;
8436}
8437
Eric Andersenc470f442003-07-28 09:56:35 +00008438char *
8439stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008440{
Eric Andersenc470f442003-07-28 09:56:35 +00008441 p = makestrspace(n, p);
8442 p = mempcpy(p, s, n);
8443 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008444}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008445
Eric Andersenc470f442003-07-28 09:56:35 +00008446char *
8447stputs(const char *s, char *p)
8448{
8449 return stnputs(s, strlen(s), p);
8450}
8451
8452/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8453
Eric Andersencb57d552001-06-28 07:25:16 +00008454/*
Eric Andersenc470f442003-07-28 09:56:35 +00008455 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008456 *
Eric Andersenc470f442003-07-28 09:56:35 +00008457 * number(s) Convert a string of digits to an integer.
8458 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008459 */
8460
Eric Andersencb57d552001-06-28 07:25:16 +00008461/*
8462 * prefix -- see if pfx is a prefix of string.
8463 */
8464
Eric Andersenc470f442003-07-28 09:56:35 +00008465char *
8466prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008467{
Eric Andersencb57d552001-06-28 07:25:16 +00008468 while (*pfx) {
8469 if (*pfx++ != *string++)
8470 return 0;
8471 }
Eric Andersenc470f442003-07-28 09:56:35 +00008472 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008473}
8474
8475
8476/*
8477 * Convert a string of digits to an integer, printing an error message on
8478 * failure.
8479 */
8480
Eric Andersenc470f442003-07-28 09:56:35 +00008481int
8482number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008483{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008484
Eric Andersenc470f442003-07-28 09:56:35 +00008485 if (! is_number(s))
8486 error(illnum, s);
8487 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008488}
8489
Eric Andersenc470f442003-07-28 09:56:35 +00008490
Eric Andersenc470f442003-07-28 09:56:35 +00008491/*
8492 * Check for a valid number. This should be elsewhere.
8493 */
8494
8495int
8496is_number(const char *p)
8497{
8498 do {
8499 if (! is_digit(*p))
8500 return 0;
8501 } while (*++p != '\0');
8502 return 1;
8503}
8504
8505
Eric Andersencb57d552001-06-28 07:25:16 +00008506/*
8507 * Produce a possibly single quoted string suitable as input to the shell.
8508 * The return string is allocated on the stack.
8509 */
8510
Eric Andersenc470f442003-07-28 09:56:35 +00008511char *
8512single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008513 char *p;
8514
8515 STARTSTACKSTR(p);
8516
8517 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008518 char *q;
8519 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008520
Eric Andersenc470f442003-07-28 09:56:35 +00008521 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008522
Eric Andersenc470f442003-07-28 09:56:35 +00008523 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008524
Eric Andersenc470f442003-07-28 09:56:35 +00008525 *q++ = '\'';
8526 q = mempcpy(q, s, len);
8527 *q++ = '\'';
8528 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008529
Eric Andersenc470f442003-07-28 09:56:35 +00008530 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008531
Eric Andersenc470f442003-07-28 09:56:35 +00008532 len = strspn(s, "'");
8533 if (!len)
8534 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008535
Eric Andersenc470f442003-07-28 09:56:35 +00008536 q = p = makestrspace(len + 3, p);
8537
8538 *q++ = '"';
8539 q = mempcpy(q, s, len);
8540 *q++ = '"';
8541 s += len;
8542
8543 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008544 } while (*s);
8545
8546 USTPUTC(0, p);
8547
Eric Andersenc470f442003-07-28 09:56:35 +00008548 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008549}
8550
8551/*
Eric Andersenc470f442003-07-28 09:56:35 +00008552 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008553 */
8554
Eric Andersenc470f442003-07-28 09:56:35 +00008555char *
8556sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008557{
Eric Andersenc470f442003-07-28 09:56:35 +00008558 size_t len = strlen(p) + 1;
8559 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008560}
Eric Andersenc470f442003-07-28 09:56:35 +00008561
8562
8563static void
8564calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008565{
Eric Andersenc470f442003-07-28 09:56:35 +00008566 if (n == NULL)
8567 return;
8568 funcblocksize += nodesize[n->type];
8569 switch (n->type) {
8570 case NCMD:
8571 calcsize(n->ncmd.redirect);
8572 calcsize(n->ncmd.args);
8573 calcsize(n->ncmd.assign);
8574 break;
8575 case NPIPE:
8576 sizenodelist(n->npipe.cmdlist);
8577 break;
8578 case NREDIR:
8579 case NBACKGND:
8580 case NSUBSHELL:
8581 calcsize(n->nredir.redirect);
8582 calcsize(n->nredir.n);
8583 break;
8584 case NAND:
8585 case NOR:
8586 case NSEMI:
8587 case NWHILE:
8588 case NUNTIL:
8589 calcsize(n->nbinary.ch2);
8590 calcsize(n->nbinary.ch1);
8591 break;
8592 case NIF:
8593 calcsize(n->nif.elsepart);
8594 calcsize(n->nif.ifpart);
8595 calcsize(n->nif.test);
8596 break;
8597 case NFOR:
8598 funcstringsize += strlen(n->nfor.var) + 1;
8599 calcsize(n->nfor.body);
8600 calcsize(n->nfor.args);
8601 break;
8602 case NCASE:
8603 calcsize(n->ncase.cases);
8604 calcsize(n->ncase.expr);
8605 break;
8606 case NCLIST:
8607 calcsize(n->nclist.body);
8608 calcsize(n->nclist.pattern);
8609 calcsize(n->nclist.next);
8610 break;
8611 case NDEFUN:
8612 case NARG:
8613 sizenodelist(n->narg.backquote);
8614 funcstringsize += strlen(n->narg.text) + 1;
8615 calcsize(n->narg.next);
8616 break;
8617 case NTO:
8618 case NCLOBBER:
8619 case NFROM:
8620 case NFROMTO:
8621 case NAPPEND:
8622 calcsize(n->nfile.fname);
8623 calcsize(n->nfile.next);
8624 break;
8625 case NTOFD:
8626 case NFROMFD:
8627 calcsize(n->ndup.vname);
8628 calcsize(n->ndup.next);
8629 break;
8630 case NHERE:
8631 case NXHERE:
8632 calcsize(n->nhere.doc);
8633 calcsize(n->nhere.next);
8634 break;
8635 case NNOT:
8636 calcsize(n->nnot.com);
8637 break;
8638 };
Eric Andersencb57d552001-06-28 07:25:16 +00008639}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008640
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008641
Eric Andersenc470f442003-07-28 09:56:35 +00008642static void
8643sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008644{
8645 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008646 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008647 calcsize(lp->n);
8648 lp = lp->next;
8649 }
8650}
Eric Andersencb57d552001-06-28 07:25:16 +00008651
8652
Eric Andersenc470f442003-07-28 09:56:35 +00008653static union node *
8654copynode(union node *n)
8655{
8656 union node *new;
8657
8658 if (n == NULL)
8659 return NULL;
8660 new = funcblock;
8661 funcblock = (char *) funcblock + nodesize[n->type];
8662 switch (n->type) {
8663 case NCMD:
8664 new->ncmd.redirect = copynode(n->ncmd.redirect);
8665 new->ncmd.args = copynode(n->ncmd.args);
8666 new->ncmd.assign = copynode(n->ncmd.assign);
8667 break;
8668 case NPIPE:
8669 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8670 new->npipe.backgnd = n->npipe.backgnd;
8671 break;
8672 case NREDIR:
8673 case NBACKGND:
8674 case NSUBSHELL:
8675 new->nredir.redirect = copynode(n->nredir.redirect);
8676 new->nredir.n = copynode(n->nredir.n);
8677 break;
8678 case NAND:
8679 case NOR:
8680 case NSEMI:
8681 case NWHILE:
8682 case NUNTIL:
8683 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8684 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8685 break;
8686 case NIF:
8687 new->nif.elsepart = copynode(n->nif.elsepart);
8688 new->nif.ifpart = copynode(n->nif.ifpart);
8689 new->nif.test = copynode(n->nif.test);
8690 break;
8691 case NFOR:
8692 new->nfor.var = nodesavestr(n->nfor.var);
8693 new->nfor.body = copynode(n->nfor.body);
8694 new->nfor.args = copynode(n->nfor.args);
8695 break;
8696 case NCASE:
8697 new->ncase.cases = copynode(n->ncase.cases);
8698 new->ncase.expr = copynode(n->ncase.expr);
8699 break;
8700 case NCLIST:
8701 new->nclist.body = copynode(n->nclist.body);
8702 new->nclist.pattern = copynode(n->nclist.pattern);
8703 new->nclist.next = copynode(n->nclist.next);
8704 break;
8705 case NDEFUN:
8706 case NARG:
8707 new->narg.backquote = copynodelist(n->narg.backquote);
8708 new->narg.text = nodesavestr(n->narg.text);
8709 new->narg.next = copynode(n->narg.next);
8710 break;
8711 case NTO:
8712 case NCLOBBER:
8713 case NFROM:
8714 case NFROMTO:
8715 case NAPPEND:
8716 new->nfile.fname = copynode(n->nfile.fname);
8717 new->nfile.fd = n->nfile.fd;
8718 new->nfile.next = copynode(n->nfile.next);
8719 break;
8720 case NTOFD:
8721 case NFROMFD:
8722 new->ndup.vname = copynode(n->ndup.vname);
8723 new->ndup.dupfd = n->ndup.dupfd;
8724 new->ndup.fd = n->ndup.fd;
8725 new->ndup.next = copynode(n->ndup.next);
8726 break;
8727 case NHERE:
8728 case NXHERE:
8729 new->nhere.doc = copynode(n->nhere.doc);
8730 new->nhere.fd = n->nhere.fd;
8731 new->nhere.next = copynode(n->nhere.next);
8732 break;
8733 case NNOT:
8734 new->nnot.com = copynode(n->nnot.com);
8735 break;
8736 };
8737 new->type = n->type;
8738 return new;
8739}
8740
8741
8742static struct nodelist *
8743copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008744{
8745 struct nodelist *start;
8746 struct nodelist **lpp;
8747
8748 lpp = &start;
8749 while (lp) {
8750 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008751 funcblock = (char *) funcblock +
8752 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008753 (*lpp)->n = copynode(lp->n);
8754 lp = lp->next;
8755 lpp = &(*lpp)->next;
8756 }
8757 *lpp = NULL;
8758 return start;
8759}
8760
8761
Eric Andersenc470f442003-07-28 09:56:35 +00008762static char *
8763nodesavestr(char *s)
8764{
8765 char *rtn = funcstring;
8766
8767 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008768 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008769}
8770
Eric Andersenc470f442003-07-28 09:56:35 +00008771
Eric Andersenc470f442003-07-28 09:56:35 +00008772/*
8773 * Free a parse tree.
8774 */
8775
8776static void
8777freefunc(struct funcnode *f)
8778{
8779 if (f && --f->count < 0)
8780 ckfree(f);
8781}
8782
8783
8784static void options(int);
8785static void setoption(int, int);
8786
Eric Andersencb57d552001-06-28 07:25:16 +00008787
Eric Andersencb57d552001-06-28 07:25:16 +00008788/*
8789 * Process the shell command line arguments.
8790 */
8791
Eric Andersenc470f442003-07-28 09:56:35 +00008792void
8793procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008794{
8795 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008796 const char *xminusc;
8797 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008798
Eric Andersenc470f442003-07-28 09:56:35 +00008799 xargv = argv;
8800 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008801 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008802 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008803 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008804 optlist[i] = 2;
8805 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008806 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008807 xargv = argptr;
8808 xminusc = minusc;
8809 if (*xargv == NULL) {
8810 if (xminusc)
8811 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008812 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008813 }
Eric Andersencb57d552001-06-28 07:25:16 +00008814 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8815 iflag = 1;
8816 if (mflag == 2)
8817 mflag = iflag;
8818 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008819 if (optlist[i] == 2)
8820 optlist[i] = 0;
8821#if DEBUG == 2
8822 debug = 1;
8823#endif
8824 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8825 if (xminusc) {
8826 minusc = *xargv++;
8827 if (*xargv)
8828 goto setarg0;
8829 } else if (!sflag) {
8830 setinputfile(*xargv, 0);
8831setarg0:
8832 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008833 commandname = arg0;
8834 }
Eric Andersencb57d552001-06-28 07:25:16 +00008835
Eric Andersenc470f442003-07-28 09:56:35 +00008836 shellparam.p = xargv;
8837#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008838 shellparam.optind = 1;
8839 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008840#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008841 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008842 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008843 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008844 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008845 }
8846 optschanged();
8847}
8848
8849
Eric Andersenc470f442003-07-28 09:56:35 +00008850void
8851optschanged(void)
8852{
8853#ifdef DEBUG
8854 opentrace();
8855#endif
8856 setinteractive(iflag);
8857 setjobctl(mflag);
8858}
Eric Andersencb57d552001-06-28 07:25:16 +00008859
Eric Andersenc470f442003-07-28 09:56:35 +00008860static inline void
8861minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008862{
8863 int i;
8864
8865 if (name == NULL) {
8866 out1str("Current option settings\n");
8867 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008868 out1fmt("%-16s%s\n", optnames(i),
8869 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008870 } else {
8871 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008872 if (equal(name, optnames(i))) {
8873 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008874 return;
8875 }
8876 error("Illegal option -o %s", name);
8877 }
8878}
8879
Eric Andersenc470f442003-07-28 09:56:35 +00008880/*
8881 * Process shell options. The global variable argptr contains a pointer
8882 * to the argument list; we advance it past the options.
8883 */
Eric Andersen62483552001-07-10 06:09:16 +00008884
Eric Andersenc470f442003-07-28 09:56:35 +00008885static void
8886options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008887{
8888 char *p;
8889 int val;
8890 int c;
8891
8892 if (cmdline)
8893 minusc = NULL;
8894 while ((p = *argptr) != NULL) {
8895 argptr++;
8896 if ((c = *p++) == '-') {
8897 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008898 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8899 if (!cmdline) {
8900 /* "-" means turn off -x and -v */
8901 if (p[0] == '\0')
8902 xflag = vflag = 0;
8903 /* "--" means reset params */
8904 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008905 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008906 }
Eric Andersenc470f442003-07-28 09:56:35 +00008907 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008908 }
8909 } else if (c == '+') {
8910 val = 0;
8911 } else {
8912 argptr--;
8913 break;
8914 }
8915 while ((c = *p++) != '\0') {
8916 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008917 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008918 } else if (c == 'o') {
8919 minus_o(*argptr, val);
8920 if (*argptr)
8921 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008922 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008923 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008924 isloginsh = 1;
8925 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008926 } else {
8927 setoption(c, val);
8928 }
8929 }
8930 }
8931}
8932
Eric Andersencb57d552001-06-28 07:25:16 +00008933
Eric Andersenc470f442003-07-28 09:56:35 +00008934static void
8935setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008936{
Eric Andersencb57d552001-06-28 07:25:16 +00008937 int i;
8938
8939 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008940 if (optletters(i) == flag) {
8941 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008942 return;
8943 }
8944 error("Illegal option -%c", flag);
8945 /* NOTREACHED */
8946}
8947
8948
8949
Eric Andersencb57d552001-06-28 07:25:16 +00008950/*
8951 * Set the shell parameters.
8952 */
8953
Eric Andersenc470f442003-07-28 09:56:35 +00008954void
8955setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008956{
Eric Andersencb57d552001-06-28 07:25:16 +00008957 char **newparam;
8958 char **ap;
8959 int nparam;
8960
Eric Andersenc470f442003-07-28 09:56:35 +00008961 for (nparam = 0 ; argv[nparam] ; nparam++);
8962 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008963 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008964 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008965 }
8966 *ap = NULL;
8967 freeparam(&shellparam);
8968 shellparam.malloc = 1;
8969 shellparam.nparam = nparam;
8970 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008971#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008972 shellparam.optind = 1;
8973 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008974#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008975}
8976
8977
8978/*
8979 * Free the list of positional parameters.
8980 */
8981
Eric Andersenc470f442003-07-28 09:56:35 +00008982void
8983freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008984{
Eric Andersencb57d552001-06-28 07:25:16 +00008985 char **ap;
8986
8987 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008988 for (ap = param->p ; *ap ; ap++)
8989 ckfree(*ap);
8990 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008991 }
8992}
8993
8994
8995
8996/*
8997 * The shift builtin command.
8998 */
8999
Eric Andersenc470f442003-07-28 09:56:35 +00009000int
9001shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009002{
9003 int n;
9004 char **ap1, **ap2;
9005
9006 n = 1;
9007 if (argc > 1)
9008 n = number(argv[1]);
9009 if (n > shellparam.nparam)
9010 error("can't shift that many");
9011 INTOFF;
9012 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009013 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009014 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009015 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009016 }
9017 ap2 = shellparam.p;
9018 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009019#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009020 shellparam.optind = 1;
9021 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009022#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009023 INTON;
9024 return 0;
9025}
9026
9027
9028
9029/*
9030 * The set command builtin.
9031 */
9032
Eric Andersenc470f442003-07-28 09:56:35 +00009033int
9034setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009035{
9036 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009037 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009038 INTOFF;
9039 options(0);
9040 optschanged();
9041 if (*argptr != NULL) {
9042 setparam(argptr);
9043 }
9044 INTON;
9045 return 0;
9046}
9047
9048
Eric Andersenc470f442003-07-28 09:56:35 +00009049#ifdef CONFIG_ASH_GETOPTS
9050static void
9051getoptsreset(value)
9052 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009053{
9054 shellparam.optind = number(value);
9055 shellparam.optoff = -1;
9056}
Eric Andersenc470f442003-07-28 09:56:35 +00009057#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009058
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009059#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009060static void change_lc_all(const char *value)
9061{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009062 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009063 setlocale(LC_ALL, value);
9064}
9065
9066static void change_lc_ctype(const char *value)
9067{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009068 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009069 setlocale(LC_CTYPE, value);
9070}
9071
9072#endif
9073
Eric Andersen16767e22004-03-16 05:14:10 +00009074#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009075/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009076static void change_random(const char *value)
9077{
Eric Andersen16767e22004-03-16 05:14:10 +00009078 if(value == NULL) {
9079 /* "get", generate */
9080 char buf[16];
9081
9082 rseed = rseed * 1103515245 + 12345;
9083 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9084 /* set without recursion */
9085 setvar(vrandom.text, buf, VNOFUNC);
9086 vrandom.flags &= ~VNOFUNC;
9087 } else {
9088 /* set/reset */
9089 rseed = strtoul(value, (char **)NULL, 10);
9090 }
Eric Andersenef02f822004-03-11 13:34:24 +00009091}
Eric Andersen16767e22004-03-16 05:14:10 +00009092#endif
9093
Eric Andersenef02f822004-03-11 13:34:24 +00009094
Eric Andersend35c5df2002-01-09 15:37:36 +00009095#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009096static int
Eric Andersenc470f442003-07-28 09:56:35 +00009097getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009098{
9099 char *p, *q;
9100 char c = '?';
9101 int done = 0;
9102 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009103 char s[12];
9104 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009105
Eric Andersena48b0a32003-10-22 10:56:47 +00009106 if(*param_optind < 1)
9107 return 1;
9108 optnext = optfirst + *param_optind - 1;
9109
9110 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009111 p = NULL;
9112 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009113 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009114 if (p == NULL || *p == '\0') {
9115 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009116 p = *optnext;
9117 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009118atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009119 p = NULL;
9120 done = 1;
9121 goto out;
9122 }
9123 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009124 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009125 goto atend;
9126 }
9127
9128 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009129 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009130 if (*q == '\0') {
9131 if (optstr[0] == ':') {
9132 s[0] = c;
9133 s[1] = '\0';
9134 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009135 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009136 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009137 (void) unsetvar("OPTARG");
9138 }
9139 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009140 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009141 }
9142 if (*++q == ':')
9143 q++;
9144 }
9145
9146 if (*++q == ':') {
9147 if (*p == '\0' && (p = *optnext) == NULL) {
9148 if (optstr[0] == ':') {
9149 s[0] = c;
9150 s[1] = '\0';
9151 err |= setvarsafe("OPTARG", s, 0);
9152 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009153 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009154 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009155 (void) unsetvar("OPTARG");
9156 c = '?';
9157 }
Eric Andersenc470f442003-07-28 09:56:35 +00009158 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009159 }
9160
9161 if (p == *optnext)
9162 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009163 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009164 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009165 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009166 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009167
Eric Andersenc470f442003-07-28 09:56:35 +00009168out:
Eric Andersencb57d552001-06-28 07:25:16 +00009169 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009170 *param_optind = optnext - optfirst + 1;
9171 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009172 err |= setvarsafe("OPTIND", s, VNOFUNC);
9173 s[0] = c;
9174 s[1] = '\0';
9175 err |= setvarsafe(optvar, s, 0);
9176 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009177 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009178 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009179 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009180 exraise(EXERROR);
9181 }
9182 return done;
9183}
Eric Andersenc470f442003-07-28 09:56:35 +00009184
9185/*
9186 * The getopts builtin. Shellparam.optnext points to the next argument
9187 * to be processed. Shellparam.optptr points to the next character to
9188 * be processed in the current argument. If shellparam.optnext is NULL,
9189 * then it's the first time getopts has been called.
9190 */
9191
9192int
9193getoptscmd(int argc, char **argv)
9194{
9195 char **optbase;
9196
9197 if (argc < 3)
9198 error("Usage: getopts optstring var [arg]");
9199 else if (argc == 3) {
9200 optbase = shellparam.p;
9201 if (shellparam.optind > shellparam.nparam + 1) {
9202 shellparam.optind = 1;
9203 shellparam.optoff = -1;
9204 }
9205 }
9206 else {
9207 optbase = &argv[3];
9208 if (shellparam.optind > argc - 2) {
9209 shellparam.optind = 1;
9210 shellparam.optoff = -1;
9211 }
9212 }
9213
9214 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9215 &shellparam.optoff);
9216}
9217#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009218
9219/*
9220 * XXX - should get rid of. have all builtins use getopt(3). the
9221 * library getopt must have the BSD extension static variable "optreset"
9222 * otherwise it can't be used within the shell safely.
9223 *
9224 * Standard option processing (a la getopt) for builtin routines. The
9225 * only argument that is passed to nextopt is the option string; the
9226 * other arguments are unnecessary. It return the character, or '\0' on
9227 * end of input.
9228 */
9229
Eric Andersenc470f442003-07-28 09:56:35 +00009230static int
9231nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009232{
Eric Andersencb57d552001-06-28 07:25:16 +00009233 char *p;
9234 const char *q;
9235 char c;
9236
9237 if ((p = optptr) == NULL || *p == '\0') {
9238 p = *argptr;
9239 if (p == NULL || *p != '-' || *++p == '\0')
9240 return '\0';
9241 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009242 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009243 return '\0';
9244 }
9245 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009246 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009247 if (*q == '\0')
9248 error("Illegal option -%c", c);
9249 if (*++q == ':')
9250 q++;
9251 }
9252 if (*++q == ':') {
9253 if (*p == '\0' && (p = *argptr++) == NULL)
9254 error("No arg for -%c option", c);
9255 optionarg = p;
9256 p = NULL;
9257 }
9258 optptr = p;
9259 return c;
9260}
9261
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009262
Eric Andersenc470f442003-07-28 09:56:35 +00009263/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9264
Eric Andersenc470f442003-07-28 09:56:35 +00009265void
9266outstr(const char *p, FILE *file)
9267{
9268 INTOFF;
9269 fputs(p, file);
9270 INTON;
9271}
9272
9273void
9274flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009275{
Eric Andersencb57d552001-06-28 07:25:16 +00009276 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009277 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009278 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009279 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009280}
9281
Eric Andersenc470f442003-07-28 09:56:35 +00009282void
Eric Andersen16767e22004-03-16 05:14:10 +00009283flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009284{
9285 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009286 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009287 INTON;
9288}
9289
9290static void
9291outcslow(int c, FILE *dest)
9292{
9293 INTOFF;
9294 putc(c, dest);
9295 fflush(dest);
9296 INTON;
9297}
9298
9299
9300static int
9301out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009302{
9303 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009304 int r;
9305
9306 INTOFF;
9307 va_start(ap, fmt);
9308 r = vprintf(fmt, ap);
9309 va_end(ap);
9310 INTON;
9311 return r;
9312}
9313
9314
9315int
9316fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9317{
9318 va_list ap;
9319 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009320
Eric Andersencb57d552001-06-28 07:25:16 +00009321 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009322 INTOFF;
9323 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009324 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009325 INTON;
9326 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009327}
9328
Eric Andersenc470f442003-07-28 09:56:35 +00009329
Eric Andersencb57d552001-06-28 07:25:16 +00009330
Eric Andersenc470f442003-07-28 09:56:35 +00009331/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9332
9333
Eric Andersencb57d552001-06-28 07:25:16 +00009334/*
9335 * Shell command parser.
9336 */
9337
9338#define EOFMARKLEN 79
9339
9340
Eric Andersencb57d552001-06-28 07:25:16 +00009341struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009342 struct heredoc *next; /* next here document in list */
9343 union node *here; /* redirection node */
9344 char *eofmark; /* string indicating end of input */
9345 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009346};
9347
9348
9349
Eric Andersenc470f442003-07-28 09:56:35 +00009350static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009351
9352
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009353static union node *list(int);
9354static union node *andor(void);
9355static union node *pipeline(void);
9356static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009357static union node *simplecmd(void);
9358static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009359static void parsefname(void);
9360static void parseheredoc(void);
9361static char peektoken(void);
9362static int readtoken(void);
9363static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009364static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009365static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009366static void synexpect(int) __attribute__((__noreturn__));
9367static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009368static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009369
9370
Eric Andersenc470f442003-07-28 09:56:35 +00009371
9372static inline int
9373isassignment(const char *p)
9374{
9375 const char *q = endofname(p);
9376 if (p == q)
9377 return 0;
9378 return *q == '=';
9379}
9380
9381
Eric Andersencb57d552001-06-28 07:25:16 +00009382/*
9383 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9384 * valid parse tree indicating a blank line.)
9385 */
9386
Eric Andersenc470f442003-07-28 09:56:35 +00009387union node *
9388parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009389{
9390 int t;
9391
9392 tokpushback = 0;
9393 doprompt = interact;
9394 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009395 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009396 needprompt = 0;
9397 t = readtoken();
9398 if (t == TEOF)
9399 return NEOF;
9400 if (t == TNL)
9401 return NULL;
9402 tokpushback++;
9403 return list(1);
9404}
9405
9406
Eric Andersenc470f442003-07-28 09:56:35 +00009407static union node *
9408list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009409{
9410 union node *n1, *n2, *n3;
9411 int tok;
9412
Eric Andersenc470f442003-07-28 09:56:35 +00009413 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9414 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009415 return NULL;
9416 n1 = NULL;
9417 for (;;) {
9418 n2 = andor();
9419 tok = readtoken();
9420 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009421 if (n2->type == NPIPE) {
9422 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009423 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009424 if (n2->type != NREDIR) {
9425 n3 = stalloc(sizeof(struct nredir));
9426 n3->nredir.n = n2;
9427 n3->nredir.redirect = NULL;
9428 n2 = n3;
9429 }
9430 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009431 }
9432 }
9433 if (n1 == NULL) {
9434 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009435 }
9436 else {
9437 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009438 n3->type = NSEMI;
9439 n3->nbinary.ch1 = n1;
9440 n3->nbinary.ch2 = n2;
9441 n1 = n3;
9442 }
9443 switch (tok) {
9444 case TBACKGND:
9445 case TSEMI:
9446 tok = readtoken();
9447 /* fall through */
9448 case TNL:
9449 if (tok == TNL) {
9450 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009451 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009452 return n1;
9453 } else {
9454 tokpushback++;
9455 }
Eric Andersenc470f442003-07-28 09:56:35 +00009456 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009457 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009458 return n1;
9459 break;
9460 case TEOF:
9461 if (heredoclist)
9462 parseheredoc();
9463 else
Eric Andersenc470f442003-07-28 09:56:35 +00009464 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009465 return n1;
9466 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009467 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009468 synexpect(-1);
9469 tokpushback++;
9470 return n1;
9471 }
9472 }
9473}
9474
9475
9476
Eric Andersenc470f442003-07-28 09:56:35 +00009477static union node *
9478andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009479{
Eric Andersencb57d552001-06-28 07:25:16 +00009480 union node *n1, *n2, *n3;
9481 int t;
9482
Eric Andersencb57d552001-06-28 07:25:16 +00009483 n1 = pipeline();
9484 for (;;) {
9485 if ((t = readtoken()) == TAND) {
9486 t = NAND;
9487 } else if (t == TOR) {
9488 t = NOR;
9489 } else {
9490 tokpushback++;
9491 return n1;
9492 }
Eric Andersenc470f442003-07-28 09:56:35 +00009493 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009494 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009495 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009496 n3->type = t;
9497 n3->nbinary.ch1 = n1;
9498 n3->nbinary.ch2 = n2;
9499 n1 = n3;
9500 }
9501}
9502
9503
9504
Eric Andersenc470f442003-07-28 09:56:35 +00009505static union node *
9506pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009507{
Eric Andersencb57d552001-06-28 07:25:16 +00009508 union node *n1, *n2, *pipenode;
9509 struct nodelist *lp, *prev;
9510 int negate;
9511
9512 negate = 0;
9513 TRACE(("pipeline: entered\n"));
9514 if (readtoken() == TNOT) {
9515 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009516 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009517 } else
9518 tokpushback++;
9519 n1 = command();
9520 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009521 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009522 pipenode->type = NPIPE;
9523 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009524 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009525 pipenode->npipe.cmdlist = lp;
9526 lp->n = n1;
9527 do {
9528 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009529 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9530 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009531 lp->n = command();
9532 prev->next = lp;
9533 } while (readtoken() == TPIPE);
9534 lp->next = NULL;
9535 n1 = pipenode;
9536 }
9537 tokpushback++;
9538 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009539 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009540 n2->type = NNOT;
9541 n2->nnot.com = n1;
9542 return n2;
9543 } else
9544 return n1;
9545}
9546
9547
9548
Eric Andersenc470f442003-07-28 09:56:35 +00009549static union node *
9550command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009551{
Eric Andersencb57d552001-06-28 07:25:16 +00009552 union node *n1, *n2;
9553 union node *ap, **app;
9554 union node *cp, **cpp;
9555 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009556 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009557 int t;
9558
9559 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009560 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009561
Eric Andersencb57d552001-06-28 07:25:16 +00009562 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009563 default:
9564 synexpect(-1);
9565 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009566 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009567 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009568 n1->type = NIF;
9569 n1->nif.test = list(0);
9570 if (readtoken() != TTHEN)
9571 synexpect(TTHEN);
9572 n1->nif.ifpart = list(0);
9573 n2 = n1;
9574 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009575 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009576 n2 = n2->nif.elsepart;
9577 n2->type = NIF;
9578 n2->nif.test = list(0);
9579 if (readtoken() != TTHEN)
9580 synexpect(TTHEN);
9581 n2->nif.ifpart = list(0);
9582 }
9583 if (lasttoken == TELSE)
9584 n2->nif.elsepart = list(0);
9585 else {
9586 n2->nif.elsepart = NULL;
9587 tokpushback++;
9588 }
Eric Andersenc470f442003-07-28 09:56:35 +00009589 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009590 break;
9591 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009592 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009593 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009594 n1 = (union node *)stalloc(sizeof (struct nbinary));
9595 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009596 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009597 if ((got=readtoken()) != TDO) {
9598TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009599 synexpect(TDO);
9600 }
9601 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009602 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009603 break;
9604 }
9605 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009606 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009607 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009608 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009609 n1->type = NFOR;
9610 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009611 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009612 if (readtoken() == TIN) {
9613 app = &ap;
9614 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009615 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009616 n2->type = NARG;
9617 n2->narg.text = wordtext;
9618 n2->narg.backquote = backquotelist;
9619 *app = n2;
9620 app = &n2->narg.next;
9621 }
9622 *app = NULL;
9623 n1->nfor.args = ap;
9624 if (lasttoken != TNL && lasttoken != TSEMI)
9625 synexpect(-1);
9626 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009627 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009628 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009629 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009630 n2->narg.backquote = NULL;
9631 n2->narg.next = NULL;
9632 n1->nfor.args = n2;
9633 /*
9634 * Newline or semicolon here is optional (but note
9635 * that the original Bourne shell only allowed NL).
9636 */
9637 if (lasttoken != TNL && lasttoken != TSEMI)
9638 tokpushback++;
9639 }
Eric Andersenc470f442003-07-28 09:56:35 +00009640 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009641 if (readtoken() != TDO)
9642 synexpect(TDO);
9643 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009644 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009645 break;
9646 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009647 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009648 n1->type = NCASE;
9649 if (readtoken() != TWORD)
9650 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009651 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009652 n2->type = NARG;
9653 n2->narg.text = wordtext;
9654 n2->narg.backquote = backquotelist;
9655 n2->narg.next = NULL;
9656 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009657 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009658 } while (readtoken() == TNL);
9659 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009660 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009661 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009662next_case:
9663 checkkwd = CHKNL | CHKKWD;
9664 t = readtoken();
9665 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009666 if (lasttoken == TLP)
9667 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009668 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009669 cp->type = NCLIST;
9670 app = &cp->nclist.pattern;
9671 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009672 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009673 ap->type = NARG;
9674 ap->narg.text = wordtext;
9675 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009676 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009677 break;
9678 app = &ap->narg.next;
9679 readtoken();
9680 }
9681 ap->narg.next = NULL;
9682 if (lasttoken != TRP)
9683 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009684 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009685
Eric Andersenc470f442003-07-28 09:56:35 +00009686 cpp = &cp->nclist.next;
9687
9688 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009689 if ((t = readtoken()) != TESAC) {
9690 if (t != TENDCASE)
9691 synexpect(TENDCASE);
9692 else
Eric Andersenc470f442003-07-28 09:56:35 +00009693 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009694 }
Eric Andersenc470f442003-07-28 09:56:35 +00009695 }
Eric Andersencb57d552001-06-28 07:25:16 +00009696 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009697 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009698 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009699 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009700 n1->type = NSUBSHELL;
9701 n1->nredir.n = list(0);
9702 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009703 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009704 break;
9705 case TBEGIN:
9706 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009707 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009708 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009709 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009710 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009711 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009712 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009713 }
9714
Eric Andersenc470f442003-07-28 09:56:35 +00009715 if (readtoken() != t)
9716 synexpect(t);
9717
9718redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009719 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009720 checkkwd = CHKKWD | CHKALIAS;
9721 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009722 while (readtoken() == TREDIR) {
9723 *rpp = n2 = redirnode;
9724 rpp = &n2->nfile.next;
9725 parsefname();
9726 }
9727 tokpushback++;
9728 *rpp = NULL;
9729 if (redir) {
9730 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009731 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009732 n2->type = NREDIR;
9733 n2->nredir.n = n1;
9734 n1 = n2;
9735 }
9736 n1->nredir.redirect = redir;
9737 }
9738
9739 return n1;
9740}
9741
9742
Eric Andersenc470f442003-07-28 09:56:35 +00009743static union node *
9744simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009745 union node *args, **app;
9746 union node *n = NULL;
9747 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009748 union node **rpp, *redir;
9749 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009750
9751 args = NULL;
9752 app = &args;
9753 vars = NULL;
9754 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009755 redir = NULL;
9756 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009757
Eric Andersenc470f442003-07-28 09:56:35 +00009758 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009759 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009760 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009761 switch (readtoken()) {
9762 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009763 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009764 n->type = NARG;
9765 n->narg.text = wordtext;
9766 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009767 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009768 *vpp = n;
9769 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009770 } else {
9771 *app = n;
9772 app = &n->narg.next;
9773 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009774 }
9775 break;
9776 case TREDIR:
9777 *rpp = n = redirnode;
9778 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009779 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009780 break;
9781 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009782 if (
9783 args && app == &args->narg.next &&
9784 !vars && !redir
9785 ) {
9786 struct builtincmd *bcmd;
9787 const char *name;
9788
Eric Andersencb57d552001-06-28 07:25:16 +00009789 /* We have a function */
9790 if (readtoken() != TRP)
9791 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009792 name = n->narg.text;
9793 if (
9794 !goodname(name) || (
9795 (bcmd = find_builtin(name)) &&
9796 IS_BUILTIN_SPECIAL(bcmd)
9797 )
9798 )
9799 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009800 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009801 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009802 n->narg.next = command();
9803 return n;
9804 }
9805 /* fall through */
9806 default:
9807 tokpushback++;
9808 goto out;
9809 }
9810 }
Eric Andersenc470f442003-07-28 09:56:35 +00009811out:
Eric Andersencb57d552001-06-28 07:25:16 +00009812 *app = NULL;
9813 *vpp = NULL;
9814 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009815 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009816 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009817 n->ncmd.args = args;
9818 n->ncmd.assign = vars;
9819 n->ncmd.redirect = redir;
9820 return n;
9821}
9822
Eric Andersenc470f442003-07-28 09:56:35 +00009823static union node *
9824makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009825{
Eric Andersencb57d552001-06-28 07:25:16 +00009826 union node *n;
9827
Eric Andersenc470f442003-07-28 09:56:35 +00009828 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009829 n->type = NARG;
9830 n->narg.next = NULL;
9831 n->narg.text = wordtext;
9832 n->narg.backquote = backquotelist;
9833 return n;
9834}
9835
Eric Andersenc470f442003-07-28 09:56:35 +00009836void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009837{
Eric Andersencb57d552001-06-28 07:25:16 +00009838 TRACE(("Fix redir %s %d\n", text, err));
9839 if (!err)
9840 n->ndup.vname = NULL;
9841
9842 if (is_digit(text[0]) && text[1] == '\0')
9843 n->ndup.dupfd = digit_val(text[0]);
9844 else if (text[0] == '-' && text[1] == '\0')
9845 n->ndup.dupfd = -1;
9846 else {
9847
9848 if (err)
9849 synerror("Bad fd number");
9850 else
9851 n->ndup.vname = makename();
9852 }
9853}
9854
9855
Eric Andersenc470f442003-07-28 09:56:35 +00009856static void
9857parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009858{
Eric Andersencb57d552001-06-28 07:25:16 +00009859 union node *n = redirnode;
9860
9861 if (readtoken() != TWORD)
9862 synexpect(-1);
9863 if (n->type == NHERE) {
9864 struct heredoc *here = heredoc;
9865 struct heredoc *p;
9866 int i;
9867
9868 if (quoteflag == 0)
9869 n->type = NXHERE;
9870 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009871 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009872 synerror("Illegal eof marker for << redirection");
9873 rmescapes(wordtext);
9874 here->eofmark = wordtext;
9875 here->next = NULL;
9876 if (heredoclist == NULL)
9877 heredoclist = here;
9878 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009879 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009880 p->next = here;
9881 }
9882 } else if (n->type == NTOFD || n->type == NFROMFD) {
9883 fixredir(n, wordtext, 0);
9884 } else {
9885 n->nfile.fname = makename();
9886 }
9887}
9888
9889
9890/*
9891 * Input any here documents.
9892 */
9893
Eric Andersenc470f442003-07-28 09:56:35 +00009894static void
9895parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009896{
Eric Andersencb57d552001-06-28 07:25:16 +00009897 struct heredoc *here;
9898 union node *n;
9899
Eric Andersenc470f442003-07-28 09:56:35 +00009900 here = heredoclist;
9901 heredoclist = 0;
9902
9903 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009904 if (needprompt) {
9905 setprompt(2);
9906 needprompt = 0;
9907 }
Eric Andersenc470f442003-07-28 09:56:35 +00009908 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9909 here->eofmark, here->striptabs);
9910 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009911 n->narg.type = NARG;
9912 n->narg.next = NULL;
9913 n->narg.text = wordtext;
9914 n->narg.backquote = backquotelist;
9915 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009916 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009917 }
9918}
9919
Eric Andersenc470f442003-07-28 09:56:35 +00009920static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009921{
Eric Andersencb57d552001-06-28 07:25:16 +00009922 int t;
9923
9924 t = readtoken();
9925 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009926 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009927}
9928
Eric Andersenc470f442003-07-28 09:56:35 +00009929static int
9930readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009931{
Eric Andersencb57d552001-06-28 07:25:16 +00009932 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009933#ifdef DEBUG
9934 int alreadyseen = tokpushback;
9935#endif
9936
Eric Andersend35c5df2002-01-09 15:37:36 +00009937#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009938top:
Eric Andersen2870d962001-07-02 17:27:21 +00009939#endif
9940
Eric Andersencb57d552001-06-28 07:25:16 +00009941 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009942
Eric Andersenc470f442003-07-28 09:56:35 +00009943 /*
9944 * eat newlines
9945 */
9946 if (checkkwd & CHKNL) {
9947 while (t == TNL) {
9948 parseheredoc();
9949 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009950 }
9951 }
9952
Eric Andersenc470f442003-07-28 09:56:35 +00009953 if (t != TWORD || quoteflag) {
9954 goto out;
9955 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009956
Eric Andersenc470f442003-07-28 09:56:35 +00009957 /*
9958 * check for keywords
9959 */
9960 if (checkkwd & CHKKWD) {
9961 const char *const *pp;
9962
9963 if ((pp = findkwd(wordtext))) {
9964 lasttoken = t = pp - tokname_array;
9965 TRACE(("keyword %s recognized\n", tokname(t)));
9966 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009967 }
Eric Andersenc470f442003-07-28 09:56:35 +00009968 }
9969
9970 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009971#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009972 struct alias *ap;
9973 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009974 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009975 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009976 }
Eric Andersencb57d552001-06-28 07:25:16 +00009977 goto top;
9978 }
Eric Andersen2870d962001-07-02 17:27:21 +00009979#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009980 }
Eric Andersenc470f442003-07-28 09:56:35 +00009981out:
9982 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009983#ifdef DEBUG
9984 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009985 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009986 else
Eric Andersenc470f442003-07-28 09:56:35 +00009987 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009988#endif
9989 return (t);
9990}
9991
9992
9993/*
9994 * Read the next input token.
9995 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009996 * backquotes. We set quoteflag to true if any part of the word was
9997 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009998 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009999 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010000 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010001 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010002 *
10003 * [Change comment: here documents and internal procedures]
10004 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10005 * word parsing code into a separate routine. In this case, readtoken
10006 * doesn't need to have any internal procedures, but parseword does.
10007 * We could also make parseoperator in essence the main routine, and
10008 * have parseword (readtoken1?) handle both words and redirection.]
10009 */
10010
Eric Andersen81fe1232003-07-29 06:38:40 +000010011#define NEW_xxreadtoken
10012#ifdef NEW_xxreadtoken
10013
10014/* singles must be first! */
10015static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10016
10017static const char xxreadtoken_tokens[] = {
10018 TNL, TLP, TRP, /* only single occurrence allowed */
10019 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10020 TEOF, /* corresponds to trailing nul */
10021 TAND, TOR, TENDCASE, /* if double occurrence */
10022};
10023
10024#define xxreadtoken_doubles \
10025 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10026#define xxreadtoken_singles \
10027 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10028
10029static int xxreadtoken()
10030{
10031 int c;
10032
10033 if (tokpushback) {
10034 tokpushback = 0;
10035 return lasttoken;
10036 }
10037 if (needprompt) {
10038 setprompt(2);
10039 needprompt = 0;
10040 }
10041 startlinno = plinno;
10042 for (;;) { /* until token or start of word found */
10043 c = pgetc_macro();
10044
10045 if ((c != ' ') && (c != '\t')
10046#ifdef CONFIG_ASH_ALIAS
10047 && (c != PEOA)
10048#endif
10049 ) {
10050 if (c == '#') {
10051 while ((c = pgetc()) != '\n' && c != PEOF);
10052 pungetc();
10053 } else if (c == '\\') {
10054 if (pgetc() != '\n') {
10055 pungetc();
10056 goto READTOKEN1;
10057 }
10058 startlinno = ++plinno;
10059 if (doprompt)
10060 setprompt(2);
10061 } else {
10062 const char *p
10063 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10064
10065 if (c != PEOF) {
10066 if (c == '\n') {
10067 plinno++;
10068 needprompt = doprompt;
10069 }
10070
10071 p = strchr(xxreadtoken_chars, c);
10072 if (p == NULL) {
10073 READTOKEN1:
10074 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10075 }
10076
10077 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10078 if (pgetc() == *p) { /* double occurrence? */
10079 p += xxreadtoken_doubles + 1;
10080 } else {
10081 pungetc();
10082 }
10083 }
10084 }
10085
10086 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10087 }
10088 }
10089 }
10090}
10091
10092
10093#else
Eric Andersen2870d962001-07-02 17:27:21 +000010094#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010095
Eric Andersenc470f442003-07-28 09:56:35 +000010096static int
10097xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010098{
Eric Andersencb57d552001-06-28 07:25:16 +000010099 int c;
10100
10101 if (tokpushback) {
10102 tokpushback = 0;
10103 return lasttoken;
10104 }
10105 if (needprompt) {
10106 setprompt(2);
10107 needprompt = 0;
10108 }
10109 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010110 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010111 c = pgetc_macro();
10112 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010113 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010114#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010115 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010116#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010117 continue;
10118 case '#':
10119 while ((c = pgetc()) != '\n' && c != PEOF);
10120 pungetc();
10121 continue;
10122 case '\\':
10123 if (pgetc() == '\n') {
10124 startlinno = ++plinno;
10125 if (doprompt)
10126 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010127 continue;
10128 }
10129 pungetc();
10130 goto breakloop;
10131 case '\n':
10132 plinno++;
10133 needprompt = doprompt;
10134 RETURN(TNL);
10135 case PEOF:
10136 RETURN(TEOF);
10137 case '&':
10138 if (pgetc() == '&')
10139 RETURN(TAND);
10140 pungetc();
10141 RETURN(TBACKGND);
10142 case '|':
10143 if (pgetc() == '|')
10144 RETURN(TOR);
10145 pungetc();
10146 RETURN(TPIPE);
10147 case ';':
10148 if (pgetc() == ';')
10149 RETURN(TENDCASE);
10150 pungetc();
10151 RETURN(TSEMI);
10152 case '(':
10153 RETURN(TLP);
10154 case ')':
10155 RETURN(TRP);
10156 default:
10157 goto breakloop;
10158 }
10159 }
Eric Andersenc470f442003-07-28 09:56:35 +000010160breakloop:
10161 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010162#undef RETURN
10163}
Eric Andersen81fe1232003-07-29 06:38:40 +000010164#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010165
Eric Andersencb57d552001-06-28 07:25:16 +000010166
Eric Andersencb57d552001-06-28 07:25:16 +000010167/*
10168 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10169 * is not NULL, read a here document. In the latter case, eofmark is the
10170 * word which marks the end of the document and striptabs is true if
10171 * leading tabs should be stripped from the document. The argument firstc
10172 * is the first character of the input token or document.
10173 *
10174 * Because C does not have internal subroutines, I have simulated them
10175 * using goto's to implement the subroutine linkage. The following macros
10176 * will run code that appears at the end of readtoken1.
10177 */
10178
Eric Andersen2870d962001-07-02 17:27:21 +000010179#define CHECKEND() {goto checkend; checkend_return:;}
10180#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10181#define PARSESUB() {goto parsesub; parsesub_return:;}
10182#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10183#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10184#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010185
10186static int
Eric Andersenc470f442003-07-28 09:56:35 +000010187readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010188{
Eric Andersencb57d552001-06-28 07:25:16 +000010189 int c = firstc;
10190 char *out;
10191 int len;
10192 char line[EOFMARKLEN + 1];
10193 struct nodelist *bqlist;
10194 int quotef;
10195 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010196 int varnest; /* levels of variables expansion */
10197 int arinest; /* levels of arithmetic expansion */
10198 int parenlevel; /* levels of parens in arithmetic */
10199 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010200 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010201 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010202#if __GNUC__
10203 /* Avoid longjmp clobbering */
10204 (void) &out;
10205 (void) &quotef;
10206 (void) &dblquote;
10207 (void) &varnest;
10208 (void) &arinest;
10209 (void) &parenlevel;
10210 (void) &dqvarnest;
10211 (void) &oldstyle;
10212 (void) &prevsyntax;
10213 (void) &syntax;
10214#endif
10215
10216 startlinno = plinno;
10217 dblquote = 0;
10218 if (syntax == DQSYNTAX)
10219 dblquote = 1;
10220 quotef = 0;
10221 bqlist = NULL;
10222 varnest = 0;
10223 arinest = 0;
10224 parenlevel = 0;
10225 dqvarnest = 0;
10226
10227 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010228 loop: { /* for each line, until end of word */
10229 CHECKEND(); /* set c to PEOF if at end of here document */
10230 for (;;) { /* until end of line or end of word */
10231 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10232 switch(SIT(c, syntax)) {
10233 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010234 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010235 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010236 USTPUTC(c, out);
10237 plinno++;
10238 if (doprompt)
10239 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010240 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010241 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010242 case CWORD:
10243 USTPUTC(c, out);
10244 break;
10245 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010246 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010247 USTPUTC(CTLESC, out);
10248 USTPUTC(c, out);
10249 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010250 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010251 c = pgetc2();
10252 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010253 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010254 USTPUTC('\\', out);
10255 pungetc();
10256 } else if (c == '\n') {
10257 if (doprompt)
10258 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010259 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010260 if (
10261 dblquote &&
10262 c != '\\' && c != '`' &&
10263 c != '$' && (
10264 c != '"' ||
10265 eofmark != NULL
10266 )
10267 ) {
10268 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010269 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010270 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010271 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010272 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010273 USTPUTC(c, out);
10274 quotef++;
10275 }
10276 break;
10277 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010278 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010279quotemark:
10280 if (eofmark == NULL) {
10281 USTPUTC(CTLQUOTEMARK, out);
10282 }
Eric Andersencb57d552001-06-28 07:25:16 +000010283 break;
10284 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010285 syntax = DQSYNTAX;
10286 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010287 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010288 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010289 if (eofmark != NULL && arinest == 0 &&
10290 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010291 USTPUTC(c, out);
10292 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010293 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010294 syntax = BASESYNTAX;
10295 dblquote = 0;
10296 }
10297 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010298 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010299 }
10300 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010301 case CVAR: /* '$' */
10302 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010303 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010304 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010305 if (varnest > 0) {
10306 varnest--;
10307 if (dqvarnest > 0) {
10308 dqvarnest--;
10309 }
10310 USTPUTC(CTLENDVAR, out);
10311 } else {
10312 USTPUTC(c, out);
10313 }
10314 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010315#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010316 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010317 parenlevel++;
10318 USTPUTC(c, out);
10319 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010320 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010321 if (parenlevel > 0) {
10322 USTPUTC(c, out);
10323 --parenlevel;
10324 } else {
10325 if (pgetc() == ')') {
10326 if (--arinest == 0) {
10327 USTPUTC(CTLENDARI, out);
10328 syntax = prevsyntax;
10329 if (syntax == DQSYNTAX)
10330 dblquote = 1;
10331 else
10332 dblquote = 0;
10333 } else
10334 USTPUTC(')', out);
10335 } else {
10336 /*
10337 * unbalanced parens
10338 * (don't 2nd guess - no error)
10339 */
10340 pungetc();
10341 USTPUTC(')', out);
10342 }
10343 }
10344 break;
10345#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010346 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010347 PARSEBACKQOLD();
10348 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010349 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010350 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010351 case CIGN:
10352 break;
10353 default:
10354 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010355 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010356#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010357 if (c != PEOA)
10358#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010359 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010360
Eric Andersencb57d552001-06-28 07:25:16 +000010361 }
10362 c = pgetc_macro();
10363 }
10364 }
Eric Andersenc470f442003-07-28 09:56:35 +000010365endword:
10366#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010367 if (syntax == ARISYNTAX)
10368 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010369#endif
10370 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010371 synerror("Unterminated quoted string");
10372 if (varnest != 0) {
10373 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010374 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010375 synerror("Missing '}'");
10376 }
10377 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010378 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010379 out = stackblock();
10380 if (eofmark == NULL) {
10381 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010382 && quotef == 0
10383 && len <= 2
10384 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010385 PARSEREDIR();
10386 return lasttoken = TREDIR;
10387 } else {
10388 pungetc();
10389 }
10390 }
10391 quoteflag = quotef;
10392 backquotelist = bqlist;
10393 grabstackblock(len);
10394 wordtext = out;
10395 return lasttoken = TWORD;
10396/* end of readtoken routine */
10397
10398
10399
10400/*
10401 * Check to see whether we are at the end of the here document. When this
10402 * is called, c is set to the first character of the next input line. If
10403 * we are at the end of the here document, this routine sets the c to PEOF.
10404 */
10405
Eric Andersenc470f442003-07-28 09:56:35 +000010406checkend: {
10407 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010408#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010409 if (c == PEOA) {
10410 c = pgetc2();
10411 }
10412#endif
10413 if (striptabs) {
10414 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010415 c = pgetc2();
10416 }
Eric Andersenc470f442003-07-28 09:56:35 +000010417 }
10418 if (c == *eofmark) {
10419 if (pfgets(line, sizeof line) != NULL) {
10420 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010421
Eric Andersenc470f442003-07-28 09:56:35 +000010422 p = line;
10423 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10424 if (*p == '\n' && *q == '\0') {
10425 c = PEOF;
10426 plinno++;
10427 needprompt = doprompt;
10428 } else {
10429 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010430 }
10431 }
10432 }
10433 }
Eric Andersenc470f442003-07-28 09:56:35 +000010434 goto checkend_return;
10435}
Eric Andersencb57d552001-06-28 07:25:16 +000010436
10437
10438/*
10439 * Parse a redirection operator. The variable "out" points to a string
10440 * specifying the fd to be redirected. The variable "c" contains the
10441 * first character of the redirection operator.
10442 */
10443
Eric Andersenc470f442003-07-28 09:56:35 +000010444parseredir: {
10445 char fd = *out;
10446 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010447
Eric Andersenc470f442003-07-28 09:56:35 +000010448 np = (union node *)stalloc(sizeof (struct nfile));
10449 if (c == '>') {
10450 np->nfile.fd = 1;
10451 c = pgetc();
10452 if (c == '>')
10453 np->type = NAPPEND;
10454 else if (c == '|')
10455 np->type = NCLOBBER;
10456 else if (c == '&')
10457 np->type = NTOFD;
10458 else {
10459 np->type = NTO;
10460 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010461 }
Eric Andersenc470f442003-07-28 09:56:35 +000010462 } else { /* c == '<' */
10463 np->nfile.fd = 0;
10464 switch (c = pgetc()) {
10465 case '<':
10466 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10467 np = (union node *)stalloc(sizeof (struct nhere));
10468 np->nfile.fd = 0;
10469 }
10470 np->type = NHERE;
10471 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10472 heredoc->here = np;
10473 if ((c = pgetc()) == '-') {
10474 heredoc->striptabs = 1;
10475 } else {
10476 heredoc->striptabs = 0;
10477 pungetc();
10478 }
10479 break;
10480
10481 case '&':
10482 np->type = NFROMFD;
10483 break;
10484
10485 case '>':
10486 np->type = NFROMTO;
10487 break;
10488
10489 default:
10490 np->type = NFROM;
10491 pungetc();
10492 break;
10493 }
Eric Andersencb57d552001-06-28 07:25:16 +000010494 }
Eric Andersenc470f442003-07-28 09:56:35 +000010495 if (fd != '\0')
10496 np->nfile.fd = digit_val(fd);
10497 redirnode = np;
10498 goto parseredir_return;
10499}
Eric Andersencb57d552001-06-28 07:25:16 +000010500
10501
10502/*
10503 * Parse a substitution. At this point, we have read the dollar sign
10504 * and nothing else.
10505 */
10506
Eric Andersenc470f442003-07-28 09:56:35 +000010507parsesub: {
10508 int subtype;
10509 int typeloc;
10510 int flags;
10511 char *p;
10512 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010513
Eric Andersenc470f442003-07-28 09:56:35 +000010514 c = pgetc();
10515 if (
10516 c <= PEOA_OR_PEOF ||
10517 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10518 ) {
10519 USTPUTC('$', out);
10520 pungetc();
10521 } else if (c == '(') { /* $(command) or $((arith)) */
10522 if (pgetc() == '(') {
10523#ifdef CONFIG_ASH_MATH_SUPPORT
10524 PARSEARITH();
10525#else
10526 synerror("We unsupport $((arith))");
10527#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010528 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010529 pungetc();
10530 PARSEBACKQNEW();
10531 }
10532 } else {
10533 USTPUTC(CTLVAR, out);
10534 typeloc = out - (char *)stackblock();
10535 USTPUTC(VSNORMAL, out);
10536 subtype = VSNORMAL;
10537 if (c == '{') {
10538 c = pgetc();
10539 if (c == '#') {
10540 if ((c = pgetc()) == '}')
10541 c = '#';
10542 else
10543 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010544 }
Eric Andersenc470f442003-07-28 09:56:35 +000010545 else
10546 subtype = 0;
10547 }
10548 if (c > PEOA_OR_PEOF && is_name(c)) {
10549 do {
10550 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010551 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010552 } while (c > PEOA_OR_PEOF && is_in_name(c));
10553 } else if (is_digit(c)) {
10554 do {
10555 STPUTC(c, out);
10556 c = pgetc();
10557 } while (is_digit(c));
10558 }
10559 else if (is_special(c)) {
10560 USTPUTC(c, out);
10561 c = pgetc();
10562 }
10563 else
10564badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010565
Eric Andersenc470f442003-07-28 09:56:35 +000010566 STPUTC('=', out);
10567 flags = 0;
10568 if (subtype == 0) {
10569 switch (c) {
10570 case ':':
10571 flags = VSNUL;
10572 c = pgetc();
10573 /*FALLTHROUGH*/
10574 default:
10575 p = strchr(types, c);
10576 if (p == NULL)
10577 goto badsub;
10578 subtype = p - types + VSNORMAL;
10579 break;
10580 case '%':
10581 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010582 {
10583 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010584 subtype = c == '#' ? VSTRIMLEFT :
10585 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010586 c = pgetc();
10587 if (c == cc)
10588 subtype++;
10589 else
10590 pungetc();
10591 break;
10592 }
10593 }
Eric Andersenc470f442003-07-28 09:56:35 +000010594 } else {
10595 pungetc();
10596 }
10597 if (dblquote || arinest)
10598 flags |= VSQUOTE;
10599 *((char *)stackblock() + typeloc) = subtype | flags;
10600 if (subtype != VSNORMAL) {
10601 varnest++;
10602 if (dblquote || arinest) {
10603 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010604 }
10605 }
10606 }
Eric Andersenc470f442003-07-28 09:56:35 +000010607 goto parsesub_return;
10608}
Eric Andersencb57d552001-06-28 07:25:16 +000010609
10610
10611/*
10612 * Called to parse command substitutions. Newstyle is set if the command
10613 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10614 * list of commands (passed by reference), and savelen is the number of
10615 * characters on the top of the stack which must be preserved.
10616 */
10617
Eric Andersenc470f442003-07-28 09:56:35 +000010618parsebackq: {
10619 struct nodelist **nlpp;
10620 int savepbq;
10621 union node *n;
10622 char *volatile str;
10623 struct jmploc jmploc;
10624 struct jmploc *volatile savehandler;
10625 size_t savelen;
10626 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010627#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010628 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010629#endif
10630
Eric Andersenc470f442003-07-28 09:56:35 +000010631 savepbq = parsebackquote;
10632 if (setjmp(jmploc.loc)) {
10633 if (str)
10634 ckfree(str);
10635 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010636 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010637 longjmp(handler->loc, 1);
10638 }
10639 INTOFF;
10640 str = NULL;
10641 savelen = out - (char *)stackblock();
10642 if (savelen > 0) {
10643 str = ckmalloc(savelen);
10644 memcpy(str, stackblock(), savelen);
10645 }
10646 savehandler = handler;
10647 handler = &jmploc;
10648 INTON;
10649 if (oldstyle) {
10650 /* We must read until the closing backquote, giving special
10651 treatment to some slashes, and then push the string and
10652 reread it as input, interpreting it normally. */
10653 char *pout;
10654 int pc;
10655 size_t psavelen;
10656 char *pstr;
10657
10658
10659 STARTSTACKSTR(pout);
10660 for (;;) {
10661 if (needprompt) {
10662 setprompt(2);
10663 needprompt = 0;
10664 }
10665 switch (pc = pgetc()) {
10666 case '`':
10667 goto done;
10668
10669 case '\\':
10670 if ((pc = pgetc()) == '\n') {
10671 plinno++;
10672 if (doprompt)
10673 setprompt(2);
10674 /*
10675 * If eating a newline, avoid putting
10676 * the newline into the new character
10677 * stream (via the STPUTC after the
10678 * switch).
10679 */
10680 continue;
10681 }
10682 if (pc != '\\' && pc != '`' && pc != '$'
10683 && (!dblquote || pc != '"'))
10684 STPUTC('\\', pout);
10685 if (pc > PEOA_OR_PEOF) {
10686 break;
10687 }
10688 /* fall through */
10689
10690 case PEOF:
10691#ifdef CONFIG_ASH_ALIAS
10692 case PEOA:
10693#endif
10694 startlinno = plinno;
10695 synerror("EOF in backquote substitution");
10696
10697 case '\n':
10698 plinno++;
10699 needprompt = doprompt;
10700 break;
10701
10702 default:
10703 break;
10704 }
10705 STPUTC(pc, pout);
10706 }
10707done:
10708 STPUTC('\0', pout);
10709 psavelen = pout - (char *)stackblock();
10710 if (psavelen > 0) {
10711 pstr = grabstackstr(pout);
10712 setinputstring(pstr);
10713 }
10714 }
10715 nlpp = &bqlist;
10716 while (*nlpp)
10717 nlpp = &(*nlpp)->next;
10718 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10719 (*nlpp)->next = NULL;
10720 parsebackquote = oldstyle;
10721
10722 if (oldstyle) {
10723 saveprompt = doprompt;
10724 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010725 }
10726
Eric Andersenc470f442003-07-28 09:56:35 +000010727 n = list(2);
10728
10729 if (oldstyle)
10730 doprompt = saveprompt;
10731 else {
10732 if (readtoken() != TRP)
10733 synexpect(TRP);
10734 }
10735
10736 (*nlpp)->n = n;
10737 if (oldstyle) {
10738 /*
10739 * Start reading from old file again, ignoring any pushed back
10740 * tokens left from the backquote parsing
10741 */
10742 popfile();
10743 tokpushback = 0;
10744 }
10745 while (stackblocksize() <= savelen)
10746 growstackblock();
10747 STARTSTACKSTR(out);
10748 if (str) {
10749 memcpy(out, str, savelen);
10750 STADJUST(savelen, out);
10751 INTOFF;
10752 ckfree(str);
10753 str = NULL;
10754 INTON;
10755 }
10756 parsebackquote = savepbq;
10757 handler = savehandler;
10758 if (arinest || dblquote)
10759 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10760 else
10761 USTPUTC(CTLBACKQ, out);
10762 if (oldstyle)
10763 goto parsebackq_oldreturn;
10764 else
10765 goto parsebackq_newreturn;
10766}
10767
10768#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010769/*
10770 * Parse an arithmetic expansion (indicate start of one and set state)
10771 */
Eric Andersenc470f442003-07-28 09:56:35 +000010772parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010773
Eric Andersenc470f442003-07-28 09:56:35 +000010774 if (++arinest == 1) {
10775 prevsyntax = syntax;
10776 syntax = ARISYNTAX;
10777 USTPUTC(CTLARI, out);
10778 if (dblquote)
10779 USTPUTC('"',out);
10780 else
10781 USTPUTC(' ',out);
10782 } else {
10783 /*
10784 * we collapse embedded arithmetic expansion to
10785 * parenthesis, which should be equivalent
10786 */
10787 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010788 }
Eric Andersenc470f442003-07-28 09:56:35 +000010789 goto parsearith_return;
10790}
10791#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010792
Eric Andersenc470f442003-07-28 09:56:35 +000010793} /* end of readtoken */
10794
Eric Andersencb57d552001-06-28 07:25:16 +000010795
10796
Eric Andersencb57d552001-06-28 07:25:16 +000010797/*
10798 * Returns true if the text contains nothing to expand (no dollar signs
10799 * or backquotes).
10800 */
10801
Eric Andersenc470f442003-07-28 09:56:35 +000010802static int
10803noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010804{
Eric Andersencb57d552001-06-28 07:25:16 +000010805 char *p;
10806 char c;
10807
10808 p = text;
10809 while ((c = *p++) != '\0') {
10810 if (c == CTLQUOTEMARK)
10811 continue;
10812 if (c == CTLESC)
10813 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010814 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010815 return 0;
10816 }
10817 return 1;
10818}
10819
10820
10821/*
Eric Andersenc470f442003-07-28 09:56:35 +000010822 * Return of a legal variable name (a letter or underscore followed by zero or
10823 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010824 */
10825
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010826static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010827endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010828{
Eric Andersenc470f442003-07-28 09:56:35 +000010829 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010830
Eric Andersenc470f442003-07-28 09:56:35 +000010831 p = (char *) name;
10832 if (! is_name(*p))
10833 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010834 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010835 if (! is_in_name(*p))
10836 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010837 }
Eric Andersenc470f442003-07-28 09:56:35 +000010838 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010839}
10840
10841
10842/*
10843 * Called when an unexpected token is read during the parse. The argument
10844 * is the token that is expected, or -1 if more than one type of token can
10845 * occur at this point.
10846 */
10847
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010848static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010849{
10850 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010851 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010852
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010853 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10854 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010855 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010856 synerror(msg);
10857 /* NOTREACHED */
10858}
10859
Eric Andersenc470f442003-07-28 09:56:35 +000010860static void
10861synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010862{
Eric Andersenc470f442003-07-28 09:56:35 +000010863 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010864 /* NOTREACHED */
10865}
10866
Eric Andersencb57d552001-06-28 07:25:16 +000010867
10868/*
10869 * called by editline -- any expansions to the prompt
10870 * should be added here.
10871 */
Eric Andersenc470f442003-07-28 09:56:35 +000010872
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010873static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010874{
Eric Andersenc470f442003-07-28 09:56:35 +000010875 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010876
10877 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010878 case 1:
10879 prompt = ps1val();
10880 break;
10881 case 2:
10882 prompt = ps2val();
10883 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010884 default: /* 0 */
10885 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010886 }
10887 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010888}
10889
Eric Andersencb57d552001-06-28 07:25:16 +000010890
Eric Andersenc470f442003-07-28 09:56:35 +000010891static const char *const *findkwd(const char *s)
10892{
10893 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010894 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010895 sizeof(const char *), pstrcmp);
10896}
10897
10898/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10899
Eric Andersencb57d552001-06-28 07:25:16 +000010900/*
10901 * Code for dealing with input/output redirection.
10902 */
10903
Eric Andersenc470f442003-07-28 09:56:35 +000010904#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010905#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010906# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010907#else
10908# define PIPESIZE PIPE_BUF
10909#endif
10910
Eric Andersen62483552001-07-10 06:09:16 +000010911/*
10912 * Open a file in noclobber mode.
10913 * The code was copied from bash.
10914 */
Eric Andersenc470f442003-07-28 09:56:35 +000010915static inline int
10916noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010917{
10918 int r, fd;
10919 struct stat finfo, finfo2;
10920
10921 /*
10922 * If the file exists and is a regular file, return an error
10923 * immediately.
10924 */
10925 r = stat(fname, &finfo);
10926 if (r == 0 && S_ISREG(finfo.st_mode)) {
10927 errno = EEXIST;
10928 return -1;
10929 }
10930
10931 /*
10932 * If the file was not present (r != 0), make sure we open it
10933 * exclusively so that if it is created before we open it, our open
10934 * will fail. Make sure that we do not truncate an existing file.
10935 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10936 * file was not a regular file, we leave O_EXCL off.
10937 */
10938 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010939 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10940 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010941
10942 /* If the open failed, return the file descriptor right away. */
10943 if (fd < 0)
10944 return fd;
10945
10946 /*
10947 * OK, the open succeeded, but the file may have been changed from a
10948 * non-regular file to a regular file between the stat and the open.
10949 * We are assuming that the O_EXCL open handles the case where FILENAME
10950 * did not exist and is symlinked to an existing file between the stat
10951 * and open.
10952 */
10953
10954 /*
10955 * If we can open it and fstat the file descriptor, and neither check
10956 * revealed that it was a regular file, and the file has not been
10957 * replaced, return the file descriptor.
10958 */
Eric Andersenc470f442003-07-28 09:56:35 +000010959 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10960 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010961 return fd;
10962
10963 /* The file has been replaced. badness. */
10964 close(fd);
10965 errno = EEXIST;
10966 return -1;
10967}
Eric Andersencb57d552001-06-28 07:25:16 +000010968
10969/*
Eric Andersen62483552001-07-10 06:09:16 +000010970 * Handle here documents. Normally we fork off a process to write the
10971 * data to a pipe. If the document is short, we can stuff the data in
10972 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010973 */
10974
Eric Andersenc470f442003-07-28 09:56:35 +000010975static inline int
10976openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010977{
10978 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010979 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010980
Eric Andersen62483552001-07-10 06:09:16 +000010981 if (pipe(pip) < 0)
10982 error("Pipe call failed");
10983 if (redir->type == NHERE) {
10984 len = strlen(redir->nhere.doc->narg.text);
10985 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010986 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010987 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010988 }
Eric Andersencb57d552001-06-28 07:25:16 +000010989 }
Eric Andersenc470f442003-07-28 09:56:35 +000010990 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010991 close(pip[0]);
10992 signal(SIGINT, SIG_IGN);
10993 signal(SIGQUIT, SIG_IGN);
10994 signal(SIGHUP, SIG_IGN);
10995#ifdef SIGTSTP
10996 signal(SIGTSTP, SIG_IGN);
10997#endif
10998 signal(SIGPIPE, SIG_DFL);
10999 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000011000 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000011001 else
11002 expandhere(redir->nhere.doc, pip[1]);
11003 _exit(0);
11004 }
Eric Andersenc470f442003-07-28 09:56:35 +000011005out:
Eric Andersen62483552001-07-10 06:09:16 +000011006 close(pip[1]);
11007 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011008}
11009
Eric Andersenc470f442003-07-28 09:56:35 +000011010static int
11011openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011012{
Eric Andersencb57d552001-06-28 07:25:16 +000011013 char *fname;
11014 int f;
11015
11016 switch (redir->nfile.type) {
11017 case NFROM:
11018 fname = redir->nfile.expfname;
11019 if ((f = open(fname, O_RDONLY)) < 0)
11020 goto eopen;
11021 break;
11022 case NFROMTO:
11023 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011024 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011025 goto ecreate;
11026 break;
11027 case NTO:
11028 /* Take care of noclobber mode. */
11029 if (Cflag) {
11030 fname = redir->nfile.expfname;
11031 if ((f = noclobberopen(fname)) < 0)
11032 goto ecreate;
11033 break;
11034 }
Eric Andersenc470f442003-07-28 09:56:35 +000011035 /* FALLTHROUGH */
11036 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011037 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011038 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011039 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011040 break;
11041 case NAPPEND:
11042 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011043 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011044 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011045 break;
11046 default:
11047#ifdef DEBUG
11048 abort();
11049#endif
11050 /* Fall through to eliminate warning. */
11051 case NTOFD:
11052 case NFROMFD:
11053 f = -1;
11054 break;
11055 case NHERE:
11056 case NXHERE:
11057 f = openhere(redir);
11058 break;
11059 }
11060
11061 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011062ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011063 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011064eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011065 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11066}
11067
Eric Andersenc470f442003-07-28 09:56:35 +000011068static inline void
11069dupredirect(union node *redir, int f)
11070{
11071 int fd = redir->nfile.fd;
11072
11073 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11074 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11075 copyfd(redir->ndup.dupfd, fd);
11076 }
11077 return;
11078 }
11079
11080 if (f != fd) {
11081 copyfd(f, fd);
11082 close(f);
11083 }
11084 return;
11085}
Eric Andersencb57d552001-06-28 07:25:16 +000011086
Eric Andersen62483552001-07-10 06:09:16 +000011087/*
11088 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11089 * old file descriptors are stashed away so that the redirection can be
11090 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11091 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011092 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011093 */
11094
Eric Andersenc470f442003-07-28 09:56:35 +000011095static void
11096redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011097{
11098 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011099 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011100 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011101 int fd;
11102 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011103 int *p;
11104 nullredirs++;
11105 if (!redir) {
11106 return;
Eric Andersen62483552001-07-10 06:09:16 +000011107 }
Eric Andersenc470f442003-07-28 09:56:35 +000011108 sv = NULL;
11109 INTOFF;
11110 if (flags & REDIR_PUSH) {
11111 struct redirtab *q;
11112 q = ckmalloc(sizeof (struct redirtab));
11113 q->next = redirlist;
11114 redirlist = q;
11115 q->nullredirs = nullredirs - 1;
11116 for (i = 0 ; i < 10 ; i++)
11117 q->renamed[i] = EMPTY;
11118 nullredirs = 0;
11119 sv = q;
11120 }
11121 n = redir;
11122 do {
Eric Andersen62483552001-07-10 06:09:16 +000011123 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011124 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011125 n->ndup.dupfd == fd)
11126 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011127
Eric Andersen62483552001-07-10 06:09:16 +000011128 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011129 if (fd == newfd)
11130 continue;
11131 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11132 i = fcntl(fd, F_DUPFD, 10);
11133
11134 if (i == -1) {
11135 i = errno;
11136 if (i != EBADF) {
11137 close(newfd);
11138 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011139 error("%d: %m", fd);
11140 /* NOTREACHED */
11141 }
Eric Andersenc470f442003-07-28 09:56:35 +000011142 } else {
11143 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011144 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011145 }
Eric Andersenc470f442003-07-28 09:56:35 +000011146 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011147 close(fd);
11148 }
Eric Andersenc470f442003-07-28 09:56:35 +000011149 dupredirect(n, newfd);
11150 } while ((n = n->nfile.next));
11151 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011152 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11153 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011154}
11155
11156
Eric Andersencb57d552001-06-28 07:25:16 +000011157/*
11158 * Undo the effects of the last redirection.
11159 */
11160
Eric Andersenc470f442003-07-28 09:56:35 +000011161void
11162popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011163{
Eric Andersenc470f442003-07-28 09:56:35 +000011164 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011165 int i;
11166
Eric Andersenc470f442003-07-28 09:56:35 +000011167 if (--nullredirs >= 0)
11168 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011169 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011170 rp = redirlist;
11171 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011172 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011173 if (!drop) {
11174 close(i);
11175 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011176 }
Eric Andersenc470f442003-07-28 09:56:35 +000011177 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011178 }
11179 }
11180 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011181 nullredirs = rp->nullredirs;
11182 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011183 INTON;
11184}
11185
11186/*
Eric Andersenc470f442003-07-28 09:56:35 +000011187 * Undo all redirections. Called on error or interrupt.
11188 */
11189
11190/*
Eric Andersencb57d552001-06-28 07:25:16 +000011191 * Discard all saved file descriptors.
11192 */
11193
Eric Andersenc470f442003-07-28 09:56:35 +000011194void
11195clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011196{
Eric Andersenc470f442003-07-28 09:56:35 +000011197 for (;;) {
11198 nullredirs = 0;
11199 if (!redirlist)
11200 break;
11201 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011202 }
Eric Andersencb57d552001-06-28 07:25:16 +000011203}
11204
11205
Eric Andersencb57d552001-06-28 07:25:16 +000011206/*
11207 * Copy a file descriptor to be >= to. Returns -1
11208 * if the source file descriptor is closed, EMPTY if there are no unused
11209 * file descriptors left.
11210 */
11211
Eric Andersenc470f442003-07-28 09:56:35 +000011212int
11213copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011214{
11215 int newfd;
11216
11217 newfd = fcntl(from, F_DUPFD, to);
11218 if (newfd < 0) {
11219 if (errno == EMFILE)
11220 return EMPTY;
11221 else
Eric Andersen2870d962001-07-02 17:27:21 +000011222 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011223 }
11224 return newfd;
11225}
11226
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011227
Eric Andersenc470f442003-07-28 09:56:35 +000011228int
11229redirectsafe(union node *redir, int flags)
11230{
11231 int err;
11232 volatile int saveint;
11233 struct jmploc *volatile savehandler = handler;
11234 struct jmploc jmploc;
11235
11236 SAVEINT(saveint);
11237 if (!(err = setjmp(jmploc.loc) * 2)) {
11238 handler = &jmploc;
11239 redirect(redir, flags);
11240 }
11241 handler = savehandler;
11242 if (err && exception != EXERROR)
11243 longjmp(handler->loc, 1);
11244 RESTOREINT(saveint);
11245 return err;
11246}
11247
11248/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11249
11250#ifdef DEBUG
11251static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011252static void shcmd(union node *, FILE *);
11253static void sharg(union node *, FILE *);
11254static void indent(int, char *, FILE *);
11255static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011256
11257
Eric Andersenc470f442003-07-28 09:56:35 +000011258void
11259showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011260{
11261 trputs("showtree called\n");
11262 shtree(n, 1, NULL, stdout);
11263}
Eric Andersencb57d552001-06-28 07:25:16 +000011264
Eric Andersenc470f442003-07-28 09:56:35 +000011265
11266static void
11267shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011268{
11269 struct nodelist *lp;
11270 const char *s;
11271
11272 if (n == NULL)
11273 return;
11274
11275 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011276 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011277 case NSEMI:
11278 s = "; ";
11279 goto binop;
11280 case NAND:
11281 s = " && ";
11282 goto binop;
11283 case NOR:
11284 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011285binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011286 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011287 /* if (ind < 0) */
11288 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011289 shtree(n->nbinary.ch2, ind, NULL, fp);
11290 break;
11291 case NCMD:
11292 shcmd(n, fp);
11293 if (ind >= 0)
11294 putc('\n', fp);
11295 break;
11296 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011297 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011298 shcmd(lp->n, fp);
11299 if (lp->next)
11300 fputs(" | ", fp);
11301 }
11302 if (n->npipe.backgnd)
11303 fputs(" &", fp);
11304 if (ind >= 0)
11305 putc('\n', fp);
11306 break;
11307 default:
11308 fprintf(fp, "<node type %d>", n->type);
11309 if (ind >= 0)
11310 putc('\n', fp);
11311 break;
11312 }
11313}
11314
11315
Eric Andersenc470f442003-07-28 09:56:35 +000011316static void
11317shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011318{
11319 union node *np;
11320 int first;
11321 const char *s;
11322 int dftfd;
11323
11324 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011325 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11326 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011327 putchar(' ');
11328 sharg(np, fp);
11329 first = 0;
11330 }
Eric Andersenc470f442003-07-28 09:56:35 +000011331 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11332 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011333 putchar(' ');
11334 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011335 case NTO: s = ">"; dftfd = 1; break;
11336 case NCLOBBER: s = ">|"; dftfd = 1; break;
11337 case NAPPEND: s = ">>"; dftfd = 1; break;
11338 case NTOFD: s = ">&"; dftfd = 1; break;
11339 case NFROM: s = "<"; dftfd = 0; break;
11340 case NFROMFD: s = "<&"; dftfd = 0; break;
11341 case NFROMTO: s = "<>"; dftfd = 0; break;
11342 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011343 }
11344 if (np->nfile.fd != dftfd)
11345 fprintf(fp, "%d", np->nfile.fd);
11346 fputs(s, fp);
11347 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11348 fprintf(fp, "%d", np->ndup.dupfd);
11349 } else {
11350 sharg(np->nfile.fname, fp);
11351 }
11352 first = 0;
11353 }
11354}
11355
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011356
Eric Andersenc470f442003-07-28 09:56:35 +000011357
11358static void
11359sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011360{
Eric Andersencb57d552001-06-28 07:25:16 +000011361 char *p;
11362 struct nodelist *bqlist;
11363 int subtype;
11364
11365 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011366 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011367 abort();
11368 }
11369 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011370 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011371 switch (*p) {
11372 case CTLESC:
11373 putc(*++p, fp);
11374 break;
11375 case CTLVAR:
11376 putc('$', fp);
11377 putc('{', fp);
11378 subtype = *++p;
11379 if (subtype == VSLENGTH)
11380 putc('#', fp);
11381
11382 while (*p != '=')
11383 putc(*p++, fp);
11384
11385 if (subtype & VSNUL)
11386 putc(':', fp);
11387
11388 switch (subtype & VSTYPE) {
11389 case VSNORMAL:
11390 putc('}', fp);
11391 break;
11392 case VSMINUS:
11393 putc('-', fp);
11394 break;
11395 case VSPLUS:
11396 putc('+', fp);
11397 break;
11398 case VSQUESTION:
11399 putc('?', fp);
11400 break;
11401 case VSASSIGN:
11402 putc('=', fp);
11403 break;
11404 case VSTRIMLEFT:
11405 putc('#', fp);
11406 break;
11407 case VSTRIMLEFTMAX:
11408 putc('#', fp);
11409 putc('#', fp);
11410 break;
11411 case VSTRIMRIGHT:
11412 putc('%', fp);
11413 break;
11414 case VSTRIMRIGHTMAX:
11415 putc('%', fp);
11416 putc('%', fp);
11417 break;
11418 case VSLENGTH:
11419 break;
11420 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011421 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011422 }
11423 break;
11424 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011425 putc('}', fp);
11426 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011427 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011428 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011429 putc('$', fp);
11430 putc('(', fp);
11431 shtree(bqlist->n, -1, NULL, fp);
11432 putc(')', fp);
11433 break;
11434 default:
11435 putc(*p, fp);
11436 break;
11437 }
11438 }
11439}
11440
11441
Eric Andersenc470f442003-07-28 09:56:35 +000011442static void
11443indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011444{
11445 int i;
11446
Eric Andersenc470f442003-07-28 09:56:35 +000011447 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011448 if (pfx && i == amount - 1)
11449 fputs(pfx, fp);
11450 putc('\t', fp);
11451 }
11452}
Eric Andersencb57d552001-06-28 07:25:16 +000011453
Eric Andersenc470f442003-07-28 09:56:35 +000011454
11455
11456/*
11457 * Debugging stuff.
11458 */
11459
11460
Eric Andersencb57d552001-06-28 07:25:16 +000011461FILE *tracefile;
11462
Eric Andersencb57d552001-06-28 07:25:16 +000011463
Eric Andersenc470f442003-07-28 09:56:35 +000011464void
11465trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011466{
Eric Andersenc470f442003-07-28 09:56:35 +000011467 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011468 return;
11469 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011470}
11471
Eric Andersenc470f442003-07-28 09:56:35 +000011472void
11473trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011474{
11475 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011476
Eric Andersenc470f442003-07-28 09:56:35 +000011477 if (debug != 1)
11478 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011479 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011480 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011481 va_end(va);
11482}
11483
Eric Andersenc470f442003-07-28 09:56:35 +000011484void
11485tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011486{
Eric Andersenc470f442003-07-28 09:56:35 +000011487 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011488 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011489 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011490}
11491
11492
Eric Andersenc470f442003-07-28 09:56:35 +000011493void
11494trputs(const char *s)
11495{
11496 if (debug != 1)
11497 return;
11498 fputs(s, tracefile);
11499}
11500
11501
11502static void
11503trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011504{
11505 char *p;
11506 char c;
11507
Eric Andersenc470f442003-07-28 09:56:35 +000011508 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011509 return;
11510 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011511 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011512 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011513 case '\n': c = 'n'; goto backslash;
11514 case '\t': c = 't'; goto backslash;
11515 case '\r': c = 'r'; goto backslash;
11516 case '"': c = '"'; goto backslash;
11517 case '\\': c = '\\'; goto backslash;
11518 case CTLESC: c = 'e'; goto backslash;
11519 case CTLVAR: c = 'v'; goto backslash;
11520 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11521 case CTLBACKQ: c = 'q'; goto backslash;
11522 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11523backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011524 putc(c, tracefile);
11525 break;
11526 default:
11527 if (*p >= ' ' && *p <= '~')
11528 putc(*p, tracefile);
11529 else {
11530 putc('\\', tracefile);
11531 putc(*p >> 6 & 03, tracefile);
11532 putc(*p >> 3 & 07, tracefile);
11533 putc(*p & 07, tracefile);
11534 }
11535 break;
11536 }
11537 }
11538 putc('"', tracefile);
11539}
11540
11541
Eric Andersenc470f442003-07-28 09:56:35 +000011542void
11543trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011544{
Eric Andersenc470f442003-07-28 09:56:35 +000011545 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011546 return;
11547 while (*ap) {
11548 trstring(*ap++);
11549 if (*ap)
11550 putc(' ', tracefile);
11551 else
11552 putc('\n', tracefile);
11553 }
Eric Andersencb57d552001-06-28 07:25:16 +000011554}
11555
11556
Eric Andersenc470f442003-07-28 09:56:35 +000011557void
11558opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011559{
Eric Andersencb57d552001-06-28 07:25:16 +000011560 char s[100];
11561#ifdef O_APPEND
11562 int flags;
11563#endif
11564
Eric Andersenc470f442003-07-28 09:56:35 +000011565 if (debug != 1) {
11566 if (tracefile)
11567 fflush(tracefile);
11568 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011569 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011570 }
Eric Andersenc470f442003-07-28 09:56:35 +000011571 scopy("./trace", s);
11572 if (tracefile) {
11573 if (!freopen(s, "a", tracefile)) {
11574 fprintf(stderr, "Can't re-open %s\n", s);
11575 debug = 0;
11576 return;
11577 }
11578 } else {
11579 if ((tracefile = fopen(s, "a")) == NULL) {
11580 fprintf(stderr, "Can't open %s\n", s);
11581 debug = 0;
11582 return;
11583 }
11584 }
Eric Andersencb57d552001-06-28 07:25:16 +000011585#ifdef O_APPEND
11586 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11587 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11588#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011589 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011590 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011591}
Eric Andersenc470f442003-07-28 09:56:35 +000011592#endif /* DEBUG */
11593
11594
11595/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11596
11597/*
11598 * Sigmode records the current value of the signal handlers for the various
11599 * modes. A value of zero means that the current handler is not known.
11600 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11601 */
11602
11603#define S_DFL 1 /* default signal handling (SIG_DFL) */
11604#define S_CATCH 2 /* signal is caught */
11605#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11606#define S_HARD_IGN 4 /* signal is ignored permenantly */
11607#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11608
Eric Andersencb57d552001-06-28 07:25:16 +000011609
11610
11611/*
Eric Andersencb57d552001-06-28 07:25:16 +000011612 * The trap builtin.
11613 */
11614
Eric Andersenc470f442003-07-28 09:56:35 +000011615int
11616trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011617{
11618 char *action;
11619 char **ap;
11620 int signo;
11621
Eric Andersenc470f442003-07-28 09:56:35 +000011622 nextopt(nullstr);
11623 ap = argptr;
11624 if (!*ap) {
11625 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011626 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011627 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011628
Eric Andersenc470f442003-07-28 09:56:35 +000011629 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011630 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011631 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011632 out1fmt("trap -- %s %s\n",
11633 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011634 }
11635 }
11636 return 0;
11637 }
Eric Andersenc470f442003-07-28 09:56:35 +000011638 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011639 action = NULL;
11640 else
11641 action = *ap++;
11642 while (*ap) {
11643 if ((signo = decode_signal(*ap, 0)) < 0)
11644 error("%s: bad trap", *ap);
11645 INTOFF;
11646 if (action) {
11647 if (action[0] == '-' && action[1] == '\0')
11648 action = NULL;
11649 else
Eric Andersenc470f442003-07-28 09:56:35 +000011650 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011651 }
Eric Andersenc470f442003-07-28 09:56:35 +000011652 if (trap[signo])
11653 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011654 trap[signo] = action;
11655 if (signo != 0)
11656 setsignal(signo);
11657 INTON;
11658 ap++;
11659 }
11660 return 0;
11661}
11662
11663
Eric Andersenc470f442003-07-28 09:56:35 +000011664/*
11665 * Clear traps on a fork.
11666 */
11667
11668void
11669clear_traps(void)
11670{
11671 char **tp;
11672
11673 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11674 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11675 INTOFF;
11676 ckfree(*tp);
11677 *tp = NULL;
11678 if (tp != &trap[0])
11679 setsignal(tp - trap);
11680 INTON;
11681 }
11682 }
11683}
11684
11685
Eric Andersencb57d552001-06-28 07:25:16 +000011686/*
11687 * Set the signal handler for the specified signal. The routine figures
11688 * out what it should be set to.
11689 */
11690
Eric Andersenc470f442003-07-28 09:56:35 +000011691void
11692setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011693{
11694 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011695 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011696 struct sigaction act;
11697
11698 if ((t = trap[signo]) == NULL)
11699 action = S_DFL;
11700 else if (*t != '\0')
11701 action = S_CATCH;
11702 else
11703 action = S_IGN;
11704 if (rootshell && action == S_DFL) {
11705 switch (signo) {
11706 case SIGINT:
11707 if (iflag || minusc || sflag == 0)
11708 action = S_CATCH;
11709 break;
11710 case SIGQUIT:
11711#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011712 if (debug)
11713 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011714#endif
11715 /* FALLTHROUGH */
11716 case SIGTERM:
11717 if (iflag)
11718 action = S_IGN;
11719 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011720#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011721 case SIGTSTP:
11722 case SIGTTOU:
11723 if (mflag)
11724 action = S_IGN;
11725 break;
11726#endif
11727 }
11728 }
11729
11730 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011731 tsig = *t;
11732 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011733 /*
11734 * current setting unknown
11735 */
11736 if (sigaction(signo, 0, &act) == -1) {
11737 /*
11738 * Pretend it worked; maybe we should give a warning
11739 * here, but other shells don't. We don't alter
11740 * sigmode, so that we retry every time.
11741 */
11742 return;
11743 }
11744 if (act.sa_handler == SIG_IGN) {
11745 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011746 signo == SIGTTIN || signo == SIGTTOU)) {
11747 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011748 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011749 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011750 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011751 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011752 }
11753 }
Eric Andersenc470f442003-07-28 09:56:35 +000011754 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011755 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011756 switch (action) {
11757 case S_CATCH:
11758 act.sa_handler = onsig;
11759 break;
11760 case S_IGN:
11761 act.sa_handler = SIG_IGN;
11762 break;
11763 default:
11764 act.sa_handler = SIG_DFL;
11765 }
Eric Andersencb57d552001-06-28 07:25:16 +000011766 *t = action;
11767 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011768 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011769 sigaction(signo, &act, 0);
11770}
11771
11772/*
11773 * Ignore a signal.
11774 */
11775
Eric Andersenc470f442003-07-28 09:56:35 +000011776void
11777ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011778{
11779 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11780 signal(signo, SIG_IGN);
11781 }
11782 sigmode[signo - 1] = S_HARD_IGN;
11783}
11784
11785
Eric Andersencb57d552001-06-28 07:25:16 +000011786/*
11787 * Signal handler.
11788 */
11789
Eric Andersenc470f442003-07-28 09:56:35 +000011790void
11791onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011792{
Eric Andersencb57d552001-06-28 07:25:16 +000011793 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011794 pendingsigs = signo;
11795
11796 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11797 if (!suppressint)
11798 onint();
11799 intpending = 1;
11800 }
Eric Andersencb57d552001-06-28 07:25:16 +000011801}
11802
11803
Eric Andersencb57d552001-06-28 07:25:16 +000011804/*
11805 * Called to execute a trap. Perhaps we should avoid entering new trap
11806 * handlers while we are executing a trap handler.
11807 */
11808
Eric Andersenc470f442003-07-28 09:56:35 +000011809void
11810dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011811{
Eric Andersenc470f442003-07-28 09:56:35 +000011812 char *p;
11813 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011814 int savestatus;
11815
Eric Andersenc470f442003-07-28 09:56:35 +000011816 savestatus = exitstatus;
11817 q = gotsig;
Glenn L McGrath2f325a02004-08-06 01:49:04 +000011818 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
Eric Andersenc470f442003-07-28 09:56:35 +000011819 *p = 0;
11820 p = trap[p - q + 1];
11821 if (!p)
11822 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011823 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011824 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011825 }
Eric Andersencb57d552001-06-28 07:25:16 +000011826}
11827
Eric Andersenc470f442003-07-28 09:56:35 +000011828
Eric Andersenc470f442003-07-28 09:56:35 +000011829/*
11830 * Controls whether the shell is interactive or not.
11831 */
11832
Eric Andersenc470f442003-07-28 09:56:35 +000011833void
11834setinteractive(int on)
11835{
11836 static int is_interactive;
11837
11838 if (++on == is_interactive)
11839 return;
11840 is_interactive = on;
11841 setsignal(SIGINT);
11842 setsignal(SIGQUIT);
11843 setsignal(SIGTERM);
11844#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11845 if(is_interactive > 1) {
11846 /* Looks like they want an interactive shell */
11847 static int do_banner;
11848
11849 if(!do_banner) {
11850 out1fmt(
11851 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11852 "Enter 'help' for a list of built-in commands.\n\n");
11853 do_banner++;
11854 }
11855 }
11856#endif
11857}
11858
11859
11860#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11861/*** List the available builtins ***/
11862
11863static int helpcmd(int argc, char **argv)
11864{
11865 int col, i;
11866
11867 out1fmt("\nBuilt-in commands:\n-------------------\n");
11868 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11869 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11870 builtincmd[i].name + 1);
11871 if (col > 60) {
11872 out1fmt("\n");
11873 col = 0;
11874 }
11875 }
11876#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11877 {
11878 extern const struct BB_applet applets[];
11879 extern const size_t NUM_APPLETS;
11880
11881 for (i = 0; i < NUM_APPLETS; i++) {
11882
11883 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11884 if (col > 60) {
11885 out1fmt("\n");
11886 col = 0;
11887 }
11888 }
11889 }
11890#endif
11891 out1fmt("\n\n");
11892 return EXIT_SUCCESS;
11893}
11894#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11895
Eric Andersencb57d552001-06-28 07:25:16 +000011896/*
11897 * Called to exit the shell.
11898 */
11899
Eric Andersenc470f442003-07-28 09:56:35 +000011900void
11901exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011902{
Eric Andersenc470f442003-07-28 09:56:35 +000011903 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011904 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011905 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011906 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011907
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011908 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011909 status = exitstatus;
11910 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011911 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011912 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011913 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011914 if ((p = trap[0]) != NULL && *p != '\0') {
11915 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011916 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011917 }
Eric Andersencb57d552001-06-28 07:25:16 +000011918 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011919 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011920#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11921 if (iflag && rootshell) {
11922 const char *hp = lookupvar("HISTFILE");
11923
11924 if(hp != NULL )
11925 save_history ( hp );
11926 }
11927#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011928out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011929 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011930 /* NOTREACHED */
11931}
11932
11933static int decode_signal(const char *string, int minsig)
11934{
11935 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011936 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011937
Eric Andersen34506362001-08-02 05:02:46 +000011938 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011939}
Eric Andersen34506362001-08-02 05:02:46 +000011940
Eric Andersenc470f442003-07-28 09:56:35 +000011941/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11942
11943static struct var *vartab[VTABSIZE];
11944
11945static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011946static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011947
11948/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011949 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011950 */
11951
Eric Andersenc470f442003-07-28 09:56:35 +000011952
11953#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011954/*
Eric Andersenc470f442003-07-28 09:56:35 +000011955 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011956 */
11957
Eric Andersenc470f442003-07-28 09:56:35 +000011958int
11959setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011960{
Eric Andersenc470f442003-07-28 09:56:35 +000011961 int err;
11962 volatile int saveint;
11963 struct jmploc *volatile savehandler = handler;
11964 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011965
Eric Andersenc470f442003-07-28 09:56:35 +000011966 SAVEINT(saveint);
11967 if (setjmp(jmploc.loc))
11968 err = 1;
11969 else {
11970 handler = &jmploc;
11971 setvar(name, val, flags);
11972 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011973 }
Eric Andersenc470f442003-07-28 09:56:35 +000011974 handler = savehandler;
11975 RESTOREINT(saveint);
11976 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011977}
Eric Andersenc470f442003-07-28 09:56:35 +000011978#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011979
11980/*
11981 * Set the value of a variable. The flags argument is ored with the
11982 * flags of the variable. If val is NULL, the variable is unset.
11983 */
11984
Eric Andersenc470f442003-07-28 09:56:35 +000011985static void
11986setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011987{
Eric Andersenc470f442003-07-28 09:56:35 +000011988 char *p, *q;
11989 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011990 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011991 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011992
Eric Andersenc470f442003-07-28 09:56:35 +000011993 q = endofname(name);
11994 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011995 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011996 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011997 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011998 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011999 if (val == NULL) {
12000 flags |= VUNSET;
12001 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012002 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000012003 }
12004 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012005 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12006 *p++ = '\0';
12007 if (vallen) {
12008 p[-1] = '=';
12009 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000012010 }
Eric Andersenc470f442003-07-28 09:56:35 +000012011 *p = '\0';
12012 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012013 INTON;
12014}
12015
12016
Eric Andersencb57d552001-06-28 07:25:16 +000012017/*
12018 * Same as setvar except that the variable and value are passed in
12019 * the first argument as name=value. Since the first argument will
12020 * be actually stored in the table, it should not be a string that
12021 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012022 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012023 */
12024
Eric Andersenc470f442003-07-28 09:56:35 +000012025void
12026setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012027{
12028 struct var *vp, **vpp;
12029
12030 vpp = hashvar(s);
12031 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012032 vp = *findvar(vpp, s);
12033 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012034 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12035 const char *n;
12036
Eric Andersenc470f442003-07-28 09:56:35 +000012037 if (flags & VNOSAVE)
12038 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012039 n = vp->text;
12040 error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012041 }
Eric Andersenc470f442003-07-28 09:56:35 +000012042
12043 if (flags & VNOSET)
12044 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012045
12046 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012047 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012048
Eric Andersenc470f442003-07-28 09:56:35 +000012049 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12050 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012051
Eric Andersenc470f442003-07-28 09:56:35 +000012052 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12053 } else {
12054 if (flags & VNOSET)
12055 return;
12056 /* not found */
12057 vp = ckmalloc(sizeof (*vp));
12058 vp->next = *vpp;
12059 vp->func = NULL;
12060 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012061 }
Eric Andersenc470f442003-07-28 09:56:35 +000012062 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12063 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012064 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012065 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012066}
12067
12068
Eric Andersencb57d552001-06-28 07:25:16 +000012069/*
12070 * Process a linked list of variable assignments.
12071 */
12072
Eric Andersenc470f442003-07-28 09:56:35 +000012073static void
12074listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012075{
Eric Andersenc470f442003-07-28 09:56:35 +000012076 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012077
Eric Andersenc470f442003-07-28 09:56:35 +000012078 if (!lp)
12079 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012080 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012081 do {
12082 setvareq(lp->text, flags);
12083 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012084 INTON;
12085}
12086
12087
Eric Andersencb57d552001-06-28 07:25:16 +000012088/*
12089 * Find the value of a variable. Returns NULL if not set.
12090 */
12091
Eric Andersenc470f442003-07-28 09:56:35 +000012092static char *
12093lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012094{
Eric Andersencb57d552001-06-28 07:25:16 +000012095 struct var *v;
12096
Eric Andersen16767e22004-03-16 05:14:10 +000012097 if ((v = *findvar(hashvar(name), name))) {
12098#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012099 /*
12100 * Dynamic variables are implemented roughly the same way they are
12101 * in bash. Namely, they're "special" so long as they aren't unset.
12102 * As soon as they're unset, they're no longer dynamic, and dynamic
12103 * lookup will no longer happen at that point. -- PFM.
12104 */
Eric Andersen16767e22004-03-16 05:14:10 +000012105 if((v->flags & VDYNAMIC))
12106 (*v->func)(NULL);
12107#endif
12108 if(!(v->flags & VUNSET))
12109 return strchrnul(v->text, '=') + 1;
12110 }
Eric Andersenef02f822004-03-11 13:34:24 +000012111
Eric Andersencb57d552001-06-28 07:25:16 +000012112 return NULL;
12113}
12114
12115
Eric Andersencb57d552001-06-28 07:25:16 +000012116/*
12117 * Search the environment of a builtin command.
12118 */
12119
Eric Andersenc470f442003-07-28 09:56:35 +000012120static char *
12121bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012122{
Eric Andersenc470f442003-07-28 09:56:35 +000012123 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012124
Eric Andersenc470f442003-07-28 09:56:35 +000012125 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012126 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012127 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012128 }
12129 return lookupvar(name);
12130}
12131
12132
Eric Andersencb57d552001-06-28 07:25:16 +000012133/*
Eric Andersenc470f442003-07-28 09:56:35 +000012134 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012135 */
12136
Eric Andersenc470f442003-07-28 09:56:35 +000012137static char **
12138listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012139{
Eric Andersencb57d552001-06-28 07:25:16 +000012140 struct var **vpp;
12141 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012142 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012143 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012144
Eric Andersenc470f442003-07-28 09:56:35 +000012145 STARTSTACKSTR(ep);
12146 vpp = vartab;
12147 mask = on | off;
12148 do {
12149 for (vp = *vpp ; vp ; vp = vp->next)
12150 if ((vp->flags & mask) == on) {
12151 if (ep == stackstrend())
12152 ep = growstackstr();
12153 *ep++ = (char *) vp->text;
12154 }
12155 } while (++vpp < vartab + VTABSIZE);
12156 if (ep == stackstrend())
12157 ep = growstackstr();
12158 if (end)
12159 *end = ep;
12160 *ep++ = NULL;
12161 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012162}
12163
12164
12165/*
Eric Andersenc470f442003-07-28 09:56:35 +000012166 * POSIX requires that 'set' (but not export or readonly) output the
12167 * variables in lexicographic order - by the locale's collating order (sigh).
12168 * Maybe we could keep them in an ordered balanced binary tree
12169 * instead of hashed lists.
12170 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012171 */
12172
Eric Andersenc470f442003-07-28 09:56:35 +000012173static int
12174showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012175{
Eric Andersenc470f442003-07-28 09:56:35 +000012176 const char *sep;
12177 char **ep, **epend;
12178
12179 ep = listvars(on, off, &epend);
12180 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12181
12182 sep = *sep_prefix ? spcstr : sep_prefix;
12183
12184 for (; ep < epend; ep++) {
12185 const char *p;
12186 const char *q;
12187
12188 p = strchrnul(*ep, '=');
12189 q = nullstr;
12190 if (*p)
12191 q = single_quote(++p);
12192
12193 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12194 }
12195
Eric Andersencb57d552001-06-28 07:25:16 +000012196 return 0;
12197}
12198
12199
12200
12201/*
12202 * The export and readonly commands.
12203 */
12204
Eric Andersenc470f442003-07-28 09:56:35 +000012205static int
12206exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012207{
12208 struct var *vp;
12209 char *name;
12210 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012211 char **aptr;
12212 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12213 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012214
Eric Andersenc470f442003-07-28 09:56:35 +000012215 notp = nextopt("p") - 'p';
12216 if (notp && ((name = *(aptr = argptr)))) {
12217 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012218 if ((p = strchr(name, '=')) != NULL) {
12219 p++;
12220 } else {
12221 if ((vp = *findvar(hashvar(name), name))) {
12222 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012223 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012224 }
12225 }
12226 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012227 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012228 } else {
12229 showvars(argv[0], flag, 0);
12230 }
12231 return 0;
12232}
12233
Eric Andersen34506362001-08-02 05:02:46 +000012234
Eric Andersencb57d552001-06-28 07:25:16 +000012235/*
Eric Andersencb57d552001-06-28 07:25:16 +000012236 * Make a variable a local variable. When a variable is made local, it's
12237 * value and flags are saved in a localvar structure. The saved values
12238 * will be restored when the shell function returns. We handle the name
12239 * "-" as a special case.
12240 */
12241
Eric Andersenc470f442003-07-28 09:56:35 +000012242static inline void
12243mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012244{
Eric Andersencb57d552001-06-28 07:25:16 +000012245 struct localvar *lvp;
12246 struct var **vpp;
12247 struct var *vp;
12248
12249 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012250 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012251 if (name[0] == '-' && name[1] == '\0') {
12252 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012253 p = ckmalloc(sizeof(optlist));
12254 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012255 vp = NULL;
12256 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012257 char *eq;
12258
Eric Andersencb57d552001-06-28 07:25:16 +000012259 vpp = hashvar(name);
12260 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012261 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012262 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012263 if (eq)
12264 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012265 else
12266 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012267 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012268 lvp->flags = VUNSET;
12269 } else {
12270 lvp->text = vp->text;
12271 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012272 vp->flags |= VSTRFIXED|VTEXTFIXED;
12273 if (eq)
12274 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012275 }
12276 }
12277 lvp->vp = vp;
12278 lvp->next = localvars;
12279 localvars = lvp;
12280 INTON;
12281}
12282
Eric Andersenc470f442003-07-28 09:56:35 +000012283/*
12284 * The "local" command.
12285 */
12286
12287static int
12288localcmd(int argc, char **argv)
12289{
12290 char *name;
12291
12292 argv = argptr;
12293 while ((name = *argv++) != NULL) {
12294 mklocal(name);
12295 }
12296 return 0;
12297}
12298
12299
Eric Andersencb57d552001-06-28 07:25:16 +000012300/*
12301 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012302 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012303 */
12304
Eric Andersenc470f442003-07-28 09:56:35 +000012305static void
12306poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012307{
Eric Andersencb57d552001-06-28 07:25:16 +000012308 struct localvar *lvp;
12309 struct var *vp;
12310
12311 while ((lvp = localvars) != NULL) {
12312 localvars = lvp->next;
12313 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012314 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12315 if (vp == NULL) { /* $- saved */
12316 memcpy(optlist, lvp->text, sizeof(optlist));
12317 ckfree(lvp->text);
12318 optschanged();
12319 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12320 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012321 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012322 if (vp->func)
12323 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12324 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12325 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012326 vp->flags = lvp->flags;
12327 vp->text = lvp->text;
12328 }
Eric Andersenc470f442003-07-28 09:56:35 +000012329 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012330 }
12331}
12332
12333
Eric Andersencb57d552001-06-28 07:25:16 +000012334/*
12335 * The unset builtin command. We unset the function before we unset the
12336 * variable to allow a function to be unset when there is a readonly variable
12337 * with the same name.
12338 */
12339
Eric Andersenc470f442003-07-28 09:56:35 +000012340int
12341unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012342{
12343 char **ap;
12344 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012345 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012346 int ret = 0;
12347
12348 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012349 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012350 }
Eric Andersencb57d552001-06-28 07:25:16 +000012351
Eric Andersenc470f442003-07-28 09:56:35 +000012352 for (ap = argptr; *ap ; ap++) {
12353 if (flag != 'f') {
12354 i = unsetvar(*ap);
12355 ret |= i;
12356 if (!(i & 2))
12357 continue;
12358 }
12359 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012360 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012361 }
Eric Andersenc470f442003-07-28 09:56:35 +000012362 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012363}
12364
12365
12366/*
12367 * Unset the specified variable.
12368 */
12369
Eric Andersenc470f442003-07-28 09:56:35 +000012370int
12371unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012372{
Eric Andersencb57d552001-06-28 07:25:16 +000012373 struct var **vpp;
12374 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012375 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012376
12377 vpp = findvar(hashvar(s), s);
12378 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012379 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012380 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012381 int flags = vp->flags;
12382
12383 retval = 1;
12384 if (flags & VREADONLY)
12385 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012386#ifdef DYNAMIC_VAR
12387 vp->flags &= ~VDYNAMIC;
12388#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012389 if (flags & VUNSET)
12390 goto ok;
12391 if ((flags & VSTRFIXED) == 0) {
12392 INTOFF;
12393 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12394 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012395 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012396 ckfree(vp);
12397 INTON;
12398 } else {
12399 setvar(s, 0, 0);
12400 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012401 }
Eric Andersenc470f442003-07-28 09:56:35 +000012402ok:
12403 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012404 }
12405
Eric Andersenc470f442003-07-28 09:56:35 +000012406out:
12407 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012408}
12409
12410
12411
12412/*
12413 * Find the appropriate entry in the hash table from the name.
12414 */
12415
Eric Andersenc470f442003-07-28 09:56:35 +000012416static struct var **
12417hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012418{
Eric Andersencb57d552001-06-28 07:25:16 +000012419 unsigned int hashval;
12420
12421 hashval = ((unsigned char) *p) << 4;
12422 while (*p && *p != '=')
12423 hashval += (unsigned char) *p++;
12424 return &vartab[hashval % VTABSIZE];
12425}
12426
12427
12428
12429/*
Eric Andersenc470f442003-07-28 09:56:35 +000012430 * Compares two strings up to the first = or '\0'. The first
12431 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012432 * either '=' or '\0'.
12433 */
12434
Eric Andersenc470f442003-07-28 09:56:35 +000012435int
12436varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012437{
Eric Andersenc470f442003-07-28 09:56:35 +000012438 int c, d;
12439
12440 while ((c = *p) == (d = *q)) {
12441 if (!c || c == '=')
12442 goto out;
12443 p++;
12444 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012445 }
Eric Andersenc470f442003-07-28 09:56:35 +000012446 if (c == '=')
12447 c = 0;
12448 if (d == '=')
12449 d = 0;
12450out:
12451 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012452}
12453
Eric Andersenc470f442003-07-28 09:56:35 +000012454static int
12455vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012456{
Eric Andersenc470f442003-07-28 09:56:35 +000012457 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012458}
12459
Eric Andersenc470f442003-07-28 09:56:35 +000012460static struct var **
12461findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012462{
12463 for (; *vpp; vpp = &(*vpp)->next) {
12464 if (varequal((*vpp)->text, name)) {
12465 break;
12466 }
12467 }
12468 return vpp;
12469}
Eric Andersenc470f442003-07-28 09:56:35 +000012470/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012471
Eric Andersenc470f442003-07-28 09:56:35 +000012472#include <sys/times.h>
12473
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012474static const unsigned char timescmd_str[] = {
12475 ' ', offsetof(struct tms, tms_utime),
12476 '\n', offsetof(struct tms, tms_stime),
12477 ' ', offsetof(struct tms, tms_cutime),
12478 '\n', offsetof(struct tms, tms_cstime),
12479 0
12480};
Eric Andersencb57d552001-06-28 07:25:16 +000012481
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012482static int timescmd(int ac, char **av)
12483{
12484 long int clk_tck, s, t;
12485 const unsigned char *p;
12486 struct tms buf;
12487
12488 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012489 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012490
12491 p = timescmd_str;
12492 do {
12493 t = *(clock_t *)(((char *) &buf) + p[1]);
12494 s = t / clk_tck;
12495 out1fmt("%ldm%ld.%.3lds%c",
12496 s/60, s%60,
12497 ((t - s * clk_tck) * 1000) / clk_tck,
12498 p[0]);
12499 } while (*(p += 2));
12500
Eric Andersencb57d552001-06-28 07:25:16 +000012501 return 0;
12502}
12503
Eric Andersend35c5df2002-01-09 15:37:36 +000012504#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012505static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012506dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012507{
Eric Andersened9ecf72004-06-22 08:29:45 +000012508 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012509 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012510
Eric Andersenc470f442003-07-28 09:56:35 +000012511 INTOFF;
12512 result = arith(s, &errcode);
12513 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012514 if (errcode == -3)
12515 error("exponent less than 0");
12516 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012517 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012518 else if (errcode == -5)
12519 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012520 else
12521 synerror(s);
12522 }
12523 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012524
Eric Andersenc470f442003-07-28 09:56:35 +000012525 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012526}
Eric Andersenc470f442003-07-28 09:56:35 +000012527
12528
12529/*
Eric Andersen90898442003-08-06 11:20:52 +000012530 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12531 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12532 *
12533 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012534 */
Eric Andersen90898442003-08-06 11:20:52 +000012535
Eric Andersenc470f442003-07-28 09:56:35 +000012536static int
Eric Andersen90898442003-08-06 11:20:52 +000012537letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012538{
Eric Andersenc470f442003-07-28 09:56:35 +000012539 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012540 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012541
Eric Andersen90898442003-08-06 11:20:52 +000012542 ap = argv + 1;
12543 if(!*ap)
12544 error("expression expected");
12545 for (ap = argv + 1; *ap; ap++) {
12546 i = dash_arith(*ap);
12547 }
Eric Andersenc470f442003-07-28 09:56:35 +000012548
Eric Andersen90898442003-08-06 11:20:52 +000012549 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012550}
12551#endif /* CONFIG_ASH_MATH_SUPPORT */
12552
12553/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12554
12555/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012556 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012557 */
12558
12559#undef rflag
12560
12561#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012562#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012563typedef enum __rlimit_resource rlim_t;
12564#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012565#endif
12566
12567
Eric Andersenc470f442003-07-28 09:56:35 +000012568/*
12569 * The read builtin. The -e option causes backslashes to escape the
12570 * following character.
12571 *
12572 * This uses unbuffered input, which may be avoidable in some cases.
12573 */
12574
12575static int
12576readcmd(int argc, char **argv)
12577{
12578 char **ap;
12579 int backslash;
12580 char c;
12581 int rflag;
12582 char *prompt;
12583 const char *ifs;
12584 char *p;
12585 int startword;
12586 int status;
12587 int i;
12588
12589 rflag = 0;
12590 prompt = NULL;
12591 while ((i = nextopt("p:r")) != '\0') {
12592 if (i == 'p')
12593 prompt = optionarg;
12594 else
12595 rflag = 1;
12596 }
12597 if (prompt && isatty(0)) {
12598 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012599 }
12600 if (*(ap = argptr) == NULL)
12601 error("arg count");
12602 if ((ifs = bltinlookup("IFS")) == NULL)
12603 ifs = defifs;
12604 status = 0;
12605 startword = 1;
12606 backslash = 0;
12607 STARTSTACKSTR(p);
12608 for (;;) {
12609 if (read(0, &c, 1) != 1) {
12610 status = 1;
12611 break;
12612 }
12613 if (c == '\0')
12614 continue;
12615 if (backslash) {
12616 backslash = 0;
12617 if (c != '\n')
12618 goto put;
12619 continue;
12620 }
12621 if (!rflag && c == '\\') {
12622 backslash++;
12623 continue;
12624 }
12625 if (c == '\n')
12626 break;
12627 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12628 continue;
12629 }
12630 startword = 0;
12631 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12632 STACKSTRNUL(p);
12633 setvar(*ap, stackblock(), 0);
12634 ap++;
12635 startword = 1;
12636 STARTSTACKSTR(p);
12637 } else {
12638put:
12639 STPUTC(c, p);
12640 }
12641 }
12642 STACKSTRNUL(p);
12643 /* Remove trailing blanks */
12644 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12645 *p = '\0';
12646 setvar(*ap, stackblock(), 0);
12647 while (*++ap != NULL)
12648 setvar(*ap, nullstr, 0);
12649 return status;
12650}
12651
12652
12653static int umaskcmd(int argc, char **argv)
12654{
12655 static const char permuser[3] = "ugo";
12656 static const char permmode[3] = "rwx";
12657 static const short int permmask[] = {
12658 S_IRUSR, S_IWUSR, S_IXUSR,
12659 S_IRGRP, S_IWGRP, S_IXGRP,
12660 S_IROTH, S_IWOTH, S_IXOTH
12661 };
12662
12663 char *ap;
12664 mode_t mask;
12665 int i;
12666 int symbolic_mode = 0;
12667
12668 while (nextopt("S") != '\0') {
12669 symbolic_mode = 1;
12670 }
12671
12672 INTOFF;
12673 mask = umask(0);
12674 umask(mask);
12675 INTON;
12676
12677 if ((ap = *argptr) == NULL) {
12678 if (symbolic_mode) {
12679 char buf[18];
12680 char *p = buf;
12681
12682 for (i = 0; i < 3; i++) {
12683 int j;
12684
12685 *p++ = permuser[i];
12686 *p++ = '=';
12687 for (j = 0; j < 3; j++) {
12688 if ((mask & permmask[3 * i + j]) == 0) {
12689 *p++ = permmode[j];
12690 }
12691 }
12692 *p++ = ',';
12693 }
12694 *--p = 0;
12695 puts(buf);
12696 } else {
12697 out1fmt("%.4o\n", mask);
12698 }
12699 } else {
12700 if (is_digit((unsigned char) *ap)) {
12701 mask = 0;
12702 do {
12703 if (*ap >= '8' || *ap < '0')
12704 error(illnum, argv[1]);
12705 mask = (mask << 3) + (*ap - '0');
12706 } while (*++ap != '\0');
12707 umask(mask);
12708 } else {
12709 mask = ~mask & 0777;
12710 if (!bb_parse_mode(ap, &mask)) {
12711 error("Illegal mode: %s", ap);
12712 }
12713 umask(~mask & 0777);
12714 }
12715 }
12716 return 0;
12717}
12718
12719/*
12720 * ulimit builtin
12721 *
12722 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12723 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12724 * ash by J.T. Conklin.
12725 *
12726 * Public domain.
12727 */
12728
12729struct limits {
12730 const char *name;
12731 int cmd;
12732 int factor; /* multiply by to get rlim_{cur,max} values */
12733 char option;
12734};
12735
12736static const struct limits limits[] = {
12737#ifdef RLIMIT_CPU
12738 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12739#endif
12740#ifdef RLIMIT_FSIZE
12741 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12742#endif
12743#ifdef RLIMIT_DATA
12744 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12745#endif
12746#ifdef RLIMIT_STACK
12747 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12748#endif
12749#ifdef RLIMIT_CORE
12750 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12751#endif
12752#ifdef RLIMIT_RSS
12753 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12754#endif
12755#ifdef RLIMIT_MEMLOCK
12756 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12757#endif
12758#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012759 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012760#endif
12761#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012762 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012763#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012764#ifdef RLIMIT_AS
12765 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012766#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012767#ifdef RLIMIT_LOCKS
12768 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012769#endif
12770 { (char *) 0, 0, 0, '\0' }
12771};
12772
Glenn L McGrath76620622004-01-13 10:19:37 +000012773enum limtype { SOFT = 0x1, HARD = 0x2 };
12774
12775static void printlim(enum limtype how, const struct rlimit *limit,
12776 const struct limits *l)
12777{
12778 rlim_t val;
12779
12780 val = limit->rlim_max;
12781 if (how & SOFT)
12782 val = limit->rlim_cur;
12783
12784 if (val == RLIM_INFINITY)
12785 out1fmt("unlimited\n");
12786 else {
12787 val /= l->factor;
12788 out1fmt("%lld\n", (long long) val);
12789 }
12790}
12791
Eric Andersenc470f442003-07-28 09:56:35 +000012792int
12793ulimitcmd(int argc, char **argv)
12794{
12795 int c;
12796 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012797 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012798 const struct limits *l;
12799 int set, all = 0;
12800 int optc, what;
12801 struct rlimit limit;
12802
12803 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012804 while ((optc = nextopt("HSa"
12805#ifdef RLIMIT_CPU
12806 "t"
12807#endif
12808#ifdef RLIMIT_FSIZE
12809 "f"
12810#endif
12811#ifdef RLIMIT_DATA
12812 "d"
12813#endif
12814#ifdef RLIMIT_STACK
12815 "s"
12816#endif
12817#ifdef RLIMIT_CORE
12818 "c"
12819#endif
12820#ifdef RLIMIT_RSS
12821 "m"
12822#endif
12823#ifdef RLIMIT_MEMLOCK
12824 "l"
12825#endif
12826#ifdef RLIMIT_NPROC
12827 "p"
12828#endif
12829#ifdef RLIMIT_NOFILE
12830 "n"
12831#endif
12832#ifdef RLIMIT_AS
12833 "v"
12834#endif
12835#ifdef RLIMIT_LOCKS
12836 "w"
12837#endif
12838 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012839 switch (optc) {
12840 case 'H':
12841 how = HARD;
12842 break;
12843 case 'S':
12844 how = SOFT;
12845 break;
12846 case 'a':
12847 all = 1;
12848 break;
12849 default:
12850 what = optc;
12851 }
12852
Glenn L McGrath76620622004-01-13 10:19:37 +000012853 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012854 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012855
12856 set = *argptr ? 1 : 0;
12857 if (set) {
12858 char *p = *argptr;
12859
12860 if (all || argptr[1])
12861 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012862 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012863 val = RLIM_INFINITY;
12864 else {
12865 val = (rlim_t) 0;
12866
12867 while ((c = *p++) >= '0' && c <= '9')
12868 {
12869 val = (val * 10) + (long)(c - '0');
12870 if (val < (rlim_t) 0)
12871 break;
12872 }
12873 if (c)
12874 error("bad number");
12875 val *= l->factor;
12876 }
12877 }
12878 if (all) {
12879 for (l = limits; l->name; l++) {
12880 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012881 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012882 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012883 }
12884 return 0;
12885 }
12886
12887 getrlimit(l->cmd, &limit);
12888 if (set) {
12889 if (how & HARD)
12890 limit.rlim_max = val;
12891 if (how & SOFT)
12892 limit.rlim_cur = val;
12893 if (setrlimit(l->cmd, &limit) < 0)
12894 error("error setting limit (%m)");
12895 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012896 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012897 }
12898 return 0;
12899}
12900
Eric Andersen90898442003-08-06 11:20:52 +000012901
12902#ifdef CONFIG_ASH_MATH_SUPPORT
12903
12904/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12905
12906 Permission is hereby granted, free of charge, to any person obtaining
12907 a copy of this software and associated documentation files (the
12908 "Software"), to deal in the Software without restriction, including
12909 without limitation the rights to use, copy, modify, merge, publish,
12910 distribute, sublicense, and/or sell copies of the Software, and to
12911 permit persons to whom the Software is furnished to do so, subject to
12912 the following conditions:
12913
12914 The above copyright notice and this permission notice shall be
12915 included in all copies or substantial portions of the Software.
12916
12917 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12918 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12919 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12920 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12921 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12922 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12923 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12924*/
12925
12926/* This is my infix parser/evaluator. It is optimized for size, intended
12927 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000012928 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000012929 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000012930 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000012931 * be that which POSIX specifies for shells. */
12932
12933/* The code uses a simple two-stack algorithm. See
12934 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000012935 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000012936 * this is based (this code differs in that it applies operators immediately
12937 * to the stack instead of adding them to a queue to end up with an
12938 * expression). */
12939
12940/* To use the routine, call it with an expression string and error return
12941 * pointer */
12942
12943/*
12944 * Aug 24, 2001 Manuel Novoa III
12945 *
12946 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12947 *
12948 * 1) In arith_apply():
12949 * a) Cached values of *numptr and &(numptr[-1]).
12950 * b) Removed redundant test for zero denominator.
12951 *
12952 * 2) In arith():
12953 * a) Eliminated redundant code for processing operator tokens by moving
12954 * to a table-based implementation. Also folded handling of parens
12955 * into the table.
12956 * b) Combined all 3 loops which called arith_apply to reduce generated
12957 * code size at the cost of speed.
12958 *
12959 * 3) The following expressions were treated as valid by the original code:
12960 * 1() , 0! , 1 ( *3 ) .
12961 * These bugs have been fixed by internally enclosing the expression in
12962 * parens and then checking that all binary ops and right parens are
12963 * preceded by a valid expression (NUM_TOKEN).
12964 *
Eric Andersenaff114c2004-04-14 17:51:38 +000012965 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000012966 * ctype's isspace() if it is used by another busybox applet or if additional
12967 * whitespace chars should be considered. Look below the "#include"s for a
12968 * precompiler test.
12969 */
12970
12971/*
12972 * Aug 26, 2001 Manuel Novoa III
12973 *
12974 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12975 *
12976 * Merge in Aaron's comments previously posted to the busybox list,
12977 * modified slightly to take account of my changes to the code.
12978 *
12979 */
12980
12981/*
12982 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12983 *
12984 * - allow access to variable,
12985 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12986 * - realize assign syntax (VAR=expr, +=, *= etc)
12987 * - realize exponentiation (** operator)
12988 * - realize comma separated - expr, expr
12989 * - realise ++expr --expr expr++ expr--
12990 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000012991 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000012992 * - was restored loses XOR operator
12993 * - remove one goto label, added three ;-)
12994 * - protect $((num num)) as true zero expr (Manuel`s error)
12995 * - always use special isspace(), see comment from bash ;-)
12996 */
12997
12998
12999#define arith_isspace(arithval) \
13000 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13001
13002
13003typedef unsigned char operator;
13004
13005/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013006 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013007 * precedence. The ID portion is so that multiple operators can have the
13008 * same precedence, ensuring that the leftmost one is evaluated first.
13009 * Consider * and /. */
13010
13011#define tok_decl(prec,id) (((id)<<5)|(prec))
13012#define PREC(op) ((op) & 0x1F)
13013
13014#define TOK_LPAREN tok_decl(0,0)
13015
13016#define TOK_COMMA tok_decl(1,0)
13017
13018#define TOK_ASSIGN tok_decl(2,0)
13019#define TOK_AND_ASSIGN tok_decl(2,1)
13020#define TOK_OR_ASSIGN tok_decl(2,2)
13021#define TOK_XOR_ASSIGN tok_decl(2,3)
13022#define TOK_PLUS_ASSIGN tok_decl(2,4)
13023#define TOK_MINUS_ASSIGN tok_decl(2,5)
13024#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13025#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13026
13027#define TOK_MUL_ASSIGN tok_decl(3,0)
13028#define TOK_DIV_ASSIGN tok_decl(3,1)
13029#define TOK_REM_ASSIGN tok_decl(3,2)
13030
13031/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13032#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13033
13034/* conditional is right associativity too */
13035#define TOK_CONDITIONAL tok_decl(4,0)
13036#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13037
13038#define TOK_OR tok_decl(5,0)
13039
13040#define TOK_AND tok_decl(6,0)
13041
13042#define TOK_BOR tok_decl(7,0)
13043
13044#define TOK_BXOR tok_decl(8,0)
13045
13046#define TOK_BAND tok_decl(9,0)
13047
13048#define TOK_EQ tok_decl(10,0)
13049#define TOK_NE tok_decl(10,1)
13050
13051#define TOK_LT tok_decl(11,0)
13052#define TOK_GT tok_decl(11,1)
13053#define TOK_GE tok_decl(11,2)
13054#define TOK_LE tok_decl(11,3)
13055
13056#define TOK_LSHIFT tok_decl(12,0)
13057#define TOK_RSHIFT tok_decl(12,1)
13058
13059#define TOK_ADD tok_decl(13,0)
13060#define TOK_SUB tok_decl(13,1)
13061
13062#define TOK_MUL tok_decl(14,0)
13063#define TOK_DIV tok_decl(14,1)
13064#define TOK_REM tok_decl(14,2)
13065
13066/* exponent is right associativity */
13067#define TOK_EXPONENT tok_decl(15,1)
13068
13069/* For now unary operators. */
13070#define UNARYPREC 16
13071#define TOK_BNOT tok_decl(UNARYPREC,0)
13072#define TOK_NOT tok_decl(UNARYPREC,1)
13073
13074#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13075#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13076
13077#define PREC_PRE (UNARYPREC+2)
13078
13079#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13080#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13081
13082#define PREC_POST (UNARYPREC+3)
13083
13084#define TOK_POST_INC tok_decl(PREC_POST, 0)
13085#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13086
13087#define SPEC_PREC (UNARYPREC+4)
13088
13089#define TOK_NUM tok_decl(SPEC_PREC, 0)
13090#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13091
13092#define NUMPTR (*numstackptr)
13093
13094static inline int tok_have_assign(operator op)
13095{
13096 operator prec = PREC(op);
13097
13098 convert_prec_is_assing(prec);
13099 return (prec == PREC(TOK_ASSIGN) ||
13100 prec == PREC_PRE || prec == PREC_POST);
13101}
13102
13103static inline int is_right_associativity(operator prec)
13104{
13105 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13106 prec == PREC(TOK_CONDITIONAL));
13107}
13108
13109
13110typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013111 arith_t val;
13112 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013113 char contidional_second_val_initialized;
13114 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013115 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013116} v_n_t;
13117
13118
13119typedef struct CHK_VAR_RECURSIVE_LOOPED {
13120 const char *var;
13121 struct CHK_VAR_RECURSIVE_LOOPED *next;
13122} chk_var_recursive_looped_t;
13123
13124static chk_var_recursive_looped_t *prev_chk_var_recursive;
13125
13126
13127static int arith_lookup_val(v_n_t *t)
13128{
13129 if(t->var) {
13130 const char * p = lookupvar(t->var);
13131
13132 if(p) {
13133 int errcode;
13134
13135 /* recursive try as expression */
13136 chk_var_recursive_looped_t *cur;
13137 chk_var_recursive_looped_t cur_save;
13138
13139 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13140 if(strcmp(cur->var, t->var) == 0) {
13141 /* expression recursion loop detected */
13142 return -5;
13143 }
13144 }
13145 /* save current lookuped var name */
13146 cur = prev_chk_var_recursive;
13147 cur_save.var = t->var;
13148 cur_save.next = cur;
13149 prev_chk_var_recursive = &cur_save;
13150
13151 t->val = arith (p, &errcode);
13152 /* restore previous ptr after recursiving */
13153 prev_chk_var_recursive = cur;
13154 return errcode;
13155 } else {
13156 /* allow undefined var as 0 */
13157 t->val = 0;
13158 }
13159 }
13160 return 0;
13161}
13162
13163/* "applying" a token means performing it on the top elements on the integer
13164 * stack. For a unary operator it will only change the top element, but a
13165 * binary operator will pop two arguments and push a result */
13166static inline int
13167arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13168{
Eric Andersen90898442003-08-06 11:20:52 +000013169 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013170 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013171 int ret_arith_lookup_val;
13172
13173 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13174 without arguments */
13175 numptr_m1 = NUMPTR - 1;
13176
13177 /* check operand is var with noninteger value */
13178 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13179 if(ret_arith_lookup_val)
13180 return ret_arith_lookup_val;
13181
13182 rez = numptr_m1->val;
13183 if (op == TOK_UMINUS)
13184 rez *= -1;
13185 else if (op == TOK_NOT)
13186 rez = !rez;
13187 else if (op == TOK_BNOT)
13188 rez = ~rez;
13189 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13190 rez++;
13191 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13192 rez--;
13193 else if (op != TOK_UPLUS) {
13194 /* Binary operators */
13195
13196 /* check and binary operators need two arguments */
13197 if (numptr_m1 == numstack) goto err;
13198
13199 /* ... and they pop one */
13200 --NUMPTR;
13201 numptr_val = rez;
13202 if (op == TOK_CONDITIONAL) {
13203 if(! numptr_m1->contidional_second_val_initialized) {
13204 /* protect $((expr1 ? expr2)) without ": expr" */
13205 goto err;
13206 }
13207 rez = numptr_m1->contidional_second_val;
13208 } else if(numptr_m1->contidional_second_val_initialized) {
13209 /* protect $((expr1 : expr2)) without "expr ? " */
13210 goto err;
13211 }
13212 numptr_m1 = NUMPTR - 1;
13213 if(op != TOK_ASSIGN) {
13214 /* check operand is var with noninteger value for not '=' */
13215 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13216 if(ret_arith_lookup_val)
13217 return ret_arith_lookup_val;
13218 }
13219 if (op == TOK_CONDITIONAL) {
13220 numptr_m1->contidional_second_val = rez;
13221 }
13222 rez = numptr_m1->val;
13223 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13224 rez |= numptr_val;
13225 else if (op == TOK_OR)
13226 rez = numptr_val || rez;
13227 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13228 rez &= numptr_val;
13229 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13230 rez ^= numptr_val;
13231 else if (op == TOK_AND)
13232 rez = rez && numptr_val;
13233 else if (op == TOK_EQ)
13234 rez = (rez == numptr_val);
13235 else if (op == TOK_NE)
13236 rez = (rez != numptr_val);
13237 else if (op == TOK_GE)
13238 rez = (rez >= numptr_val);
13239 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13240 rez >>= numptr_val;
13241 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13242 rez <<= numptr_val;
13243 else if (op == TOK_GT)
13244 rez = (rez > numptr_val);
13245 else if (op == TOK_LT)
13246 rez = (rez < numptr_val);
13247 else if (op == TOK_LE)
13248 rez = (rez <= numptr_val);
13249 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13250 rez *= numptr_val;
13251 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13252 rez += numptr_val;
13253 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13254 rez -= numptr_val;
13255 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13256 rez = numptr_val;
13257 else if (op == TOK_CONDITIONAL_SEP) {
13258 if (numptr_m1 == numstack) {
13259 /* protect $((expr : expr)) without "expr ? " */
13260 goto err;
13261 }
13262 numptr_m1->contidional_second_val_initialized = op;
13263 numptr_m1->contidional_second_val = numptr_val;
13264 }
13265 else if (op == TOK_CONDITIONAL) {
13266 rez = rez ?
13267 numptr_val : numptr_m1->contidional_second_val;
13268 }
13269 else if(op == TOK_EXPONENT) {
13270 if(numptr_val < 0)
13271 return -3; /* exponent less than 0 */
13272 else {
13273 long c = 1;
13274
13275 if(numptr_val)
13276 while(numptr_val--)
13277 c *= rez;
13278 rez = c;
13279 }
13280 }
13281 else if(numptr_val==0) /* zero divisor check */
13282 return -2;
13283 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13284 rez /= numptr_val;
13285 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13286 rez %= numptr_val;
13287 }
13288 if(tok_have_assign(op)) {
13289 char buf[32];
13290
13291 if(numptr_m1->var == NULL) {
13292 /* Hmm, 1=2 ? */
13293 goto err;
13294 }
13295 /* save to shell variable */
Eric Andersened9ecf72004-06-22 08:29:45 +000013296 sprintf(buf, "%lld", (long long) rez);
Eric Andersen90898442003-08-06 11:20:52 +000013297 setvar(numptr_m1->var, buf, 0);
13298 /* after saving, make previous value for v++ or v-- */
13299 if(op == TOK_POST_INC)
13300 rez--;
13301 else if(op == TOK_POST_DEC)
13302 rez++;
13303 }
13304 numptr_m1->val = rez;
13305 /* protect geting var value, is number now */
13306 numptr_m1->var = NULL;
13307 return 0;
13308err: return(-1);
13309}
13310
13311/* longest must first */
13312static const char op_tokens[] = {
13313 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13314 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13315 '<','<', 0, TOK_LSHIFT,
13316 '>','>', 0, TOK_RSHIFT,
13317 '|','|', 0, TOK_OR,
13318 '&','&', 0, TOK_AND,
13319 '!','=', 0, TOK_NE,
13320 '<','=', 0, TOK_LE,
13321 '>','=', 0, TOK_GE,
13322 '=','=', 0, TOK_EQ,
13323 '|','=', 0, TOK_OR_ASSIGN,
13324 '&','=', 0, TOK_AND_ASSIGN,
13325 '*','=', 0, TOK_MUL_ASSIGN,
13326 '/','=', 0, TOK_DIV_ASSIGN,
13327 '%','=', 0, TOK_REM_ASSIGN,
13328 '+','=', 0, TOK_PLUS_ASSIGN,
13329 '-','=', 0, TOK_MINUS_ASSIGN,
13330 '-','-', 0, TOK_POST_DEC,
13331 '^','=', 0, TOK_XOR_ASSIGN,
13332 '+','+', 0, TOK_POST_INC,
13333 '*','*', 0, TOK_EXPONENT,
13334 '!', 0, TOK_NOT,
13335 '<', 0, TOK_LT,
13336 '>', 0, TOK_GT,
13337 '=', 0, TOK_ASSIGN,
13338 '|', 0, TOK_BOR,
13339 '&', 0, TOK_BAND,
13340 '*', 0, TOK_MUL,
13341 '/', 0, TOK_DIV,
13342 '%', 0, TOK_REM,
13343 '+', 0, TOK_ADD,
13344 '-', 0, TOK_SUB,
13345 '^', 0, TOK_BXOR,
13346 /* uniq */
13347 '~', 0, TOK_BNOT,
13348 ',', 0, TOK_COMMA,
13349 '?', 0, TOK_CONDITIONAL,
13350 ':', 0, TOK_CONDITIONAL_SEP,
13351 ')', 0, TOK_RPAREN,
13352 '(', 0, TOK_LPAREN,
13353 0
13354};
13355/* ptr to ")" */
13356#define endexpression &op_tokens[sizeof(op_tokens)-7]
13357
13358
Eric Andersened9ecf72004-06-22 08:29:45 +000013359static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013360{
13361 register char arithval; /* Current character under analysis */
13362 operator lasttok, op;
13363 operator prec;
13364
13365 const char *p = endexpression;
13366 int errcode;
13367
13368 size_t datasizes = strlen(expr) + 2;
13369
13370 /* Stack of integers */
13371 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013372 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013373 * the reader. */
13374 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13375 *numstackptr = numstack;
13376 /* Stack of operator tokens */
13377 operator *stack = alloca((datasizes) * sizeof(operator)),
13378 *stackptr = stack;
13379
13380 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13381 *perrcode = errcode = 0;
13382
13383 while(1) {
13384 if ((arithval = *expr) == 0) {
13385 if (p == endexpression) {
13386 /* Null expression. */
13387 return 0;
13388 }
13389
13390 /* This is only reached after all tokens have been extracted from the
13391 * input stream. If there are still tokens on the operator stack, they
13392 * are to be applied in order. At the end, there should be a final
13393 * result on the integer stack */
13394
13395 if (expr != endexpression + 1) {
13396 /* If we haven't done so already, */
13397 /* append a closing right paren */
13398 expr = endexpression;
13399 /* and let the loop process it. */
13400 continue;
13401 }
13402 /* At this point, we're done with the expression. */
13403 if (numstackptr != numstack+1) {
13404 /* ... but if there isn't, it's bad */
13405 err:
13406 return (*perrcode = -1);
13407 }
13408 if(numstack->var) {
13409 /* expression is $((var)) only, lookup now */
13410 errcode = arith_lookup_val(numstack);
13411 }
13412 ret:
13413 *perrcode = errcode;
13414 return numstack->val;
13415 } else {
13416 /* Continue processing the expression. */
13417 if (arith_isspace(arithval)) {
13418 /* Skip whitespace */
13419 goto prologue;
13420 }
13421 if((p = endofname(expr)) != expr) {
13422 int var_name_size = (p-expr) + 1; /* trailing zero */
13423
13424 numstackptr->var = alloca(var_name_size);
13425 safe_strncpy(numstackptr->var, expr, var_name_size);
13426 expr = p;
13427 num:
13428 numstackptr->contidional_second_val_initialized = 0;
13429 numstackptr++;
13430 lasttok = TOK_NUM;
13431 continue;
13432 } else if (is_digit(arithval)) {
13433 numstackptr->var = NULL;
13434 numstackptr->val = strtol(expr, (char **) &expr, 0);
13435 goto num;
13436 }
13437 for(p = op_tokens; ; p++) {
13438 const char *o;
13439
13440 if(*p == 0) {
13441 /* strange operator not found */
13442 goto err;
13443 }
13444 for(o = expr; *p && *o == *p; p++)
13445 o++;
13446 if(! *p) {
13447 /* found */
13448 expr = o - 1;
13449 break;
13450 }
13451 /* skip tail uncompared token */
13452 while(*p)
13453 p++;
13454 /* skip zero delim */
13455 p++;
13456 }
13457 op = p[1];
13458
13459 /* post grammar: a++ reduce to num */
13460 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13461 lasttok = TOK_NUM;
13462
13463 /* Plus and minus are binary (not unary) _only_ if the last
13464 * token was as number, or a right paren (which pretends to be
13465 * a number, since it evaluates to one). Think about it.
13466 * It makes sense. */
13467 if (lasttok != TOK_NUM) {
13468 switch(op) {
13469 case TOK_ADD:
13470 op = TOK_UPLUS;
13471 break;
13472 case TOK_SUB:
13473 op = TOK_UMINUS;
13474 break;
13475 case TOK_POST_INC:
13476 op = TOK_PRE_INC;
13477 break;
13478 case TOK_POST_DEC:
13479 op = TOK_PRE_DEC;
13480 break;
13481 }
13482 }
13483 /* We don't want a unary operator to cause recursive descent on the
13484 * stack, because there can be many in a row and it could cause an
13485 * operator to be evaluated before its argument is pushed onto the
13486 * integer stack. */
13487 /* But for binary operators, "apply" everything on the operator
13488 * stack until we find an operator with a lesser priority than the
13489 * one we have just extracted. */
13490 /* Left paren is given the lowest priority so it will never be
13491 * "applied" in this way.
13492 * if associativity is right and priority eq, applied also skip
13493 */
13494 prec = PREC(op);
13495 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13496 /* not left paren or unary */
13497 if (lasttok != TOK_NUM) {
13498 /* binary op must be preceded by a num */
13499 goto err;
13500 }
13501 while (stackptr != stack) {
13502 if (op == TOK_RPAREN) {
13503 /* The algorithm employed here is simple: while we don't
13504 * hit an open paren nor the bottom of the stack, pop
13505 * tokens and apply them */
13506 if (stackptr[-1] == TOK_LPAREN) {
13507 --stackptr;
13508 /* Any operator directly after a */
13509 lasttok = TOK_NUM;
13510 /* close paren should consider itself binary */
13511 goto prologue;
13512 }
13513 } else {
13514 operator prev_prec = PREC(stackptr[-1]);
13515
13516 convert_prec_is_assing(prec);
13517 convert_prec_is_assing(prev_prec);
13518 if (prev_prec < prec)
13519 break;
13520 /* check right assoc */
13521 if(prev_prec == prec && is_right_associativity(prec))
13522 break;
13523 }
13524 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13525 if(errcode) goto ret;
13526 }
13527 if (op == TOK_RPAREN) {
13528 goto err;
13529 }
13530 }
13531
13532 /* Push this operator to the stack and remember it. */
13533 *stackptr++ = lasttok = op;
13534
13535 prologue:
13536 ++expr;
13537 }
13538 }
13539}
13540#endif /* CONFIG_ASH_MATH_SUPPORT */
13541
13542
Eric Andersenc470f442003-07-28 09:56:35 +000013543#ifdef DEBUG
13544const char *bb_applet_name = "debug stuff usage";
13545int main(int argc, char **argv)
13546{
13547 return ash_main(argc, argv);
13548}
13549#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013550
Eric Andersendf82f612001-06-28 07:46:40 +000013551/*-
13552 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013553 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013554 *
13555 * This code is derived from software contributed to Berkeley by
13556 * Kenneth Almquist.
13557 *
13558 * Redistribution and use in source and binary forms, with or without
13559 * modification, are permitted provided that the following conditions
13560 * are met:
13561 * 1. Redistributions of source code must retain the above copyright
13562 * notice, this list of conditions and the following disclaimer.
13563 * 2. Redistributions in binary form must reproduce the above copyright
13564 * notice, this list of conditions and the following disclaimer in the
13565 * documentation and/or other materials provided with the distribution.
13566 *
Eric Andersen2870d962001-07-02 17:27:21 +000013567 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13568 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013569 *
13570 * 4. Neither the name of the University nor the names of its contributors
13571 * may be used to endorse or promote products derived from this software
13572 * without specific prior written permission.
13573 *
13574 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13575 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13576 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13577 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13578 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13579 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13580 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13581 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13582 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13583 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13584 * SUCH DAMAGE.
13585 */