blob: 5f859a1fbdce283bdb385354bf7741a366038292 [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 **);
Paul Fox0b621582005-08-09 19:38:05 +00001252#ifdef CONFIG_ASH_BUILTIN_ECHO
1253static int echocmd(int, char **);
1254#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001255static int execcmd(int, char **);
1256static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001257static int exportcmd(int, char **);
1258static int falsecmd(int, char **);
1259#ifdef JOBS
1260static int fgcmd(int, char **);
1261#endif
1262#ifdef CONFIG_ASH_GETOPTS
1263static int getoptscmd(int, char **);
1264#endif
1265static int hashcmd(int, char **);
1266#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1267static int helpcmd(int argc, char **argv);
1268#endif
1269#ifdef JOBS
1270static int jobscmd(int, char **);
1271#endif
Eric Andersen90898442003-08-06 11:20:52 +00001272#ifdef CONFIG_ASH_MATH_SUPPORT
1273static int letcmd(int, char **);
1274#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001275static int localcmd(int, char **);
1276static int pwdcmd(int, char **);
1277static int readcmd(int, char **);
1278static int returncmd(int, char **);
1279static int setcmd(int, char **);
1280static int shiftcmd(int, char **);
1281static int timescmd(int, char **);
1282static int trapcmd(int, char **);
1283static int truecmd(int, char **);
1284static int typecmd(int, char **);
1285static int umaskcmd(int, char **);
1286static int unsetcmd(int, char **);
1287static int waitcmd(int, char **);
1288static int ulimitcmd(int, char **);
1289#ifdef JOBS
1290static int killcmd(int, char **);
1291#endif
1292
1293/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1294
1295#ifdef CONFIG_ASH_MAIL
1296static void chkmail(void);
1297static void changemail(const char *);
1298#endif
1299
1300/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1301
1302/* values of cmdtype */
1303#define CMDUNKNOWN -1 /* no entry in table for command */
1304#define CMDNORMAL 0 /* command is an executable program */
1305#define CMDFUNCTION 1 /* command is a shell function */
1306#define CMDBUILTIN 2 /* command is a shell builtin */
1307
1308struct builtincmd {
1309 const char *name;
1310 int (*builtin)(int, char **);
1311 /* unsigned flags; */
1312};
1313
Paul Fox0b621582005-08-09 19:38:05 +00001314
1315#define COMMANDCMD (builtincmd + 5 + \
1316 ENABLE_ASH_ALIAS + ENABLE_ASH_JOB_CONTROL)
1317#define EXECCMD (builtincmd + 7 + \
1318 ENABLE_ASH_CMDCMD + ENABLE_ASH_ALIAS + \
1319 ENABLE_ASH_BUILTIN_ECHO + ENABLE_ASH_JOB_CONTROL)
Eric Andersenc470f442003-07-28 09:56:35 +00001320
1321#define BUILTIN_NOSPEC "0"
1322#define BUILTIN_SPECIAL "1"
1323#define BUILTIN_REGULAR "2"
1324#define BUILTIN_SPEC_REG "3"
1325#define BUILTIN_ASSIGN "4"
1326#define BUILTIN_SPEC_ASSG "5"
1327#define BUILTIN_REG_ASSG "6"
1328#define BUILTIN_SPEC_REG_ASSG "7"
1329
1330#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1331#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
Paul Foxc3850c82005-07-20 18:23:39 +00001332#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001333
1334static const struct builtincmd builtincmd[] = {
1335 { BUILTIN_SPEC_REG ".", dotcmd },
1336 { BUILTIN_SPEC_REG ":", truecmd },
1337#ifdef CONFIG_ASH_ALIAS
1338 { BUILTIN_REG_ASSG "alias", aliascmd },
1339#endif
1340#ifdef JOBS
1341 { BUILTIN_REGULAR "bg", bgcmd },
1342#endif
1343 { BUILTIN_SPEC_REG "break", breakcmd },
1344 { BUILTIN_REGULAR "cd", cdcmd },
1345 { BUILTIN_NOSPEC "chdir", cdcmd },
1346#ifdef CONFIG_ASH_CMDCMD
1347 { BUILTIN_REGULAR "command", commandcmd },
1348#endif
1349 { BUILTIN_SPEC_REG "continue", breakcmd },
Paul Fox0b621582005-08-09 19:38:05 +00001350#ifdef CONFIG_ASH_BUILTIN_ECHO
1351 { BUILTIN_REGULAR "echo", echocmd },
1352#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001353 { BUILTIN_SPEC_REG "eval", evalcmd },
1354 { BUILTIN_SPEC_REG "exec", execcmd },
1355 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001356 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1357 { BUILTIN_REGULAR "false", falsecmd },
1358#ifdef JOBS
1359 { BUILTIN_REGULAR "fg", fgcmd },
1360#endif
1361#ifdef CONFIG_ASH_GETOPTS
1362 { BUILTIN_REGULAR "getopts", getoptscmd },
1363#endif
1364 { BUILTIN_NOSPEC "hash", hashcmd },
1365#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1366 { BUILTIN_NOSPEC "help", helpcmd },
1367#endif
1368#ifdef JOBS
1369 { BUILTIN_REGULAR "jobs", jobscmd },
1370 { BUILTIN_REGULAR "kill", killcmd },
1371#endif
1372#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001373 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001374#endif
1375 { BUILTIN_ASSIGN "local", localcmd },
1376 { BUILTIN_NOSPEC "pwd", pwdcmd },
1377 { BUILTIN_REGULAR "read", readcmd },
1378 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1379 { BUILTIN_SPEC_REG "return", returncmd },
1380 { BUILTIN_SPEC_REG "set", setcmd },
1381 { BUILTIN_SPEC_REG "shift", shiftcmd },
1382 { BUILTIN_SPEC_REG "times", timescmd },
1383 { BUILTIN_SPEC_REG "trap", trapcmd },
1384 { BUILTIN_REGULAR "true", truecmd },
1385 { BUILTIN_NOSPEC "type", typecmd },
1386 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1387 { BUILTIN_REGULAR "umask", umaskcmd },
1388#ifdef CONFIG_ASH_ALIAS
1389 { BUILTIN_REGULAR "unalias", unaliascmd },
1390#endif
1391 { BUILTIN_SPEC_REG "unset", unsetcmd },
1392 { BUILTIN_REGULAR "wait", waitcmd },
1393};
1394
1395#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1396
1397
1398
1399struct cmdentry {
1400 int cmdtype;
1401 union param {
1402 int index;
1403 const struct builtincmd *cmd;
1404 struct funcnode *func;
1405 } u;
1406};
1407
1408
1409/* action to find_command() */
1410#define DO_ERR 0x01 /* prints errors */
1411#define DO_ABS 0x02 /* checks absolute paths */
1412#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1413#define DO_ALTPATH 0x08 /* using alternate path */
1414#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1415
1416static const char *pathopt; /* set by padvance */
1417
1418static void shellexec(char **, const char *, int)
1419 __attribute__((__noreturn__));
1420static char *padvance(const char **, const char *);
1421static void find_command(char *, struct cmdentry *, int, const char *);
1422static struct builtincmd *find_builtin(const char *);
1423static void hashcd(void);
1424static void changepath(const char *);
1425static void defun(char *, union node *);
1426static void unsetfunc(const char *);
1427
Eric Andersened9ecf72004-06-22 08:29:45 +00001428#ifdef CONFIG_ASH_MATH_SUPPORT_64
1429typedef int64_t arith_t;
1430#else
1431typedef long arith_t;
1432#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001433
1434#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001435static arith_t dash_arith(const char *);
1436static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001437#endif
1438
Eric Andersen16767e22004-03-16 05:14:10 +00001439#ifdef CONFIG_ASH_RANDOM_SUPPORT
1440static unsigned long rseed;
1441static void change_random(const char *);
1442# ifndef DYNAMIC_VAR
1443# define DYNAMIC_VAR
1444# endif
1445#endif
1446
Eric Andersenc470f442003-07-28 09:56:35 +00001447/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1448
1449static void reset(void);
1450
1451/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001452
1453/*
1454 * Shell variables.
1455 */
1456
1457/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001458#define VEXPORT 0x01 /* variable is exported */
1459#define VREADONLY 0x02 /* variable cannot be modified */
1460#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1461#define VTEXTFIXED 0x08 /* text is statically allocated */
1462#define VSTACK 0x10 /* text is allocated on the stack */
1463#define VUNSET 0x20 /* the variable is not set */
1464#define VNOFUNC 0x40 /* don't call the callback function */
1465#define VNOSET 0x80 /* do not set variable - just readonly test */
1466#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001467#ifdef DYNAMIC_VAR
1468# define VDYNAMIC 0x200 /* dynamic variable */
1469# else
1470# define VDYNAMIC 0
1471#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001472
1473struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001474 struct var *next; /* next entry in hash list */
1475 int flags; /* flags are defined above */
1476 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001477 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001478 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001479};
1480
1481struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001482 struct localvar *next; /* next local variable in list */
1483 struct var *vp; /* the variable that was made local */
1484 int flags; /* saved flags */
1485 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001486};
1487
1488
Eric Andersen2870d962001-07-02 17:27:21 +00001489static struct localvar *localvars;
1490
Eric Andersenc470f442003-07-28 09:56:35 +00001491/*
1492 * Shell variables.
1493 */
1494
1495#ifdef CONFIG_ASH_GETOPTS
1496static void getoptsreset(const char *);
1497#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001498
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001499#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001500#include <locale.h>
1501static void change_lc_all(const char *value);
1502static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001503#endif
1504
Eric Andersenef02f822004-03-11 13:34:24 +00001505
Eric Andersen2870d962001-07-02 17:27:21 +00001506#define VTABSIZE 39
1507
Eric Andersen90898442003-08-06 11:20:52 +00001508static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001509#ifdef IFS_BROKEN
1510static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001511#define defifs (defifsvar + 4)
1512#else
Eric Andersenc470f442003-07-28 09:56:35 +00001513static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001514#endif
1515
Eric Andersenc470f442003-07-28 09:56:35 +00001516
1517static struct var varinit[] = {
1518#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001519 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001520#else
Eric Andersen16767e22004-03-16 05:14:10 +00001521 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001522#endif
1523
1524#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001525 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1526 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001527#endif
1528
Eric Andersen16767e22004-03-16 05:14:10 +00001529 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1530 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1531 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1532 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001533#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001534 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1535#endif
1536#ifdef CONFIG_ASH_RANDOM_SUPPORT
1537 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001538#endif
1539#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001540 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1541 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001542#endif
1543#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001544 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001545#endif
1546};
1547
1548#define vifs varinit[0]
1549#ifdef CONFIG_ASH_MAIL
1550#define vmail (&vifs)[1]
1551#define vmpath (&vmail)[1]
1552#else
1553#define vmpath vifs
1554#endif
1555#define vpath (&vmpath)[1]
1556#define vps1 (&vpath)[1]
1557#define vps2 (&vps1)[1]
1558#define vps4 (&vps2)[1]
1559#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001560#ifdef CONFIG_ASH_GETOPTS
1561#define vrandom (&voptind)[1]
1562#else
1563#define vrandom (&vps4)[1]
1564#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001565#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001566
1567/*
1568 * The following macros access the values of the above variables.
1569 * They have to skip over the name. They return the null string
1570 * for unset variables.
1571 */
1572
1573#define ifsval() (vifs.text + 4)
1574#define ifsset() ((vifs.flags & VUNSET) == 0)
1575#define mailval() (vmail.text + 5)
1576#define mpathval() (vmpath.text + 9)
1577#define pathval() (vpath.text + 5)
1578#define ps1val() (vps1.text + 4)
1579#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001580#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001581#define optindval() (voptind.text + 7)
1582
1583#define mpathset() ((vmpath.flags & VUNSET) == 0)
1584
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001585static void setvar(const char *, const char *, int);
1586static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001587static void listsetvar(struct strlist *, int);
1588static char *lookupvar(const char *);
1589static char *bltinlookup(const char *);
1590static char **listvars(int, int, char ***);
1591#define environment() listvars(VEXPORT, VUNSET, 0)
1592static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001593static void poplocalvars(void);
1594static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001595#ifdef CONFIG_ASH_GETOPTS
1596static int setvarsafe(const char *, const char *, int);
1597#endif
1598static int varcmp(const char *, const char *);
1599static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001600
1601
Eric Andersenc470f442003-07-28 09:56:35 +00001602static inline int varequal(const char *a, const char *b) {
1603 return !varcmp(a, b);
1604}
Eric Andersen2870d962001-07-02 17:27:21 +00001605
1606
Eric Andersenc470f442003-07-28 09:56:35 +00001607static int loopnest; /* current loop nesting level */
1608
Eric Andersenc470f442003-07-28 09:56:35 +00001609/*
1610 * The parsefile structure pointed to by the global variable parsefile
1611 * contains information about the current file being read.
1612 */
1613
1614
1615struct redirtab {
1616 struct redirtab *next;
1617 int renamed[10];
1618 int nullredirs;
1619};
1620
1621static struct redirtab *redirlist;
1622static int nullredirs;
1623
1624extern char **environ;
1625
1626/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1627
1628
1629static void outstr(const char *, FILE *);
1630static void outcslow(int, FILE *);
1631static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001632static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001633static int out1fmt(const char *, ...)
1634 __attribute__((__format__(__printf__,1,2)));
1635static int fmtstr(char *, size_t, const char *, ...)
1636 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001637
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001638static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001639
Eric Andersenc470f442003-07-28 09:56:35 +00001640
1641static void out1str(const char *p)
1642{
1643 outstr(p, stdout);
1644}
1645
1646static void out2str(const char *p)
1647{
1648 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001649 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001650}
1651
1652/*
1653 * Initialization code.
1654 */
1655
1656/*
1657 * This routine initializes the builtin variables.
1658 */
1659
1660static inline void
1661initvar(void)
1662{
1663 struct var *vp;
1664 struct var *end;
1665 struct var **vpp;
1666
1667 /*
1668 * PS1 depends on uid
1669 */
1670#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1671 vps1.text = "PS1=\\w \\$ ";
1672#else
1673 if (!geteuid())
1674 vps1.text = "PS1=# ";
1675#endif
1676 vp = varinit;
1677 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1678 do {
1679 vpp = hashvar(vp->text);
1680 vp->next = *vpp;
1681 *vpp = vp;
1682 } while (++vp < end);
1683}
1684
1685static inline void
1686init(void)
1687{
1688
1689 /* from input.c: */
1690 {
1691 basepf.nextc = basepf.buf = basebuf;
1692 }
1693
1694 /* from trap.c: */
1695 {
1696 signal(SIGCHLD, SIG_DFL);
1697 }
1698
1699 /* from var.c: */
1700 {
1701 char **envp;
1702 char ppid[32];
1703
1704 initvar();
1705 for (envp = environ ; *envp ; envp++) {
1706 if (strchr(*envp, '=')) {
1707 setvareq(*envp, VEXPORT|VTEXTFIXED);
1708 }
1709 }
1710
1711 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1712 setvar("PPID", ppid, 0);
1713 setpwd(0, 0);
1714 }
1715}
1716
1717/* PEOF (the end of file marker) */
1718
1719/*
1720 * The input line number. Input.c just defines this variable, and saves
1721 * and restores it when files are pushed and popped. The user of this
1722 * package must set its value.
1723 */
1724
1725static int pgetc(void);
1726static int pgetc2(void);
1727static int preadbuffer(void);
1728static void pungetc(void);
1729static void pushstring(char *, void *);
1730static void popstring(void);
1731static void setinputfile(const char *, int);
1732static void setinputfd(int, int);
1733static void setinputstring(char *);
1734static void popfile(void);
1735static void popallfiles(void);
1736static void closescript(void);
1737
1738
1739/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1740
1741
1742/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1743#define FORK_FG 0
1744#define FORK_BG 1
1745#define FORK_NOJOB 2
1746
1747/* mode flags for showjob(s) */
1748#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1749#define SHOW_PID 0x04 /* include process pid */
1750#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1751
1752
1753/*
1754 * A job structure contains information about a job. A job is either a
1755 * single process or a set of processes contained in a pipeline. In the
1756 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1757 * array of pids.
1758 */
1759
1760struct procstat {
1761 pid_t pid; /* process id */
1762 int status; /* last process status from wait() */
1763 char *cmd; /* text of command being run */
1764};
1765
1766struct job {
1767 struct procstat ps0; /* status of process */
1768 struct procstat *ps; /* status or processes when more than one */
1769#if JOBS
1770 int stopstatus; /* status of a stopped job */
1771#endif
1772 uint32_t
1773 nprocs: 16, /* number of processes */
1774 state: 8,
1775#define JOBRUNNING 0 /* at least one proc running */
1776#define JOBSTOPPED 1 /* all procs are stopped */
1777#define JOBDONE 2 /* all procs are completed */
1778#if JOBS
1779 sigint: 1, /* job was killed by SIGINT */
1780 jobctl: 1, /* job running under job control */
1781#endif
1782 waited: 1, /* true if this entry has been waited for */
1783 used: 1, /* true if this entry is in used */
1784 changed: 1; /* true if status has changed */
1785 struct job *prev_job; /* previous job */
1786};
1787
1788static pid_t backgndpid; /* pid of last background process */
1789static int job_warning; /* user was warned about stopped jobs */
1790#if JOBS
1791static int jobctl; /* true if doing job control */
1792#endif
1793
1794static struct job *makejob(union node *, int);
1795static int forkshell(struct job *, union node *, int);
1796static int waitforjob(struct job *);
1797static int stoppedjobs(void);
1798
1799#if ! JOBS
1800#define setjobctl(on) /* do nothing */
1801#else
1802static void setjobctl(int);
1803static void showjobs(FILE *, int);
1804#endif
1805
1806/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1807
1808
1809/* pid of main shell */
1810static int rootpid;
1811/* true if we aren't a child of the main shell */
1812static int rootshell;
1813
1814static void readcmdfile(char *);
1815static void cmdloop(int);
1816
1817/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1818
1819
1820struct stackmark {
1821 struct stack_block *stackp;
1822 char *stacknxt;
1823 size_t stacknleft;
1824 struct stackmark *marknext;
1825};
1826
1827/* minimum size of a block */
1828#define MINSIZE SHELL_ALIGN(504)
1829
1830struct stack_block {
1831 struct stack_block *prev;
1832 char space[MINSIZE];
1833};
1834
1835static struct stack_block stackbase;
1836static struct stack_block *stackp = &stackbase;
1837static struct stackmark *markp;
1838static char *stacknxt = stackbase.space;
1839static size_t stacknleft = MINSIZE;
1840static char *sstrend = stackbase.space + MINSIZE;
1841static int herefd = -1;
1842
1843
1844static pointer ckmalloc(size_t);
1845static pointer ckrealloc(pointer, size_t);
1846static char *savestr(const char *);
1847static pointer stalloc(size_t);
1848static void stunalloc(pointer);
1849static void setstackmark(struct stackmark *);
1850static void popstackmark(struct stackmark *);
1851static void growstackblock(void);
1852static void *growstackstr(void);
1853static char *makestrspace(size_t, char *);
1854static char *stnputs(const char *, size_t, char *);
1855static char *stputs(const char *, char *);
1856
1857
1858static inline char *_STPUTC(char c, char *p) {
1859 if (p == sstrend)
1860 p = growstackstr();
1861 *p++ = c;
1862 return p;
1863}
1864
1865#define stackblock() ((void *)stacknxt)
1866#define stackblocksize() stacknleft
1867#define STARTSTACKSTR(p) ((p) = stackblock())
1868#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1869#define CHECKSTRSPACE(n, p) \
1870 ({ \
1871 char *q = (p); \
1872 size_t l = (n); \
1873 size_t m = sstrend - q; \
1874 if (l > m) \
1875 (p) = makestrspace(l, q); \
1876 0; \
1877 })
1878#define USTPUTC(c, p) (*p++ = (c))
1879#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1880#define STUNPUTC(p) (--p)
1881#define STTOPC(p) p[-1]
1882#define STADJUST(amount, p) (p += (amount))
1883
1884#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1885#define ungrabstackstr(s, p) stunalloc((s))
1886#define stackstrend() ((void *)sstrend)
1887
1888#define ckfree(p) free((pointer)(p))
1889
1890/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1891
1892
1893#define DOLATSTRLEN 4
1894
1895static char *prefix(const char *, const char *);
1896static int number(const char *);
1897static int is_number(const char *);
1898static char *single_quote(const char *);
1899static char *sstrdup(const char *);
1900
1901#define equal(s1, s2) (strcmp(s1, s2) == 0)
1902#define scopy(s1, s2) ((void)strcpy(s2, s1))
1903
1904/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1905
1906struct shparam {
1907 int nparam; /* # of positional parameters (without $0) */
1908 unsigned char malloc; /* if parameter list dynamically allocated */
1909 char **p; /* parameter list */
1910#ifdef CONFIG_ASH_GETOPTS
1911 int optind; /* next parameter to be processed by getopts */
1912 int optoff; /* used by getopts */
1913#endif
1914};
1915
1916
1917#define eflag optlist[0]
1918#define fflag optlist[1]
1919#define Iflag optlist[2]
1920#define iflag optlist[3]
1921#define mflag optlist[4]
1922#define nflag optlist[5]
1923#define sflag optlist[6]
1924#define xflag optlist[7]
1925#define vflag optlist[8]
1926#define Cflag optlist[9]
1927#define aflag optlist[10]
1928#define bflag optlist[11]
1929#define uflag optlist[12]
1930#define qflag optlist[13]
Paul Fox3f11b1b2005-08-04 19:04:46 +00001931#define viflag optlist[14]
Eric Andersenc470f442003-07-28 09:56:35 +00001932
1933#ifdef DEBUG
Paul Fox3f11b1b2005-08-04 19:04:46 +00001934#define nolog optlist[15]
1935#define debug optlist[16]
1936#endif
1937
1938#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1939#define setvimode(on) viflag = 0 /* forcibly keep the option off */
Eric Andersenc470f442003-07-28 09:56:35 +00001940#endif
1941
1942/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1943
1944
Paul Fox3f11b1b2005-08-04 19:04:46 +00001945static const char *const optletters_optnames[] = {
Eric Andersenc470f442003-07-28 09:56:35 +00001946 "e" "errexit",
1947 "f" "noglob",
1948 "I" "ignoreeof",
1949 "i" "interactive",
1950 "m" "monitor",
1951 "n" "noexec",
1952 "s" "stdin",
1953 "x" "xtrace",
1954 "v" "verbose",
1955 "C" "noclobber",
1956 "a" "allexport",
1957 "b" "notify",
1958 "u" "nounset",
1959 "q" "quietprofile",
Paul Fox3f11b1b2005-08-04 19:04:46 +00001960 "\0" "vi",
Eric Andersenc470f442003-07-28 09:56:35 +00001961#ifdef DEBUG
1962 "\0" "nolog",
1963 "\0" "debug",
1964#endif
1965};
1966
1967#define optletters(n) optletters_optnames[(n)][0]
1968#define optnames(n) (&optletters_optnames[(n)][1])
1969
Paul Fox3f11b1b2005-08-04 19:04:46 +00001970#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001971
1972static char optlist[NOPTS];
1973
1974
1975static char *arg0; /* value of $0 */
1976static struct shparam shellparam; /* $@ current positional parameters */
1977static char **argptr; /* argument list for builtin commands */
1978static char *optionarg; /* set by nextopt (like getopt) */
1979static char *optptr; /* used by nextopt */
1980
1981static char *minusc; /* argument to -c option */
1982
1983
1984static void procargs(int, char **);
1985static void optschanged(void);
1986static void setparam(char **);
1987static void freeparam(volatile struct shparam *);
1988static int shiftcmd(int, char **);
1989static int setcmd(int, char **);
1990static int nextopt(const char *);
1991
1992/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1993
1994/* flags passed to redirect */
1995#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001996#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00001997
1998union node;
1999static void redirect(union node *, int);
2000static void popredir(int);
2001static void clearredir(int);
2002static int copyfd(int, int);
2003static int redirectsafe(union node *, int);
2004
2005/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2006
2007
2008#ifdef DEBUG
2009static void showtree(union node *);
2010static void trace(const char *, ...);
2011static void tracev(const char *, va_list);
2012static void trargs(char **);
2013static void trputc(int);
2014static void trputs(const char *);
2015static void opentrace(void);
2016#endif
2017
2018/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2019
2020
2021/* trap handler commands */
2022static char *trap[NSIG];
2023/* current value of signal */
2024static char sigmode[NSIG - 1];
2025/* indicates specified signal received */
2026static char gotsig[NSIG - 1];
2027
2028static void clear_traps(void);
2029static void setsignal(int);
2030static void ignoresig(int);
2031static void onsig(int);
2032static void dotrap(void);
2033static void setinteractive(int);
2034static void exitshell(void) __attribute__((__noreturn__));
2035static int decode_signal(const char *, int);
2036
2037/*
2038 * This routine is called when an error or an interrupt occurs in an
2039 * interactive shell and control is returned to the main command loop.
2040 */
2041
2042static void
2043reset(void)
2044{
2045 /* from eval.c: */
2046 {
2047 evalskip = 0;
2048 loopnest = 0;
2049 funcnest = 0;
2050 }
2051
2052 /* from input.c: */
2053 {
2054 parselleft = parsenleft = 0; /* clear input buffer */
2055 popallfiles();
2056 }
2057
2058 /* from parser.c: */
2059 {
2060 tokpushback = 0;
2061 checkkwd = 0;
2062 }
2063
2064 /* from redir.c: */
2065 {
2066 clearredir(0);
2067 }
2068
2069}
2070
2071#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002072static struct alias *atab[ATABSIZE];
2073
Eric Andersenc470f442003-07-28 09:56:35 +00002074static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002075static struct alias *freealias(struct alias *);
2076static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002077
Eric Andersenc470f442003-07-28 09:56:35 +00002078static void
2079setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002080{
2081 struct alias *ap, **app;
2082
2083 app = __lookupalias(name);
2084 ap = *app;
2085 INTOFF;
2086 if (ap) {
2087 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002088 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002089 }
Eric Andersenc470f442003-07-28 09:56:35 +00002090 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002091 ap->flag &= ~ALIASDEAD;
2092 } else {
2093 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002094 ap = ckmalloc(sizeof (struct alias));
2095 ap->name = savestr(name);
2096 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002097 ap->flag = 0;
2098 ap->next = 0;
2099 *app = ap;
2100 }
2101 INTON;
2102}
2103
Eric Andersenc470f442003-07-28 09:56:35 +00002104static int
2105unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002106{
Eric Andersencb57d552001-06-28 07:25:16 +00002107 struct alias **app;
2108
2109 app = __lookupalias(name);
2110
2111 if (*app) {
2112 INTOFF;
2113 *app = freealias(*app);
2114 INTON;
2115 return (0);
2116 }
2117
2118 return (1);
2119}
2120
Eric Andersenc470f442003-07-28 09:56:35 +00002121static void
2122rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002123{
Eric Andersencb57d552001-06-28 07:25:16 +00002124 struct alias *ap, **app;
2125 int i;
2126
2127 INTOFF;
2128 for (i = 0; i < ATABSIZE; i++) {
2129 app = &atab[i];
2130 for (ap = *app; ap; ap = *app) {
2131 *app = freealias(*app);
2132 if (ap == *app) {
2133 app = &ap->next;
2134 }
2135 }
2136 }
2137 INTON;
2138}
2139
Eric Andersenc470f442003-07-28 09:56:35 +00002140static struct alias *
2141lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002142{
Eric Andersenc470f442003-07-28 09:56:35 +00002143 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002144
Eric Andersenc470f442003-07-28 09:56:35 +00002145 if (check && ap && (ap->flag & ALIASINUSE))
2146 return (NULL);
2147 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002148}
2149
Eric Andersencb57d552001-06-28 07:25:16 +00002150/*
2151 * TODO - sort output
2152 */
Eric Andersenc470f442003-07-28 09:56:35 +00002153static int
2154aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002155{
2156 char *n, *v;
2157 int ret = 0;
2158 struct alias *ap;
2159
2160 if (argc == 1) {
2161 int i;
2162
2163 for (i = 0; i < ATABSIZE; i++)
2164 for (ap = atab[i]; ap; ap = ap->next) {
2165 printalias(ap);
2166 }
2167 return (0);
2168 }
2169 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002170 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002171 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002172 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002173 ret = 1;
2174 } else
2175 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002176 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002177 *v++ = '\0';
2178 setalias(n, v);
2179 }
2180 }
2181
2182 return (ret);
2183}
2184
Eric Andersenc470f442003-07-28 09:56:35 +00002185static int
2186unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002187{
2188 int i;
2189
2190 while ((i = nextopt("a")) != '\0') {
2191 if (i == 'a') {
2192 rmaliases();
2193 return (0);
2194 }
2195 }
2196 for (i = 0; *argptr; argptr++) {
2197 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002198 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002199 i = 1;
2200 }
2201 }
2202
2203 return (i);
2204}
2205
Eric Andersenc470f442003-07-28 09:56:35 +00002206static struct alias *
2207freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002208 struct alias *next;
2209
2210 if (ap->flag & ALIASINUSE) {
2211 ap->flag |= ALIASDEAD;
2212 return ap;
2213 }
2214
2215 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002216 ckfree(ap->name);
2217 ckfree(ap->val);
2218 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002219 return next;
2220}
2221
Eric Andersenc470f442003-07-28 09:56:35 +00002222static void
2223printalias(const struct alias *ap) {
2224 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2225}
Eric Andersencb57d552001-06-28 07:25:16 +00002226
Eric Andersenc470f442003-07-28 09:56:35 +00002227static struct alias **
2228__lookupalias(const char *name) {
2229 unsigned int hashval;
2230 struct alias **app;
2231 const char *p;
2232 unsigned int ch;
2233
2234 p = name;
2235
2236 ch = (unsigned char)*p;
2237 hashval = ch << 4;
2238 while (ch) {
2239 hashval += ch;
2240 ch = (unsigned char)*++p;
2241 }
2242 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002243
2244 for (; *app; app = &(*app)->next) {
2245 if (equal(name, (*app)->name)) {
2246 break;
2247 }
2248 }
2249
2250 return app;
2251}
Eric Andersenc470f442003-07-28 09:56:35 +00002252#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002253
Eric Andersencb57d552001-06-28 07:25:16 +00002254
Eric Andersenc470f442003-07-28 09:56:35 +00002255/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00002256
Eric Andersencb57d552001-06-28 07:25:16 +00002257/*
Eric Andersenc470f442003-07-28 09:56:35 +00002258 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002259 */
2260
Eric Andersenc470f442003-07-28 09:56:35 +00002261#define CD_PHYSICAL 1
2262#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002263
Eric Andersenc470f442003-07-28 09:56:35 +00002264static int docd(const char *, int);
2265static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002266
Eric Andersenc470f442003-07-28 09:56:35 +00002267static char *curdir = nullstr; /* current working directory */
2268static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002269
Eric Andersenc470f442003-07-28 09:56:35 +00002270static int
2271cdopt(void)
2272{
2273 int flags = 0;
2274 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002275
Eric Andersenc470f442003-07-28 09:56:35 +00002276 j = 'L';
2277 while ((i = nextopt("LP"))) {
2278 if (i != j) {
2279 flags ^= CD_PHYSICAL;
2280 j = i;
2281 }
2282 }
Eric Andersencb57d552001-06-28 07:25:16 +00002283
Eric Andersenc470f442003-07-28 09:56:35 +00002284 return flags;
2285}
Eric Andersen2870d962001-07-02 17:27:21 +00002286
Eric Andersenc470f442003-07-28 09:56:35 +00002287static int
2288cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002289{
2290 const char *dest;
2291 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002292 const char *p;
2293 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002294 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002295 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002296
Eric Andersenc470f442003-07-28 09:56:35 +00002297 flags = cdopt();
2298 dest = *argptr;
2299 if (!dest)
2300 dest = bltinlookup(homestr);
2301 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002302 dest = bltinlookup("OLDPWD");
Eric Andersenc00e11d2004-10-08 08:14:58 +00002303 if ( !dest ) goto out;
Eric Andersenc470f442003-07-28 09:56:35 +00002304 flags |= CD_PRINT;
2305 goto step7;
Eric Andersencb57d552001-06-28 07:25:16 +00002306 }
Eric Andersenc470f442003-07-28 09:56:35 +00002307 if (!dest)
2308 dest = nullstr;
2309 if (*dest == '/')
2310 goto step7;
2311 if (*dest == '.') {
2312 c = dest[1];
2313dotdot:
2314 switch (c) {
2315 case '\0':
2316 case '/':
2317 goto step6;
2318 case '.':
2319 c = dest[2];
2320 if (c != '.')
2321 goto dotdot;
2322 }
2323 }
2324 if (!*dest)
2325 dest = ".";
2326 if (!(path = bltinlookup("CDPATH"))) {
2327step6:
2328step7:
2329 p = dest;
2330 goto docd;
2331 }
2332 do {
2333 c = *path;
2334 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002335 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002336 if (c && c != ':')
2337 flags |= CD_PRINT;
2338docd:
2339 if (!docd(p, flags))
2340 goto out;
2341 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002342 }
Eric Andersenc470f442003-07-28 09:56:35 +00002343 } while (path);
Eric Andersencb57d552001-06-28 07:25:16 +00002344 error("can't cd to %s", dest);
2345 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002346out:
2347 if (flags & CD_PRINT)
2348 out1fmt(snlfmt, curdir);
2349 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002350}
2351
2352
2353/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002354 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002355 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002356 */
2357
Eric Andersenc470f442003-07-28 09:56:35 +00002358static inline const char *
2359updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002360{
Eric Andersenc470f442003-07-28 09:56:35 +00002361 char *new;
2362 char *p;
2363 char *cdcomppath;
2364 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002365
Eric Andersenc470f442003-07-28 09:56:35 +00002366 cdcomppath = sstrdup(dir);
2367 STARTSTACKSTR(new);
2368 if (*dir != '/') {
2369 if (curdir == nullstr)
2370 return 0;
2371 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002372 }
Eric Andersenc470f442003-07-28 09:56:35 +00002373 new = makestrspace(strlen(dir) + 2, new);
2374 lim = stackblock() + 1;
2375 if (*dir != '/') {
2376 if (new[-1] != '/')
2377 USTPUTC('/', new);
2378 if (new > lim && *lim == '/')
2379 lim++;
2380 } else {
2381 USTPUTC('/', new);
2382 cdcomppath++;
2383 if (dir[1] == '/' && dir[2] != '/') {
2384 USTPUTC('/', new);
2385 cdcomppath++;
2386 lim++;
2387 }
2388 }
2389 p = strtok(cdcomppath, "/");
2390 while (p) {
2391 switch(*p) {
2392 case '.':
2393 if (p[1] == '.' && p[2] == '\0') {
2394 while (new > lim) {
2395 STUNPUTC(new);
2396 if (new[-1] == '/')
2397 break;
2398 }
2399 break;
2400 } else if (p[1] == '\0')
2401 break;
2402 /* fall through */
2403 default:
2404 new = stputs(p, new);
2405 USTPUTC('/', new);
2406 }
2407 p = strtok(0, "/");
2408 }
2409 if (new > lim)
2410 STUNPUTC(new);
2411 *new = 0;
2412 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002413}
2414
2415/*
Eric Andersenc470f442003-07-28 09:56:35 +00002416 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2417 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002418 */
2419
Eric Andersenc470f442003-07-28 09:56:35 +00002420static int
2421docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002422{
Eric Andersenc470f442003-07-28 09:56:35 +00002423 const char *dir = 0;
2424 int err;
2425
2426 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2427
Eric Andersencb57d552001-06-28 07:25:16 +00002428 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002429 if (!(flags & CD_PHYSICAL)) {
2430 dir = updatepwd(dest);
2431 if (dir)
2432 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002433 }
Eric Andersenc470f442003-07-28 09:56:35 +00002434 err = chdir(dest);
2435 if (err)
2436 goto out;
2437 setpwd(dir, 1);
2438 hashcd();
2439out:
Eric Andersencb57d552001-06-28 07:25:16 +00002440 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002441 return err;
2442}
2443
2444/*
2445 * Find out what the current directory is. If we already know the current
2446 * directory, this routine returns immediately.
2447 */
2448static inline char *
2449getpwd(void)
2450{
2451 char *dir = getcwd(0, 0);
2452 return dir ? dir : nullstr;
2453}
2454
2455static int
2456pwdcmd(int argc, char **argv)
2457{
2458 int flags;
2459 const char *dir = curdir;
2460
2461 flags = cdopt();
2462 if (flags) {
2463 if (physdir == nullstr)
2464 setpwd(dir, 0);
2465 dir = physdir;
2466 }
2467 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002468 return 0;
2469}
2470
Eric Andersenc470f442003-07-28 09:56:35 +00002471static void
2472setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002473{
Eric Andersenc470f442003-07-28 09:56:35 +00002474 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002475
Eric Andersenc470f442003-07-28 09:56:35 +00002476 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002477
Eric Andersencb57d552001-06-28 07:25:16 +00002478 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002479 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002480 }
2481 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002482 if (physdir != nullstr) {
2483 if (physdir != oldcur)
2484 free(physdir);
2485 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002486 }
Eric Andersenc470f442003-07-28 09:56:35 +00002487 if (oldcur == val || !val) {
2488 char *s = getpwd();
2489 physdir = s;
2490 if (!val)
2491 dir = s;
2492 } else
2493 dir = savestr(val);
2494 if (oldcur != dir && oldcur != nullstr) {
2495 free(oldcur);
2496 }
2497 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002498 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002499 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002500}
2501
Eric Andersenc470f442003-07-28 09:56:35 +00002502/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2503
Eric Andersencb57d552001-06-28 07:25:16 +00002504/*
2505 * Errors and exceptions.
2506 */
2507
2508/*
2509 * Code to handle exceptions in C.
2510 */
2511
Eric Andersen2870d962001-07-02 17:27:21 +00002512
Eric Andersencb57d552001-06-28 07:25:16 +00002513
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002514static void exverror(int, const char *, va_list)
Eric Andersenc470f442003-07-28 09:56:35 +00002515 __attribute__((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00002516
2517/*
2518 * Called to raise an exception. Since C doesn't include exceptions, we
2519 * just do a longjmp to the exception handler. The type of exception is
2520 * stored in the global variable "exception".
2521 */
2522
Eric Andersenc470f442003-07-28 09:56:35 +00002523static void
2524exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002525{
2526#ifdef DEBUG
2527 if (handler == NULL)
2528 abort();
2529#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002530 INTOFF;
2531
Eric Andersencb57d552001-06-28 07:25:16 +00002532 exception = e;
2533 longjmp(handler->loc, 1);
2534}
2535
2536
2537/*
2538 * Called from trap.c when a SIGINT is received. (If the user specifies
2539 * that SIGINT is to be trapped or ignored using the trap builtin, then
2540 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002541 * are held using the INTOFF macro. (The test for iflag is just
2542 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002543 */
2544
Eric Andersenc470f442003-07-28 09:56:35 +00002545static void
2546onint(void) {
2547 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002548
Eric Andersencb57d552001-06-28 07:25:16 +00002549 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002550 sigsetmask(0);
2551 i = EXSIG;
2552 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2553 if (!(rootshell && iflag)) {
2554 signal(SIGINT, SIG_DFL);
2555 raise(SIGINT);
2556 }
2557 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002558 }
Eric Andersenc470f442003-07-28 09:56:35 +00002559 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002560 /* NOTREACHED */
2561}
2562
Eric Andersenc470f442003-07-28 09:56:35 +00002563static void
2564exvwarning(const char *msg, va_list ap)
2565{
2566 FILE *errs;
2567 const char *name;
2568 const char *fmt;
Eric Andersencb57d552001-06-28 07:25:16 +00002569
Eric Andersenc470f442003-07-28 09:56:35 +00002570 errs = stderr;
2571 name = arg0;
2572 fmt = "%s: ";
2573 if (commandname) {
2574 name = commandname;
2575 fmt = "%s: %d: ";
2576 }
2577 fprintf(errs, fmt, name, startlinno);
2578 vfprintf(errs, msg, ap);
2579 outcslow('\n', errs);
2580}
Eric Andersen2870d962001-07-02 17:27:21 +00002581
Eric Andersencb57d552001-06-28 07:25:16 +00002582/*
Eric Andersenc470f442003-07-28 09:56:35 +00002583 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002584 * is not NULL then error prints an error message using printf style
2585 * formatting. It then raises the error exception.
2586 */
Eric Andersenc470f442003-07-28 09:56:35 +00002587static void
2588exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002589{
Eric Andersencb57d552001-06-28 07:25:16 +00002590#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002591 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002592 TRACE(("exverror(%d, \"", cond));
2593 TRACEV((msg, ap));
2594 TRACE(("\") pid=%d\n", getpid()));
2595 } else
2596 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2597 if (msg)
2598#endif
2599 exvwarning(msg, ap);
2600
2601 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002602 exraise(cond);
2603 /* NOTREACHED */
2604}
2605
2606
Eric Andersenc470f442003-07-28 09:56:35 +00002607static void
2608error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002609{
Eric Andersencb57d552001-06-28 07:25:16 +00002610 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002611
Eric Andersencb57d552001-06-28 07:25:16 +00002612 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002613 exverror(EXERROR, msg, ap);
2614 /* NOTREACHED */
2615 va_end(ap);
2616}
2617
2618
Eric Andersenc470f442003-07-28 09:56:35 +00002619static void
2620exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002621{
Eric Andersencb57d552001-06-28 07:25:16 +00002622 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002623
Eric Andersencb57d552001-06-28 07:25:16 +00002624 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002625 exverror(cond, msg, ap);
2626 /* NOTREACHED */
2627 va_end(ap);
2628}
2629
Eric Andersencb57d552001-06-28 07:25:16 +00002630/*
Eric Andersenc470f442003-07-28 09:56:35 +00002631 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002632 */
2633
Eric Andersenc470f442003-07-28 09:56:35 +00002634static void
2635sh_warnx(const char *fmt, ...)
2636{
2637 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002638
Eric Andersenc470f442003-07-28 09:56:35 +00002639 va_start(ap, fmt);
2640 exvwarning(fmt, ap);
2641 va_end(ap);
2642}
Eric Andersen2870d962001-07-02 17:27:21 +00002643
Eric Andersencb57d552001-06-28 07:25:16 +00002644
2645/*
2646 * Return a string describing an error. The returned string may be a
2647 * pointer to a static buffer that will be overwritten on the next call.
2648 * Action describes the operation that got the error.
2649 */
2650
Eric Andersenc470f442003-07-28 09:56:35 +00002651static const char *
2652errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002653{
Eric Andersenc470f442003-07-28 09:56:35 +00002654 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002655
Eric Andersenc470f442003-07-28 09:56:35 +00002656 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002657 }
Eric Andersenc470f442003-07-28 09:56:35 +00002658 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002659}
2660
2661
Eric Andersenc470f442003-07-28 09:56:35 +00002662/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2663
2664/*
2665 * Evaluate a command.
2666 */
Eric Andersencb57d552001-06-28 07:25:16 +00002667
2668/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002669#define EV_EXIT 01 /* exit after evaluating tree */
2670#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2671#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002672
2673
Eric Andersenc470f442003-07-28 09:56:35 +00002674static void evalloop(union node *, int);
2675static void evalfor(union node *, int);
2676static void evalcase(union node *, int);
2677static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002678static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002679static void evalpipe(union node *, int);
2680static void evalcommand(union node *, int);
2681static int evalbltin(const struct builtincmd *, int, char **);
2682static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002683static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002684static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002685
Eric Andersenc470f442003-07-28 09:56:35 +00002686
2687static const struct builtincmd bltin = {
2688 "\0\0", bltincmd
2689};
2690
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002691
Eric Andersencb57d552001-06-28 07:25:16 +00002692/*
2693 * Called to reset things after an exception.
2694 */
2695
Eric Andersencb57d552001-06-28 07:25:16 +00002696/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002697 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002698 */
2699
Eric Andersenc470f442003-07-28 09:56:35 +00002700static int
2701evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002702{
Eric Andersen2870d962001-07-02 17:27:21 +00002703 char *p;
2704 char *concat;
2705 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002706
Eric Andersen2870d962001-07-02 17:27:21 +00002707 if (argc > 1) {
2708 p = argv[1];
2709 if (argc > 2) {
2710 STARTSTACKSTR(concat);
2711 ap = argv + 2;
2712 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002713 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002714 if ((p = *ap++) == NULL)
2715 break;
2716 STPUTC(' ', concat);
2717 }
2718 STPUTC('\0', concat);
2719 p = grabstackstr(concat);
2720 }
Glenn L McGrath76620622004-01-13 10:19:37 +00002721 evalstring(p);
Eric Andersen2870d962001-07-02 17:27:21 +00002722 }
2723 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002724}
2725
Eric Andersenc470f442003-07-28 09:56:35 +00002726
Eric Andersencb57d552001-06-28 07:25:16 +00002727/*
2728 * Execute a command or commands contained in a string.
2729 */
2730
Eric Andersenc470f442003-07-28 09:56:35 +00002731static void
Glenn L McGrath76620622004-01-13 10:19:37 +00002732evalstring(char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00002733{
Eric Andersencb57d552001-06-28 07:25:16 +00002734 union node *n;
2735 struct stackmark smark;
2736
2737 setstackmark(&smark);
2738 setinputstring(s);
Eric Andersenc470f442003-07-28 09:56:35 +00002739
Eric Andersencb57d552001-06-28 07:25:16 +00002740 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002741 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002742 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002743 if (evalskip)
2744 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002745 }
2746 popfile();
2747 popstackmark(&smark);
2748}
2749
Eric Andersenc470f442003-07-28 09:56:35 +00002750
Eric Andersen62483552001-07-10 06:09:16 +00002751
2752/*
Eric Andersenc470f442003-07-28 09:56:35 +00002753 * Evaluate a parse tree. The value is left in the global variable
2754 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002755 */
2756
Eric Andersenc470f442003-07-28 09:56:35 +00002757static void
2758evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002759{
Eric Andersenc470f442003-07-28 09:56:35 +00002760 int checkexit = 0;
2761 void (*evalfn)(union node *, int);
2762 unsigned isor;
2763 int status;
2764 if (n == NULL) {
2765 TRACE(("evaltree(NULL) called\n"));
2766 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002767 }
Eric Andersenc470f442003-07-28 09:56:35 +00002768 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2769 getpid(), n, n->type, flags));
2770 switch (n->type) {
2771 default:
2772#ifdef DEBUG
2773 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002774 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002775 break;
2776#endif
2777 case NNOT:
2778 evaltree(n->nnot.com, EV_TESTED);
2779 status = !exitstatus;
2780 goto setstatus;
2781 case NREDIR:
2782 expredir(n->nredir.redirect);
2783 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2784 if (!status) {
2785 evaltree(n->nredir.n, flags & EV_TESTED);
2786 status = exitstatus;
2787 }
2788 popredir(0);
2789 goto setstatus;
2790 case NCMD:
2791 evalfn = evalcommand;
2792checkexit:
2793 if (eflag && !(flags & EV_TESTED))
2794 checkexit = ~0;
2795 goto calleval;
2796 case NFOR:
2797 evalfn = evalfor;
2798 goto calleval;
2799 case NWHILE:
2800 case NUNTIL:
2801 evalfn = evalloop;
2802 goto calleval;
2803 case NSUBSHELL:
2804 case NBACKGND:
2805 evalfn = evalsubshell;
2806 goto calleval;
2807 case NPIPE:
2808 evalfn = evalpipe;
2809 goto checkexit;
2810 case NCASE:
2811 evalfn = evalcase;
2812 goto calleval;
2813 case NAND:
2814 case NOR:
2815 case NSEMI:
2816#if NAND + 1 != NOR
2817#error NAND + 1 != NOR
2818#endif
2819#if NOR + 1 != NSEMI
2820#error NOR + 1 != NSEMI
2821#endif
2822 isor = n->type - NAND;
2823 evaltree(
2824 n->nbinary.ch1,
2825 (flags | ((isor >> 1) - 1)) & EV_TESTED
2826 );
2827 if (!exitstatus == isor)
2828 break;
2829 if (!evalskip) {
2830 n = n->nbinary.ch2;
2831evaln:
2832 evalfn = evaltree;
2833calleval:
2834 evalfn(n, flags);
2835 break;
2836 }
2837 break;
2838 case NIF:
2839 evaltree(n->nif.test, EV_TESTED);
2840 if (evalskip)
2841 break;
2842 if (exitstatus == 0) {
2843 n = n->nif.ifpart;
2844 goto evaln;
2845 } else if (n->nif.elsepart) {
2846 n = n->nif.elsepart;
2847 goto evaln;
2848 }
2849 goto success;
2850 case NDEFUN:
2851 defun(n->narg.text, n->narg.next);
2852success:
2853 status = 0;
2854setstatus:
2855 exitstatus = status;
2856 break;
2857 }
2858out:
2859 if (pendingsigs)
2860 dotrap();
2861 if (flags & EV_EXIT || checkexit & exitstatus)
2862 exraise(EXEXIT);
Eric Andersen62483552001-07-10 06:09:16 +00002863}
2864
Eric Andersenc470f442003-07-28 09:56:35 +00002865
2866#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2867static
2868#endif
2869void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2870
2871
2872static void
2873evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002874{
2875 int status;
2876
2877 loopnest++;
2878 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002879 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002880 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002881 int i;
2882
Eric Andersencb57d552001-06-28 07:25:16 +00002883 evaltree(n->nbinary.ch1, EV_TESTED);
2884 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002885skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002886 evalskip = 0;
2887 continue;
2888 }
2889 if (evalskip == SKIPBREAK && --skipcount <= 0)
2890 evalskip = 0;
2891 break;
2892 }
Eric Andersenc470f442003-07-28 09:56:35 +00002893 i = exitstatus;
2894 if (n->type != NWHILE)
2895 i = !i;
2896 if (i != 0)
2897 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002898 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002899 status = exitstatus;
2900 if (evalskip)
2901 goto skipping;
2902 }
2903 loopnest--;
2904 exitstatus = status;
2905}
2906
Eric Andersenc470f442003-07-28 09:56:35 +00002907
2908
2909static void
2910evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002911{
2912 struct arglist arglist;
2913 union node *argp;
2914 struct strlist *sp;
2915 struct stackmark smark;
2916
2917 setstackmark(&smark);
2918 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002919 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002920 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002921 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002922 if (evalskip)
2923 goto out;
2924 }
2925 *arglist.lastp = NULL;
2926
2927 exitstatus = 0;
2928 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002929 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002930 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002931 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002932 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002933 if (evalskip) {
2934 if (evalskip == SKIPCONT && --skipcount <= 0) {
2935 evalskip = 0;
2936 continue;
2937 }
2938 if (evalskip == SKIPBREAK && --skipcount <= 0)
2939 evalskip = 0;
2940 break;
2941 }
2942 }
2943 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002944out:
Eric Andersencb57d552001-06-28 07:25:16 +00002945 popstackmark(&smark);
2946}
2947
Eric Andersenc470f442003-07-28 09:56:35 +00002948
2949
2950static void
2951evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002952{
2953 union node *cp;
2954 union node *patp;
2955 struct arglist arglist;
2956 struct stackmark smark;
2957
2958 setstackmark(&smark);
2959 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002960 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002961 exitstatus = 0;
2962 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2963 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002964 if (casematch(patp, arglist.list->text)) {
2965 if (evalskip == 0) {
2966 evaltree(cp->nclist.body, flags);
2967 }
2968 goto out;
2969 }
2970 }
2971 }
Eric Andersenc470f442003-07-28 09:56:35 +00002972out:
Eric Andersencb57d552001-06-28 07:25:16 +00002973 popstackmark(&smark);
2974}
2975
Eric Andersenc470f442003-07-28 09:56:35 +00002976
2977
2978/*
2979 * Kick off a subshell to evaluate a tree.
2980 */
2981
2982static void
2983evalsubshell(union node *n, int flags)
2984{
2985 struct job *jp;
2986 int backgnd = (n->type == NBACKGND);
2987 int status;
2988
2989 expredir(n->nredir.redirect);
2990 if (!backgnd && flags & EV_EXIT && !trap[0])
2991 goto nofork;
2992 INTOFF;
2993 jp = makejob(n, 1);
2994 if (forkshell(jp, n, backgnd) == 0) {
2995 INTON;
2996 flags |= EV_EXIT;
2997 if (backgnd)
2998 flags &=~ EV_TESTED;
2999nofork:
3000 redirect(n->nredir.redirect, 0);
3001 evaltreenr(n->nredir.n, flags);
3002 /* never returns */
3003 }
3004 status = 0;
3005 if (! backgnd)
3006 status = waitforjob(jp);
3007 exitstatus = status;
3008 INTON;
3009}
3010
3011
3012
3013/*
3014 * Compute the names of the files in a redirection list.
3015 */
3016
3017static void
3018expredir(union node *n)
3019{
3020 union node *redir;
3021
3022 for (redir = n ; redir ; redir = redir->nfile.next) {
3023 struct arglist fn;
3024 fn.lastp = &fn.list;
3025 switch (redir->type) {
3026 case NFROMTO:
3027 case NFROM:
3028 case NTO:
3029 case NCLOBBER:
3030 case NAPPEND:
3031 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3032 redir->nfile.expfname = fn.list->text;
3033 break;
3034 case NFROMFD:
3035 case NTOFD:
3036 if (redir->ndup.vname) {
3037 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3038 fixredir(redir, fn.list->text, 1);
3039 }
3040 break;
3041 }
3042 }
3043}
3044
3045
3046
Eric Andersencb57d552001-06-28 07:25:16 +00003047/*
Eric Andersencb57d552001-06-28 07:25:16 +00003048 * Evaluate a pipeline. All the processes in the pipeline are children
3049 * of the process creating the pipeline. (This differs from some versions
3050 * of the shell, which make the last process in a pipeline the parent
3051 * of all the rest.)
3052 */
3053
Eric Andersenc470f442003-07-28 09:56:35 +00003054static void
3055evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003056{
3057 struct job *jp;
3058 struct nodelist *lp;
3059 int pipelen;
3060 int prevfd;
3061 int pip[2];
3062
Eric Andersenc470f442003-07-28 09:56:35 +00003063 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003064 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003065 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003066 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003067 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003068 INTOFF;
3069 jp = makejob(n, pipelen);
3070 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003071 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003072 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003073 pip[1] = -1;
3074 if (lp->next) {
3075 if (pipe(pip) < 0) {
3076 close(prevfd);
3077 error("Pipe call failed");
3078 }
3079 }
3080 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3081 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003082 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003083 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003084 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003085 if (prevfd > 0) {
3086 dup2(prevfd, 0);
3087 close(prevfd);
3088 }
3089 if (pip[1] > 1) {
3090 dup2(pip[1], 1);
3091 close(pip[1]);
3092 }
Eric Andersenc470f442003-07-28 09:56:35 +00003093 evaltreenr(lp->n, flags);
3094 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003095 }
3096 if (prevfd >= 0)
3097 close(prevfd);
3098 prevfd = pip[0];
3099 close(pip[1]);
3100 }
Eric Andersencb57d552001-06-28 07:25:16 +00003101 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003102 exitstatus = waitforjob(jp);
3103 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003104 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003105 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003106}
3107
Eric Andersen62483552001-07-10 06:09:16 +00003108
3109
3110/*
3111 * Execute a command inside back quotes. If it's a builtin command, we
3112 * want to save its output in a block obtained from malloc. Otherwise
3113 * we fork off a subprocess and get the output of the command via a pipe.
3114 * Should be called with interrupts off.
3115 */
3116
Eric Andersenc470f442003-07-28 09:56:35 +00003117static void
3118evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003119{
Eric Andersenc470f442003-07-28 09:56:35 +00003120 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003121
Eric Andersen62483552001-07-10 06:09:16 +00003122 result->fd = -1;
3123 result->buf = NULL;
3124 result->nleft = 0;
3125 result->jp = NULL;
3126 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003127 goto out;
3128 }
Eric Andersenc470f442003-07-28 09:56:35 +00003129
3130 saveherefd = herefd;
3131 herefd = -1;
3132
3133 {
3134 int pip[2];
3135 struct job *jp;
3136
3137 if (pipe(pip) < 0)
3138 error("Pipe call failed");
3139 jp = makejob(n, 1);
3140 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3141 FORCEINTON;
3142 close(pip[0]);
3143 if (pip[1] != 1) {
3144 close(1);
3145 copyfd(pip[1], 1);
3146 close(pip[1]);
3147 }
3148 eflag = 0;
3149 evaltreenr(n, EV_EXIT);
3150 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003151 }
Eric Andersenc470f442003-07-28 09:56:35 +00003152 close(pip[1]);
3153 result->fd = pip[0];
3154 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003155 }
Eric Andersenc470f442003-07-28 09:56:35 +00003156 herefd = saveherefd;
3157out:
Eric Andersen62483552001-07-10 06:09:16 +00003158 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003159 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003160}
3161
Eric Andersenc470f442003-07-28 09:56:35 +00003162#ifdef CONFIG_ASH_CMDCMD
3163static inline char **
3164parse_command_args(char **argv, const char **path)
3165{
3166 char *cp, c;
3167
3168 for (;;) {
3169 cp = *++argv;
3170 if (!cp)
3171 return 0;
3172 if (*cp++ != '-')
3173 break;
3174 if (!(c = *cp++))
3175 break;
3176 if (c == '-' && !*cp) {
3177 argv++;
3178 break;
3179 }
3180 do {
3181 switch (c) {
3182 case 'p':
3183 *path = defpath;
3184 break;
3185 default:
3186 /* run 'typecmd' for other options */
3187 return 0;
3188 }
3189 } while ((c = *cp++));
3190 }
3191 return argv;
3192}
3193#endif
3194
Paul Foxc3850c82005-07-20 18:23:39 +00003195static inline int
3196isassignment(const char *p)
3197{
3198 const char *q = endofname(p);
3199 if (p == q)
3200 return 0;
3201 return *q == '=';
3202}
Eric Andersen62483552001-07-10 06:09:16 +00003203
3204/*
3205 * Execute a simple command.
3206 */
Eric Andersencb57d552001-06-28 07:25:16 +00003207
Eric Andersenc470f442003-07-28 09:56:35 +00003208static void
3209evalcommand(union node *cmd, int flags)
3210{
3211 struct stackmark smark;
3212 union node *argp;
3213 struct arglist arglist;
3214 struct arglist varlist;
3215 char **argv;
3216 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003217 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003218 struct cmdentry cmdentry;
3219 struct job *jp;
3220 char *lastarg;
3221 const char *path;
3222 int spclbltin;
3223 int cmd_is_exec;
3224 int status;
3225 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003226 struct builtincmd *bcmd;
3227 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003228
3229 /* First expand the arguments. */
3230 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3231 setstackmark(&smark);
3232 back_exitstatus = 0;
3233
3234 cmdentry.cmdtype = CMDBUILTIN;
3235 cmdentry.u.cmd = &bltin;
3236 varlist.lastp = &varlist.list;
3237 *varlist.lastp = NULL;
3238 arglist.lastp = &arglist.list;
3239 *arglist.lastp = NULL;
3240
3241 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003242 if (cmd->ncmd.args)
3243 {
3244 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3245 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3246 }
3247
Eric Andersenc470f442003-07-28 09:56:35 +00003248 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3249 struct strlist **spp;
3250
3251 spp = arglist.lastp;
Paul Foxc3850c82005-07-20 18:23:39 +00003252 if (pseudovarflag && isassignment(argp->narg.text))
3253 expandarg(argp, &arglist, EXP_VARTILDE);
3254 else
3255 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3256
Eric Andersenc470f442003-07-28 09:56:35 +00003257 for (sp = *spp; sp; sp = sp->next)
3258 argc++;
3259 }
3260
3261 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3262 for (sp = arglist.list ; sp ; sp = sp->next) {
3263 TRACE(("evalcommand arg: %s\n", sp->text));
3264 *nargv++ = sp->text;
3265 }
3266 *nargv = NULL;
3267
3268 lastarg = NULL;
3269 if (iflag && funcnest == 0 && argc > 0)
3270 lastarg = nargv[-1];
3271
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003272 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003273 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003274 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003275
3276 path = vpath.text;
3277 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3278 struct strlist **spp;
3279 char *p;
3280
3281 spp = varlist.lastp;
3282 expandarg(argp, &varlist, EXP_VARTILDE);
3283
3284 /*
3285 * Modify the command lookup path, if a PATH= assignment
3286 * is present
3287 */
3288 p = (*spp)->text;
3289 if (varequal(p, path))
3290 path = p;
3291 }
3292
3293 /* Print the command if xflag is set. */
3294 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003295 int n;
3296 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003297
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003298 p++;
3299 dprintf(preverrout_fd, p, ps4val());
3300
3301 sp = varlist.list;
3302 for(n = 0; n < 2; n++) {
3303 while (sp) {
3304 dprintf(preverrout_fd, p, sp->text);
3305 sp = sp->next;
3306 if(*p == '%') {
3307 p--;
3308 }
3309 }
3310 sp = arglist.list;
3311 }
Eric Andersen16767e22004-03-16 05:14:10 +00003312 bb_full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003313 }
3314
3315 cmd_is_exec = 0;
3316 spclbltin = -1;
3317
3318 /* Now locate the command. */
3319 if (argc) {
3320 const char *oldpath;
3321 int cmd_flag = DO_ERR;
3322
3323 path += 5;
3324 oldpath = path;
3325 for (;;) {
3326 find_command(argv[0], &cmdentry, cmd_flag, path);
3327 if (cmdentry.cmdtype == CMDUNKNOWN) {
3328 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003329 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003330 goto bail;
3331 }
3332
3333 /* implement bltin and command here */
3334 if (cmdentry.cmdtype != CMDBUILTIN)
3335 break;
3336 if (spclbltin < 0)
3337 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3338 if (cmdentry.u.cmd == EXECCMD)
3339 cmd_is_exec++;
3340#ifdef CONFIG_ASH_CMDCMD
3341 if (cmdentry.u.cmd == COMMANDCMD) {
3342
3343 path = oldpath;
3344 nargv = parse_command_args(argv, &path);
3345 if (!nargv)
3346 break;
3347 argc -= nargv - argv;
3348 argv = nargv;
3349 cmd_flag |= DO_NOFUNC;
3350 } else
3351#endif
3352 break;
3353 }
3354 }
3355
3356 if (status) {
3357 /* We have a redirection error. */
3358 if (spclbltin > 0)
3359 exraise(EXERROR);
3360bail:
3361 exitstatus = status;
3362 goto out;
3363 }
3364
3365 /* Execute the command. */
3366 switch (cmdentry.cmdtype) {
3367 default:
3368 /* Fork off a child process if necessary. */
3369 if (!(flags & EV_EXIT) || trap[0]) {
3370 INTOFF;
3371 jp = makejob(cmd, 1);
3372 if (forkshell(jp, cmd, FORK_FG) != 0) {
3373 exitstatus = waitforjob(jp);
3374 INTON;
3375 break;
3376 }
3377 FORCEINTON;
3378 }
3379 listsetvar(varlist.list, VEXPORT|VSTACK);
3380 shellexec(argv, path, cmdentry.u.index);
3381 /* NOTREACHED */
3382
3383 case CMDBUILTIN:
3384 cmdenviron = varlist.list;
3385 if (cmdenviron) {
3386 struct strlist *list = cmdenviron;
3387 int i = VNOSET;
3388 if (spclbltin > 0 || argc == 0) {
3389 i = 0;
3390 if (cmd_is_exec && argc > 1)
3391 i = VEXPORT;
3392 }
3393 listsetvar(list, i);
3394 }
3395 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3396 int exit_status;
3397 int i, j;
3398
3399 i = exception;
3400 if (i == EXEXIT)
3401 goto raise;
3402
3403 exit_status = 2;
3404 j = 0;
3405 if (i == EXINT)
3406 j = SIGINT;
3407 if (i == EXSIG)
3408 j = pendingsigs;
3409 if (j)
3410 exit_status = j + 128;
3411 exitstatus = exit_status;
3412
3413 if (i == EXINT || spclbltin > 0) {
3414raise:
3415 longjmp(handler->loc, 1);
3416 }
3417 FORCEINTON;
3418 }
3419 break;
3420
3421 case CMDFUNCTION:
3422 listsetvar(varlist.list, 0);
3423 if (evalfun(cmdentry.u.func, argc, argv, flags))
3424 goto raise;
3425 break;
3426 }
3427
3428out:
3429 popredir(cmd_is_exec);
3430 if (lastarg)
3431 /* dsl: I think this is intended to be used to support
3432 * '_' in 'vi' command mode during line editing...
3433 * However I implemented that within libedit itself.
3434 */
3435 setvar("_", lastarg, 0);
3436 popstackmark(&smark);
3437}
3438
3439static int
3440evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3441 char *volatile savecmdname;
3442 struct jmploc *volatile savehandler;
3443 struct jmploc jmploc;
3444 int i;
3445
3446 savecmdname = commandname;
3447 if ((i = setjmp(jmploc.loc)))
3448 goto cmddone;
3449 savehandler = handler;
3450 handler = &jmploc;
3451 commandname = argv[0];
3452 argptr = argv + 1;
3453 optptr = NULL; /* initialize nextopt */
3454 exitstatus = (*cmd->builtin)(argc, argv);
3455 flushall();
3456cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003457 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003458 commandname = savecmdname;
3459 exsig = 0;
3460 handler = savehandler;
3461
3462 return i;
3463}
3464
3465static int
3466evalfun(struct funcnode *func, int argc, char **argv, int flags)
3467{
3468 volatile struct shparam saveparam;
3469 struct localvar *volatile savelocalvars;
3470 struct jmploc *volatile savehandler;
3471 struct jmploc jmploc;
3472 int e;
3473
3474 saveparam = shellparam;
3475 savelocalvars = localvars;
3476 if ((e = setjmp(jmploc.loc))) {
3477 goto funcdone;
3478 }
3479 INTOFF;
3480 savehandler = handler;
3481 handler = &jmploc;
3482 localvars = NULL;
3483 shellparam.malloc = 0;
3484 func->count++;
3485 INTON;
3486 shellparam.nparam = argc - 1;
3487 shellparam.p = argv + 1;
3488#ifdef CONFIG_ASH_GETOPTS
3489 shellparam.optind = 1;
3490 shellparam.optoff = -1;
3491#endif
3492 funcnest++;
3493 evaltree(&func->n, flags & EV_TESTED);
3494 funcnest--;
3495funcdone:
3496 INTOFF;
3497 freefunc(func);
3498 poplocalvars();
3499 localvars = savelocalvars;
3500 freeparam(&shellparam);
3501 shellparam = saveparam;
3502 handler = savehandler;
3503 INTON;
3504 if (evalskip == SKIPFUNC) {
3505 evalskip = 0;
3506 skipcount = 0;
3507 }
3508 return e;
3509}
3510
3511
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003512static inline int
3513goodname(const char *p)
3514{
3515 return !*endofname(p);
3516}
3517
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003518/*
3519 * Search for a command. This is called before we fork so that the
3520 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003521 * the child. The check for "goodname" is an overly conservative
3522 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003523 */
3524
Eric Andersenc470f442003-07-28 09:56:35 +00003525static void
3526prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003527{
3528 struct cmdentry entry;
3529
3530 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003531 if (goodname(n->ncmd.args->narg.text))
3532 find_command(n->ncmd.args->narg.text, &entry, 0,
3533 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003534}
3535
Eric Andersencb57d552001-06-28 07:25:16 +00003536
Eric Andersenc470f442003-07-28 09:56:35 +00003537
Eric Andersencb57d552001-06-28 07:25:16 +00003538/*
3539 * Builtin commands. Builtin commands whose functions are closely
3540 * tied to evaluation are implemented here.
3541 */
3542
3543/*
Eric Andersenc470f442003-07-28 09:56:35 +00003544 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003545 */
3546
Eric Andersenc470f442003-07-28 09:56:35 +00003547static int
3548bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003549{
3550 /*
3551 * Preserve exitstatus of a previous possible redirection
3552 * as POSIX mandates
3553 */
Eric Andersenc470f442003-07-28 09:56:35 +00003554 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003555}
3556
3557
3558/*
3559 * Handle break and continue commands. Break, continue, and return are
3560 * all handled by setting the evalskip flag. The evaluation routines
3561 * above all check this flag, and if it is set they start skipping
3562 * commands rather than executing them. The variable skipcount is
3563 * the number of loops to break/continue, or the number of function
3564 * levels to return. (The latter is always 1.) It should probably
3565 * be an error to break out of more loops than exist, but it isn't
3566 * in the standard shell so we don't make it one here.
3567 */
3568
Eric Andersenc470f442003-07-28 09:56:35 +00003569static int
3570breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003571{
3572 int n = argc > 1 ? number(argv[1]) : 1;
3573
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003574 if (n <= 0)
Eric Andersenc470f442003-07-28 09:56:35 +00003575 error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003576 if (n > loopnest)
3577 n = loopnest;
3578 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003579 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003580 skipcount = n;
3581 }
3582 return 0;
3583}
3584
3585
3586/*
3587 * The return command.
3588 */
3589
Eric Andersenc470f442003-07-28 09:56:35 +00003590static int
3591returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003592{
Eric Andersenc470f442003-07-28 09:56:35 +00003593 int ret = argc > 1 ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003594
3595 if (funcnest) {
3596 evalskip = SKIPFUNC;
3597 skipcount = 1;
3598 return ret;
Eric Andersenc470f442003-07-28 09:56:35 +00003599 }
3600 else {
Eric Andersencb57d552001-06-28 07:25:16 +00003601 /* Do what ksh does; skip the rest of the file */
3602 evalskip = SKIPFILE;
3603 skipcount = 1;
3604 return ret;
3605 }
3606}
3607
3608
Eric Andersenc470f442003-07-28 09:56:35 +00003609static int
3610falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003611{
3612 return 1;
3613}
3614
Eric Andersenc470f442003-07-28 09:56:35 +00003615
3616static int
3617truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003618{
3619 return 0;
3620}
Eric Andersen2870d962001-07-02 17:27:21 +00003621
Eric Andersencb57d552001-06-28 07:25:16 +00003622
Eric Andersenc470f442003-07-28 09:56:35 +00003623static int
3624execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003625{
3626 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003627 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003628 mflag = 0;
3629 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003630 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003631 }
3632 return 0;
3633}
3634
Eric Andersenc470f442003-07-28 09:56:35 +00003635
Eric Andersenc470f442003-07-28 09:56:35 +00003636/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3637
3638/*
3639 * When commands are first encountered, they are entered in a hash table.
3640 * This ensures that a full path search will not have to be done for them
3641 * on each invocation.
3642 *
3643 * We should investigate converting to a linear search, even though that
3644 * would make the command name "hash" a misnomer.
3645 */
3646
3647#define CMDTABLESIZE 31 /* should be prime */
3648#define ARB 1 /* actual size determined at run time */
3649
3650
3651
3652struct tblentry {
3653 struct tblentry *next; /* next entry in hash chain */
3654 union param param; /* definition of builtin function */
3655 short cmdtype; /* index identifying command */
3656 char rehash; /* if set, cd done since entry created */
3657 char cmdname[ARB]; /* name of command */
3658};
3659
3660
3661static struct tblentry *cmdtable[CMDTABLESIZE];
3662static int builtinloc = -1; /* index in path of %builtin, or -1 */
3663
3664
3665static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003666static void clearcmdentry(int);
3667static struct tblentry *cmdlookup(const char *, int);
3668static void delete_cmd_entry(void);
3669
Eric Andersencb57d552001-06-28 07:25:16 +00003670
3671/*
3672 * Exec a program. Never returns. If you change this routine, you may
3673 * have to change the find_command routine as well.
3674 */
3675
Eric Andersenc470f442003-07-28 09:56:35 +00003676static void
3677shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003678{
3679 char *cmdname;
3680 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003681 char **envp;
Eric Andersencb57d552001-06-28 07:25:16 +00003682
Eric Andersenc470f442003-07-28 09:56:35 +00003683 clearredir(1);
3684 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003685 if (strchr(argv[0], '/') != NULL
3686#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3687 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003688#endif
3689 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003690 tryexec(argv[0], argv, envp);
3691 e = errno;
3692 } else {
3693 e = ENOENT;
3694 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3695 if (--idx < 0 && pathopt == NULL) {
3696 tryexec(cmdname, argv, envp);
3697 if (errno != ENOENT && errno != ENOTDIR)
3698 e = errno;
3699 }
3700 stunalloc(cmdname);
3701 }
3702 }
3703
3704 /* Map to POSIX errors */
3705 switch (e) {
3706 case EACCES:
3707 exerrno = 126;
3708 break;
3709 case ENOENT:
3710 exerrno = 127;
3711 break;
3712 default:
3713 exerrno = 2;
3714 break;
3715 }
Eric Andersenc470f442003-07-28 09:56:35 +00003716 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3717 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003718 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3719 /* NOTREACHED */
3720}
3721
Eric Andersen2870d962001-07-02 17:27:21 +00003722
Eric Andersenc470f442003-07-28 09:56:35 +00003723static void
3724tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003725{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003726 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003727#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003728 if(find_applet_by_name(cmd) != NULL) {
3729 /* re-exec ourselves with the new arguments */
3730 execve("/proc/self/exe",argv,envp);
3731 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3732 execve("/bin/busybox",argv,envp);
3733 /* If they called chroot or otherwise made the binary no longer
3734 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003735 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003736#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003737
3738repeat:
3739#ifdef SYSV
3740 do {
3741 execve(cmd, argv, envp);
3742 } while (errno == EINTR);
3743#else
Eric Andersencb57d552001-06-28 07:25:16 +00003744 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003745#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003746 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003747 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003748 } else if (errno == ENOEXEC) {
3749 char **ap;
3750 char **new;
3751
Eric Andersenc470f442003-07-28 09:56:35 +00003752 for (ap = argv; *ap; ap++)
3753 ;
3754 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003755 ap[1] = cmd;
3756 *ap = cmd = (char *)DEFAULT_SHELL;
3757 ap += 2;
3758 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003759 while ((*ap++ = *argv++))
3760 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003761 argv = new;
3762 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003763 }
Eric Andersencb57d552001-06-28 07:25:16 +00003764}
3765
Eric Andersenc470f442003-07-28 09:56:35 +00003766
Eric Andersencb57d552001-06-28 07:25:16 +00003767
3768/*
3769 * Do a path search. The variable path (passed by reference) should be
3770 * set to the start of the path before the first call; padvance will update
3771 * this value as it proceeds. Successive calls to padvance will return
3772 * the possible path expansions in sequence. If an option (indicated by
3773 * a percent sign) appears in the path entry then the global variable
3774 * pathopt will be set to point to it; otherwise pathopt will be set to
3775 * NULL.
3776 */
3777
Eric Andersenc470f442003-07-28 09:56:35 +00003778static char *
3779padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003780{
Eric Andersencb57d552001-06-28 07:25:16 +00003781 const char *p;
3782 char *q;
3783 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003784 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003785
3786 if (*path == NULL)
3787 return NULL;
3788 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003789 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3790 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003791 while (stackblocksize() < len)
3792 growstackblock();
3793 q = stackblock();
3794 if (p != start) {
3795 memcpy(q, start, p - start);
3796 q += p - start;
3797 *q++ = '/';
3798 }
3799 strcpy(q, name);
3800 pathopt = NULL;
3801 if (*p == '%') {
3802 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003803 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003804 }
3805 if (*p == ':')
3806 *path = p + 1;
3807 else
3808 *path = NULL;
3809 return stalloc(len);
3810}
3811
3812
Eric Andersencb57d552001-06-28 07:25:16 +00003813/*** Command hashing code ***/
3814
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003815static void
3816printentry(struct tblentry *cmdp)
3817{
3818 int idx;
3819 const char *path;
3820 char *name;
3821
3822 idx = cmdp->param.index;
3823 path = pathval();
3824 do {
3825 name = padvance(&path, cmdp->cmdname);
3826 stunalloc(name);
3827 } while (--idx >= 0);
3828 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3829}
3830
Eric Andersenc470f442003-07-28 09:56:35 +00003831
3832static int
3833hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003834{
3835 struct tblentry **pp;
3836 struct tblentry *cmdp;
3837 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003838 struct cmdentry entry;
3839 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003840
Eric Andersenc470f442003-07-28 09:56:35 +00003841 while ((c = nextopt("r")) != '\0') {
3842 clearcmdentry(0);
3843 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003844 }
3845 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003846 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3847 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3848 if (cmdp->cmdtype == CMDNORMAL)
3849 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003850 }
3851 }
3852 return 0;
3853 }
3854 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003855 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003856 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003857 && (cmdp->cmdtype == CMDNORMAL
3858 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003859 delete_cmd_entry();
3860 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003861 if (entry.cmdtype == CMDUNKNOWN)
3862 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003863 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003864 }
3865 return c;
3866}
3867
Eric Andersenc470f442003-07-28 09:56:35 +00003868
Eric Andersencb57d552001-06-28 07:25:16 +00003869/*
3870 * Resolve a command name. If you change this routine, you may have to
3871 * change the shellexec routine as well.
3872 */
3873
3874static void
Eric Andersenc470f442003-07-28 09:56:35 +00003875find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003876{
3877 struct tblentry *cmdp;
3878 int idx;
3879 int prev;
3880 char *fullname;
3881 struct stat statb;
3882 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003883 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003884 struct builtincmd *bcmd;
3885
Eric Andersenc470f442003-07-28 09:56:35 +00003886 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003887 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003888 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003889 if (act & DO_ABS) {
3890 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003891#ifdef SYSV
3892 if (errno == EINTR)
3893 continue;
3894#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003895 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003896 return;
3897 }
Eric Andersencb57d552001-06-28 07:25:16 +00003898 }
3899 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003900 return;
3901 }
3902
Eric Andersenbf8bf102002-09-17 08:41:08 +00003903#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3904 if (find_applet_by_name(name)) {
3905 entry->cmdtype = CMDNORMAL;
3906 entry->u.index = -1;
3907 return;
3908 }
3909#endif
3910
Eric Andersenc470f442003-07-28 09:56:35 +00003911 updatetbl = (path == pathval());
3912 if (!updatetbl) {
3913 act |= DO_ALTPATH;
3914 if (strstr(path, "%builtin") != NULL)
3915 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003916 }
3917
Eric Andersenc470f442003-07-28 09:56:35 +00003918 /* If name is in the table, check answer will be ok */
3919 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3920 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003921
Eric Andersenc470f442003-07-28 09:56:35 +00003922 switch (cmdp->cmdtype) {
3923 default:
3924#if DEBUG
3925 abort();
3926#endif
3927 case CMDNORMAL:
3928 bit = DO_ALTPATH;
3929 break;
3930 case CMDFUNCTION:
3931 bit = DO_NOFUNC;
3932 break;
3933 case CMDBUILTIN:
3934 bit = DO_ALTBLTIN;
3935 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003936 }
Eric Andersenc470f442003-07-28 09:56:35 +00003937 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003938 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003939 cmdp = NULL;
3940 } else if (cmdp->rehash == 0)
3941 /* if not invalidated by cd, we're done */
3942 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003943 }
3944
3945 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003946 bcmd = find_builtin(name);
3947 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3948 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3949 )))
3950 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003951
3952 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003953 prev = -1; /* where to start */
3954 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003955 if (cmdp->cmdtype == CMDBUILTIN)
3956 prev = builtinloc;
3957 else
3958 prev = cmdp->param.index;
3959 }
3960
3961 e = ENOENT;
3962 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003963loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003964 while ((fullname = padvance(&path, name)) != NULL) {
3965 stunalloc(fullname);
3966 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003967 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003968 if (prefix(pathopt, "builtin")) {
3969 if (bcmd)
3970 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003971 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003972 } else if (!(act & DO_NOFUNC) &&
3973 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003974 /* handled below */
3975 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003976 /* ignore unimplemented options */
3977 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003978 }
3979 }
3980 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003981 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003982 if (idx < prev)
3983 continue;
3984 TRACE(("searchexec \"%s\": no change\n", name));
3985 goto success;
3986 }
3987 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003988#ifdef SYSV
3989 if (errno == EINTR)
3990 continue;
3991#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003992 if (errno != ENOENT && errno != ENOTDIR)
3993 e = errno;
3994 goto loop;
3995 }
Eric Andersenc470f442003-07-28 09:56:35 +00003996 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003997 if (!S_ISREG(statb.st_mode))
3998 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003999 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004000 stalloc(strlen(fullname) + 1);
4001 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004002 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4003 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004004 error("%s not defined in %s", name, fullname);
4005 stunalloc(fullname);
4006 goto success;
4007 }
Eric Andersencb57d552001-06-28 07:25:16 +00004008 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004009 if (!updatetbl) {
4010 entry->cmdtype = CMDNORMAL;
4011 entry->u.index = idx;
4012 return;
4013 }
4014 INTOFF;
4015 cmdp = cmdlookup(name, 1);
4016 cmdp->cmdtype = CMDNORMAL;
4017 cmdp->param.index = idx;
4018 INTON;
4019 goto success;
4020 }
4021
4022 /* We failed. If there was an entry for this command, delete it */
4023 if (cmdp && updatetbl)
4024 delete_cmd_entry();
4025 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004026 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004027 entry->cmdtype = CMDUNKNOWN;
4028 return;
4029
Eric Andersenc470f442003-07-28 09:56:35 +00004030builtin_success:
4031 if (!updatetbl) {
4032 entry->cmdtype = CMDBUILTIN;
4033 entry->u.cmd = bcmd;
4034 return;
4035 }
4036 INTOFF;
4037 cmdp = cmdlookup(name, 1);
4038 cmdp->cmdtype = CMDBUILTIN;
4039 cmdp->param.cmd = bcmd;
4040 INTON;
4041success:
Eric Andersencb57d552001-06-28 07:25:16 +00004042 cmdp->rehash = 0;
4043 entry->cmdtype = cmdp->cmdtype;
4044 entry->u = cmdp->param;
4045}
4046
4047
Eric Andersenc470f442003-07-28 09:56:35 +00004048/*
4049 * Wrapper around strcmp for qsort/bsearch/...
4050 */
4051static int pstrcmp(const void *a, const void *b)
4052{
4053 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4054}
Eric Andersencb57d552001-06-28 07:25:16 +00004055
4056/*
4057 * Search the table of builtin commands.
4058 */
4059
Eric Andersenc470f442003-07-28 09:56:35 +00004060static struct builtincmd *
4061find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004062{
4063 struct builtincmd *bp;
4064
Eric Andersenc470f442003-07-28 09:56:35 +00004065 bp = bsearch(
4066 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4067 pstrcmp
4068 );
Eric Andersencb57d552001-06-28 07:25:16 +00004069 return bp;
4070}
4071
4072
Eric Andersenc470f442003-07-28 09:56:35 +00004073
Eric Andersencb57d552001-06-28 07:25:16 +00004074/*
4075 * Called when a cd is done. Marks all commands so the next time they
4076 * are executed they will be rehashed.
4077 */
4078
Eric Andersenc470f442003-07-28 09:56:35 +00004079static void
4080hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004081{
Eric Andersencb57d552001-06-28 07:25:16 +00004082 struct tblentry **pp;
4083 struct tblentry *cmdp;
4084
Eric Andersenc470f442003-07-28 09:56:35 +00004085 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4086 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4087 if (cmdp->cmdtype == CMDNORMAL || (
4088 cmdp->cmdtype == CMDBUILTIN &&
4089 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4090 builtinloc > 0
4091 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004092 cmdp->rehash = 1;
4093 }
4094 }
4095}
4096
4097
4098
4099/*
Eric Andersenc470f442003-07-28 09:56:35 +00004100 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004101 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004102 * pathval() still returns the old value at this point.
4103 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004104 */
4105
Eric Andersenc470f442003-07-28 09:56:35 +00004106static void
4107changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004108{
Eric Andersenc470f442003-07-28 09:56:35 +00004109 const char *old, *new;
4110 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004111 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004112 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004113
Eric Andersenc470f442003-07-28 09:56:35 +00004114 old = pathval();
4115 new = newval;
4116 firstchange = 9999; /* assume no change */
4117 idx = 0;
4118 idx_bltin = -1;
4119 for (;;) {
4120 if (*old != *new) {
4121 firstchange = idx;
4122 if ((*old == '\0' && *new == ':')
4123 || (*old == ':' && *new == '\0'))
4124 firstchange++;
4125 old = new; /* ignore subsequent differences */
4126 }
4127 if (*new == '\0')
4128 break;
4129 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4130 idx_bltin = idx;
4131 if (*new == ':') {
4132 idx++;
4133 }
4134 new++, old++;
4135 }
4136 if (builtinloc < 0 && idx_bltin >= 0)
4137 builtinloc = idx_bltin; /* zap builtins */
4138 if (builtinloc >= 0 && idx_bltin < 0)
4139 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004140 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004141 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004142}
4143
4144
4145/*
4146 * Clear out command entries. The argument specifies the first entry in
4147 * PATH which has changed.
4148 */
4149
Eric Andersenc470f442003-07-28 09:56:35 +00004150static void
4151clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004152{
4153 struct tblentry **tblp;
4154 struct tblentry **pp;
4155 struct tblentry *cmdp;
4156
4157 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004158 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004159 pp = tblp;
4160 while ((cmdp = *pp) != NULL) {
4161 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004162 cmdp->param.index >= firstchange)
4163 || (cmdp->cmdtype == CMDBUILTIN &&
4164 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004165 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004166 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004167 } else {
4168 pp = &cmdp->next;
4169 }
4170 }
4171 }
4172 INTON;
4173}
4174
4175
Eric Andersenc470f442003-07-28 09:56:35 +00004176
Eric Andersencb57d552001-06-28 07:25:16 +00004177/*
Eric Andersencb57d552001-06-28 07:25:16 +00004178 * Locate a command in the command hash table. If "add" is nonzero,
4179 * add the command to the table if it is not already present. The
4180 * variable "lastcmdentry" is set to point to the address of the link
4181 * pointing to the entry, so that delete_cmd_entry can delete the
4182 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004183 *
4184 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004185 */
4186
Eric Andersen2870d962001-07-02 17:27:21 +00004187static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004188
Eric Andersenc470f442003-07-28 09:56:35 +00004189
4190static struct tblentry *
4191cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004192{
Eric Andersenc470f442003-07-28 09:56:35 +00004193 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004194 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004195 struct tblentry *cmdp;
4196 struct tblentry **pp;
4197
4198 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004199 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004200 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004201 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004202 hashval &= 0x7FFF;
4203 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004204 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004205 if (equal(cmdp->cmdname, name))
4206 break;
4207 pp = &cmdp->next;
4208 }
4209 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004210 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4211 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004212 cmdp->next = NULL;
4213 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004214 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004215 }
4216 lastcmdentry = pp;
4217 return cmdp;
4218}
4219
4220/*
4221 * Delete the command entry returned on the last lookup.
4222 */
4223
Eric Andersenc470f442003-07-28 09:56:35 +00004224static void
4225delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004226{
Eric Andersencb57d552001-06-28 07:25:16 +00004227 struct tblentry *cmdp;
4228
4229 INTOFF;
4230 cmdp = *lastcmdentry;
4231 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004232 if (cmdp->cmdtype == CMDFUNCTION)
4233 freefunc(cmdp->param.func);
4234 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004235 INTON;
4236}
4237
4238
Eric Andersenc470f442003-07-28 09:56:35 +00004239/*
4240 * Add a new command entry, replacing any existing command entry for
4241 * the same name - except special builtins.
4242 */
Eric Andersencb57d552001-06-28 07:25:16 +00004243
Eric Andersenc470f442003-07-28 09:56:35 +00004244static inline void
4245addcmdentry(char *name, struct cmdentry *entry)
4246{
4247 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004248
Eric Andersenc470f442003-07-28 09:56:35 +00004249 cmdp = cmdlookup(name, 1);
4250 if (cmdp->cmdtype == CMDFUNCTION) {
4251 freefunc(cmdp->param.func);
4252 }
4253 cmdp->cmdtype = entry->cmdtype;
4254 cmdp->param = entry->u;
4255 cmdp->rehash = 0;
4256}
Eric Andersencb57d552001-06-28 07:25:16 +00004257
Eric Andersenc470f442003-07-28 09:56:35 +00004258/*
4259 * Make a copy of a parse tree.
4260 */
Eric Andersencb57d552001-06-28 07:25:16 +00004261
Eric Andersenc470f442003-07-28 09:56:35 +00004262static inline struct funcnode *
4263copyfunc(union node *n)
4264{
4265 struct funcnode *f;
4266 size_t blocksize;
4267
4268 funcblocksize = offsetof(struct funcnode, n);
4269 funcstringsize = 0;
4270 calcsize(n);
4271 blocksize = funcblocksize;
4272 f = ckmalloc(blocksize + funcstringsize);
4273 funcblock = (char *) f + offsetof(struct funcnode, n);
4274 funcstring = (char *) f + blocksize;
4275 copynode(n);
4276 f->count = 0;
4277 return f;
4278}
4279
4280/*
4281 * Define a shell function.
4282 */
4283
4284static void
4285defun(char *name, union node *func)
4286{
4287 struct cmdentry entry;
4288
4289 INTOFF;
4290 entry.cmdtype = CMDFUNCTION;
4291 entry.u.func = copyfunc(func);
4292 addcmdentry(name, &entry);
4293 INTON;
4294}
Eric Andersencb57d552001-06-28 07:25:16 +00004295
4296
4297/*
4298 * Delete a function if it exists.
4299 */
4300
Eric Andersenc470f442003-07-28 09:56:35 +00004301static void
4302unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004303{
Eric Andersencb57d552001-06-28 07:25:16 +00004304 struct tblentry *cmdp;
4305
Eric Andersenc470f442003-07-28 09:56:35 +00004306 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4307 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004308 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004309}
4310
Eric Andersen2870d962001-07-02 17:27:21 +00004311/*
Eric Andersencb57d552001-06-28 07:25:16 +00004312 * Locate and print what a word is...
4313 */
4314
Eric Andersenc470f442003-07-28 09:56:35 +00004315
4316#ifdef CONFIG_ASH_CMDCMD
4317static int
4318describe_command(char *command, int describe_command_verbose)
4319#else
4320#define describe_command_verbose 1
4321static int
4322describe_command(char *command)
4323#endif
4324{
4325 struct cmdentry entry;
4326 struct tblentry *cmdp;
4327#ifdef CONFIG_ASH_ALIAS
4328 const struct alias *ap;
4329#endif
4330 const char *path = pathval();
4331
4332 if (describe_command_verbose) {
4333 out1str(command);
4334 }
4335
4336 /* First look at the keywords */
4337 if (findkwd(command)) {
4338 out1str(describe_command_verbose ? " is a shell keyword" : command);
4339 goto out;
4340 }
4341
4342#ifdef CONFIG_ASH_ALIAS
4343 /* Then look at the aliases */
4344 if ((ap = lookupalias(command, 0)) != NULL) {
4345 if (describe_command_verbose) {
4346 out1fmt(" is an alias for %s", ap->val);
4347 } else {
4348 out1str("alias ");
4349 printalias(ap);
4350 return 0;
4351 }
4352 goto out;
4353 }
4354#endif
4355 /* Then check if it is a tracked alias */
4356 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4357 entry.cmdtype = cmdp->cmdtype;
4358 entry.u = cmdp->param;
4359 } else {
4360 /* Finally use brute force */
4361 find_command(command, &entry, DO_ABS, path);
4362 }
4363
4364 switch (entry.cmdtype) {
4365 case CMDNORMAL: {
4366 int j = entry.u.index;
4367 char *p;
4368 if (j == -1) {
4369 p = command;
4370 } else {
4371 do {
4372 p = padvance(&path, command);
4373 stunalloc(p);
4374 } while (--j >= 0);
4375 }
4376 if (describe_command_verbose) {
4377 out1fmt(" is%s %s",
4378 (cmdp ? " a tracked alias for" : nullstr), p
4379 );
4380 } else {
4381 out1str(p);
4382 }
4383 break;
4384 }
4385
4386 case CMDFUNCTION:
4387 if (describe_command_verbose) {
4388 out1str(" is a shell function");
4389 } else {
4390 out1str(command);
4391 }
4392 break;
4393
4394 case CMDBUILTIN:
4395 if (describe_command_verbose) {
4396 out1fmt(" is a %sshell builtin",
4397 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4398 "special " : nullstr
4399 );
4400 } else {
4401 out1str(command);
4402 }
4403 break;
4404
4405 default:
4406 if (describe_command_verbose) {
4407 out1str(": not found\n");
4408 }
4409 return 127;
4410 }
4411
4412out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004413 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004414 return 0;
4415}
4416
4417static int
4418typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004419{
4420 int i;
4421 int err = 0;
4422
4423 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004424#ifdef CONFIG_ASH_CMDCMD
4425 err |= describe_command(argv[i], 1);
4426#else
4427 err |= describe_command(argv[i]);
4428#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004429 }
4430 return err;
4431}
4432
Eric Andersend35c5df2002-01-09 15:37:36 +00004433#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004434static int
4435commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004436{
4437 int c;
4438 int default_path = 0;
4439 int verify_only = 0;
4440 int verbose_verify_only = 0;
4441
4442 while ((c = nextopt("pvV")) != '\0')
4443 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004444 default:
4445#ifdef DEBUG
4446 fprintf(stderr,
4447"command: nextopt returned character code 0%o\n", c);
4448 return EX_SOFTWARE;
4449#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004450 case 'p':
4451 default_path = 1;
4452 break;
4453 case 'v':
4454 verify_only = 1;
4455 break;
4456 case 'V':
4457 verbose_verify_only = 1;
4458 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004459 }
4460
Eric Andersenc470f442003-07-28 09:56:35 +00004461 if (default_path + verify_only + verbose_verify_only > 1 ||
4462 !*argptr) {
4463 fprintf(stderr,
4464 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004465 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004466 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004467 }
4468
Eric Andersencb57d552001-06-28 07:25:16 +00004469 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004470 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004471 }
Eric Andersencb57d552001-06-28 07:25:16 +00004472
4473 return 0;
4474}
Eric Andersen2870d962001-07-02 17:27:21 +00004475#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004476
Eric Andersenc470f442003-07-28 09:56:35 +00004477/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004478
Eric Andersencb57d552001-06-28 07:25:16 +00004479/*
4480 * Routines to expand arguments to commands. We have to deal with
4481 * backquotes, shell variables, and file metacharacters.
4482 */
Eric Andersenc470f442003-07-28 09:56:35 +00004483
Eric Andersencb57d552001-06-28 07:25:16 +00004484/*
4485 * _rmescape() flags
4486 */
Eric Andersenc470f442003-07-28 09:56:35 +00004487#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4488#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4489#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4490#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4491#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004492
4493/*
4494 * Structure specifying which parts of the string should be searched
4495 * for IFS characters.
4496 */
4497
4498struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004499 struct ifsregion *next; /* next region in list */
4500 int begoff; /* offset of start of region */
4501 int endoff; /* offset of end of region */
4502 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004503};
4504
Eric Andersenc470f442003-07-28 09:56:35 +00004505/* output of current string */
4506static char *expdest;
4507/* list of back quote expressions */
4508static struct nodelist *argbackq;
4509/* first struct in list of ifs regions */
4510static struct ifsregion ifsfirst;
4511/* last struct in list */
4512static struct ifsregion *ifslastp;
4513/* holds expanded arg list */
4514static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004515
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004516static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004517static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004518static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004519static const char *subevalvar(char *, char *, int, int, int, int, int);
4520static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004521static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004522static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004523static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004524static void recordregion(int, int, int);
4525static void removerecordregions(int);
4526static void ifsbreakup(char *, struct arglist *);
4527static void ifsfree(void);
4528static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004529static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004530
Eric Andersened9ecf72004-06-22 08:29:45 +00004531static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004532static size_t esclen(const char *, const char *);
4533static char *scanleft(char *, char *, char *, char *, int, int);
4534static char *scanright(char *, char *, char *, char *, int, int);
4535static void varunset(const char *, const char *, const char *, int)
4536 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004537
Eric Andersenc470f442003-07-28 09:56:35 +00004538
4539#define pmatch(a, b) !fnmatch((a), (b), 0)
4540/*
Eric Andersen90898442003-08-06 11:20:52 +00004541 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004542 *
4543 * Returns an stalloced string.
4544 */
4545
4546static inline char *
4547preglob(const char *pattern, int quoted, int flag) {
4548 flag |= RMESCAPE_GLOB;
4549 if (quoted) {
4550 flag |= RMESCAPE_QUOTED;
4551 }
4552 return _rmescapes((char *)pattern, flag);
4553}
4554
4555
4556static size_t
4557esclen(const char *start, const char *p) {
4558 size_t esc = 0;
4559
4560 while (p > start && *--p == CTLESC) {
4561 esc++;
4562 }
4563 return esc;
4564}
4565
Eric Andersencb57d552001-06-28 07:25:16 +00004566
4567/*
4568 * Expand shell variables and backquotes inside a here document.
4569 */
4570
Eric Andersenc470f442003-07-28 09:56:35 +00004571static inline void
4572expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004573{
Eric Andersencb57d552001-06-28 07:25:16 +00004574 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004575 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004576 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004577}
4578
4579
4580/*
4581 * Perform variable substitution and command substitution on an argument,
4582 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4583 * perform splitting and file name expansion. When arglist is NULL, perform
4584 * here document expansion.
4585 */
4586
Eric Andersenc470f442003-07-28 09:56:35 +00004587void
4588expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004589{
4590 struct strlist *sp;
4591 char *p;
4592
4593 argbackq = arg->narg.backquote;
4594 STARTSTACKSTR(expdest);
4595 ifsfirst.next = NULL;
4596 ifslastp = NULL;
4597 argstr(arg->narg.text, flag);
4598 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004599 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004600 }
4601 STPUTC('\0', expdest);
4602 p = grabstackstr(expdest);
4603 exparg.lastp = &exparg.list;
4604 /*
4605 * TODO - EXP_REDIR
4606 */
4607 if (flag & EXP_FULL) {
4608 ifsbreakup(p, &exparg);
4609 *exparg.lastp = NULL;
4610 exparg.lastp = &exparg.list;
4611 expandmeta(exparg.list, flag);
4612 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004613 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004614 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004615 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004616 sp->text = p;
4617 *exparg.lastp = sp;
4618 exparg.lastp = &sp->next;
4619 }
Eric Andersenc470f442003-07-28 09:56:35 +00004620 if (ifsfirst.next)
4621 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004622 *exparg.lastp = NULL;
4623 if (exparg.list) {
4624 *arglist->lastp = exparg.list;
4625 arglist->lastp = exparg.lastp;
4626 }
4627}
4628
4629
Eric Andersenc470f442003-07-28 09:56:35 +00004630/*
4631 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4632 * characters to allow for further processing. Otherwise treat
4633 * $@ like $* since no splitting will be performed.
4634 */
4635
4636static void
4637argstr(char *p, int flag)
4638{
4639 static const char spclchars[] = {
4640 '=',
4641 ':',
4642 CTLQUOTEMARK,
4643 CTLENDVAR,
4644 CTLESC,
4645 CTLVAR,
4646 CTLBACKQ,
4647 CTLBACKQ | CTLQUOTE,
4648#ifdef CONFIG_ASH_MATH_SUPPORT
4649 CTLENDARI,
4650#endif
4651 0
4652 };
4653 const char *reject = spclchars;
4654 int c;
4655 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4656 int breakall = flag & EXP_WORD;
4657 int inquotes;
4658 size_t length;
4659 int startloc;
4660
4661 if (!(flag & EXP_VARTILDE)) {
4662 reject += 2;
4663 } else if (flag & EXP_VARTILDE2) {
4664 reject++;
4665 }
4666 inquotes = 0;
4667 length = 0;
4668 if (flag & EXP_TILDE) {
4669 char *q;
4670
4671 flag &= ~EXP_TILDE;
4672tilde:
4673 q = p;
4674 if (*q == CTLESC && (flag & EXP_QWORD))
4675 q++;
4676 if (*q == '~')
4677 p = exptilde(p, q, flag);
4678 }
4679start:
4680 startloc = expdest - (char *)stackblock();
4681 for (;;) {
4682 length += strcspn(p + length, reject);
4683 c = p[length];
4684 if (c && (!(c & 0x80)
4685#ifdef CONFIG_ASH_MATH_SUPPORT
4686 || c == CTLENDARI
4687#endif
4688 )) {
4689 /* c == '=' || c == ':' || c == CTLENDARI */
4690 length++;
4691 }
4692 if (length > 0) {
4693 int newloc;
4694 expdest = stnputs(p, length, expdest);
4695 newloc = expdest - (char *)stackblock();
4696 if (breakall && !inquotes && newloc > startloc) {
4697 recordregion(startloc, newloc, 0);
4698 }
4699 startloc = newloc;
4700 }
4701 p += length + 1;
4702 length = 0;
4703
4704 switch (c) {
4705 case '\0':
4706 goto breakloop;
4707 case '=':
4708 if (flag & EXP_VARTILDE2) {
4709 p--;
4710 continue;
4711 }
4712 flag |= EXP_VARTILDE2;
4713 reject++;
4714 /* fall through */
4715 case ':':
4716 /*
4717 * sort of a hack - expand tildes in variable
4718 * assignments (after the first '=' and after ':'s).
4719 */
4720 if (*--p == '~') {
4721 goto tilde;
4722 }
4723 continue;
4724 }
4725
4726 switch (c) {
4727 case CTLENDVAR: /* ??? */
4728 goto breakloop;
4729 case CTLQUOTEMARK:
4730 /* "$@" syntax adherence hack */
4731 if (
4732 !inquotes &&
4733 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4734 (p[4] == CTLQUOTEMARK || (
4735 p[4] == CTLENDVAR &&
4736 p[5] == CTLQUOTEMARK
4737 ))
4738 ) {
4739 p = evalvar(p + 1, flag) + 1;
4740 goto start;
4741 }
4742 inquotes = !inquotes;
4743addquote:
4744 if (quotes) {
4745 p--;
4746 length++;
4747 startloc++;
4748 }
4749 break;
4750 case CTLESC:
4751 startloc++;
4752 length++;
4753 goto addquote;
4754 case CTLVAR:
4755 p = evalvar(p, flag);
4756 goto start;
4757 case CTLBACKQ:
4758 c = 0;
4759 case CTLBACKQ|CTLQUOTE:
4760 expbackq(argbackq->n, c, quotes);
4761 argbackq = argbackq->next;
4762 goto start;
4763#ifdef CONFIG_ASH_MATH_SUPPORT
4764 case CTLENDARI:
4765 p--;
4766 expari(quotes);
4767 goto start;
4768#endif
4769 }
4770 }
4771breakloop:
4772 ;
4773}
4774
4775static char *
4776exptilde(char *startp, char *p, int flag)
4777{
4778 char c;
4779 char *name;
4780 struct passwd *pw;
4781 const char *home;
4782 int quotes = flag & (EXP_FULL | EXP_CASE);
4783 int startloc;
4784
4785 name = p + 1;
4786
4787 while ((c = *++p) != '\0') {
4788 switch(c) {
4789 case CTLESC:
4790 return (startp);
4791 case CTLQUOTEMARK:
4792 return (startp);
4793 case ':':
4794 if (flag & EXP_VARTILDE)
4795 goto done;
4796 break;
4797 case '/':
4798 case CTLENDVAR:
4799 goto done;
4800 }
4801 }
4802done:
4803 *p = '\0';
4804 if (*name == '\0') {
4805 if ((home = lookupvar(homestr)) == NULL)
4806 goto lose;
4807 } else {
4808 if ((pw = getpwnam(name)) == NULL)
4809 goto lose;
4810 home = pw->pw_dir;
4811 }
4812 if (*home == '\0')
4813 goto lose;
4814 *p = c;
4815 startloc = expdest - (char *)stackblock();
4816 strtodest(home, SQSYNTAX, quotes);
4817 recordregion(startloc, expdest - (char *)stackblock(), 0);
4818 return (p);
4819lose:
4820 *p = c;
4821 return (startp);
4822}
4823
4824
4825static void
4826removerecordregions(int endoff)
4827{
4828 if (ifslastp == NULL)
4829 return;
4830
4831 if (ifsfirst.endoff > endoff) {
4832 while (ifsfirst.next != NULL) {
4833 struct ifsregion *ifsp;
4834 INTOFF;
4835 ifsp = ifsfirst.next->next;
4836 ckfree(ifsfirst.next);
4837 ifsfirst.next = ifsp;
4838 INTON;
4839 }
4840 if (ifsfirst.begoff > endoff)
4841 ifslastp = NULL;
4842 else {
4843 ifslastp = &ifsfirst;
4844 ifsfirst.endoff = endoff;
4845 }
4846 return;
4847 }
4848
4849 ifslastp = &ifsfirst;
4850 while (ifslastp->next && ifslastp->next->begoff < endoff)
4851 ifslastp=ifslastp->next;
4852 while (ifslastp->next != NULL) {
4853 struct ifsregion *ifsp;
4854 INTOFF;
4855 ifsp = ifslastp->next->next;
4856 ckfree(ifslastp->next);
4857 ifslastp->next = ifsp;
4858 INTON;
4859 }
4860 if (ifslastp->endoff > endoff)
4861 ifslastp->endoff = endoff;
4862}
4863
4864
4865#ifdef CONFIG_ASH_MATH_SUPPORT
4866/*
4867 * Expand arithmetic expression. Backup to start of expression,
4868 * evaluate, place result in (backed up) result, adjust string position.
4869 */
4870void
4871expari(int quotes)
4872{
4873 char *p, *start;
4874 int begoff;
4875 int flag;
4876 int len;
4877
4878 /* ifsfree(); */
4879
4880 /*
4881 * This routine is slightly over-complicated for
4882 * efficiency. Next we scan backwards looking for the
4883 * start of arithmetic.
4884 */
4885 start = stackblock();
4886 p = expdest - 1;
4887 *p = '\0';
4888 p--;
4889 do {
4890 int esc;
4891
4892 while (*p != CTLARI) {
4893 p--;
4894#ifdef DEBUG
4895 if (p < start) {
4896 error("missing CTLARI (shouldn't happen)");
4897 }
4898#endif
4899 }
4900
4901 esc = esclen(start, p);
4902 if (!(esc % 2)) {
4903 break;
4904 }
4905
4906 p -= esc + 1;
4907 } while (1);
4908
4909 begoff = p - start;
4910
4911 removerecordregions(begoff);
4912
4913 flag = p[1];
4914
4915 expdest = p;
4916
4917 if (quotes)
4918 rmescapes(p + 2);
4919
4920 len = cvtnum(dash_arith(p + 2));
4921
4922 if (flag != '"')
4923 recordregion(begoff, begoff + len, 0);
4924}
4925#endif
4926
4927/*
4928 * Expand stuff in backwards quotes.
4929 */
4930
4931static void
4932expbackq(union node *cmd, int quoted, int quotes)
4933{
4934 struct backcmd in;
4935 int i;
4936 char buf[128];
4937 char *p;
4938 char *dest;
4939 int startloc;
4940 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4941 struct stackmark smark;
4942
4943 INTOFF;
4944 setstackmark(&smark);
4945 dest = expdest;
4946 startloc = dest - (char *)stackblock();
4947 grabstackstr(dest);
4948 evalbackcmd(cmd, (struct backcmd *) &in);
4949 popstackmark(&smark);
4950
4951 p = in.buf;
4952 i = in.nleft;
4953 if (i == 0)
4954 goto read;
4955 for (;;) {
4956 memtodest(p, i, syntax, quotes);
4957read:
4958 if (in.fd < 0)
4959 break;
4960 i = safe_read(in.fd, buf, sizeof buf);
4961 TRACE(("expbackq: read returns %d\n", i));
4962 if (i <= 0)
4963 break;
4964 p = buf;
4965 }
4966
4967 if (in.buf)
4968 ckfree(in.buf);
4969 if (in.fd >= 0) {
4970 close(in.fd);
4971 back_exitstatus = waitforjob(in.jp);
4972 }
4973 INTON;
4974
4975 /* Eat all trailing newlines */
4976 dest = expdest;
4977 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4978 STUNPUTC(dest);
4979 expdest = dest;
4980
4981 if (quoted == 0)
4982 recordregion(startloc, dest - (char *)stackblock(), 0);
4983 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4984 (dest - (char *)stackblock()) - startloc,
4985 (dest - (char *)stackblock()) - startloc,
4986 stackblock() + startloc));
4987}
4988
4989
4990static char *
Eric Andersen90898442003-08-06 11:20:52 +00004991scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4992 int zero)
4993{
Eric Andersenc470f442003-07-28 09:56:35 +00004994 char *loc;
4995 char *loc2;
4996 char c;
4997
4998 loc = startp;
4999 loc2 = rmesc;
5000 do {
5001 int match;
5002 const char *s = loc2;
5003 c = *loc2;
5004 if (zero) {
5005 *loc2 = '\0';
5006 s = rmesc;
5007 }
5008 match = pmatch(str, s);
5009 *loc2 = c;
5010 if (match)
5011 return loc;
5012 if (quotes && *loc == CTLESC)
5013 loc++;
5014 loc++;
5015 loc2++;
5016 } while (c);
5017 return 0;
5018}
5019
5020
5021static char *
Eric Andersen90898442003-08-06 11:20:52 +00005022scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5023 int zero)
5024{
Eric Andersenc470f442003-07-28 09:56:35 +00005025 int esc = 0;
5026 char *loc;
5027 char *loc2;
5028
5029 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5030 int match;
5031 char c = *loc2;
5032 const char *s = loc2;
5033 if (zero) {
5034 *loc2 = '\0';
5035 s = rmesc;
5036 }
5037 match = pmatch(str, s);
5038 *loc2 = c;
5039 if (match)
5040 return loc;
5041 loc--;
5042 if (quotes) {
5043 if (--esc < 0) {
5044 esc = esclen(startp, loc);
5045 }
5046 if (esc % 2) {
5047 esc--;
5048 loc--;
5049 }
5050 }
5051 }
5052 return 0;
5053}
5054
5055static const char *
5056subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5057{
5058 char *startp;
5059 char *loc;
5060 int saveherefd = herefd;
5061 struct nodelist *saveargbackq = argbackq;
5062 int amount;
5063 char *rmesc, *rmescend;
5064 int zero;
5065 char *(*scan)(char *, char *, char *, char *, int , int);
5066
5067 herefd = -1;
5068 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5069 STPUTC('\0', expdest);
5070 herefd = saveherefd;
5071 argbackq = saveargbackq;
5072 startp = stackblock() + startloc;
5073
5074 switch (subtype) {
5075 case VSASSIGN:
5076 setvar(str, startp, 0);
5077 amount = startp - expdest;
5078 STADJUST(amount, expdest);
5079 return startp;
5080
5081 case VSQUESTION:
5082 varunset(p, str, startp, varflags);
5083 /* NOTREACHED */
5084 }
5085
5086 subtype -= VSTRIMRIGHT;
5087#ifdef DEBUG
5088 if (subtype < 0 || subtype > 3)
5089 abort();
5090#endif
5091
5092 rmesc = startp;
5093 rmescend = stackblock() + strloc;
5094 if (quotes) {
5095 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5096 if (rmesc != startp) {
5097 rmescend = expdest;
5098 startp = stackblock() + startloc;
5099 }
5100 }
5101 rmescend--;
5102 str = stackblock() + strloc;
5103 preglob(str, varflags & VSQUOTE, 0);
5104
5105 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5106 zero = subtype >> 1;
5107 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5108 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5109
5110 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5111 if (loc) {
5112 if (zero) {
5113 memmove(startp, loc, str - loc);
5114 loc = startp + (str - loc) - 1;
5115 }
5116 *loc = '\0';
5117 amount = loc - expdest;
5118 STADJUST(amount, expdest);
5119 }
5120 return loc;
5121}
5122
5123
Eric Andersen62483552001-07-10 06:09:16 +00005124/*
5125 * Expand a variable, and return a pointer to the next character in the
5126 * input string.
5127 */
Eric Andersenc470f442003-07-28 09:56:35 +00005128static char *
5129evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005130{
5131 int subtype;
5132 int varflags;
5133 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005134 int patloc;
5135 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005136 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005137 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005138 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005139 int quotes;
5140 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005141
Eric Andersenc470f442003-07-28 09:56:35 +00005142 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005143 varflags = *p++;
5144 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005145 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005146 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005147 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005148 startloc = expdest - (char *)stackblock();
5149 p = strchr(p, '=') + 1;
5150
Eric Andersenc470f442003-07-28 09:56:35 +00005151again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005152 varlen = varvalue(var, varflags, flag);
5153 if (varflags & VSNUL)
5154 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005155
Glenn L McGrath76620622004-01-13 10:19:37 +00005156 if (subtype == VSPLUS) {
5157 varlen = -1 - varlen;
5158 goto vsplus;
5159 }
Eric Andersen62483552001-07-10 06:09:16 +00005160
Eric Andersenc470f442003-07-28 09:56:35 +00005161 if (subtype == VSMINUS) {
5162vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005163 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005164 argstr(
5165 p, flag | EXP_TILDE |
5166 (quoted ? EXP_QWORD : EXP_WORD)
5167 );
5168 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005169 }
5170 if (easy)
5171 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005172 goto end;
5173 }
Eric Andersen62483552001-07-10 06:09:16 +00005174
Eric Andersenc470f442003-07-28 09:56:35 +00005175 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005176 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005177 if (subevalvar(p, var, 0, subtype, startloc,
5178 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005179 varflags &= ~VSNUL;
5180 /*
5181 * Remove any recorded regions beyond
5182 * start of variable
5183 */
5184 removerecordregions(startloc);
5185 goto again;
5186 }
Eric Andersenc470f442003-07-28 09:56:35 +00005187 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005188 }
5189 if (easy)
5190 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005191 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005192 }
5193
Glenn L McGrath76620622004-01-13 10:19:37 +00005194 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005195 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005196
Eric Andersenc470f442003-07-28 09:56:35 +00005197 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005198 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005199 goto record;
5200 }
5201
5202 if (subtype == VSNORMAL) {
5203 if (!easy)
5204 goto end;
5205record:
5206 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5207 goto end;
5208 }
5209
5210#ifdef DEBUG
5211 switch (subtype) {
5212 case VSTRIMLEFT:
5213 case VSTRIMLEFTMAX:
5214 case VSTRIMRIGHT:
5215 case VSTRIMRIGHTMAX:
5216 break;
5217 default:
5218 abort();
5219 }
5220#endif
5221
Glenn L McGrath76620622004-01-13 10:19:37 +00005222 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005223 /*
5224 * Terminate the string and start recording the pattern
5225 * right after it
5226 */
5227 STPUTC('\0', expdest);
5228 patloc = expdest - (char *)stackblock();
5229 if (subevalvar(p, NULL, patloc, subtype,
5230 startloc, varflags, quotes) == 0) {
5231 int amount = expdest - (
5232 (char *)stackblock() + patloc - 1
5233 );
5234 STADJUST(-amount, expdest);
5235 }
5236 /* Remove any recorded regions beyond start of variable */
5237 removerecordregions(startloc);
5238 goto record;
5239 }
5240
5241end:
5242 if (subtype != VSNORMAL) { /* skip to end of alternative */
5243 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005244 for (;;) {
5245 if ((c = *p++) == CTLESC)
5246 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005247 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005248 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005249 argbackq = argbackq->next;
5250 } else if (c == CTLVAR) {
5251 if ((*p++ & VSTYPE) != VSNORMAL)
5252 nesting++;
5253 } else if (c == CTLENDVAR) {
5254 if (--nesting == 0)
5255 break;
5256 }
5257 }
5258 }
5259 return p;
5260}
5261
Eric Andersencb57d552001-06-28 07:25:16 +00005262
Eric Andersencb57d552001-06-28 07:25:16 +00005263/*
5264 * Put a string on the stack.
5265 */
5266
Eric Andersenc470f442003-07-28 09:56:35 +00005267static void
5268memtodest(const char *p, size_t len, int syntax, int quotes) {
5269 char *q = expdest;
5270
5271 q = makestrspace(len * 2, q);
5272
5273 while (len--) {
5274 int c = *p++;
5275 if (!c)
5276 continue;
5277 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5278 USTPUTC(CTLESC, q);
5279 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005280 }
Eric Andersenc470f442003-07-28 09:56:35 +00005281
5282 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005283}
5284
Eric Andersenc470f442003-07-28 09:56:35 +00005285
5286static void
5287strtodest(const char *p, int syntax, int quotes)
5288{
5289 memtodest(p, strlen(p), syntax, quotes);
5290}
5291
5292
Eric Andersencb57d552001-06-28 07:25:16 +00005293/*
5294 * Add the value of a specialized variable to the stack string.
5295 */
5296
Glenn L McGrath76620622004-01-13 10:19:37 +00005297static ssize_t
5298varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005299{
5300 int num;
5301 char *p;
5302 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005303 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005304 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005305 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005306 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005307 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005308 int quoted = varflags & VSQUOTE;
5309 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005310 int quotes = flags & (EXP_FULL | EXP_CASE);
5311
Glenn L McGrath76620622004-01-13 10:19:37 +00005312 if (quoted && (flags & EXP_FULL))
5313 sep = 1 << CHAR_BIT;
5314
Eric Andersencb57d552001-06-28 07:25:16 +00005315 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5316 switch (*name) {
5317 case '$':
5318 num = rootpid;
5319 goto numvar;
5320 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005321 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005322 goto numvar;
5323 case '#':
5324 num = shellparam.nparam;
5325 goto numvar;
5326 case '!':
5327 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005328 if (num == 0)
5329 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005330numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005331 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005332 break;
5333 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005334 p = makestrspace(NOPTS, expdest);
5335 for (i = NOPTS - 1; i >= 0; i--) {
5336 if (optlist[i]) {
5337 USTPUTC(optletters(i), p);
5338 len++;
5339 }
Eric Andersencb57d552001-06-28 07:25:16 +00005340 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005341 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005342 break;
5343 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005344 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005345 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005346 /* fall through */
5347 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005348 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005349 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5350 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005351param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005352 if (!(ap = shellparam.p))
5353 return -1;
5354 while ((p = *ap++)) {
5355 size_t partlen;
5356
5357 partlen = strlen(p);
5358
5359 len += partlen;
5360 if (len > partlen && sep) {
5361 char *q;
5362
5363 len++;
5364 if (subtype == VSPLUS || subtype == VSLENGTH) {
5365 continue;
5366 }
5367 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005368 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005369 STPUTC(CTLESC, q);
5370 STPUTC(sep, q);
5371 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005372 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005373
5374 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5375 memtodest(p, partlen, syntax, quotes);
Eric Andersencb57d552001-06-28 07:25:16 +00005376 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005377 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005378 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005379 case '1':
5380 case '2':
5381 case '3':
5382 case '4':
5383 case '5':
5384 case '6':
5385 case '7':
5386 case '8':
5387 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005388 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005389 if (num < 0 || num > shellparam.nparam)
5390 return -1;
5391 p = num ? shellparam.p[num - 1] : arg0;
5392 goto value;
5393 default:
5394 p = lookupvar(name);
5395value:
5396 if (!p)
5397 return -1;
5398
5399 len = strlen(p);
5400 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5401 memtodest(p, len, syntax, quotes);
5402 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005403 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005404
5405 if (subtype == VSPLUS || subtype == VSLENGTH)
5406 STADJUST(-len, expdest);
5407 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005408}
5409
5410
Eric Andersencb57d552001-06-28 07:25:16 +00005411/*
5412 * Record the fact that we have to scan this region of the
5413 * string for IFS characters.
5414 */
5415
Eric Andersenc470f442003-07-28 09:56:35 +00005416static void
5417recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005418{
5419 struct ifsregion *ifsp;
5420
5421 if (ifslastp == NULL) {
5422 ifsp = &ifsfirst;
5423 } else {
5424 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005425 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005426 ifsp->next = NULL;
5427 ifslastp->next = ifsp;
5428 INTON;
5429 }
5430 ifslastp = ifsp;
5431 ifslastp->begoff = start;
5432 ifslastp->endoff = end;
5433 ifslastp->nulonly = nulonly;
5434}
5435
5436
Eric Andersencb57d552001-06-28 07:25:16 +00005437/*
5438 * Break the argument string into pieces based upon IFS and add the
5439 * strings to the argument list. The regions of the string to be
5440 * searched for IFS characters have been stored by recordregion.
5441 */
Eric Andersenc470f442003-07-28 09:56:35 +00005442static void
5443ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005444{
Eric Andersencb57d552001-06-28 07:25:16 +00005445 struct ifsregion *ifsp;
5446 struct strlist *sp;
5447 char *start;
5448 char *p;
5449 char *q;
5450 const char *ifs, *realifs;
5451 int ifsspc;
5452 int nulonly;
5453
5454
5455 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005456 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005457 ifsspc = 0;
5458 nulonly = 0;
5459 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005460 ifsp = &ifsfirst;
5461 do {
5462 p = string + ifsp->begoff;
5463 nulonly = ifsp->nulonly;
5464 ifs = nulonly ? nullstr : realifs;
5465 ifsspc = 0;
5466 while (p < string + ifsp->endoff) {
5467 q = p;
5468 if (*p == CTLESC)
5469 p++;
5470 if (strchr(ifs, *p)) {
5471 if (!nulonly)
5472 ifsspc = (strchr(defifs, *p) != NULL);
5473 /* Ignore IFS whitespace at start */
5474 if (q == start && ifsspc) {
5475 p++;
5476 start = p;
5477 continue;
5478 }
5479 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005480 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005481 sp->text = start;
5482 *arglist->lastp = sp;
5483 arglist->lastp = &sp->next;
5484 p++;
5485 if (!nulonly) {
5486 for (;;) {
5487 if (p >= string + ifsp->endoff) {
5488 break;
5489 }
5490 q = p;
5491 if (*p == CTLESC)
5492 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005493 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005494 p = q;
5495 break;
5496 } else if (strchr(defifs, *p) == NULL) {
5497 if (ifsspc) {
5498 p++;
5499 ifsspc = 0;
5500 } else {
5501 p = q;
5502 break;
5503 }
5504 } else
5505 p++;
5506 }
5507 }
5508 start = p;
5509 } else
5510 p++;
5511 }
5512 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005513 if (nulonly)
5514 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005515 }
5516
Eric Andersenc470f442003-07-28 09:56:35 +00005517 if (!*start)
5518 return;
5519
5520add:
5521 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005522 sp->text = start;
5523 *arglist->lastp = sp;
5524 arglist->lastp = &sp->next;
5525}
5526
Eric Andersenc470f442003-07-28 09:56:35 +00005527static void
5528ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005529{
Eric Andersenc470f442003-07-28 09:56:35 +00005530 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005531
Eric Andersenc470f442003-07-28 09:56:35 +00005532 INTOFF;
5533 p = ifsfirst.next;
5534 do {
5535 struct ifsregion *ifsp;
5536 ifsp = p->next;
5537 ckfree(p);
5538 p = ifsp;
5539 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005540 ifslastp = NULL;
5541 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005542 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005543}
5544
Eric Andersen90898442003-08-06 11:20:52 +00005545static void expmeta(char *, char *);
5546static struct strlist *expsort(struct strlist *);
5547static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005548
Eric Andersen90898442003-08-06 11:20:52 +00005549static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005550
Eric Andersencb57d552001-06-28 07:25:16 +00005551
Eric Andersenc470f442003-07-28 09:56:35 +00005552static void
Eric Andersen90898442003-08-06 11:20:52 +00005553expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005554{
Eric Andersen90898442003-08-06 11:20:52 +00005555 static const char metachars[] = {
5556 '*', '?', '[', 0
5557 };
Eric Andersencb57d552001-06-28 07:25:16 +00005558 /* TODO - EXP_REDIR */
5559
5560 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005561 struct strlist **savelastp;
5562 struct strlist *sp;
5563 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005564
Eric Andersencb57d552001-06-28 07:25:16 +00005565 if (fflag)
5566 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005567 if (!strpbrk(str->text, metachars))
5568 goto nometa;
5569 savelastp = exparg.lastp;
5570
Eric Andersencb57d552001-06-28 07:25:16 +00005571 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005572 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005573 {
5574 int i = strlen(str->text);
5575 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5576 }
5577
5578 expmeta(expdir, p);
5579 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005580 if (p != str->text)
5581 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005582 INTON;
5583 if (exparg.lastp == savelastp) {
5584 /*
5585 * no matches
5586 */
Eric Andersenc470f442003-07-28 09:56:35 +00005587nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005588 *exparg.lastp = str;
5589 rmescapes(str->text);
5590 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005591 } else {
5592 *exparg.lastp = NULL;
5593 *savelastp = sp = expsort(*savelastp);
5594 while (sp->next != NULL)
5595 sp = sp->next;
5596 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005597 }
5598 str = str->next;
5599 }
5600}
5601
Eric Andersencb57d552001-06-28 07:25:16 +00005602/*
Eric Andersenc470f442003-07-28 09:56:35 +00005603 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005604 */
5605
Eric Andersenc470f442003-07-28 09:56:35 +00005606static void
Eric Andersen90898442003-08-06 11:20:52 +00005607addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005608{
Eric Andersencb57d552001-06-28 07:25:16 +00005609 struct strlist *sp;
5610
Eric Andersenc470f442003-07-28 09:56:35 +00005611 sp = (struct strlist *)stalloc(sizeof *sp);
5612 sp->text = sstrdup(name);
5613 *exparg.lastp = sp;
5614 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005615}
5616
5617
Eric Andersencb57d552001-06-28 07:25:16 +00005618/*
Eric Andersen90898442003-08-06 11:20:52 +00005619 * Do metacharacter (i.e. *, ?, [...]) expansion.
5620 */
5621
5622static void
5623expmeta(char *enddir, char *name)
5624{
5625 char *p;
5626 const char *cp;
5627 char *start;
5628 char *endname;
5629 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005630 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005631 DIR *dirp;
5632 struct dirent *dp;
5633 int atend;
5634 int matchdot;
5635
5636 metaflag = 0;
5637 start = name;
5638 for (p = name; *p; p++) {
5639 if (*p == '*' || *p == '?')
5640 metaflag = 1;
5641 else if (*p == '[') {
5642 char *q = p + 1;
5643 if (*q == '!')
5644 q++;
5645 for (;;) {
5646 if (*q == '\\')
5647 q++;
5648 if (*q == '/' || *q == '\0')
5649 break;
5650 if (*++q == ']') {
5651 metaflag = 1;
5652 break;
5653 }
5654 }
5655 } else if (*p == '\\')
5656 p++;
5657 else if (*p == '/') {
5658 if (metaflag)
5659 goto out;
5660 start = p + 1;
5661 }
5662 }
5663out:
5664 if (metaflag == 0) { /* we've reached the end of the file name */
5665 if (enddir != expdir)
5666 metaflag++;
5667 p = name;
5668 do {
5669 if (*p == '\\')
5670 p++;
5671 *enddir++ = *p;
5672 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005673 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005674 addfname(expdir);
5675 return;
5676 }
5677 endname = p;
5678 if (name < start) {
5679 p = name;
5680 do {
5681 if (*p == '\\')
5682 p++;
5683 *enddir++ = *p++;
5684 } while (p < start);
5685 }
5686 if (enddir == expdir) {
5687 cp = ".";
5688 } else if (enddir == expdir + 1 && *expdir == '/') {
5689 cp = "/";
5690 } else {
5691 cp = expdir;
5692 enddir[-1] = '\0';
5693 }
5694 if ((dirp = opendir(cp)) == NULL)
5695 return;
5696 if (enddir != expdir)
5697 enddir[-1] = '/';
5698 if (*endname == 0) {
5699 atend = 1;
5700 } else {
5701 atend = 0;
5702 *endname++ = '\0';
5703 }
5704 matchdot = 0;
5705 p = start;
5706 if (*p == '\\')
5707 p++;
5708 if (*p == '.')
5709 matchdot++;
5710 while (! intpending && (dp = readdir(dirp)) != NULL) {
5711 if (dp->d_name[0] == '.' && ! matchdot)
5712 continue;
5713 if (pmatch(start, dp->d_name)) {
5714 if (atend) {
5715 scopy(dp->d_name, enddir);
5716 addfname(expdir);
5717 } else {
5718 for (p = enddir, cp = dp->d_name;
5719 (*p++ = *cp++) != '\0';)
5720 continue;
5721 p[-1] = '/';
5722 expmeta(p, endname);
5723 }
5724 }
5725 }
5726 closedir(dirp);
5727 if (! atend)
5728 endname[-1] = '/';
5729}
5730
5731/*
5732 * Sort the results of file name expansion. It calculates the number of
5733 * strings to sort and then calls msort (short for merge sort) to do the
5734 * work.
5735 */
5736
5737static struct strlist *
5738expsort(struct strlist *str)
5739{
5740 int len;
5741 struct strlist *sp;
5742
5743 len = 0;
5744 for (sp = str ; sp ; sp = sp->next)
5745 len++;
5746 return msort(str, len);
5747}
5748
5749
5750static struct strlist *
5751msort(struct strlist *list, int len)
5752{
5753 struct strlist *p, *q = NULL;
5754 struct strlist **lpp;
5755 int half;
5756 int n;
5757
5758 if (len <= 1)
5759 return list;
5760 half = len >> 1;
5761 p = list;
5762 for (n = half ; --n >= 0 ; ) {
5763 q = p;
5764 p = p->next;
5765 }
5766 q->next = NULL; /* terminate first half of list */
5767 q = msort(list, half); /* sort first half of list */
5768 p = msort(p, len - half); /* sort second half */
5769 lpp = &list;
5770 for (;;) {
5771#ifdef CONFIG_LOCALE_SUPPORT
5772 if (strcoll(p->text, q->text) < 0)
5773#else
5774 if (strcmp(p->text, q->text) < 0)
5775#endif
5776 {
5777 *lpp = p;
5778 lpp = &p->next;
5779 if ((p = *lpp) == NULL) {
5780 *lpp = q;
5781 break;
5782 }
5783 } else {
5784 *lpp = q;
5785 lpp = &q->next;
5786 if ((q = *lpp) == NULL) {
5787 *lpp = p;
5788 break;
5789 }
5790 }
5791 }
5792 return list;
5793}
5794
5795
5796/*
Eric Andersencb57d552001-06-28 07:25:16 +00005797 * Returns true if the pattern matches the string.
5798 */
5799
Eric Andersenc470f442003-07-28 09:56:35 +00005800static inline int
5801patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005802{
Eric Andersenc470f442003-07-28 09:56:35 +00005803 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005804}
5805
5806
Eric Andersencb57d552001-06-28 07:25:16 +00005807/*
5808 * Remove any CTLESC characters from a string.
5809 */
5810
Eric Andersenc470f442003-07-28 09:56:35 +00005811static char *
5812_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005813{
5814 char *p, *q, *r;
5815 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005816 unsigned inquotes;
5817 int notescaped;
5818 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005819
5820 p = strpbrk(str, qchars);
5821 if (!p) {
5822 return str;
5823 }
5824 q = p;
5825 r = str;
5826 if (flag & RMESCAPE_ALLOC) {
5827 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005828 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005829
Eric Andersenc470f442003-07-28 09:56:35 +00005830 if (flag & RMESCAPE_GROW) {
5831 r = makestrspace(fulllen, expdest);
5832 } else if (flag & RMESCAPE_HEAP) {
5833 r = ckmalloc(fulllen);
5834 } else {
5835 r = stalloc(fulllen);
5836 }
5837 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005838 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005839 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005840 }
5841 }
Eric Andersenc470f442003-07-28 09:56:35 +00005842 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5843 globbing = flag & RMESCAPE_GLOB;
5844 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005845 while (*p) {
5846 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005847 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005848 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005849 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005850 continue;
5851 }
Eric Andersenc470f442003-07-28 09:56:35 +00005852 if (*p == '\\') {
5853 /* naked back slash */
5854 notescaped = 0;
5855 goto copy;
5856 }
Eric Andersencb57d552001-06-28 07:25:16 +00005857 if (*p == CTLESC) {
5858 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005859 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005860 *q++ = '\\';
5861 }
5862 }
Eric Andersenc470f442003-07-28 09:56:35 +00005863 notescaped = globbing;
5864copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005865 *q++ = *p++;
5866 }
5867 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005868 if (flag & RMESCAPE_GROW) {
5869 expdest = r;
5870 STADJUST(q - r + 1, expdest);
5871 }
Eric Andersencb57d552001-06-28 07:25:16 +00005872 return r;
5873}
Eric Andersencb57d552001-06-28 07:25:16 +00005874
5875
Eric Andersencb57d552001-06-28 07:25:16 +00005876/*
5877 * See if a pattern matches in a case statement.
5878 */
5879
Eric Andersenc470f442003-07-28 09:56:35 +00005880int
5881casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005882{
Eric Andersencb57d552001-06-28 07:25:16 +00005883 struct stackmark smark;
5884 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005885
5886 setstackmark(&smark);
5887 argbackq = pattern->narg.backquote;
5888 STARTSTACKSTR(expdest);
5889 ifslastp = NULL;
5890 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005891 STACKSTRNUL(expdest);
5892 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005893 popstackmark(&smark);
5894 return result;
5895}
5896
5897/*
5898 * Our own itoa().
5899 */
5900
Eric Andersenc470f442003-07-28 09:56:35 +00005901static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005902cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005903{
Eric Andersencb57d552001-06-28 07:25:16 +00005904 int len;
5905
Eric Andersenc470f442003-07-28 09:56:35 +00005906 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005907#ifdef CONFIG_ASH_MATH_SUPPORT_64
5908 len = fmtstr(expdest, 32, "%lld", (long long) num);
5909#else
Eric Andersenc470f442003-07-28 09:56:35 +00005910 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005911#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005912 STADJUST(len, expdest);
5913 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005914}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005915
Eric Andersenc470f442003-07-28 09:56:35 +00005916static void
5917varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005918{
Eric Andersenc470f442003-07-28 09:56:35 +00005919 const char *msg;
5920 const char *tail;
5921
5922 tail = nullstr;
5923 msg = "parameter not set";
5924 if (umsg) {
5925 if (*end == CTLENDVAR) {
5926 if (varflags & VSNUL)
5927 tail = " or null";
5928 } else
5929 msg = umsg;
5930 }
5931 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005932}
Eric Andersen90898442003-08-06 11:20:52 +00005933
5934
Eric Andersenc470f442003-07-28 09:56:35 +00005935/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005936
Eric Andersencb57d552001-06-28 07:25:16 +00005937/*
Eric Andersen90898442003-08-06 11:20:52 +00005938 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005939 */
5940
Eric Andersenc470f442003-07-28 09:56:35 +00005941#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5942#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005943
Eric Andersenc470f442003-07-28 09:56:35 +00005944static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005945
Eric Andersencb57d552001-06-28 07:25:16 +00005946/*
Eric Andersenc470f442003-07-28 09:56:35 +00005947 * Read a character from the script, returning PEOF on end of file.
5948 * Nul characters in the input are silently discarded.
5949 */
5950
5951#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5952
5953#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5954#define pgetc_macro() pgetc()
5955static int
5956pgetc(void)
5957{
5958 return pgetc_as_macro();
5959}
5960#else
5961#define pgetc_macro() pgetc_as_macro()
5962static int
5963pgetc(void)
5964{
5965 return pgetc_macro();
5966}
5967#endif
5968
5969
5970/*
5971 * Same as pgetc(), but ignores PEOA.
5972 */
5973#ifdef CONFIG_ASH_ALIAS
5974static int pgetc2(void)
5975{
5976 int c;
5977
5978 do {
5979 c = pgetc_macro();
5980 } while (c == PEOA);
5981 return c;
5982}
5983#else
5984static inline int pgetc2(void)
5985{
5986 return pgetc_macro();
5987}
5988#endif
5989
Glenn L McGrath28939ad2004-07-21 10:20:19 +00005990/*
5991 * Read a line from the script.
5992 */
5993
5994static inline char *
5995pfgets(char *line, int len)
5996{
5997 char *p = line;
5998 int nleft = len;
5999 int c;
6000
6001 while (--nleft > 0) {
6002 c = pgetc2();
6003 if (c == PEOF) {
6004 if (p == line)
6005 return NULL;
6006 break;
6007 }
6008 *p++ = c;
6009 if (c == '\n')
6010 break;
6011 }
6012 *p = '\0';
6013 return line;
6014}
6015
6016
Eric Andersenc470f442003-07-28 09:56:35 +00006017
6018#ifdef CONFIG_FEATURE_COMMAND_EDITING
6019static const char *cmdedit_prompt;
6020static inline void putprompt(const char *s)
6021{
6022 cmdedit_prompt = s;
6023}
6024#else
6025static inline void putprompt(const char *s)
6026{
6027 out2str(s);
6028}
6029#endif
6030
6031static inline int
6032preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006033{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006034 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006035 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006036 parsenextc = buf;
6037
Eric Andersenc470f442003-07-28 09:56:35 +00006038retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006039#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006040 if (!iflag || parsefile->fd)
6041 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6042 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006043#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006044 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006045#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006046 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6047 if(nr == 0) {
6048 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006049 if(trap[SIGINT]) {
6050 buf[0] = '\n';
6051 buf[1] = 0;
6052 raise(SIGINT);
6053 return 1;
6054 }
Eric Andersenc470f442003-07-28 09:56:35 +00006055 goto retry;
6056 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006057 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006058 /* Ctrl+D presend */
6059 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006060 }
Eric Andersencb57d552001-06-28 07:25:16 +00006061 }
6062#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006063 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006064#endif
6065
6066 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006067 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6068 int flags = fcntl(0, F_GETFL, 0);
6069 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006070 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006071 if (fcntl(0, F_SETFL, flags) >= 0) {
6072 out2str("sh: turning off NDELAY mode\n");
6073 goto retry;
6074 }
6075 }
6076 }
6077 }
6078 return nr;
6079}
6080
6081/*
6082 * Refill the input buffer and return the next input character:
6083 *
6084 * 1) If a string was pushed back on the input, pop it;
6085 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6086 * from a string so we can't refill the buffer, return EOF.
6087 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6088 * 4) Process input up to the next newline, deleting nul characters.
6089 */
6090
Eric Andersenc470f442003-07-28 09:56:35 +00006091int
6092preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006093{
6094 char *p, *q;
6095 int more;
6096 char savec;
6097
6098 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006099#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006100 if (parsenleft == -1 && parsefile->strpush->ap &&
6101 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006102 return PEOA;
6103 }
Eric Andersen2870d962001-07-02 17:27:21 +00006104#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006105 popstring();
6106 if (--parsenleft >= 0)
6107 return (*parsenextc++);
6108 }
6109 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6110 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006111 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006112
Eric Andersenc470f442003-07-28 09:56:35 +00006113again:
Eric Andersencb57d552001-06-28 07:25:16 +00006114 if (parselleft <= 0) {
6115 if ((parselleft = preadfd()) <= 0) {
6116 parselleft = parsenleft = EOF_NLEFT;
6117 return PEOF;
6118 }
6119 }
6120
6121 q = p = parsenextc;
6122
6123 /* delete nul characters */
6124 for (more = 1; more;) {
6125 switch (*p) {
6126 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006127 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006128 goto check;
6129
Eric Andersencb57d552001-06-28 07:25:16 +00006130 case '\n':
6131 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006132 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006133 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006134
Eric Andersencb57d552001-06-28 07:25:16 +00006135 }
6136
6137 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006138check:
Eric Andersencb57d552001-06-28 07:25:16 +00006139 if (--parselleft <= 0 && more) {
6140 parsenleft = q - parsenextc - 1;
6141 if (parsenleft < 0)
6142 goto again;
6143 more = 0;
6144 }
6145 }
6146
6147 savec = *q;
6148 *q = '\0';
6149
6150 if (vflag) {
6151 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006152 }
6153
6154 *q = savec;
6155
6156 return *parsenextc++;
6157}
6158
Eric Andersenc470f442003-07-28 09:56:35 +00006159/*
6160 * Undo the last call to pgetc. Only one character may be pushed back.
6161 * PEOF may be pushed back.
6162 */
6163
6164void
6165pungetc(void)
6166{
6167 parsenleft++;
6168 parsenextc--;
6169}
Eric Andersencb57d552001-06-28 07:25:16 +00006170
6171/*
6172 * Push a string back onto the input at this current parsefile level.
6173 * We handle aliases this way.
6174 */
Eric Andersenc470f442003-07-28 09:56:35 +00006175void
6176pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006177{
Eric Andersencb57d552001-06-28 07:25:16 +00006178 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006179 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006180
Eric Andersenc470f442003-07-28 09:56:35 +00006181 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006182 INTOFF;
6183/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6184 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006185 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006186 sp->prev = parsefile->strpush;
6187 parsefile->strpush = sp;
6188 } else
6189 sp = parsefile->strpush = &(parsefile->basestrpush);
6190 sp->prevstring = parsenextc;
6191 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006192#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006193 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006194 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006195 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006196 sp->string = s;
6197 }
Eric Andersen2870d962001-07-02 17:27:21 +00006198#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006199 parsenextc = s;
6200 parsenleft = len;
6201 INTON;
6202}
6203
Eric Andersenc470f442003-07-28 09:56:35 +00006204void
6205popstring(void)
6206{
6207 struct strpush *sp = parsefile->strpush;
6208
6209 INTOFF;
6210#ifdef CONFIG_ASH_ALIAS
6211 if (sp->ap) {
6212 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6213 checkkwd |= CHKALIAS;
6214 }
6215 if (sp->string != sp->ap->val) {
6216 ckfree(sp->string);
6217 }
6218 sp->ap->flag &= ~ALIASINUSE;
6219 if (sp->ap->flag & ALIASDEAD) {
6220 unalias(sp->ap->name);
6221 }
6222 }
6223#endif
6224 parsenextc = sp->prevstring;
6225 parsenleft = sp->prevnleft;
6226/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6227 parsefile->strpush = sp->prev;
6228 if (sp != &(parsefile->basestrpush))
6229 ckfree(sp);
6230 INTON;
6231}
6232
6233/*
6234 * Set the input to take input from a file. If push is set, push the
6235 * old input onto the stack first.
6236 */
6237
6238void
6239setinputfile(const char *fname, int push)
6240{
6241 int fd;
6242 int fd2;
6243
6244 INTOFF;
6245 if ((fd = open(fname, O_RDONLY)) < 0)
6246 error("Can't open %s", fname);
6247 if (fd < 10) {
6248 fd2 = copyfd(fd, 10);
6249 close(fd);
6250 if (fd2 < 0)
6251 error("Out of file descriptors");
6252 fd = fd2;
6253 }
6254 setinputfd(fd, push);
6255 INTON;
6256}
6257
6258
6259/*
6260 * Like setinputfile, but takes an open file descriptor. Call this with
6261 * interrupts off.
6262 */
6263
6264static void
6265setinputfd(int fd, int push)
6266{
6267 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6268 if (push) {
6269 pushfile();
6270 parsefile->buf = 0;
6271 }
6272 parsefile->fd = fd;
6273 if (parsefile->buf == NULL)
6274 parsefile->buf = ckmalloc(IBUFSIZ);
6275 parselleft = parsenleft = 0;
6276 plinno = 1;
6277}
6278
Eric Andersencb57d552001-06-28 07:25:16 +00006279
Eric Andersencb57d552001-06-28 07:25:16 +00006280/*
6281 * Like setinputfile, but takes input from a string.
6282 */
6283
Eric Andersenc470f442003-07-28 09:56:35 +00006284static void
6285setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006286{
Eric Andersencb57d552001-06-28 07:25:16 +00006287 INTOFF;
6288 pushfile();
6289 parsenextc = string;
6290 parsenleft = strlen(string);
6291 parsefile->buf = NULL;
6292 plinno = 1;
6293 INTON;
6294}
6295
6296
Eric Andersencb57d552001-06-28 07:25:16 +00006297/*
6298 * To handle the "." command, a stack of input files is used. Pushfile
6299 * adds a new entry to the stack and popfile restores the previous level.
6300 */
6301
Eric Andersenc470f442003-07-28 09:56:35 +00006302static void
6303pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006304{
Eric Andersencb57d552001-06-28 07:25:16 +00006305 struct parsefile *pf;
6306
6307 parsefile->nleft = parsenleft;
6308 parsefile->lleft = parselleft;
6309 parsefile->nextc = parsenextc;
6310 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006311 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006312 pf->prev = parsefile;
6313 pf->fd = -1;
6314 pf->strpush = NULL;
6315 pf->basestrpush.prev = NULL;
6316 parsefile = pf;
6317}
6318
Eric Andersenc470f442003-07-28 09:56:35 +00006319
6320static void
6321popfile(void)
6322{
6323 struct parsefile *pf = parsefile;
6324
6325 INTOFF;
6326 if (pf->fd >= 0)
6327 close(pf->fd);
6328 if (pf->buf)
6329 ckfree(pf->buf);
6330 while (pf->strpush)
6331 popstring();
6332 parsefile = pf->prev;
6333 ckfree(pf);
6334 parsenleft = parsefile->nleft;
6335 parselleft = parsefile->lleft;
6336 parsenextc = parsefile->nextc;
6337 plinno = parsefile->linno;
6338 INTON;
6339}
Eric Andersencb57d552001-06-28 07:25:16 +00006340
6341
Eric Andersen2870d962001-07-02 17:27:21 +00006342/*
Eric Andersenc470f442003-07-28 09:56:35 +00006343 * Return to top level.
6344 */
Eric Andersen2870d962001-07-02 17:27:21 +00006345
Eric Andersenc470f442003-07-28 09:56:35 +00006346static void
6347popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006348{
Eric Andersenc470f442003-07-28 09:56:35 +00006349 while (parsefile != &basepf)
6350 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006351}
6352
Eric Andersen2870d962001-07-02 17:27:21 +00006353
Eric Andersenc470f442003-07-28 09:56:35 +00006354/*
6355 * Close the file(s) that the shell is reading commands from. Called
6356 * after a fork is done.
6357 */
6358
6359static void
6360closescript(void)
6361{
6362 popallfiles();
6363 if (parsefile->fd > 0) {
6364 close(parsefile->fd);
6365 parsefile->fd = 0;
6366 }
6367}
Eric Andersenc470f442003-07-28 09:56:35 +00006368
Eric Andersen90898442003-08-06 11:20:52 +00006369/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006370
6371/* mode flags for set_curjob */
6372#define CUR_DELETE 2
6373#define CUR_RUNNING 1
6374#define CUR_STOPPED 0
6375
6376/* mode flags for dowait */
6377#define DOWAIT_NORMAL 0
6378#define DOWAIT_BLOCK 1
6379
6380/* array of jobs */
6381static struct job *jobtab;
6382/* size of array */
6383static unsigned njobs;
6384#if JOBS
6385/* pgrp of shell on invocation */
6386static int initialpgrp;
6387static int ttyfd = -1;
6388#endif
6389/* current job */
6390static struct job *curjob;
6391/* number of presumed living untracked jobs */
6392static int jobless;
6393
6394static void set_curjob(struct job *, unsigned);
6395#if JOBS
6396static int restartjob(struct job *, int);
6397static void xtcsetpgrp(int, pid_t);
6398static char *commandtext(union node *);
6399static void cmdlist(union node *, int);
6400static void cmdtxt(union node *);
6401static void cmdputs(const char *);
6402static void showpipe(struct job *, FILE *);
6403#endif
6404static int sprint_status(char *, int, int);
6405static void freejob(struct job *);
6406static struct job *getjob(const char *, int);
6407static struct job *growjobtab(void);
6408static void forkchild(struct job *, union node *, int);
6409static void forkparent(struct job *, union node *, int, pid_t);
6410static int dowait(int, struct job *);
6411static int getstatus(struct job *);
6412
6413static void
6414set_curjob(struct job *jp, unsigned mode)
6415{
6416 struct job *jp1;
6417 struct job **jpp, **curp;
6418
6419 /* first remove from list */
6420 jpp = curp = &curjob;
6421 do {
6422 jp1 = *jpp;
6423 if (jp1 == jp)
6424 break;
6425 jpp = &jp1->prev_job;
6426 } while (1);
6427 *jpp = jp1->prev_job;
6428
6429 /* Then re-insert in correct position */
6430 jpp = curp;
6431 switch (mode) {
6432 default:
6433#ifdef DEBUG
6434 abort();
6435#endif
6436 case CUR_DELETE:
6437 /* job being deleted */
6438 break;
6439 case CUR_RUNNING:
6440 /* newly created job or backgrounded job,
6441 put after all stopped jobs. */
6442 do {
6443 jp1 = *jpp;
6444#ifdef JOBS
6445 if (!jp1 || jp1->state != JOBSTOPPED)
6446#endif
6447 break;
6448 jpp = &jp1->prev_job;
6449 } while (1);
6450 /* FALLTHROUGH */
6451#ifdef JOBS
6452 case CUR_STOPPED:
6453#endif
6454 /* newly stopped job - becomes curjob */
6455 jp->prev_job = *jpp;
6456 *jpp = jp;
6457 break;
6458 }
6459}
6460
6461#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006462/*
6463 * Turn job control on and off.
6464 *
6465 * Note: This code assumes that the third arg to ioctl is a character
6466 * pointer, which is true on Berkeley systems but not System V. Since
6467 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006468 *
6469 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006470 */
6471
Eric Andersenc470f442003-07-28 09:56:35 +00006472void
6473setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006474{
Eric Andersenc470f442003-07-28 09:56:35 +00006475 int fd;
6476 int pgrp;
6477
6478 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006479 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006480 if (on) {
6481 int ofd;
6482 ofd = fd = open(_PATH_TTY, O_RDWR);
6483 if (fd < 0) {
6484 fd += 3;
6485 while (!isatty(fd) && --fd >= 0)
6486 ;
6487 }
6488 fd = fcntl(fd, F_DUPFD, 10);
6489 close(ofd);
6490 if (fd < 0)
6491 goto out;
6492 fcntl(fd, F_SETFD, FD_CLOEXEC);
6493 do { /* while we are in the background */
6494 if ((pgrp = tcgetpgrp(fd)) < 0) {
6495out:
6496 sh_warnx("can't access tty; job control turned off");
6497 mflag = on = 0;
6498 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006499 }
Eric Andersenc470f442003-07-28 09:56:35 +00006500 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006501 break;
6502 killpg(0, SIGTTIN);
6503 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006504 initialpgrp = pgrp;
6505
Eric Andersencb57d552001-06-28 07:25:16 +00006506 setsignal(SIGTSTP);
6507 setsignal(SIGTTOU);
6508 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006509 pgrp = rootpid;
6510 setpgid(0, pgrp);
6511 xtcsetpgrp(fd, pgrp);
6512 } else {
6513 /* turning job control off */
6514 fd = ttyfd;
6515 pgrp = initialpgrp;
6516 xtcsetpgrp(fd, pgrp);
6517 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006518 setsignal(SIGTSTP);
6519 setsignal(SIGTTOU);
6520 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006521close:
6522 close(fd);
6523 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006524 }
Eric Andersenc470f442003-07-28 09:56:35 +00006525 ttyfd = fd;
6526 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006527}
Eric Andersencb57d552001-06-28 07:25:16 +00006528
Eric Andersenc470f442003-07-28 09:56:35 +00006529static int
Eric Andersen90898442003-08-06 11:20:52 +00006530killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006531{
6532 int signo = -1;
6533 int list = 0;
6534 int i;
6535 pid_t pid;
6536 struct job *jp;
6537
6538 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006539usage:
6540 error(
6541"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6542"kill -l [exitstatus]"
6543 );
Eric Andersencb57d552001-06-28 07:25:16 +00006544 }
6545
Eric Andersenc470f442003-07-28 09:56:35 +00006546 if (**++argv == '-') {
6547 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006548 if (signo < 0) {
6549 int c;
6550
6551 while ((c = nextopt("ls:")) != '\0')
6552 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006553 default:
6554#ifdef DEBUG
6555 abort();
6556#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006557 case 'l':
6558 list = 1;
6559 break;
6560 case 's':
6561 signo = decode_signal(optionarg, 1);
6562 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006563 error(
6564 "invalid signal number or name: %s",
6565 optionarg
6566 );
Eric Andersencb57d552001-06-28 07:25:16 +00006567 }
Eric Andersen2870d962001-07-02 17:27:21 +00006568 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006569 }
Eric Andersenc470f442003-07-28 09:56:35 +00006570 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006571 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006572 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006573 }
6574
6575 if (!list && signo < 0)
6576 signo = SIGTERM;
6577
Eric Andersenc470f442003-07-28 09:56:35 +00006578 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006579 goto usage;
6580 }
6581
6582 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006583 const char *name;
6584
Eric Andersenc470f442003-07-28 09:56:35 +00006585 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006586 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006587 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006588 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006589 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006590 }
6591 return 0;
6592 }
Eric Andersen34506362001-08-02 05:02:46 +00006593 name = u_signal_names(*argptr, &signo, -1);
6594 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006595 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006596 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006597 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006598 return 0;
6599 }
6600
Eric Andersenc470f442003-07-28 09:56:35 +00006601 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006602 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006603 if (**argv == '%') {
6604 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006605 pid = -jp->ps[0].pid;
6606 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006607 pid = number(*argv);
6608 if (kill(pid, signo) != 0) {
Rob Landley23246f32005-08-14 19:16:51 +00006609 sh_warnx("kill %d: %s", pid, errmsg(errno, NULL));
Eric Andersenc470f442003-07-28 09:56:35 +00006610 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006611 }
Eric Andersenc470f442003-07-28 09:56:35 +00006612 } while (*++argv);
6613
6614 return i;
6615}
6616#endif /* JOBS */
6617
6618#if defined(JOBS) || defined(DEBUG)
6619static int
6620jobno(const struct job *jp)
6621{
6622 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006623}
6624#endif
6625
Eric Andersenc470f442003-07-28 09:56:35 +00006626#ifdef JOBS
6627static int
6628fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006629{
Eric Andersenc470f442003-07-28 09:56:35 +00006630 struct job *jp;
6631 FILE *out;
6632 int mode;
6633 int retval;
6634
6635 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6636 nextopt(nullstr);
6637 argv = argptr;
6638 out = stdout;
6639 do {
6640 jp = getjob(*argv, 1);
6641 if (mode == FORK_BG) {
6642 set_curjob(jp, CUR_RUNNING);
6643 fprintf(out, "[%d] ", jobno(jp));
6644 }
6645 outstr(jp->ps->cmd, out);
6646 showpipe(jp, out);
6647 retval = restartjob(jp, mode);
6648 } while (*argv && *++argv);
6649 return retval;
6650}
6651
6652static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6653
6654
6655static int
6656restartjob(struct job *jp, int mode)
6657{
6658 struct procstat *ps;
6659 int i;
6660 int status;
6661 pid_t pgid;
6662
6663 INTOFF;
6664 if (jp->state == JOBDONE)
6665 goto out;
6666 jp->state = JOBRUNNING;
6667 pgid = jp->ps->pid;
6668 if (mode == FORK_FG)
6669 xtcsetpgrp(ttyfd, pgid);
6670 killpg(pgid, SIGCONT);
6671 ps = jp->ps;
6672 i = jp->nprocs;
6673 do {
6674 if (WIFSTOPPED(ps->status)) {
6675 ps->status = -1;
6676 }
6677 } while (ps++, --i);
6678out:
6679 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6680 INTON;
6681 return status;
6682}
6683#endif
6684
6685static int
6686sprint_status(char *s, int status, int sigonly)
6687{
6688 int col;
6689 int st;
6690
6691 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006692 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006693#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006694 if (WIFSTOPPED(status))
6695 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006696 else
Eric Andersenc470f442003-07-28 09:56:35 +00006697#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006698 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006699 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006700 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006701 goto out;
6702#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006703 if (WIFSTOPPED(status))
6704 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006705#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006706 }
6707 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006708 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006709 if (WCOREDUMP(status)) {
6710 col += fmtstr(s + col, 16, " (core dumped)");
6711 }
6712 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006713 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006714 if (st)
6715 col = fmtstr(s, 16, "Done(%d)", st);
6716 else
6717 col = fmtstr(s, 16, "Done");
6718 }
6719
6720out:
6721 return col;
6722}
6723
6724#if JOBS
6725static void
6726showjob(FILE *out, struct job *jp, int mode)
6727{
6728 struct procstat *ps;
6729 struct procstat *psend;
6730 int col;
6731 int indent;
6732 char s[80];
6733
6734 ps = jp->ps;
6735
6736 if (mode & SHOW_PGID) {
6737 /* just output process (group) id of pipeline */
6738 fprintf(out, "%d\n", ps->pid);
6739 return;
6740 }
6741
6742 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6743 indent = col;
6744
6745 if (jp == curjob)
6746 s[col - 2] = '+';
6747 else if (curjob && jp == curjob->prev_job)
6748 s[col - 2] = '-';
6749
6750 if (mode & SHOW_PID)
6751 col += fmtstr(s + col, 16, "%d ", ps->pid);
6752
6753 psend = ps + jp->nprocs;
6754
6755 if (jp->state == JOBRUNNING) {
6756 scopy("Running", s + col);
6757 col += strlen("Running");
6758 } else {
6759 int status = psend[-1].status;
6760#if JOBS
6761 if (jp->state == JOBSTOPPED)
6762 status = jp->stopstatus;
6763#endif
6764 col += sprint_status(s + col, status, 0);
6765 }
6766
6767 goto start;
6768
6769 do {
6770 /* for each process */
6771 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6772
6773start:
Eric Andersen90898442003-08-06 11:20:52 +00006774 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006775 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6776 );
6777 if (!(mode & SHOW_PID)) {
6778 showpipe(jp, out);
6779 break;
6780 }
6781 if (++ps == psend) {
6782 outcslow('\n', out);
6783 break;
6784 }
6785 } while (1);
6786
6787 jp->changed = 0;
6788
6789 if (jp->state == JOBDONE) {
6790 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6791 freejob(jp);
6792 }
6793}
6794
6795
6796static int
6797jobscmd(int argc, char **argv)
6798{
6799 int mode, m;
6800 FILE *out;
6801
6802 mode = 0;
6803 while ((m = nextopt("lp")))
6804 if (m == 'l')
6805 mode = SHOW_PID;
6806 else
6807 mode = SHOW_PGID;
6808
6809 out = stdout;
6810 argv = argptr;
6811 if (*argv)
6812 do
6813 showjob(out, getjob(*argv,0), mode);
6814 while (*++argv);
6815 else
6816 showjobs(out, mode);
6817
Eric Andersencb57d552001-06-28 07:25:16 +00006818 return 0;
6819}
6820
6821
6822/*
6823 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6824 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006825 */
6826
Eric Andersenc470f442003-07-28 09:56:35 +00006827static void
6828showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006829{
Eric Andersencb57d552001-06-28 07:25:16 +00006830 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006831
Eric Andersenc470f442003-07-28 09:56:35 +00006832 TRACE(("showjobs(%x) called\n", mode));
6833
6834 /* If not even one one job changed, there is nothing to do */
6835 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6836 continue;
6837
6838 for (jp = curjob; jp; jp = jp->prev_job) {
6839 if (!(mode & SHOW_CHANGED) || jp->changed)
6840 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006841 }
6842}
Eric Andersenc470f442003-07-28 09:56:35 +00006843#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006844
6845/*
6846 * Mark a job structure as unused.
6847 */
6848
Eric Andersenc470f442003-07-28 09:56:35 +00006849static void
6850freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006851{
Eric Andersenc470f442003-07-28 09:56:35 +00006852 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006853 int i;
6854
6855 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006856 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006857 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006858 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006859 }
6860 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006861 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006862 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006863 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006864 INTON;
6865}
6866
6867
Eric Andersenc470f442003-07-28 09:56:35 +00006868static int
6869waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006870{
6871 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006872 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006873 struct job *jp;
6874
Eric Andersenc470f442003-07-28 09:56:35 +00006875 EXSIGON();
6876
6877 nextopt(nullstr);
6878 retval = 0;
6879
6880 argv = argptr;
6881 if (!*argv) {
6882 /* wait for all jobs */
6883 for (;;) {
6884 jp = curjob;
6885 while (1) {
6886 if (!jp) {
6887 /* no running procs */
6888 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006889 }
Eric Andersenc470f442003-07-28 09:56:35 +00006890 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006891 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006892 jp->waited = 1;
6893 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006894 }
Eric Andersenc470f442003-07-28 09:56:35 +00006895 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006896 }
6897 }
Eric Andersenc470f442003-07-28 09:56:35 +00006898
6899 retval = 127;
6900 do {
6901 if (**argv != '%') {
6902 pid_t pid = number(*argv);
6903 job = curjob;
6904 goto start;
6905 do {
6906 if (job->ps[job->nprocs - 1].pid == pid)
6907 break;
6908 job = job->prev_job;
6909start:
6910 if (!job)
6911 goto repeat;
6912 } while (1);
6913 } else
6914 job = getjob(*argv, 0);
6915 /* loop until process terminated or stopped */
6916 while (job->state == JOBRUNNING)
6917 dowait(DOWAIT_BLOCK, 0);
6918 job->waited = 1;
6919 retval = getstatus(job);
6920repeat:
6921 ;
6922 } while (*++argv);
6923
6924out:
6925 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006926}
6927
6928
Eric Andersencb57d552001-06-28 07:25:16 +00006929/*
6930 * Convert a job name to a job structure.
6931 */
6932
Eric Andersenc470f442003-07-28 09:56:35 +00006933static struct job *
6934getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006935{
Eric Andersencb57d552001-06-28 07:25:16 +00006936 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006937 struct job *found;
6938 const char *err_msg = "No such job: %s";
6939 unsigned num;
6940 int c;
6941 const char *p;
6942 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006943
Eric Andersenc470f442003-07-28 09:56:35 +00006944 jp = curjob;
6945 p = name;
6946 if (!p)
6947 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006948
Eric Andersenc470f442003-07-28 09:56:35 +00006949 if (*p != '%')
6950 goto err;
6951
6952 c = *++p;
6953 if (!c)
6954 goto currentjob;
6955
6956 if (!p[1]) {
6957 if (c == '+' || c == '%') {
6958currentjob:
6959 err_msg = "No current job";
6960 goto check;
6961 } else if (c == '-') {
6962 if (jp)
6963 jp = jp->prev_job;
6964 err_msg = "No previous job";
6965check:
6966 if (!jp)
6967 goto err;
6968 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006969 }
6970 }
Eric Andersenc470f442003-07-28 09:56:35 +00006971
6972 if (is_number(p)) {
6973 num = atoi(p);
6974 if (num < njobs) {
6975 jp = jobtab + num - 1;
6976 if (jp->used)
6977 goto gotit;
6978 goto err;
6979 }
6980 }
6981
6982 match = prefix;
6983 if (*p == '?') {
6984 match = strstr;
6985 p++;
6986 }
6987
6988 found = 0;
6989 while (1) {
6990 if (!jp)
6991 goto err;
6992 if (match(jp->ps[0].cmd, p)) {
6993 if (found)
6994 goto err;
6995 found = jp;
6996 err_msg = "%s: ambiguous";
6997 }
6998 jp = jp->prev_job;
6999 }
7000
7001gotit:
7002#if JOBS
7003 err_msg = "job %s not created under job control";
7004 if (getctl && jp->jobctl == 0)
7005 goto err;
7006#endif
7007 return jp;
7008err:
7009 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007010}
7011
7012
Eric Andersencb57d552001-06-28 07:25:16 +00007013/*
Eric Andersenc470f442003-07-28 09:56:35 +00007014 * Return a new job structure.
7015 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007016 */
7017
Eric Andersenc470f442003-07-28 09:56:35 +00007018static struct job *
7019makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007020{
7021 int i;
7022 struct job *jp;
7023
Eric Andersenc470f442003-07-28 09:56:35 +00007024 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007025 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007026 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007027 break;
7028 }
7029 if (jp->used == 0)
7030 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007031 if (jp->state != JOBDONE || !jp->waited)
7032 continue;
7033#if JOBS
7034 if (jobctl)
7035 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007036#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007037 freejob(jp);
7038 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007039 }
Eric Andersenc470f442003-07-28 09:56:35 +00007040 memset(jp, 0, sizeof(*jp));
7041#if JOBS
7042 if (jobctl)
7043 jp->jobctl = 1;
7044#endif
7045 jp->prev_job = curjob;
7046 curjob = jp;
7047 jp->used = 1;
7048 jp->ps = &jp->ps0;
7049 if (nprocs > 1) {
7050 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7051 }
7052 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7053 jobno(jp)));
7054 return jp;
7055}
7056
7057static struct job *
7058growjobtab(void)
7059{
7060 size_t len;
7061 ptrdiff_t offset;
7062 struct job *jp, *jq;
7063
7064 len = njobs * sizeof(*jp);
7065 jq = jobtab;
7066 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7067
7068 offset = (char *)jp - (char *)jq;
7069 if (offset) {
7070 /* Relocate pointers */
7071 size_t l = len;
7072
7073 jq = (struct job *)((char *)jq + l);
7074 while (l) {
7075 l -= sizeof(*jp);
7076 jq--;
7077#define joff(p) ((struct job *)((char *)(p) + l))
7078#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007079 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007080 jmove(joff(jp)->ps);
7081 if (joff(jp)->prev_job)
7082 jmove(joff(jp)->prev_job);
7083 }
7084 if (curjob)
7085 jmove(curjob);
7086#undef joff
7087#undef jmove
7088 }
7089
7090 njobs += 4;
7091 jobtab = jp;
7092 jp = (struct job *)((char *)jp + len);
7093 jq = jp + 3;
7094 do {
7095 jq->used = 0;
7096 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007097 return jp;
7098}
7099
7100
7101/*
Eric Andersenc470f442003-07-28 09:56:35 +00007102 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007103 * own process group. Jp is a job structure that the job is to be added to.
7104 * N is the command that will be evaluated by the child. Both jp and n may
7105 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007106 * FORK_FG - Fork off a foreground process.
7107 * FORK_BG - Fork off a background process.
7108 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7109 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007110 *
7111 * When job control is turned off, background processes have their standard
7112 * input redirected to /dev/null (except for the second and later processes
7113 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007114 *
7115 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007116 */
7117
Eric Andersenc470f442003-07-28 09:56:35 +00007118static inline void
7119forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007120{
Eric Andersenc470f442003-07-28 09:56:35 +00007121 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007122
Eric Andersenc470f442003-07-28 09:56:35 +00007123 TRACE(("Child shell %d\n", getpid()));
7124 wasroot = rootshell;
7125 rootshell = 0;
7126
7127 closescript();
7128 clear_traps();
7129#if JOBS
7130 /* do job control only in root shell */
7131 jobctl = 0;
7132 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7133 pid_t pgrp;
7134
7135 if (jp->nprocs == 0)
7136 pgrp = getpid();
7137 else
7138 pgrp = jp->ps[0].pid;
7139 /* This can fail because we are doing it in the parent also */
7140 (void)setpgid(0, pgrp);
7141 if (mode == FORK_FG)
7142 xtcsetpgrp(ttyfd, pgrp);
7143 setsignal(SIGTSTP);
7144 setsignal(SIGTTOU);
7145 } else
Eric Andersen62483552001-07-10 06:09:16 +00007146#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007147 if (mode == FORK_BG) {
7148 ignoresig(SIGINT);
7149 ignoresig(SIGQUIT);
7150 if (jp->nprocs == 0) {
7151 close(0);
7152 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7153 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007154 }
Eric Andersencb57d552001-06-28 07:25:16 +00007155 }
Eric Andersenc470f442003-07-28 09:56:35 +00007156 if (wasroot && iflag) {
7157 setsignal(SIGINT);
7158 setsignal(SIGQUIT);
7159 setsignal(SIGTERM);
7160 }
7161 for (jp = curjob; jp; jp = jp->prev_job)
7162 freejob(jp);
7163 jobless = 0;
7164}
7165
7166static inline void
7167forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7168{
7169 TRACE(("In parent shell: child = %d\n", pid));
7170 if (!jp) {
7171 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7172 jobless++;
7173 return;
7174 }
7175#if JOBS
7176 if (mode != FORK_NOJOB && jp->jobctl) {
7177 int pgrp;
7178
7179 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007180 pgrp = pid;
7181 else
7182 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007183 /* This can fail because we are doing it in the child also */
7184 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007185 }
Eric Andersen62483552001-07-10 06:09:16 +00007186#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007187 if (mode == FORK_BG) {
7188 backgndpid = pid; /* set $! */
7189 set_curjob(jp, CUR_RUNNING);
7190 }
Eric Andersencb57d552001-06-28 07:25:16 +00007191 if (jp) {
7192 struct procstat *ps = &jp->ps[jp->nprocs++];
7193 ps->pid = pid;
7194 ps->status = -1;
7195 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007196#if JOBS
7197 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007198 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007199#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007200 }
Eric Andersencb57d552001-06-28 07:25:16 +00007201}
7202
Eric Andersenc470f442003-07-28 09:56:35 +00007203static int
7204forkshell(struct job *jp, union node *n, int mode)
7205{
7206 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007207
Eric Andersenc470f442003-07-28 09:56:35 +00007208 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7209 pid = fork();
7210 if (pid < 0) {
7211 TRACE(("Fork failed, errno=%d", errno));
7212 if (jp)
7213 freejob(jp);
7214 error("Cannot fork");
7215 }
7216 if (pid == 0)
7217 forkchild(jp, n, mode);
7218 else
7219 forkparent(jp, n, mode, pid);
7220 return pid;
7221}
Eric Andersencb57d552001-06-28 07:25:16 +00007222
7223/*
7224 * Wait for job to finish.
7225 *
7226 * Under job control we have the problem that while a child process is
7227 * running interrupts generated by the user are sent to the child but not
7228 * to the shell. This means that an infinite loop started by an inter-
7229 * active user may be hard to kill. With job control turned off, an
7230 * interactive user may place an interactive program inside a loop. If
7231 * the interactive program catches interrupts, the user doesn't want
7232 * these interrupts to also abort the loop. The approach we take here
7233 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007234 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007235 * signal if the child process was terminated by an interrupt signal.
7236 * Unfortunately, some programs want to do a bit of cleanup and then
7237 * exit on interrupt; unless these processes terminate themselves by
7238 * sending a signal to themselves (instead of calling exit) they will
7239 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007240 *
7241 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007242 */
7243
Eric Andersenc470f442003-07-28 09:56:35 +00007244int
7245waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007246{
Eric Andersencb57d552001-06-28 07:25:16 +00007247 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007248
Eric Andersenc470f442003-07-28 09:56:35 +00007249 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7250 while (jp->state == JOBRUNNING) {
7251 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007252 }
Eric Andersenc470f442003-07-28 09:56:35 +00007253 st = getstatus(jp);
7254#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007255 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007256 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007257 /*
7258 * This is truly gross.
7259 * If we're doing job control, then we did a TIOCSPGRP which
7260 * caused us (the shell) to no longer be in the controlling
7261 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7262 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007263 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007264 */
Eric Andersenc470f442003-07-28 09:56:35 +00007265 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007266 raise(SIGINT);
7267 }
Eric Andersen2870d962001-07-02 17:27:21 +00007268 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007269#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007270 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007271 return st;
7272}
7273
7274
Eric Andersen62483552001-07-10 06:09:16 +00007275/*
7276 * Do a wait system call. If job control is compiled in, we accept
7277 * stopped processes. If block is zero, we return a value of zero
7278 * rather than blocking.
7279 *
7280 * System V doesn't have a non-blocking wait system call. It does
7281 * have a SIGCLD signal that is sent to a process when one of it's
7282 * children dies. The obvious way to use SIGCLD would be to install
7283 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7284 * was received, and have waitproc bump another counter when it got
7285 * the status of a process. Waitproc would then know that a wait
7286 * system call would not block if the two counters were different.
7287 * This approach doesn't work because if a process has children that
7288 * have not been waited for, System V will send it a SIGCLD when it
7289 * installs a signal handler for SIGCLD. What this means is that when
7290 * a child exits, the shell will be sent SIGCLD signals continuously
7291 * until is runs out of stack space, unless it does a wait call before
7292 * restoring the signal handler. The code below takes advantage of
7293 * this (mis)feature by installing a signal handler for SIGCLD and
7294 * then checking to see whether it was called. If there are any
7295 * children to be waited for, it will be.
7296 *
Eric Andersenc470f442003-07-28 09:56:35 +00007297 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7298 * waits at all. In this case, the user will not be informed when
7299 * a background process until the next time she runs a real program
7300 * (as opposed to running a builtin command or just typing return),
7301 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007302 */
7303
Eric Andersenc470f442003-07-28 09:56:35 +00007304static inline int
7305waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007306{
Eric Andersenc470f442003-07-28 09:56:35 +00007307 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007308
Eric Andersenc470f442003-07-28 09:56:35 +00007309#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007310 if (jobctl)
7311 flags |= WUNTRACED;
7312#endif
7313 if (block == 0)
7314 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007315 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007316}
7317
Eric Andersenc470f442003-07-28 09:56:35 +00007318/*
7319 * Wait for a process to terminate.
7320 */
7321
7322static int
7323dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007324{
7325 int pid;
7326 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007327 struct job *jp;
7328 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007329 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007330
7331 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007332 pid = waitproc(block, &status);
7333 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007334 if (pid <= 0)
7335 return pid;
7336 INTOFF;
7337 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007338 for (jp = curjob; jp; jp = jp->prev_job) {
7339 struct procstat *sp;
7340 struct procstat *spend;
7341 if (jp->state == JOBDONE)
7342 continue;
7343 state = JOBDONE;
7344 spend = jp->ps + jp->nprocs;
7345 sp = jp->ps;
7346 do {
7347 if (sp->pid == pid) {
7348 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7349 sp->status = status;
7350 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007351 }
Eric Andersenc470f442003-07-28 09:56:35 +00007352 if (sp->status == -1)
7353 state = JOBRUNNING;
7354#ifdef JOBS
7355 if (state == JOBRUNNING)
7356 continue;
7357 if (WIFSTOPPED(sp->status)) {
7358 jp->stopstatus = sp->status;
7359 state = JOBSTOPPED;
7360 }
Eric Andersencb57d552001-06-28 07:25:16 +00007361#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007362 } while (++sp < spend);
7363 if (thisjob)
7364 goto gotjob;
7365 }
7366#ifdef JOBS
7367 if (!WIFSTOPPED(status))
7368#endif
7369
7370 jobless--;
7371 goto out;
7372
7373gotjob:
7374 if (state != JOBRUNNING) {
7375 thisjob->changed = 1;
7376
7377 if (thisjob->state != state) {
7378 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7379 thisjob->state = state;
7380#ifdef JOBS
7381 if (state == JOBSTOPPED) {
7382 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007383 }
Eric Andersenc470f442003-07-28 09:56:35 +00007384#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007385 }
7386 }
Eric Andersencb57d552001-06-28 07:25:16 +00007387
Eric Andersenc470f442003-07-28 09:56:35 +00007388out:
7389 INTON;
7390
7391 if (thisjob && thisjob == job) {
7392 char s[48 + 1];
7393 int len;
7394
7395 len = sprint_status(s, status, 1);
7396 if (len) {
7397 s[len] = '\n';
7398 s[len + 1] = 0;
7399 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007400 }
Eric Andersencb57d552001-06-28 07:25:16 +00007401 }
7402 return pid;
7403}
7404
7405
Eric Andersencb57d552001-06-28 07:25:16 +00007406/*
7407 * return 1 if there are stopped jobs, otherwise 0
7408 */
Eric Andersen90898442003-08-06 11:20:52 +00007409
Eric Andersenc470f442003-07-28 09:56:35 +00007410int
7411stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007412{
Eric Andersencb57d552001-06-28 07:25:16 +00007413 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007414 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007415
Eric Andersenc470f442003-07-28 09:56:35 +00007416 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007417 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007418 goto out;
7419 jp = curjob;
7420 if (jp && jp->state == JOBSTOPPED) {
7421 out2str("You have stopped jobs.\n");
7422 job_warning = 2;
7423 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007424 }
7425
Eric Andersenc470f442003-07-28 09:56:35 +00007426out:
7427 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007428}
7429
7430/*
7431 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007432 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007433 */
7434
Eric Andersenc470f442003-07-28 09:56:35 +00007435#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007436static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007437
Eric Andersenc470f442003-07-28 09:56:35 +00007438static char *
7439commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007440{
Eric Andersenc470f442003-07-28 09:56:35 +00007441 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007442
Eric Andersenc470f442003-07-28 09:56:35 +00007443 STARTSTACKSTR(cmdnextc);
7444 cmdtxt(n);
7445 name = stackblock();
7446 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7447 name, cmdnextc, cmdnextc));
7448 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007449}
7450
Eric Andersenc470f442003-07-28 09:56:35 +00007451static void
7452cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007453{
Eric Andersencb57d552001-06-28 07:25:16 +00007454 union node *np;
7455 struct nodelist *lp;
7456 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007457 char s[2];
7458
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007459 if (!n)
7460 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007461 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007462 default:
7463#if DEBUG
7464 abort();
7465#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007466 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007467 lp = n->npipe.cmdlist;
7468 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007469 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007470 lp = lp->next;
7471 if (!lp)
7472 break;
7473 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007474 }
7475 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007476 case NSEMI:
7477 p = "; ";
7478 goto binop;
7479 case NAND:
7480 p = " && ";
7481 goto binop;
7482 case NOR:
7483 p = " || ";
7484binop:
7485 cmdtxt(n->nbinary.ch1);
7486 cmdputs(p);
7487 n = n->nbinary.ch2;
7488 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007489 case NREDIR:
7490 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007491 n = n->nredir.n;
7492 goto donode;
7493 case NNOT:
7494 cmdputs("!");
7495 n = n->nnot.com;
7496donode:
7497 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007498 break;
7499 case NIF:
7500 cmdputs("if ");
7501 cmdtxt(n->nif.test);
7502 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007503 n = n->nif.ifpart;
7504 if (n->nif.elsepart) {
7505 cmdtxt(n);
7506 cmdputs("; else ");
7507 n = n->nif.elsepart;
7508 }
7509 p = "; fi";
7510 goto dotail;
7511 case NSUBSHELL:
7512 cmdputs("(");
7513 n = n->nredir.n;
7514 p = ")";
7515 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007516 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007517 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007518 goto until;
7519 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007520 p = "until ";
7521until:
7522 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007523 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007524 n = n->nbinary.ch2;
7525 p = "; done";
7526dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007527 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007528dotail:
7529 cmdtxt(n);
7530 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007531 case NFOR:
7532 cmdputs("for ");
7533 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007534 cmdputs(" in ");
7535 cmdlist(n->nfor.args, 1);
7536 n = n->nfor.body;
7537 p = "; done";
7538 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007539 case NDEFUN:
7540 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007541 p = "() { ... }";
7542 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007543 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007544 cmdlist(n->ncmd.args, 1);
7545 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007546 break;
7547 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007548 p = n->narg.text;
7549dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007550 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007551 break;
7552 case NHERE:
7553 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007554 p = "<<...";
7555 goto dotail2;
7556 case NCASE:
7557 cmdputs("case ");
7558 cmdputs(n->ncase.expr->narg.text);
7559 cmdputs(" in ");
7560 for (np = n->ncase.cases; np; np = np->nclist.next) {
7561 cmdtxt(np->nclist.pattern);
7562 cmdputs(") ");
7563 cmdtxt(np->nclist.body);
7564 cmdputs(";; ");
7565 }
7566 p = "esac";
7567 goto dotail2;
7568 case NTO:
7569 p = ">";
7570 goto redir;
7571 case NCLOBBER:
7572 p = ">|";
7573 goto redir;
7574 case NAPPEND:
7575 p = ">>";
7576 goto redir;
7577 case NTOFD:
7578 p = ">&";
7579 goto redir;
7580 case NFROM:
7581 p = "<";
7582 goto redir;
7583 case NFROMFD:
7584 p = "<&";
7585 goto redir;
7586 case NFROMTO:
7587 p = "<>";
7588redir:
7589 s[0] = n->nfile.fd + '0';
7590 s[1] = '\0';
7591 cmdputs(s);
7592 cmdputs(p);
7593 if (n->type == NTOFD || n->type == NFROMFD) {
7594 s[0] = n->ndup.dupfd + '0';
7595 p = s;
7596 goto dotail2;
7597 } else {
7598 n = n->nfile.fname;
7599 goto donode;
7600 }
Eric Andersencb57d552001-06-28 07:25:16 +00007601 }
7602}
Eric Andersencb57d552001-06-28 07:25:16 +00007603
Eric Andersenc470f442003-07-28 09:56:35 +00007604static void
7605cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007606{
Eric Andersenc470f442003-07-28 09:56:35 +00007607 for (; np; np = np->narg.next) {
7608 if (!sep)
7609 cmdputs(spcstr);
7610 cmdtxt(np);
7611 if (sep && np->narg.next)
7612 cmdputs(spcstr);
7613 }
Eric Andersencb57d552001-06-28 07:25:16 +00007614}
7615
Eric Andersenc470f442003-07-28 09:56:35 +00007616static void
7617cmdputs(const char *s)
7618{
7619 const char *p, *str;
7620 char c, cc[2] = " ";
7621 char *nextc;
7622 int subtype = 0;
7623 int quoted = 0;
7624 static const char *const vstype[16] = {
7625 nullstr, "}", "-", "+", "?", "=",
Eric Andersenc7bda1c2004-03-15 08:29:22 +00007626 "%", "%%", "#", "##", nullstr
Eric Andersenc470f442003-07-28 09:56:35 +00007627 };
7628
7629 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7630 p = s;
7631 while ((c = *p++) != 0) {
7632 str = 0;
7633 switch (c) {
7634 case CTLESC:
7635 c = *p++;
7636 break;
7637 case CTLVAR:
7638 subtype = *p++;
7639 if ((subtype & VSTYPE) == VSLENGTH)
7640 str = "${#";
7641 else
7642 str = "${";
7643 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7644 quoted ^= 1;
7645 c = '"';
7646 } else
7647 goto dostr;
7648 break;
7649 case CTLENDVAR:
7650 quoted >>= 1;
7651 subtype = 0;
7652 if (quoted & 1) {
7653 str = "\"}";
7654 goto dostr;
7655 }
7656 c = '}';
7657 break;
7658 case CTLBACKQ:
7659 str = "$(...)";
7660 goto dostr;
7661 case CTLBACKQ+CTLQUOTE:
7662 str = "\"$(...)\"";
7663 goto dostr;
7664#ifdef CONFIG_ASH_MATH_SUPPORT
7665 case CTLARI:
7666 str = "$((";
7667 goto dostr;
7668 case CTLENDARI:
7669 str = "))";
7670 goto dostr;
7671#endif
7672 case CTLQUOTEMARK:
7673 quoted ^= 1;
7674 c = '"';
7675 break;
7676 case '=':
7677 if (subtype == 0)
7678 break;
7679 str = vstype[subtype & VSTYPE];
7680 if (subtype & VSNUL)
7681 c = ':';
7682 else
7683 c = *str++;
7684 if (c != '}')
7685 quoted <<= 1;
7686 break;
7687 case '\'':
7688 case '\\':
7689 case '"':
7690 case '$':
7691 /* These can only happen inside quotes */
7692 cc[0] = c;
7693 str = cc;
7694 c = '\\';
7695 break;
7696 default:
7697 break;
7698 }
7699 USTPUTC(c, nextc);
7700 if (!str)
7701 continue;
7702dostr:
7703 while ((c = *str++)) {
7704 USTPUTC(c, nextc);
7705 }
7706 }
7707 if (quoted & 1) {
7708 USTPUTC('"', nextc);
7709 }
7710 *nextc = 0;
7711 cmdnextc = nextc;
7712}
7713
7714
7715static void
7716showpipe(struct job *jp, FILE *out)
7717{
7718 struct procstat *sp;
7719 struct procstat *spend;
7720
7721 spend = jp->ps + jp->nprocs;
7722 for (sp = jp->ps + 1; sp < spend; sp++)
7723 fprintf(out, " | %s", sp->cmd);
7724 outcslow('\n', out);
7725 flushall();
7726}
7727
7728static void
7729xtcsetpgrp(int fd, pid_t pgrp)
7730{
7731 if (tcsetpgrp(fd, pgrp))
7732 error("Cannot set tty process group (%m)");
7733}
7734#endif /* JOBS */
7735
7736static int
7737getstatus(struct job *job) {
7738 int status;
7739 int retval;
7740
7741 status = job->ps[job->nprocs - 1].status;
7742 retval = WEXITSTATUS(status);
7743 if (!WIFEXITED(status)) {
7744#if JOBS
7745 retval = WSTOPSIG(status);
7746 if (!WIFSTOPPED(status))
7747#endif
7748 {
7749 /* XXX: limits number of signals */
7750 retval = WTERMSIG(status);
7751#if JOBS
7752 if (retval == SIGINT)
7753 job->sigint = 1;
7754#endif
7755 }
7756 retval += 128;
7757 }
7758 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7759 jobno(job), job->nprocs, status, retval));
7760 return retval;
7761}
7762
Eric Andersend35c5df2002-01-09 15:37:36 +00007763#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007764/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007765
Eric Andersencb57d552001-06-28 07:25:16 +00007766/*
Eric Andersenc470f442003-07-28 09:56:35 +00007767 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007768 */
7769
Eric Andersencb57d552001-06-28 07:25:16 +00007770#define MAXMBOXES 10
7771
Eric Andersenc470f442003-07-28 09:56:35 +00007772/* times of mailboxes */
7773static time_t mailtime[MAXMBOXES];
7774/* Set if MAIL or MAILPATH is changed. */
7775static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007776
7777
7778
7779/*
Eric Andersenc470f442003-07-28 09:56:35 +00007780 * Print appropriate message(s) if mail has arrived.
7781 * If mail_var_path_changed is set,
7782 * then the value of MAIL has mail_var_path_changed,
7783 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007784 */
7785
Eric Andersenc470f442003-07-28 09:56:35 +00007786static void
7787chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007788{
Eric Andersencb57d552001-06-28 07:25:16 +00007789 const char *mpath;
7790 char *p;
7791 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007792 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007793 struct stackmark smark;
7794 struct stat statb;
7795
Eric Andersencb57d552001-06-28 07:25:16 +00007796 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007797 mpath = mpathset() ? mpathval() : mailval();
7798 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007799 p = padvance(&mpath, nullstr);
7800 if (p == NULL)
7801 break;
7802 if (*p == '\0')
7803 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007804 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007805#ifdef DEBUG
7806 if (q[-1] != '/')
7807 abort();
7808#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007809 q[-1] = '\0'; /* delete trailing '/' */
7810 if (stat(p, &statb) < 0) {
7811 *mtp = 0;
7812 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007813 }
Eric Andersenc470f442003-07-28 09:56:35 +00007814 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7815 fprintf(
7816 stderr, snlfmt,
7817 pathopt ? pathopt : "you have mail"
7818 );
7819 }
7820 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007821 }
Eric Andersenc470f442003-07-28 09:56:35 +00007822 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007823 popstackmark(&smark);
7824}
Eric Andersencb57d552001-06-28 07:25:16 +00007825
Eric Andersenec074692001-10-31 11:05:49 +00007826
Eric Andersenc470f442003-07-28 09:56:35 +00007827static void
7828changemail(const char *val)
7829{
7830 mail_var_path_changed++;
7831}
7832
7833#endif /* CONFIG_ASH_MAIL */
7834
7835/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7836
Eric Andersencb57d552001-06-28 07:25:16 +00007837
Eric Andersencb57d552001-06-28 07:25:16 +00007838#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007839static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007840extern int etext();
7841#endif
7842
Eric Andersenc470f442003-07-28 09:56:35 +00007843static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007844
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007845static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007846
Eric Andersencb57d552001-06-28 07:25:16 +00007847/*
7848 * Main routine. We initialize things, parse the arguments, execute
7849 * profiles if we're a login shell, and then call cmdloop to execute
7850 * commands. The setjmp call sets up the location to jump to when an
7851 * exception occurs. When an exception occurs the variable "state"
7852 * is used to figure out how far we had gotten.
7853 */
7854
Eric Andersenc470f442003-07-28 09:56:35 +00007855int
7856ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007857{
Eric Andersenc470f442003-07-28 09:56:35 +00007858 char *shinit;
7859 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007860 struct jmploc jmploc;
7861 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007862
Eric Andersenc470f442003-07-28 09:56:35 +00007863#ifdef __GLIBC__
7864 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007865#endif
7866
Eric Andersencb57d552001-06-28 07:25:16 +00007867#if PROFILE
7868 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7869#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007870 state = 0;
7871 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007872 int status;
7873 int e;
7874
Eric Andersencb57d552001-06-28 07:25:16 +00007875 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007876
7877 e = exception;
7878 switch (exception) {
7879 case EXEXEC:
7880 status = exerrno;
7881 break;
7882
7883 case EXERROR:
7884 status = 2;
7885 break;
7886
7887 default:
7888 status = exitstatus;
7889 break;
7890 }
7891 exitstatus = status;
7892
7893 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7894 exitshell();
7895
Eric Andersen90898442003-08-06 11:20:52 +00007896 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007897 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007898 }
7899 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007900 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007901 if (state == 1)
7902 goto state1;
7903 else if (state == 2)
7904 goto state2;
7905 else if (state == 3)
7906 goto state3;
7907 else
7908 goto state4;
7909 }
7910 handler = &jmploc;
7911#ifdef DEBUG
7912 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007913 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007914#endif
7915 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007916
7917#ifdef CONFIG_ASH_RANDOM_SUPPORT
7918 rseed = rootpid + ((time_t)time((time_t *)0));
7919#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007920 rootshell = 1;
7921 init();
7922 setstackmark(&smark);
7923 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007924#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7925 if ( iflag ) {
7926 const char *hp = lookupvar("HISTFILE");
7927
7928 if(hp == NULL ) {
7929 hp = lookupvar("HOME");
7930 if(hp != NULL) {
7931 char *defhp = concat_path_file(hp, ".ash_history");
7932 setvar("HISTFILE", defhp, 0);
7933 free(defhp);
7934 }
7935 }
7936 }
7937#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007938 if (argv[0] && argv[0][0] == '-')
7939 isloginsh = 1;
7940 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007941 state = 1;
7942 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007943state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007944 state = 2;
7945 read_profile(".profile");
7946 }
Eric Andersenc470f442003-07-28 09:56:35 +00007947state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007948 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007949 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007950#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007951 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007952#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007953 iflag
7954 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007955 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007956 read_profile(shinit);
7957 }
Eric Andersencb57d552001-06-28 07:25:16 +00007958 }
Eric Andersenc470f442003-07-28 09:56:35 +00007959state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007960 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007961 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007962 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007963
7964 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007965#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007966 if ( iflag ) {
7967 const char *hp = lookupvar("HISTFILE");
7968
7969 if(hp != NULL )
7970 load_history ( hp );
7971 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007972#endif
Eric Andersen90898442003-08-06 11:20:52 +00007973state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007974 cmdloop(1);
7975 }
7976#if PROFILE
7977 monitor(0);
7978#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007979#if GPROF
7980 {
7981 extern void _mcleanup(void);
7982 _mcleanup();
7983 }
7984#endif
7985 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007986 /* NOTREACHED */
7987}
7988
7989
7990/*
7991 * Read and execute commands. "Top" is nonzero for the top level command
7992 * loop; it turns on prompting if the shell is interactive.
7993 */
7994
Eric Andersenc470f442003-07-28 09:56:35 +00007995static void
7996cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007997{
7998 union node *n;
7999 struct stackmark smark;
8000 int inter;
8001 int numeof = 0;
8002
8003 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008004 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00008005 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00008006 if (pendingsigs)
8007 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00008008#if JOBS
8009 if (jobctl)
8010 showjobs(stderr, SHOW_CHANGED);
8011#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008012 inter = 0;
8013 if (iflag && top) {
8014 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008015#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008016 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008017#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008018 }
8019 n = parsecmd(inter);
8020 /* showtree(n); DEBUG */
8021 if (n == NEOF) {
8022 if (!top || numeof >= 50)
8023 break;
8024 if (!stoppedjobs()) {
8025 if (!Iflag)
8026 break;
8027 out2str("\nUse \"exit\" to leave shell.\n");
8028 }
8029 numeof++;
8030 } else if (n != NULL && nflag == 0) {
8031 job_warning = (job_warning == 2) ? 1 : 0;
8032 numeof = 0;
8033 evaltree(n, 0);
8034 }
8035 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008036 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008037 evalskip = 0;
8038 break;
8039 }
8040 }
Eric Andersencb57d552001-06-28 07:25:16 +00008041}
8042
8043
Eric Andersencb57d552001-06-28 07:25:16 +00008044/*
8045 * Read /etc/profile or .profile. Return on error.
8046 */
8047
Eric Andersenc470f442003-07-28 09:56:35 +00008048static void
8049read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008050{
8051 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008052 int xflag_set = 0;
8053 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008054
8055 INTOFF;
8056 if ((fd = open(name, O_RDONLY)) >= 0)
8057 setinputfd(fd, 1);
8058 INTON;
8059 if (fd < 0)
8060 return;
8061 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008062 if (qflag) {
8063 if (xflag)
8064 xflag = 0, xflag_set = 1;
8065 if (vflag)
8066 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008067 }
8068 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008069 if (qflag) {
8070 if (xflag_set)
8071 xflag = 1;
8072 if (vflag_set)
8073 vflag = 1;
8074 }
Eric Andersencb57d552001-06-28 07:25:16 +00008075 popfile();
8076}
8077
8078
Eric Andersencb57d552001-06-28 07:25:16 +00008079/*
8080 * Read a file containing shell functions.
8081 */
8082
Eric Andersenc470f442003-07-28 09:56:35 +00008083static void
8084readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008085{
8086 int fd;
8087
8088 INTOFF;
8089 if ((fd = open(name, O_RDONLY)) >= 0)
8090 setinputfd(fd, 1);
8091 else
8092 error("Can't open %s", name);
8093 INTON;
8094 cmdloop(0);
8095 popfile();
8096}
8097
8098
Eric Andersencb57d552001-06-28 07:25:16 +00008099/*
Eric Andersenc470f442003-07-28 09:56:35 +00008100 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008101 * search for the file, which is necessary to find sub-commands.
8102 */
8103
Eric Andersenc470f442003-07-28 09:56:35 +00008104static inline char *
8105find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008106{
8107 char *fullname;
8108 const char *path = pathval();
8109 struct stat statb;
8110
8111 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008112 if (strchr(name, '/'))
8113 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008114
Eric Andersenc470f442003-07-28 09:56:35 +00008115 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008116 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8117 /*
8118 * Don't bother freeing here, since it will
8119 * be freed by the caller.
8120 */
8121 return fullname;
8122 }
8123 stunalloc(fullname);
8124 }
8125
8126 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008127 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008128 /* NOTREACHED */
8129}
8130
Eric Andersen1e6aba92004-04-12 19:12:13 +00008131static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008132{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008133 struct strlist *sp;
8134 volatile struct shparam saveparam;
8135
Eric Andersencb57d552001-06-28 07:25:16 +00008136 exitstatus = 0;
8137
Eric Andersen1e6aba92004-04-12 19:12:13 +00008138 for (sp = cmdenviron; sp; sp = sp->next)
8139 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8140
8141 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008142 char *fullname;
8143 struct stackmark smark;
8144
8145 setstackmark(&smark);
8146 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008147
8148 if (argc > 2) {
8149 saveparam = shellparam;
8150 shellparam.malloc = 0;
8151 shellparam.nparam = argc - 2;
8152 shellparam.p = argv + 2;
8153 };
8154
Eric Andersencb57d552001-06-28 07:25:16 +00008155 setinputfile(fullname, 1);
8156 commandname = fullname;
8157 cmdloop(0);
8158 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008159
8160 if (argc > 2) {
8161 freeparam(&shellparam);
8162 shellparam = saveparam;
8163 };
8164
Eric Andersencb57d552001-06-28 07:25:16 +00008165 popstackmark(&smark);
8166 }
8167 return exitstatus;
8168}
8169
8170
Eric Andersenc470f442003-07-28 09:56:35 +00008171static int
8172exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008173{
8174 if (stoppedjobs())
8175 return 0;
8176 if (argc > 1)
8177 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008178 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008179 /* NOTREACHED */
8180}
Eric Andersen62483552001-07-10 06:09:16 +00008181
Paul Fox0b621582005-08-09 19:38:05 +00008182#ifdef CONFIG_ASH_BUILTIN_ECHO
8183static int
8184echocmd(int argc, char **argv)
8185{
8186 return bb_echo(argc, argv);
8187}
8188#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008189/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8190
8191/*
Eric Andersen90898442003-08-06 11:20:52 +00008192 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008193 */
8194
8195static pointer
8196ckrealloc(pointer p, size_t nbytes)
8197{
8198 p = realloc(p, nbytes);
8199 if (p == NULL)
8200 error(bb_msg_memory_exhausted);
8201 return p;
8202}
8203
Eric Andersen90898442003-08-06 11:20:52 +00008204static pointer
8205ckmalloc(size_t nbytes)
8206{
8207 return ckrealloc(NULL, nbytes);
8208}
Eric Andersenc470f442003-07-28 09:56:35 +00008209
8210/*
8211 * Make a copy of a string in safe storage.
8212 */
8213
8214static char *
8215savestr(const char *s)
8216{
8217 char *p = strdup(s);
8218 if (!p)
8219 error(bb_msg_memory_exhausted);
8220 return p;
8221}
8222
8223
8224/*
8225 * Parse trees for commands are allocated in lifo order, so we use a stack
8226 * to make this more efficient, and also to avoid all sorts of exception
8227 * handling code to handle interrupts in the middle of a parse.
8228 *
8229 * The size 504 was chosen because the Ultrix malloc handles that size
8230 * well.
8231 */
8232
8233
8234static pointer
8235stalloc(size_t nbytes)
8236{
8237 char *p;
8238 size_t aligned;
8239
8240 aligned = SHELL_ALIGN(nbytes);
8241 if (aligned > stacknleft) {
8242 size_t len;
8243 size_t blocksize;
8244 struct stack_block *sp;
8245
8246 blocksize = aligned;
8247 if (blocksize < MINSIZE)
8248 blocksize = MINSIZE;
8249 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8250 if (len < blocksize)
8251 error(bb_msg_memory_exhausted);
8252 INTOFF;
8253 sp = ckmalloc(len);
8254 sp->prev = stackp;
8255 stacknxt = sp->space;
8256 stacknleft = blocksize;
8257 sstrend = stacknxt + blocksize;
8258 stackp = sp;
8259 INTON;
8260 }
8261 p = stacknxt;
8262 stacknxt += aligned;
8263 stacknleft -= aligned;
8264 return p;
8265}
8266
8267
8268void
8269stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008270{
Eric Andersencb57d552001-06-28 07:25:16 +00008271#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008272 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008273 write(2, "stunalloc\n", 10);
8274 abort();
8275 }
8276#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008277 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008278 stacknxt = p;
8279}
8280
8281
Eric Andersenc470f442003-07-28 09:56:35 +00008282void
8283setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008284{
Eric Andersencb57d552001-06-28 07:25:16 +00008285 mark->stackp = stackp;
8286 mark->stacknxt = stacknxt;
8287 mark->stacknleft = stacknleft;
8288 mark->marknext = markp;
8289 markp = mark;
8290}
8291
8292
Eric Andersenc470f442003-07-28 09:56:35 +00008293void
8294popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008295{
Eric Andersencb57d552001-06-28 07:25:16 +00008296 struct stack_block *sp;
8297
8298 INTOFF;
8299 markp = mark->marknext;
8300 while (stackp != mark->stackp) {
8301 sp = stackp;
8302 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008303 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008304 }
8305 stacknxt = mark->stacknxt;
8306 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008307 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008308 INTON;
8309}
8310
8311
8312/*
8313 * When the parser reads in a string, it wants to stick the string on the
8314 * stack and only adjust the stack pointer when it knows how big the
8315 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8316 * of space on top of the stack and stackblocklen returns the length of
8317 * this block. Growstackblock will grow this space by at least one byte,
8318 * possibly moving it (like realloc). Grabstackblock actually allocates the
8319 * part of the block that has been used.
8320 */
8321
Eric Andersenc470f442003-07-28 09:56:35 +00008322void
8323growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008324{
Eric Andersenc470f442003-07-28 09:56:35 +00008325 size_t newlen;
8326
8327 newlen = stacknleft * 2;
8328 if (newlen < stacknleft)
8329 error(bb_msg_memory_exhausted);
8330 if (newlen < 128)
8331 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008332
8333 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008334 struct stack_block *oldstackp;
8335 struct stackmark *xmark;
8336 struct stack_block *sp;
8337 struct stack_block *prevstackp;
8338 size_t grosslen;
8339
Eric Andersencb57d552001-06-28 07:25:16 +00008340 INTOFF;
8341 oldstackp = stackp;
8342 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008343 prevstackp = sp->prev;
8344 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8345 sp = ckrealloc((pointer)sp, grosslen);
8346 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008347 stackp = sp;
8348 stacknxt = sp->space;
8349 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008350 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008351
Eric Andersenc470f442003-07-28 09:56:35 +00008352 /*
8353 * Stack marks pointing to the start of the old block
8354 * must be relocated to point to the new block
8355 */
8356 xmark = markp;
8357 while (xmark != NULL && xmark->stackp == oldstackp) {
8358 xmark->stackp = stackp;
8359 xmark->stacknxt = stacknxt;
8360 xmark->stacknleft = stacknleft;
8361 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008362 }
8363 INTON;
8364 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008365 char *oldspace = stacknxt;
8366 int oldlen = stacknleft;
8367 char *p = stalloc(newlen);
8368
8369 /* free the space we just allocated */
8370 stacknxt = memcpy(p, oldspace, oldlen);
8371 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008372 }
8373}
8374
Eric Andersenc470f442003-07-28 09:56:35 +00008375static inline void
8376grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008377{
Eric Andersenc470f442003-07-28 09:56:35 +00008378 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008379 stacknxt += len;
8380 stacknleft -= len;
8381}
8382
Eric Andersencb57d552001-06-28 07:25:16 +00008383/*
Eric Andersenc470f442003-07-28 09:56:35 +00008384 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008385 * The user declares a variable of type STACKSTR, which may be declared
8386 * to be a register. The macro STARTSTACKSTR initializes things. Then
8387 * the user uses the macro STPUTC to add characters to the string. In
8388 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8389 * grown as necessary. When the user is done, she can just leave the
8390 * string there and refer to it using stackblock(). Or she can allocate
8391 * the space for it using grabstackstr(). If it is necessary to allow
8392 * someone else to use the stack temporarily and then continue to grow
8393 * the string, the user should use grabstack to allocate the space, and
8394 * then call ungrabstr(p) to return to the previous mode of operation.
8395 *
8396 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8397 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8398 * is space for at least one character.
8399 */
8400
Eric Andersenc470f442003-07-28 09:56:35 +00008401void *
8402growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008403{
Eric Andersenc470f442003-07-28 09:56:35 +00008404 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008405 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008406 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008407 return stackblock();
8408 }
8409 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008410 return stackblock() + len;
8411}
8412
Eric Andersencb57d552001-06-28 07:25:16 +00008413/*
8414 * Called from CHECKSTRSPACE.
8415 */
8416
Eric Andersenc470f442003-07-28 09:56:35 +00008417char *
8418makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008419{
Eric Andersenc470f442003-07-28 09:56:35 +00008420 size_t len = p - stacknxt;
8421 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008422
Eric Andersenc470f442003-07-28 09:56:35 +00008423 for (;;) {
8424 size_t nleft;
8425
8426 size = stackblocksize();
8427 nleft = size - len;
8428 if (nleft >= newlen)
8429 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008430 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008431 }
Eric Andersencb57d552001-06-28 07:25:16 +00008432 return stackblock() + len;
8433}
8434
Eric Andersenc470f442003-07-28 09:56:35 +00008435char *
8436stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008437{
Eric Andersenc470f442003-07-28 09:56:35 +00008438 p = makestrspace(n, p);
8439 p = mempcpy(p, s, n);
8440 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008441}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008442
Eric Andersenc470f442003-07-28 09:56:35 +00008443char *
8444stputs(const char *s, char *p)
8445{
8446 return stnputs(s, strlen(s), p);
8447}
8448
8449/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8450
Eric Andersencb57d552001-06-28 07:25:16 +00008451/*
Eric Andersenc470f442003-07-28 09:56:35 +00008452 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008453 *
Eric Andersenc470f442003-07-28 09:56:35 +00008454 * number(s) Convert a string of digits to an integer.
8455 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008456 */
8457
Eric Andersencb57d552001-06-28 07:25:16 +00008458/*
8459 * prefix -- see if pfx is a prefix of string.
8460 */
8461
Eric Andersenc470f442003-07-28 09:56:35 +00008462char *
8463prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008464{
Eric Andersencb57d552001-06-28 07:25:16 +00008465 while (*pfx) {
8466 if (*pfx++ != *string++)
8467 return 0;
8468 }
Eric Andersenc470f442003-07-28 09:56:35 +00008469 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008470}
8471
8472
8473/*
8474 * Convert a string of digits to an integer, printing an error message on
8475 * failure.
8476 */
8477
Eric Andersenc470f442003-07-28 09:56:35 +00008478int
8479number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008480{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008481
Eric Andersenc470f442003-07-28 09:56:35 +00008482 if (! is_number(s))
8483 error(illnum, s);
8484 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008485}
8486
Eric Andersenc470f442003-07-28 09:56:35 +00008487
Eric Andersenc470f442003-07-28 09:56:35 +00008488/*
8489 * Check for a valid number. This should be elsewhere.
8490 */
8491
8492int
8493is_number(const char *p)
8494{
8495 do {
8496 if (! is_digit(*p))
8497 return 0;
8498 } while (*++p != '\0');
8499 return 1;
8500}
8501
8502
Eric Andersencb57d552001-06-28 07:25:16 +00008503/*
8504 * Produce a possibly single quoted string suitable as input to the shell.
8505 * The return string is allocated on the stack.
8506 */
8507
Eric Andersenc470f442003-07-28 09:56:35 +00008508char *
8509single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008510 char *p;
8511
8512 STARTSTACKSTR(p);
8513
8514 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008515 char *q;
8516 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008517
Eric Andersenc470f442003-07-28 09:56:35 +00008518 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008519
Eric Andersenc470f442003-07-28 09:56:35 +00008520 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008521
Eric Andersenc470f442003-07-28 09:56:35 +00008522 *q++ = '\'';
8523 q = mempcpy(q, s, len);
8524 *q++ = '\'';
8525 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008526
Eric Andersenc470f442003-07-28 09:56:35 +00008527 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008528
Eric Andersenc470f442003-07-28 09:56:35 +00008529 len = strspn(s, "'");
8530 if (!len)
8531 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008532
Eric Andersenc470f442003-07-28 09:56:35 +00008533 q = p = makestrspace(len + 3, p);
8534
8535 *q++ = '"';
8536 q = mempcpy(q, s, len);
8537 *q++ = '"';
8538 s += len;
8539
8540 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008541 } while (*s);
8542
8543 USTPUTC(0, p);
8544
Eric Andersenc470f442003-07-28 09:56:35 +00008545 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008546}
8547
8548/*
Eric Andersenc470f442003-07-28 09:56:35 +00008549 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008550 */
8551
Eric Andersenc470f442003-07-28 09:56:35 +00008552char *
8553sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008554{
Eric Andersenc470f442003-07-28 09:56:35 +00008555 size_t len = strlen(p) + 1;
8556 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008557}
Eric Andersenc470f442003-07-28 09:56:35 +00008558
8559
8560static void
8561calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008562{
Eric Andersenc470f442003-07-28 09:56:35 +00008563 if (n == NULL)
8564 return;
8565 funcblocksize += nodesize[n->type];
8566 switch (n->type) {
8567 case NCMD:
8568 calcsize(n->ncmd.redirect);
8569 calcsize(n->ncmd.args);
8570 calcsize(n->ncmd.assign);
8571 break;
8572 case NPIPE:
8573 sizenodelist(n->npipe.cmdlist);
8574 break;
8575 case NREDIR:
8576 case NBACKGND:
8577 case NSUBSHELL:
8578 calcsize(n->nredir.redirect);
8579 calcsize(n->nredir.n);
8580 break;
8581 case NAND:
8582 case NOR:
8583 case NSEMI:
8584 case NWHILE:
8585 case NUNTIL:
8586 calcsize(n->nbinary.ch2);
8587 calcsize(n->nbinary.ch1);
8588 break;
8589 case NIF:
8590 calcsize(n->nif.elsepart);
8591 calcsize(n->nif.ifpart);
8592 calcsize(n->nif.test);
8593 break;
8594 case NFOR:
8595 funcstringsize += strlen(n->nfor.var) + 1;
8596 calcsize(n->nfor.body);
8597 calcsize(n->nfor.args);
8598 break;
8599 case NCASE:
8600 calcsize(n->ncase.cases);
8601 calcsize(n->ncase.expr);
8602 break;
8603 case NCLIST:
8604 calcsize(n->nclist.body);
8605 calcsize(n->nclist.pattern);
8606 calcsize(n->nclist.next);
8607 break;
8608 case NDEFUN:
8609 case NARG:
8610 sizenodelist(n->narg.backquote);
8611 funcstringsize += strlen(n->narg.text) + 1;
8612 calcsize(n->narg.next);
8613 break;
8614 case NTO:
8615 case NCLOBBER:
8616 case NFROM:
8617 case NFROMTO:
8618 case NAPPEND:
8619 calcsize(n->nfile.fname);
8620 calcsize(n->nfile.next);
8621 break;
8622 case NTOFD:
8623 case NFROMFD:
8624 calcsize(n->ndup.vname);
8625 calcsize(n->ndup.next);
8626 break;
8627 case NHERE:
8628 case NXHERE:
8629 calcsize(n->nhere.doc);
8630 calcsize(n->nhere.next);
8631 break;
8632 case NNOT:
8633 calcsize(n->nnot.com);
8634 break;
8635 };
Eric Andersencb57d552001-06-28 07:25:16 +00008636}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008637
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008638
Eric Andersenc470f442003-07-28 09:56:35 +00008639static void
8640sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008641{
8642 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008643 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008644 calcsize(lp->n);
8645 lp = lp->next;
8646 }
8647}
Eric Andersencb57d552001-06-28 07:25:16 +00008648
8649
Eric Andersenc470f442003-07-28 09:56:35 +00008650static union node *
8651copynode(union node *n)
8652{
8653 union node *new;
8654
8655 if (n == NULL)
8656 return NULL;
8657 new = funcblock;
8658 funcblock = (char *) funcblock + nodesize[n->type];
8659 switch (n->type) {
8660 case NCMD:
8661 new->ncmd.redirect = copynode(n->ncmd.redirect);
8662 new->ncmd.args = copynode(n->ncmd.args);
8663 new->ncmd.assign = copynode(n->ncmd.assign);
8664 break;
8665 case NPIPE:
8666 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8667 new->npipe.backgnd = n->npipe.backgnd;
8668 break;
8669 case NREDIR:
8670 case NBACKGND:
8671 case NSUBSHELL:
8672 new->nredir.redirect = copynode(n->nredir.redirect);
8673 new->nredir.n = copynode(n->nredir.n);
8674 break;
8675 case NAND:
8676 case NOR:
8677 case NSEMI:
8678 case NWHILE:
8679 case NUNTIL:
8680 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8681 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8682 break;
8683 case NIF:
8684 new->nif.elsepart = copynode(n->nif.elsepart);
8685 new->nif.ifpart = copynode(n->nif.ifpart);
8686 new->nif.test = copynode(n->nif.test);
8687 break;
8688 case NFOR:
8689 new->nfor.var = nodesavestr(n->nfor.var);
8690 new->nfor.body = copynode(n->nfor.body);
8691 new->nfor.args = copynode(n->nfor.args);
8692 break;
8693 case NCASE:
8694 new->ncase.cases = copynode(n->ncase.cases);
8695 new->ncase.expr = copynode(n->ncase.expr);
8696 break;
8697 case NCLIST:
8698 new->nclist.body = copynode(n->nclist.body);
8699 new->nclist.pattern = copynode(n->nclist.pattern);
8700 new->nclist.next = copynode(n->nclist.next);
8701 break;
8702 case NDEFUN:
8703 case NARG:
8704 new->narg.backquote = copynodelist(n->narg.backquote);
8705 new->narg.text = nodesavestr(n->narg.text);
8706 new->narg.next = copynode(n->narg.next);
8707 break;
8708 case NTO:
8709 case NCLOBBER:
8710 case NFROM:
8711 case NFROMTO:
8712 case NAPPEND:
8713 new->nfile.fname = copynode(n->nfile.fname);
8714 new->nfile.fd = n->nfile.fd;
8715 new->nfile.next = copynode(n->nfile.next);
8716 break;
8717 case NTOFD:
8718 case NFROMFD:
8719 new->ndup.vname = copynode(n->ndup.vname);
8720 new->ndup.dupfd = n->ndup.dupfd;
8721 new->ndup.fd = n->ndup.fd;
8722 new->ndup.next = copynode(n->ndup.next);
8723 break;
8724 case NHERE:
8725 case NXHERE:
8726 new->nhere.doc = copynode(n->nhere.doc);
8727 new->nhere.fd = n->nhere.fd;
8728 new->nhere.next = copynode(n->nhere.next);
8729 break;
8730 case NNOT:
8731 new->nnot.com = copynode(n->nnot.com);
8732 break;
8733 };
8734 new->type = n->type;
8735 return new;
8736}
8737
8738
8739static struct nodelist *
8740copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008741{
8742 struct nodelist *start;
8743 struct nodelist **lpp;
8744
8745 lpp = &start;
8746 while (lp) {
8747 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008748 funcblock = (char *) funcblock +
8749 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008750 (*lpp)->n = copynode(lp->n);
8751 lp = lp->next;
8752 lpp = &(*lpp)->next;
8753 }
8754 *lpp = NULL;
8755 return start;
8756}
8757
8758
Eric Andersenc470f442003-07-28 09:56:35 +00008759static char *
8760nodesavestr(char *s)
8761{
8762 char *rtn = funcstring;
8763
8764 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008765 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008766}
8767
Eric Andersenc470f442003-07-28 09:56:35 +00008768
Eric Andersenc470f442003-07-28 09:56:35 +00008769/*
8770 * Free a parse tree.
8771 */
8772
8773static void
8774freefunc(struct funcnode *f)
8775{
8776 if (f && --f->count < 0)
8777 ckfree(f);
8778}
8779
8780
8781static void options(int);
8782static void setoption(int, int);
8783
Eric Andersencb57d552001-06-28 07:25:16 +00008784
Eric Andersencb57d552001-06-28 07:25:16 +00008785/*
8786 * Process the shell command line arguments.
8787 */
8788
Eric Andersenc470f442003-07-28 09:56:35 +00008789void
8790procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008791{
8792 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008793 const char *xminusc;
8794 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008795
Eric Andersenc470f442003-07-28 09:56:35 +00008796 xargv = argv;
8797 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008798 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008799 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008800 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008801 optlist[i] = 2;
8802 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008803 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008804 xargv = argptr;
8805 xminusc = minusc;
8806 if (*xargv == NULL) {
8807 if (xminusc)
8808 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008809 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008810 }
Eric Andersencb57d552001-06-28 07:25:16 +00008811 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8812 iflag = 1;
8813 if (mflag == 2)
8814 mflag = iflag;
8815 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008816 if (optlist[i] == 2)
8817 optlist[i] = 0;
8818#if DEBUG == 2
8819 debug = 1;
8820#endif
8821 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8822 if (xminusc) {
8823 minusc = *xargv++;
8824 if (*xargv)
8825 goto setarg0;
8826 } else if (!sflag) {
8827 setinputfile(*xargv, 0);
8828setarg0:
8829 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008830 commandname = arg0;
8831 }
Eric Andersencb57d552001-06-28 07:25:16 +00008832
Eric Andersenc470f442003-07-28 09:56:35 +00008833 shellparam.p = xargv;
8834#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008835 shellparam.optind = 1;
8836 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008837#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008838 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008839 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008840 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008841 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008842 }
8843 optschanged();
8844}
8845
8846
Eric Andersenc470f442003-07-28 09:56:35 +00008847void
8848optschanged(void)
8849{
8850#ifdef DEBUG
8851 opentrace();
8852#endif
8853 setinteractive(iflag);
8854 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008855 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008856}
Eric Andersencb57d552001-06-28 07:25:16 +00008857
Eric Andersenc470f442003-07-28 09:56:35 +00008858static inline void
8859minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008860{
8861 int i;
8862
8863 if (name == NULL) {
8864 out1str("Current option settings\n");
8865 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008866 out1fmt("%-16s%s\n", optnames(i),
8867 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008868 } else {
8869 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008870 if (equal(name, optnames(i))) {
8871 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008872 return;
8873 }
8874 error("Illegal option -o %s", name);
8875 }
8876}
8877
Eric Andersenc470f442003-07-28 09:56:35 +00008878/*
8879 * Process shell options. The global variable argptr contains a pointer
8880 * to the argument list; we advance it past the options.
8881 */
Eric Andersen62483552001-07-10 06:09:16 +00008882
Eric Andersenc470f442003-07-28 09:56:35 +00008883static void
8884options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008885{
8886 char *p;
8887 int val;
8888 int c;
8889
8890 if (cmdline)
8891 minusc = NULL;
8892 while ((p = *argptr) != NULL) {
8893 argptr++;
8894 if ((c = *p++) == '-') {
8895 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008896 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8897 if (!cmdline) {
8898 /* "-" means turn off -x and -v */
8899 if (p[0] == '\0')
8900 xflag = vflag = 0;
8901 /* "--" means reset params */
8902 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008903 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008904 }
Eric Andersenc470f442003-07-28 09:56:35 +00008905 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008906 }
8907 } else if (c == '+') {
8908 val = 0;
8909 } else {
8910 argptr--;
8911 break;
8912 }
8913 while ((c = *p++) != '\0') {
8914 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008915 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008916 } else if (c == 'o') {
8917 minus_o(*argptr, val);
8918 if (*argptr)
8919 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008920 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008921 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008922 isloginsh = 1;
8923 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008924 } else {
8925 setoption(c, val);
8926 }
8927 }
8928 }
8929}
8930
Eric Andersencb57d552001-06-28 07:25:16 +00008931
Eric Andersenc470f442003-07-28 09:56:35 +00008932static void
8933setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008934{
Eric Andersencb57d552001-06-28 07:25:16 +00008935 int i;
8936
8937 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008938 if (optletters(i) == flag) {
8939 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008940 return;
8941 }
8942 error("Illegal option -%c", flag);
8943 /* NOTREACHED */
8944}
8945
8946
8947
Eric Andersencb57d552001-06-28 07:25:16 +00008948/*
8949 * Set the shell parameters.
8950 */
8951
Eric Andersenc470f442003-07-28 09:56:35 +00008952void
8953setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008954{
Eric Andersencb57d552001-06-28 07:25:16 +00008955 char **newparam;
8956 char **ap;
8957 int nparam;
8958
Eric Andersenc470f442003-07-28 09:56:35 +00008959 for (nparam = 0 ; argv[nparam] ; nparam++);
8960 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008961 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008962 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008963 }
8964 *ap = NULL;
8965 freeparam(&shellparam);
8966 shellparam.malloc = 1;
8967 shellparam.nparam = nparam;
8968 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008969#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008970 shellparam.optind = 1;
8971 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008972#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008973}
8974
8975
8976/*
8977 * Free the list of positional parameters.
8978 */
8979
Eric Andersenc470f442003-07-28 09:56:35 +00008980void
8981freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008982{
Eric Andersencb57d552001-06-28 07:25:16 +00008983 char **ap;
8984
8985 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008986 for (ap = param->p ; *ap ; ap++)
8987 ckfree(*ap);
8988 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008989 }
8990}
8991
8992
8993
8994/*
8995 * The shift builtin command.
8996 */
8997
Eric Andersenc470f442003-07-28 09:56:35 +00008998int
8999shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009000{
9001 int n;
9002 char **ap1, **ap2;
9003
9004 n = 1;
9005 if (argc > 1)
9006 n = number(argv[1]);
9007 if (n > shellparam.nparam)
9008 error("can't shift that many");
9009 INTOFF;
9010 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009011 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009012 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009013 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009014 }
9015 ap2 = shellparam.p;
9016 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009017#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009018 shellparam.optind = 1;
9019 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009020#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009021 INTON;
9022 return 0;
9023}
9024
9025
9026
9027/*
9028 * The set command builtin.
9029 */
9030
Eric Andersenc470f442003-07-28 09:56:35 +00009031int
9032setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009033{
9034 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009035 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009036 INTOFF;
9037 options(0);
9038 optschanged();
9039 if (*argptr != NULL) {
9040 setparam(argptr);
9041 }
9042 INTON;
9043 return 0;
9044}
9045
9046
Eric Andersenc470f442003-07-28 09:56:35 +00009047#ifdef CONFIG_ASH_GETOPTS
9048static void
9049getoptsreset(value)
9050 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009051{
9052 shellparam.optind = number(value);
9053 shellparam.optoff = -1;
9054}
Eric Andersenc470f442003-07-28 09:56:35 +00009055#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009056
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009057#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009058static void change_lc_all(const char *value)
9059{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009060 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009061 setlocale(LC_ALL, value);
9062}
9063
9064static void change_lc_ctype(const char *value)
9065{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009066 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009067 setlocale(LC_CTYPE, value);
9068}
9069
9070#endif
9071
Eric Andersen16767e22004-03-16 05:14:10 +00009072#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009073/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009074static void change_random(const char *value)
9075{
Eric Andersen16767e22004-03-16 05:14:10 +00009076 if(value == NULL) {
9077 /* "get", generate */
9078 char buf[16];
9079
9080 rseed = rseed * 1103515245 + 12345;
9081 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9082 /* set without recursion */
9083 setvar(vrandom.text, buf, VNOFUNC);
9084 vrandom.flags &= ~VNOFUNC;
9085 } else {
9086 /* set/reset */
9087 rseed = strtoul(value, (char **)NULL, 10);
9088 }
Eric Andersenef02f822004-03-11 13:34:24 +00009089}
Eric Andersen16767e22004-03-16 05:14:10 +00009090#endif
9091
Eric Andersenef02f822004-03-11 13:34:24 +00009092
Eric Andersend35c5df2002-01-09 15:37:36 +00009093#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009094static int
Eric Andersenc470f442003-07-28 09:56:35 +00009095getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009096{
9097 char *p, *q;
9098 char c = '?';
9099 int done = 0;
9100 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009101 char s[12];
9102 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009103
Eric Andersena48b0a32003-10-22 10:56:47 +00009104 if(*param_optind < 1)
9105 return 1;
9106 optnext = optfirst + *param_optind - 1;
9107
9108 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009109 p = NULL;
9110 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009111 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009112 if (p == NULL || *p == '\0') {
9113 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009114 p = *optnext;
9115 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009116atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009117 p = NULL;
9118 done = 1;
9119 goto out;
9120 }
9121 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009122 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009123 goto atend;
9124 }
9125
9126 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009127 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009128 if (*q == '\0') {
9129 if (optstr[0] == ':') {
9130 s[0] = c;
9131 s[1] = '\0';
9132 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009133 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009134 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009135 (void) unsetvar("OPTARG");
9136 }
9137 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009138 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009139 }
9140 if (*++q == ':')
9141 q++;
9142 }
9143
9144 if (*++q == ':') {
9145 if (*p == '\0' && (p = *optnext) == NULL) {
9146 if (optstr[0] == ':') {
9147 s[0] = c;
9148 s[1] = '\0';
9149 err |= setvarsafe("OPTARG", s, 0);
9150 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009151 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009152 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009153 (void) unsetvar("OPTARG");
9154 c = '?';
9155 }
Eric Andersenc470f442003-07-28 09:56:35 +00009156 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009157 }
9158
9159 if (p == *optnext)
9160 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009161 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009162 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009163 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009164 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009165
Eric Andersenc470f442003-07-28 09:56:35 +00009166out:
Eric Andersencb57d552001-06-28 07:25:16 +00009167 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009168 *param_optind = optnext - optfirst + 1;
9169 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009170 err |= setvarsafe("OPTIND", s, VNOFUNC);
9171 s[0] = c;
9172 s[1] = '\0';
9173 err |= setvarsafe(optvar, s, 0);
9174 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009175 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009176 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009177 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009178 exraise(EXERROR);
9179 }
9180 return done;
9181}
Eric Andersenc470f442003-07-28 09:56:35 +00009182
9183/*
9184 * The getopts builtin. Shellparam.optnext points to the next argument
9185 * to be processed. Shellparam.optptr points to the next character to
9186 * be processed in the current argument. If shellparam.optnext is NULL,
9187 * then it's the first time getopts has been called.
9188 */
9189
9190int
9191getoptscmd(int argc, char **argv)
9192{
9193 char **optbase;
9194
9195 if (argc < 3)
9196 error("Usage: getopts optstring var [arg]");
9197 else if (argc == 3) {
9198 optbase = shellparam.p;
9199 if (shellparam.optind > shellparam.nparam + 1) {
9200 shellparam.optind = 1;
9201 shellparam.optoff = -1;
9202 }
9203 }
9204 else {
9205 optbase = &argv[3];
9206 if (shellparam.optind > argc - 2) {
9207 shellparam.optind = 1;
9208 shellparam.optoff = -1;
9209 }
9210 }
9211
9212 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9213 &shellparam.optoff);
9214}
9215#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009216
9217/*
9218 * XXX - should get rid of. have all builtins use getopt(3). the
9219 * library getopt must have the BSD extension static variable "optreset"
9220 * otherwise it can't be used within the shell safely.
9221 *
9222 * Standard option processing (a la getopt) for builtin routines. The
9223 * only argument that is passed to nextopt is the option string; the
9224 * other arguments are unnecessary. It return the character, or '\0' on
9225 * end of input.
9226 */
9227
Eric Andersenc470f442003-07-28 09:56:35 +00009228static int
9229nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009230{
Eric Andersencb57d552001-06-28 07:25:16 +00009231 char *p;
9232 const char *q;
9233 char c;
9234
9235 if ((p = optptr) == NULL || *p == '\0') {
9236 p = *argptr;
9237 if (p == NULL || *p != '-' || *++p == '\0')
9238 return '\0';
9239 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009240 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009241 return '\0';
9242 }
9243 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009244 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009245 if (*q == '\0')
9246 error("Illegal option -%c", c);
9247 if (*++q == ':')
9248 q++;
9249 }
9250 if (*++q == ':') {
9251 if (*p == '\0' && (p = *argptr++) == NULL)
9252 error("No arg for -%c option", c);
9253 optionarg = p;
9254 p = NULL;
9255 }
9256 optptr = p;
9257 return c;
9258}
9259
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009260
Eric Andersenc470f442003-07-28 09:56:35 +00009261/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9262
Eric Andersenc470f442003-07-28 09:56:35 +00009263void
9264outstr(const char *p, FILE *file)
9265{
9266 INTOFF;
9267 fputs(p, file);
9268 INTON;
9269}
9270
9271void
9272flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009273{
Eric Andersencb57d552001-06-28 07:25:16 +00009274 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009275 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009276 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009277 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009278}
9279
Eric Andersenc470f442003-07-28 09:56:35 +00009280void
Eric Andersen16767e22004-03-16 05:14:10 +00009281flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009282{
9283 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009284 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009285 INTON;
9286}
9287
9288static void
9289outcslow(int c, FILE *dest)
9290{
9291 INTOFF;
9292 putc(c, dest);
9293 fflush(dest);
9294 INTON;
9295}
9296
9297
9298static int
9299out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009300{
9301 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009302 int r;
9303
9304 INTOFF;
9305 va_start(ap, fmt);
9306 r = vprintf(fmt, ap);
9307 va_end(ap);
9308 INTON;
9309 return r;
9310}
9311
9312
9313int
9314fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9315{
9316 va_list ap;
9317 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009318
Eric Andersencb57d552001-06-28 07:25:16 +00009319 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009320 INTOFF;
9321 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009322 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009323 INTON;
9324 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009325}
9326
Eric Andersenc470f442003-07-28 09:56:35 +00009327
Eric Andersencb57d552001-06-28 07:25:16 +00009328
Eric Andersenc470f442003-07-28 09:56:35 +00009329/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9330
9331
Eric Andersencb57d552001-06-28 07:25:16 +00009332/*
9333 * Shell command parser.
9334 */
9335
9336#define EOFMARKLEN 79
9337
9338
Eric Andersencb57d552001-06-28 07:25:16 +00009339struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009340 struct heredoc *next; /* next here document in list */
9341 union node *here; /* redirection node */
9342 char *eofmark; /* string indicating end of input */
9343 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009344};
9345
9346
9347
Eric Andersenc470f442003-07-28 09:56:35 +00009348static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009349
9350
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009351static union node *list(int);
9352static union node *andor(void);
9353static union node *pipeline(void);
9354static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009355static union node *simplecmd(void);
9356static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009357static void parsefname(void);
9358static void parseheredoc(void);
9359static char peektoken(void);
9360static int readtoken(void);
9361static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009362static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009363static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009364static void synexpect(int) __attribute__((__noreturn__));
9365static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009366static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009367
9368
Eric Andersenc470f442003-07-28 09:56:35 +00009369
Eric Andersenc470f442003-07-28 09:56:35 +00009370
Eric Andersencb57d552001-06-28 07:25:16 +00009371/*
9372 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9373 * valid parse tree indicating a blank line.)
9374 */
9375
Eric Andersenc470f442003-07-28 09:56:35 +00009376union node *
9377parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009378{
9379 int t;
9380
9381 tokpushback = 0;
9382 doprompt = interact;
9383 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009384 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009385 needprompt = 0;
9386 t = readtoken();
9387 if (t == TEOF)
9388 return NEOF;
9389 if (t == TNL)
9390 return NULL;
9391 tokpushback++;
9392 return list(1);
9393}
9394
9395
Eric Andersenc470f442003-07-28 09:56:35 +00009396static union node *
9397list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009398{
9399 union node *n1, *n2, *n3;
9400 int tok;
9401
Eric Andersenc470f442003-07-28 09:56:35 +00009402 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9403 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009404 return NULL;
9405 n1 = NULL;
9406 for (;;) {
9407 n2 = andor();
9408 tok = readtoken();
9409 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009410 if (n2->type == NPIPE) {
9411 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009412 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009413 if (n2->type != NREDIR) {
9414 n3 = stalloc(sizeof(struct nredir));
9415 n3->nredir.n = n2;
9416 n3->nredir.redirect = NULL;
9417 n2 = n3;
9418 }
9419 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009420 }
9421 }
9422 if (n1 == NULL) {
9423 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009424 }
9425 else {
9426 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009427 n3->type = NSEMI;
9428 n3->nbinary.ch1 = n1;
9429 n3->nbinary.ch2 = n2;
9430 n1 = n3;
9431 }
9432 switch (tok) {
9433 case TBACKGND:
9434 case TSEMI:
9435 tok = readtoken();
9436 /* fall through */
9437 case TNL:
9438 if (tok == TNL) {
9439 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009440 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009441 return n1;
9442 } else {
9443 tokpushback++;
9444 }
Eric Andersenc470f442003-07-28 09:56:35 +00009445 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009446 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009447 return n1;
9448 break;
9449 case TEOF:
9450 if (heredoclist)
9451 parseheredoc();
9452 else
Eric Andersenc470f442003-07-28 09:56:35 +00009453 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009454 return n1;
9455 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009456 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009457 synexpect(-1);
9458 tokpushback++;
9459 return n1;
9460 }
9461 }
9462}
9463
9464
9465
Eric Andersenc470f442003-07-28 09:56:35 +00009466static union node *
9467andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009468{
Eric Andersencb57d552001-06-28 07:25:16 +00009469 union node *n1, *n2, *n3;
9470 int t;
9471
Eric Andersencb57d552001-06-28 07:25:16 +00009472 n1 = pipeline();
9473 for (;;) {
9474 if ((t = readtoken()) == TAND) {
9475 t = NAND;
9476 } else if (t == TOR) {
9477 t = NOR;
9478 } else {
9479 tokpushback++;
9480 return n1;
9481 }
Eric Andersenc470f442003-07-28 09:56:35 +00009482 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009483 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009484 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009485 n3->type = t;
9486 n3->nbinary.ch1 = n1;
9487 n3->nbinary.ch2 = n2;
9488 n1 = n3;
9489 }
9490}
9491
9492
9493
Eric Andersenc470f442003-07-28 09:56:35 +00009494static union node *
9495pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009496{
Eric Andersencb57d552001-06-28 07:25:16 +00009497 union node *n1, *n2, *pipenode;
9498 struct nodelist *lp, *prev;
9499 int negate;
9500
9501 negate = 0;
9502 TRACE(("pipeline: entered\n"));
9503 if (readtoken() == TNOT) {
9504 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009505 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009506 } else
9507 tokpushback++;
9508 n1 = command();
9509 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009510 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009511 pipenode->type = NPIPE;
9512 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009513 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009514 pipenode->npipe.cmdlist = lp;
9515 lp->n = n1;
9516 do {
9517 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009518 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9519 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009520 lp->n = command();
9521 prev->next = lp;
9522 } while (readtoken() == TPIPE);
9523 lp->next = NULL;
9524 n1 = pipenode;
9525 }
9526 tokpushback++;
9527 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009528 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009529 n2->type = NNOT;
9530 n2->nnot.com = n1;
9531 return n2;
9532 } else
9533 return n1;
9534}
9535
9536
9537
Eric Andersenc470f442003-07-28 09:56:35 +00009538static union node *
9539command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009540{
Eric Andersencb57d552001-06-28 07:25:16 +00009541 union node *n1, *n2;
9542 union node *ap, **app;
9543 union node *cp, **cpp;
9544 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009545 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009546 int t;
9547
9548 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009549 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009550
Eric Andersencb57d552001-06-28 07:25:16 +00009551 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009552 default:
9553 synexpect(-1);
9554 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009555 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009556 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009557 n1->type = NIF;
9558 n1->nif.test = list(0);
9559 if (readtoken() != TTHEN)
9560 synexpect(TTHEN);
9561 n1->nif.ifpart = list(0);
9562 n2 = n1;
9563 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009564 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009565 n2 = n2->nif.elsepart;
9566 n2->type = NIF;
9567 n2->nif.test = list(0);
9568 if (readtoken() != TTHEN)
9569 synexpect(TTHEN);
9570 n2->nif.ifpart = list(0);
9571 }
9572 if (lasttoken == TELSE)
9573 n2->nif.elsepart = list(0);
9574 else {
9575 n2->nif.elsepart = NULL;
9576 tokpushback++;
9577 }
Eric Andersenc470f442003-07-28 09:56:35 +00009578 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009579 break;
9580 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009581 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009582 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009583 n1 = (union node *)stalloc(sizeof (struct nbinary));
9584 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009585 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009586 if ((got=readtoken()) != TDO) {
9587TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009588 synexpect(TDO);
9589 }
9590 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009591 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009592 break;
9593 }
9594 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009595 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009596 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009597 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009598 n1->type = NFOR;
9599 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009600 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009601 if (readtoken() == TIN) {
9602 app = &ap;
9603 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009604 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009605 n2->type = NARG;
9606 n2->narg.text = wordtext;
9607 n2->narg.backquote = backquotelist;
9608 *app = n2;
9609 app = &n2->narg.next;
9610 }
9611 *app = NULL;
9612 n1->nfor.args = ap;
9613 if (lasttoken != TNL && lasttoken != TSEMI)
9614 synexpect(-1);
9615 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009616 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009617 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009618 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009619 n2->narg.backquote = NULL;
9620 n2->narg.next = NULL;
9621 n1->nfor.args = n2;
9622 /*
9623 * Newline or semicolon here is optional (but note
9624 * that the original Bourne shell only allowed NL).
9625 */
9626 if (lasttoken != TNL && lasttoken != TSEMI)
9627 tokpushback++;
9628 }
Eric Andersenc470f442003-07-28 09:56:35 +00009629 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009630 if (readtoken() != TDO)
9631 synexpect(TDO);
9632 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009633 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009634 break;
9635 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009636 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009637 n1->type = NCASE;
9638 if (readtoken() != TWORD)
9639 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009640 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009641 n2->type = NARG;
9642 n2->narg.text = wordtext;
9643 n2->narg.backquote = backquotelist;
9644 n2->narg.next = NULL;
9645 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009646 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009647 } while (readtoken() == TNL);
9648 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009649 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009650 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009651next_case:
9652 checkkwd = CHKNL | CHKKWD;
9653 t = readtoken();
9654 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009655 if (lasttoken == TLP)
9656 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009657 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009658 cp->type = NCLIST;
9659 app = &cp->nclist.pattern;
9660 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009661 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009662 ap->type = NARG;
9663 ap->narg.text = wordtext;
9664 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009665 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009666 break;
9667 app = &ap->narg.next;
9668 readtoken();
9669 }
9670 ap->narg.next = NULL;
9671 if (lasttoken != TRP)
9672 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009673 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009674
Eric Andersenc470f442003-07-28 09:56:35 +00009675 cpp = &cp->nclist.next;
9676
9677 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009678 if ((t = readtoken()) != TESAC) {
9679 if (t != TENDCASE)
9680 synexpect(TENDCASE);
9681 else
Eric Andersenc470f442003-07-28 09:56:35 +00009682 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009683 }
Eric Andersenc470f442003-07-28 09:56:35 +00009684 }
Eric Andersencb57d552001-06-28 07:25:16 +00009685 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009686 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009687 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009688 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009689 n1->type = NSUBSHELL;
9690 n1->nredir.n = list(0);
9691 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009692 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009693 break;
9694 case TBEGIN:
9695 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009696 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009697 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009698 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009699 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009700 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009701 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009702 }
9703
Eric Andersenc470f442003-07-28 09:56:35 +00009704 if (readtoken() != t)
9705 synexpect(t);
9706
9707redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009708 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009709 checkkwd = CHKKWD | CHKALIAS;
9710 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009711 while (readtoken() == TREDIR) {
9712 *rpp = n2 = redirnode;
9713 rpp = &n2->nfile.next;
9714 parsefname();
9715 }
9716 tokpushback++;
9717 *rpp = NULL;
9718 if (redir) {
9719 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009720 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009721 n2->type = NREDIR;
9722 n2->nredir.n = n1;
9723 n1 = n2;
9724 }
9725 n1->nredir.redirect = redir;
9726 }
9727
9728 return n1;
9729}
9730
9731
Eric Andersenc470f442003-07-28 09:56:35 +00009732static union node *
9733simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009734 union node *args, **app;
9735 union node *n = NULL;
9736 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009737 union node **rpp, *redir;
9738 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009739
9740 args = NULL;
9741 app = &args;
9742 vars = NULL;
9743 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009744 redir = NULL;
9745 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009746
Eric Andersenc470f442003-07-28 09:56:35 +00009747 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009748 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009749 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009750 switch (readtoken()) {
9751 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009752 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009753 n->type = NARG;
9754 n->narg.text = wordtext;
9755 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009756 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009757 *vpp = n;
9758 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009759 } else {
9760 *app = n;
9761 app = &n->narg.next;
9762 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009763 }
9764 break;
9765 case TREDIR:
9766 *rpp = n = redirnode;
9767 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009768 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009769 break;
9770 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009771 if (
9772 args && app == &args->narg.next &&
9773 !vars && !redir
9774 ) {
9775 struct builtincmd *bcmd;
9776 const char *name;
9777
Eric Andersencb57d552001-06-28 07:25:16 +00009778 /* We have a function */
9779 if (readtoken() != TRP)
9780 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009781 name = n->narg.text;
9782 if (
9783 !goodname(name) || (
9784 (bcmd = find_builtin(name)) &&
9785 IS_BUILTIN_SPECIAL(bcmd)
9786 )
9787 )
9788 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009789 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009790 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009791 n->narg.next = command();
9792 return n;
9793 }
9794 /* fall through */
9795 default:
9796 tokpushback++;
9797 goto out;
9798 }
9799 }
Eric Andersenc470f442003-07-28 09:56:35 +00009800out:
Eric Andersencb57d552001-06-28 07:25:16 +00009801 *app = NULL;
9802 *vpp = NULL;
9803 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009804 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009805 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009806 n->ncmd.args = args;
9807 n->ncmd.assign = vars;
9808 n->ncmd.redirect = redir;
9809 return n;
9810}
9811
Eric Andersenc470f442003-07-28 09:56:35 +00009812static union node *
9813makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009814{
Eric Andersencb57d552001-06-28 07:25:16 +00009815 union node *n;
9816
Eric Andersenc470f442003-07-28 09:56:35 +00009817 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009818 n->type = NARG;
9819 n->narg.next = NULL;
9820 n->narg.text = wordtext;
9821 n->narg.backquote = backquotelist;
9822 return n;
9823}
9824
Eric Andersenc470f442003-07-28 09:56:35 +00009825void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009826{
Eric Andersencb57d552001-06-28 07:25:16 +00009827 TRACE(("Fix redir %s %d\n", text, err));
9828 if (!err)
9829 n->ndup.vname = NULL;
9830
9831 if (is_digit(text[0]) && text[1] == '\0')
9832 n->ndup.dupfd = digit_val(text[0]);
9833 else if (text[0] == '-' && text[1] == '\0')
9834 n->ndup.dupfd = -1;
9835 else {
9836
9837 if (err)
9838 synerror("Bad fd number");
9839 else
9840 n->ndup.vname = makename();
9841 }
9842}
9843
9844
Eric Andersenc470f442003-07-28 09:56:35 +00009845static void
9846parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009847{
Eric Andersencb57d552001-06-28 07:25:16 +00009848 union node *n = redirnode;
9849
9850 if (readtoken() != TWORD)
9851 synexpect(-1);
9852 if (n->type == NHERE) {
9853 struct heredoc *here = heredoc;
9854 struct heredoc *p;
9855 int i;
9856
9857 if (quoteflag == 0)
9858 n->type = NXHERE;
9859 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009860 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009861 synerror("Illegal eof marker for << redirection");
9862 rmescapes(wordtext);
9863 here->eofmark = wordtext;
9864 here->next = NULL;
9865 if (heredoclist == NULL)
9866 heredoclist = here;
9867 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009868 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009869 p->next = here;
9870 }
9871 } else if (n->type == NTOFD || n->type == NFROMFD) {
9872 fixredir(n, wordtext, 0);
9873 } else {
9874 n->nfile.fname = makename();
9875 }
9876}
9877
9878
9879/*
9880 * Input any here documents.
9881 */
9882
Eric Andersenc470f442003-07-28 09:56:35 +00009883static void
9884parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009885{
Eric Andersencb57d552001-06-28 07:25:16 +00009886 struct heredoc *here;
9887 union node *n;
9888
Eric Andersenc470f442003-07-28 09:56:35 +00009889 here = heredoclist;
9890 heredoclist = 0;
9891
9892 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009893 if (needprompt) {
9894 setprompt(2);
9895 needprompt = 0;
9896 }
Eric Andersenc470f442003-07-28 09:56:35 +00009897 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9898 here->eofmark, here->striptabs);
9899 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009900 n->narg.type = NARG;
9901 n->narg.next = NULL;
9902 n->narg.text = wordtext;
9903 n->narg.backquote = backquotelist;
9904 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009905 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009906 }
9907}
9908
Eric Andersenc470f442003-07-28 09:56:35 +00009909static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009910{
Eric Andersencb57d552001-06-28 07:25:16 +00009911 int t;
9912
9913 t = readtoken();
9914 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009915 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009916}
9917
Eric Andersenc470f442003-07-28 09:56:35 +00009918static int
9919readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009920{
Eric Andersencb57d552001-06-28 07:25:16 +00009921 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009922#ifdef DEBUG
9923 int alreadyseen = tokpushback;
9924#endif
9925
Eric Andersend35c5df2002-01-09 15:37:36 +00009926#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009927top:
Eric Andersen2870d962001-07-02 17:27:21 +00009928#endif
9929
Eric Andersencb57d552001-06-28 07:25:16 +00009930 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009931
Eric Andersenc470f442003-07-28 09:56:35 +00009932 /*
9933 * eat newlines
9934 */
9935 if (checkkwd & CHKNL) {
9936 while (t == TNL) {
9937 parseheredoc();
9938 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009939 }
9940 }
9941
Eric Andersenc470f442003-07-28 09:56:35 +00009942 if (t != TWORD || quoteflag) {
9943 goto out;
9944 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009945
Eric Andersenc470f442003-07-28 09:56:35 +00009946 /*
9947 * check for keywords
9948 */
9949 if (checkkwd & CHKKWD) {
9950 const char *const *pp;
9951
9952 if ((pp = findkwd(wordtext))) {
9953 lasttoken = t = pp - tokname_array;
9954 TRACE(("keyword %s recognized\n", tokname(t)));
9955 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009956 }
Eric Andersenc470f442003-07-28 09:56:35 +00009957 }
9958
9959 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009960#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009961 struct alias *ap;
9962 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009963 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009964 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009965 }
Eric Andersencb57d552001-06-28 07:25:16 +00009966 goto top;
9967 }
Eric Andersen2870d962001-07-02 17:27:21 +00009968#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009969 }
Eric Andersenc470f442003-07-28 09:56:35 +00009970out:
9971 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009972#ifdef DEBUG
9973 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009974 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009975 else
Eric Andersenc470f442003-07-28 09:56:35 +00009976 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009977#endif
9978 return (t);
9979}
9980
9981
9982/*
9983 * Read the next input token.
9984 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009985 * backquotes. We set quoteflag to true if any part of the word was
9986 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009987 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009988 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009989 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009990 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009991 *
9992 * [Change comment: here documents and internal procedures]
9993 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9994 * word parsing code into a separate routine. In this case, readtoken
9995 * doesn't need to have any internal procedures, but parseword does.
9996 * We could also make parseoperator in essence the main routine, and
9997 * have parseword (readtoken1?) handle both words and redirection.]
9998 */
9999
Eric Andersen81fe1232003-07-29 06:38:40 +000010000#define NEW_xxreadtoken
10001#ifdef NEW_xxreadtoken
10002
10003/* singles must be first! */
10004static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10005
10006static const char xxreadtoken_tokens[] = {
10007 TNL, TLP, TRP, /* only single occurrence allowed */
10008 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10009 TEOF, /* corresponds to trailing nul */
10010 TAND, TOR, TENDCASE, /* if double occurrence */
10011};
10012
10013#define xxreadtoken_doubles \
10014 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10015#define xxreadtoken_singles \
10016 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10017
10018static int xxreadtoken()
10019{
10020 int c;
10021
10022 if (tokpushback) {
10023 tokpushback = 0;
10024 return lasttoken;
10025 }
10026 if (needprompt) {
10027 setprompt(2);
10028 needprompt = 0;
10029 }
10030 startlinno = plinno;
10031 for (;;) { /* until token or start of word found */
10032 c = pgetc_macro();
10033
10034 if ((c != ' ') && (c != '\t')
10035#ifdef CONFIG_ASH_ALIAS
10036 && (c != PEOA)
10037#endif
10038 ) {
10039 if (c == '#') {
10040 while ((c = pgetc()) != '\n' && c != PEOF);
10041 pungetc();
10042 } else if (c == '\\') {
10043 if (pgetc() != '\n') {
10044 pungetc();
10045 goto READTOKEN1;
10046 }
10047 startlinno = ++plinno;
10048 if (doprompt)
10049 setprompt(2);
10050 } else {
10051 const char *p
10052 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10053
10054 if (c != PEOF) {
10055 if (c == '\n') {
10056 plinno++;
10057 needprompt = doprompt;
10058 }
10059
10060 p = strchr(xxreadtoken_chars, c);
10061 if (p == NULL) {
10062 READTOKEN1:
10063 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10064 }
10065
10066 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10067 if (pgetc() == *p) { /* double occurrence? */
10068 p += xxreadtoken_doubles + 1;
10069 } else {
10070 pungetc();
10071 }
10072 }
10073 }
10074
10075 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10076 }
10077 }
10078 }
10079}
10080
10081
10082#else
Eric Andersen2870d962001-07-02 17:27:21 +000010083#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010084
Eric Andersenc470f442003-07-28 09:56:35 +000010085static int
10086xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010087{
Eric Andersencb57d552001-06-28 07:25:16 +000010088 int c;
10089
10090 if (tokpushback) {
10091 tokpushback = 0;
10092 return lasttoken;
10093 }
10094 if (needprompt) {
10095 setprompt(2);
10096 needprompt = 0;
10097 }
10098 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010099 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010100 c = pgetc_macro();
10101 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010102 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010103#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010104 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010105#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010106 continue;
10107 case '#':
10108 while ((c = pgetc()) != '\n' && c != PEOF);
10109 pungetc();
10110 continue;
10111 case '\\':
10112 if (pgetc() == '\n') {
10113 startlinno = ++plinno;
10114 if (doprompt)
10115 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010116 continue;
10117 }
10118 pungetc();
10119 goto breakloop;
10120 case '\n':
10121 plinno++;
10122 needprompt = doprompt;
10123 RETURN(TNL);
10124 case PEOF:
10125 RETURN(TEOF);
10126 case '&':
10127 if (pgetc() == '&')
10128 RETURN(TAND);
10129 pungetc();
10130 RETURN(TBACKGND);
10131 case '|':
10132 if (pgetc() == '|')
10133 RETURN(TOR);
10134 pungetc();
10135 RETURN(TPIPE);
10136 case ';':
10137 if (pgetc() == ';')
10138 RETURN(TENDCASE);
10139 pungetc();
10140 RETURN(TSEMI);
10141 case '(':
10142 RETURN(TLP);
10143 case ')':
10144 RETURN(TRP);
10145 default:
10146 goto breakloop;
10147 }
10148 }
Eric Andersenc470f442003-07-28 09:56:35 +000010149breakloop:
10150 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010151#undef RETURN
10152}
Eric Andersen81fe1232003-07-29 06:38:40 +000010153#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010154
Eric Andersencb57d552001-06-28 07:25:16 +000010155
Eric Andersencb57d552001-06-28 07:25:16 +000010156/*
10157 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10158 * is not NULL, read a here document. In the latter case, eofmark is the
10159 * word which marks the end of the document and striptabs is true if
10160 * leading tabs should be stripped from the document. The argument firstc
10161 * is the first character of the input token or document.
10162 *
10163 * Because C does not have internal subroutines, I have simulated them
10164 * using goto's to implement the subroutine linkage. The following macros
10165 * will run code that appears at the end of readtoken1.
10166 */
10167
Eric Andersen2870d962001-07-02 17:27:21 +000010168#define CHECKEND() {goto checkend; checkend_return:;}
10169#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10170#define PARSESUB() {goto parsesub; parsesub_return:;}
10171#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10172#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10173#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010174
10175static int
Eric Andersenc470f442003-07-28 09:56:35 +000010176readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010177{
Eric Andersencb57d552001-06-28 07:25:16 +000010178 int c = firstc;
10179 char *out;
10180 int len;
10181 char line[EOFMARKLEN + 1];
10182 struct nodelist *bqlist;
10183 int quotef;
10184 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010185 int varnest; /* levels of variables expansion */
10186 int arinest; /* levels of arithmetic expansion */
10187 int parenlevel; /* levels of parens in arithmetic */
10188 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010189 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010190 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010191#if __GNUC__
10192 /* Avoid longjmp clobbering */
10193 (void) &out;
10194 (void) &quotef;
10195 (void) &dblquote;
10196 (void) &varnest;
10197 (void) &arinest;
10198 (void) &parenlevel;
10199 (void) &dqvarnest;
10200 (void) &oldstyle;
10201 (void) &prevsyntax;
10202 (void) &syntax;
10203#endif
10204
10205 startlinno = plinno;
10206 dblquote = 0;
10207 if (syntax == DQSYNTAX)
10208 dblquote = 1;
10209 quotef = 0;
10210 bqlist = NULL;
10211 varnest = 0;
10212 arinest = 0;
10213 parenlevel = 0;
10214 dqvarnest = 0;
10215
10216 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010217 loop: { /* for each line, until end of word */
10218 CHECKEND(); /* set c to PEOF if at end of here document */
10219 for (;;) { /* until end of line or end of word */
10220 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10221 switch(SIT(c, syntax)) {
10222 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010223 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010224 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010225 USTPUTC(c, out);
10226 plinno++;
10227 if (doprompt)
10228 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010229 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010230 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010231 case CWORD:
10232 USTPUTC(c, out);
10233 break;
10234 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010235 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010236 USTPUTC(CTLESC, out);
10237 USTPUTC(c, out);
10238 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010239 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010240 c = pgetc2();
10241 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010242 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010243 USTPUTC('\\', out);
10244 pungetc();
10245 } else if (c == '\n') {
10246 if (doprompt)
10247 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010248 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010249 if (
10250 dblquote &&
10251 c != '\\' && c != '`' &&
10252 c != '$' && (
10253 c != '"' ||
10254 eofmark != NULL
10255 )
10256 ) {
10257 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010258 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010259 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010260 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010261 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010262 USTPUTC(c, out);
10263 quotef++;
10264 }
10265 break;
10266 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010267 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010268quotemark:
10269 if (eofmark == NULL) {
10270 USTPUTC(CTLQUOTEMARK, out);
10271 }
Eric Andersencb57d552001-06-28 07:25:16 +000010272 break;
10273 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010274 syntax = DQSYNTAX;
10275 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010276 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010277 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010278 if (eofmark != NULL && arinest == 0 &&
10279 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010280 USTPUTC(c, out);
10281 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010282 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010283 syntax = BASESYNTAX;
10284 dblquote = 0;
10285 }
10286 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010287 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010288 }
10289 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010290 case CVAR: /* '$' */
10291 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010292 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010293 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010294 if (varnest > 0) {
10295 varnest--;
10296 if (dqvarnest > 0) {
10297 dqvarnest--;
10298 }
10299 USTPUTC(CTLENDVAR, out);
10300 } else {
10301 USTPUTC(c, out);
10302 }
10303 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010304#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010305 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010306 parenlevel++;
10307 USTPUTC(c, out);
10308 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010309 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010310 if (parenlevel > 0) {
10311 USTPUTC(c, out);
10312 --parenlevel;
10313 } else {
10314 if (pgetc() == ')') {
10315 if (--arinest == 0) {
10316 USTPUTC(CTLENDARI, out);
10317 syntax = prevsyntax;
10318 if (syntax == DQSYNTAX)
10319 dblquote = 1;
10320 else
10321 dblquote = 0;
10322 } else
10323 USTPUTC(')', out);
10324 } else {
10325 /*
10326 * unbalanced parens
10327 * (don't 2nd guess - no error)
10328 */
10329 pungetc();
10330 USTPUTC(')', out);
10331 }
10332 }
10333 break;
10334#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010335 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010336 PARSEBACKQOLD();
10337 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010338 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010339 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010340 case CIGN:
10341 break;
10342 default:
10343 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010344 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010345#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010346 if (c != PEOA)
10347#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010348 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010349
Eric Andersencb57d552001-06-28 07:25:16 +000010350 }
10351 c = pgetc_macro();
10352 }
10353 }
Eric Andersenc470f442003-07-28 09:56:35 +000010354endword:
10355#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010356 if (syntax == ARISYNTAX)
10357 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010358#endif
10359 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010360 synerror("Unterminated quoted string");
10361 if (varnest != 0) {
10362 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010363 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010364 synerror("Missing '}'");
10365 }
10366 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010367 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010368 out = stackblock();
10369 if (eofmark == NULL) {
10370 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010371 && quotef == 0
10372 && len <= 2
10373 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010374 PARSEREDIR();
10375 return lasttoken = TREDIR;
10376 } else {
10377 pungetc();
10378 }
10379 }
10380 quoteflag = quotef;
10381 backquotelist = bqlist;
10382 grabstackblock(len);
10383 wordtext = out;
10384 return lasttoken = TWORD;
10385/* end of readtoken routine */
10386
10387
10388
10389/*
10390 * Check to see whether we are at the end of the here document. When this
10391 * is called, c is set to the first character of the next input line. If
10392 * we are at the end of the here document, this routine sets the c to PEOF.
10393 */
10394
Eric Andersenc470f442003-07-28 09:56:35 +000010395checkend: {
10396 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010397#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010398 if (c == PEOA) {
10399 c = pgetc2();
10400 }
10401#endif
10402 if (striptabs) {
10403 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010404 c = pgetc2();
10405 }
Eric Andersenc470f442003-07-28 09:56:35 +000010406 }
10407 if (c == *eofmark) {
10408 if (pfgets(line, sizeof line) != NULL) {
10409 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010410
Eric Andersenc470f442003-07-28 09:56:35 +000010411 p = line;
10412 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10413 if (*p == '\n' && *q == '\0') {
10414 c = PEOF;
10415 plinno++;
10416 needprompt = doprompt;
10417 } else {
10418 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010419 }
10420 }
10421 }
10422 }
Eric Andersenc470f442003-07-28 09:56:35 +000010423 goto checkend_return;
10424}
Eric Andersencb57d552001-06-28 07:25:16 +000010425
10426
10427/*
10428 * Parse a redirection operator. The variable "out" points to a string
10429 * specifying the fd to be redirected. The variable "c" contains the
10430 * first character of the redirection operator.
10431 */
10432
Eric Andersenc470f442003-07-28 09:56:35 +000010433parseredir: {
10434 char fd = *out;
10435 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010436
Eric Andersenc470f442003-07-28 09:56:35 +000010437 np = (union node *)stalloc(sizeof (struct nfile));
10438 if (c == '>') {
10439 np->nfile.fd = 1;
10440 c = pgetc();
10441 if (c == '>')
10442 np->type = NAPPEND;
10443 else if (c == '|')
10444 np->type = NCLOBBER;
10445 else if (c == '&')
10446 np->type = NTOFD;
10447 else {
10448 np->type = NTO;
10449 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010450 }
Eric Andersenc470f442003-07-28 09:56:35 +000010451 } else { /* c == '<' */
10452 np->nfile.fd = 0;
10453 switch (c = pgetc()) {
10454 case '<':
10455 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10456 np = (union node *)stalloc(sizeof (struct nhere));
10457 np->nfile.fd = 0;
10458 }
10459 np->type = NHERE;
10460 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10461 heredoc->here = np;
10462 if ((c = pgetc()) == '-') {
10463 heredoc->striptabs = 1;
10464 } else {
10465 heredoc->striptabs = 0;
10466 pungetc();
10467 }
10468 break;
10469
10470 case '&':
10471 np->type = NFROMFD;
10472 break;
10473
10474 case '>':
10475 np->type = NFROMTO;
10476 break;
10477
10478 default:
10479 np->type = NFROM;
10480 pungetc();
10481 break;
10482 }
Eric Andersencb57d552001-06-28 07:25:16 +000010483 }
Eric Andersenc470f442003-07-28 09:56:35 +000010484 if (fd != '\0')
10485 np->nfile.fd = digit_val(fd);
10486 redirnode = np;
10487 goto parseredir_return;
10488}
Eric Andersencb57d552001-06-28 07:25:16 +000010489
10490
10491/*
10492 * Parse a substitution. At this point, we have read the dollar sign
10493 * and nothing else.
10494 */
10495
Eric Andersenc470f442003-07-28 09:56:35 +000010496parsesub: {
10497 int subtype;
10498 int typeloc;
10499 int flags;
10500 char *p;
10501 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010502
Eric Andersenc470f442003-07-28 09:56:35 +000010503 c = pgetc();
10504 if (
10505 c <= PEOA_OR_PEOF ||
10506 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10507 ) {
10508 USTPUTC('$', out);
10509 pungetc();
10510 } else if (c == '(') { /* $(command) or $((arith)) */
10511 if (pgetc() == '(') {
10512#ifdef CONFIG_ASH_MATH_SUPPORT
10513 PARSEARITH();
10514#else
10515 synerror("We unsupport $((arith))");
10516#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010517 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010518 pungetc();
10519 PARSEBACKQNEW();
10520 }
10521 } else {
10522 USTPUTC(CTLVAR, out);
10523 typeloc = out - (char *)stackblock();
10524 USTPUTC(VSNORMAL, out);
10525 subtype = VSNORMAL;
10526 if (c == '{') {
10527 c = pgetc();
10528 if (c == '#') {
10529 if ((c = pgetc()) == '}')
10530 c = '#';
10531 else
10532 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010533 }
Eric Andersenc470f442003-07-28 09:56:35 +000010534 else
10535 subtype = 0;
10536 }
10537 if (c > PEOA_OR_PEOF && is_name(c)) {
10538 do {
10539 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010540 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010541 } while (c > PEOA_OR_PEOF && is_in_name(c));
10542 } else if (is_digit(c)) {
10543 do {
10544 STPUTC(c, out);
10545 c = pgetc();
10546 } while (is_digit(c));
10547 }
10548 else if (is_special(c)) {
10549 USTPUTC(c, out);
10550 c = pgetc();
10551 }
10552 else
10553badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010554
Eric Andersenc470f442003-07-28 09:56:35 +000010555 STPUTC('=', out);
10556 flags = 0;
10557 if (subtype == 0) {
10558 switch (c) {
10559 case ':':
10560 flags = VSNUL;
10561 c = pgetc();
10562 /*FALLTHROUGH*/
10563 default:
10564 p = strchr(types, c);
10565 if (p == NULL)
10566 goto badsub;
10567 subtype = p - types + VSNORMAL;
10568 break;
10569 case '%':
10570 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010571 {
10572 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010573 subtype = c == '#' ? VSTRIMLEFT :
10574 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010575 c = pgetc();
10576 if (c == cc)
10577 subtype++;
10578 else
10579 pungetc();
10580 break;
10581 }
10582 }
Eric Andersenc470f442003-07-28 09:56:35 +000010583 } else {
10584 pungetc();
10585 }
10586 if (dblquote || arinest)
10587 flags |= VSQUOTE;
10588 *((char *)stackblock() + typeloc) = subtype | flags;
10589 if (subtype != VSNORMAL) {
10590 varnest++;
10591 if (dblquote || arinest) {
10592 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010593 }
10594 }
10595 }
Eric Andersenc470f442003-07-28 09:56:35 +000010596 goto parsesub_return;
10597}
Eric Andersencb57d552001-06-28 07:25:16 +000010598
10599
10600/*
10601 * Called to parse command substitutions. Newstyle is set if the command
10602 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10603 * list of commands (passed by reference), and savelen is the number of
10604 * characters on the top of the stack which must be preserved.
10605 */
10606
Eric Andersenc470f442003-07-28 09:56:35 +000010607parsebackq: {
10608 struct nodelist **nlpp;
10609 int savepbq;
10610 union node *n;
10611 char *volatile str;
10612 struct jmploc jmploc;
10613 struct jmploc *volatile savehandler;
10614 size_t savelen;
10615 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010616#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010617 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010618#endif
10619
Eric Andersenc470f442003-07-28 09:56:35 +000010620 savepbq = parsebackquote;
10621 if (setjmp(jmploc.loc)) {
10622 if (str)
10623 ckfree(str);
10624 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010625 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010626 longjmp(handler->loc, 1);
10627 }
10628 INTOFF;
10629 str = NULL;
10630 savelen = out - (char *)stackblock();
10631 if (savelen > 0) {
10632 str = ckmalloc(savelen);
10633 memcpy(str, stackblock(), savelen);
10634 }
10635 savehandler = handler;
10636 handler = &jmploc;
10637 INTON;
10638 if (oldstyle) {
10639 /* We must read until the closing backquote, giving special
10640 treatment to some slashes, and then push the string and
10641 reread it as input, interpreting it normally. */
10642 char *pout;
10643 int pc;
10644 size_t psavelen;
10645 char *pstr;
10646
10647
10648 STARTSTACKSTR(pout);
10649 for (;;) {
10650 if (needprompt) {
10651 setprompt(2);
10652 needprompt = 0;
10653 }
10654 switch (pc = pgetc()) {
10655 case '`':
10656 goto done;
10657
10658 case '\\':
10659 if ((pc = pgetc()) == '\n') {
10660 plinno++;
10661 if (doprompt)
10662 setprompt(2);
10663 /*
10664 * If eating a newline, avoid putting
10665 * the newline into the new character
10666 * stream (via the STPUTC after the
10667 * switch).
10668 */
10669 continue;
10670 }
10671 if (pc != '\\' && pc != '`' && pc != '$'
10672 && (!dblquote || pc != '"'))
10673 STPUTC('\\', pout);
10674 if (pc > PEOA_OR_PEOF) {
10675 break;
10676 }
10677 /* fall through */
10678
10679 case PEOF:
10680#ifdef CONFIG_ASH_ALIAS
10681 case PEOA:
10682#endif
10683 startlinno = plinno;
10684 synerror("EOF in backquote substitution");
10685
10686 case '\n':
10687 plinno++;
10688 needprompt = doprompt;
10689 break;
10690
10691 default:
10692 break;
10693 }
10694 STPUTC(pc, pout);
10695 }
10696done:
10697 STPUTC('\0', pout);
10698 psavelen = pout - (char *)stackblock();
10699 if (psavelen > 0) {
10700 pstr = grabstackstr(pout);
10701 setinputstring(pstr);
10702 }
10703 }
10704 nlpp = &bqlist;
10705 while (*nlpp)
10706 nlpp = &(*nlpp)->next;
10707 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10708 (*nlpp)->next = NULL;
10709 parsebackquote = oldstyle;
10710
10711 if (oldstyle) {
10712 saveprompt = doprompt;
10713 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010714 }
10715
Eric Andersenc470f442003-07-28 09:56:35 +000010716 n = list(2);
10717
10718 if (oldstyle)
10719 doprompt = saveprompt;
10720 else {
10721 if (readtoken() != TRP)
10722 synexpect(TRP);
10723 }
10724
10725 (*nlpp)->n = n;
10726 if (oldstyle) {
10727 /*
10728 * Start reading from old file again, ignoring any pushed back
10729 * tokens left from the backquote parsing
10730 */
10731 popfile();
10732 tokpushback = 0;
10733 }
10734 while (stackblocksize() <= savelen)
10735 growstackblock();
10736 STARTSTACKSTR(out);
10737 if (str) {
10738 memcpy(out, str, savelen);
10739 STADJUST(savelen, out);
10740 INTOFF;
10741 ckfree(str);
10742 str = NULL;
10743 INTON;
10744 }
10745 parsebackquote = savepbq;
10746 handler = savehandler;
10747 if (arinest || dblquote)
10748 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10749 else
10750 USTPUTC(CTLBACKQ, out);
10751 if (oldstyle)
10752 goto parsebackq_oldreturn;
10753 else
10754 goto parsebackq_newreturn;
10755}
10756
10757#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010758/*
10759 * Parse an arithmetic expansion (indicate start of one and set state)
10760 */
Eric Andersenc470f442003-07-28 09:56:35 +000010761parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010762
Eric Andersenc470f442003-07-28 09:56:35 +000010763 if (++arinest == 1) {
10764 prevsyntax = syntax;
10765 syntax = ARISYNTAX;
10766 USTPUTC(CTLARI, out);
10767 if (dblquote)
10768 USTPUTC('"',out);
10769 else
10770 USTPUTC(' ',out);
10771 } else {
10772 /*
10773 * we collapse embedded arithmetic expansion to
10774 * parenthesis, which should be equivalent
10775 */
10776 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010777 }
Eric Andersenc470f442003-07-28 09:56:35 +000010778 goto parsearith_return;
10779}
10780#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010781
Eric Andersenc470f442003-07-28 09:56:35 +000010782} /* end of readtoken */
10783
Eric Andersencb57d552001-06-28 07:25:16 +000010784
10785
Eric Andersencb57d552001-06-28 07:25:16 +000010786/*
10787 * Returns true if the text contains nothing to expand (no dollar signs
10788 * or backquotes).
10789 */
10790
Eric Andersenc470f442003-07-28 09:56:35 +000010791static int
10792noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010793{
Eric Andersencb57d552001-06-28 07:25:16 +000010794 char *p;
10795 char c;
10796
10797 p = text;
10798 while ((c = *p++) != '\0') {
10799 if (c == CTLQUOTEMARK)
10800 continue;
10801 if (c == CTLESC)
10802 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010803 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010804 return 0;
10805 }
10806 return 1;
10807}
10808
10809
10810/*
Eric Andersenc470f442003-07-28 09:56:35 +000010811 * Return of a legal variable name (a letter or underscore followed by zero or
10812 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010813 */
10814
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010815static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010816endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010817{
Eric Andersenc470f442003-07-28 09:56:35 +000010818 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010819
Eric Andersenc470f442003-07-28 09:56:35 +000010820 p = (char *) name;
10821 if (! is_name(*p))
10822 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010823 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010824 if (! is_in_name(*p))
10825 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010826 }
Eric Andersenc470f442003-07-28 09:56:35 +000010827 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010828}
10829
10830
10831/*
10832 * Called when an unexpected token is read during the parse. The argument
10833 * is the token that is expected, or -1 if more than one type of token can
10834 * occur at this point.
10835 */
10836
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010837static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010838{
10839 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010840 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010841
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010842 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10843 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010844 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010845 synerror(msg);
10846 /* NOTREACHED */
10847}
10848
Eric Andersenc470f442003-07-28 09:56:35 +000010849static void
10850synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010851{
Eric Andersenc470f442003-07-28 09:56:35 +000010852 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010853 /* NOTREACHED */
10854}
10855
Eric Andersencb57d552001-06-28 07:25:16 +000010856
10857/*
10858 * called by editline -- any expansions to the prompt
10859 * should be added here.
10860 */
Eric Andersenc470f442003-07-28 09:56:35 +000010861
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010862static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010863{
Eric Andersenc470f442003-07-28 09:56:35 +000010864 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010865
10866 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010867 case 1:
10868 prompt = ps1val();
10869 break;
10870 case 2:
10871 prompt = ps2val();
10872 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010873 default: /* 0 */
10874 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010875 }
10876 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010877}
10878
Eric Andersencb57d552001-06-28 07:25:16 +000010879
Eric Andersenc470f442003-07-28 09:56:35 +000010880static const char *const *findkwd(const char *s)
10881{
10882 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010883 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010884 sizeof(const char *), pstrcmp);
10885}
10886
10887/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10888
Eric Andersencb57d552001-06-28 07:25:16 +000010889/*
10890 * Code for dealing with input/output redirection.
10891 */
10892
Eric Andersenc470f442003-07-28 09:56:35 +000010893#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010894#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010895# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010896#else
10897# define PIPESIZE PIPE_BUF
10898#endif
10899
Eric Andersen62483552001-07-10 06:09:16 +000010900/*
10901 * Open a file in noclobber mode.
10902 * The code was copied from bash.
10903 */
Eric Andersenc470f442003-07-28 09:56:35 +000010904static inline int
10905noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010906{
10907 int r, fd;
10908 struct stat finfo, finfo2;
10909
10910 /*
10911 * If the file exists and is a regular file, return an error
10912 * immediately.
10913 */
10914 r = stat(fname, &finfo);
10915 if (r == 0 && S_ISREG(finfo.st_mode)) {
10916 errno = EEXIST;
10917 return -1;
10918 }
10919
10920 /*
10921 * If the file was not present (r != 0), make sure we open it
10922 * exclusively so that if it is created before we open it, our open
10923 * will fail. Make sure that we do not truncate an existing file.
10924 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10925 * file was not a regular file, we leave O_EXCL off.
10926 */
10927 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010928 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10929 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010930
10931 /* If the open failed, return the file descriptor right away. */
10932 if (fd < 0)
10933 return fd;
10934
10935 /*
10936 * OK, the open succeeded, but the file may have been changed from a
10937 * non-regular file to a regular file between the stat and the open.
10938 * We are assuming that the O_EXCL open handles the case where FILENAME
10939 * did not exist and is symlinked to an existing file between the stat
10940 * and open.
10941 */
10942
10943 /*
10944 * If we can open it and fstat the file descriptor, and neither check
10945 * revealed that it was a regular file, and the file has not been
10946 * replaced, return the file descriptor.
10947 */
Eric Andersenc470f442003-07-28 09:56:35 +000010948 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10949 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010950 return fd;
10951
10952 /* The file has been replaced. badness. */
10953 close(fd);
10954 errno = EEXIST;
10955 return -1;
10956}
Eric Andersencb57d552001-06-28 07:25:16 +000010957
10958/*
Eric Andersen62483552001-07-10 06:09:16 +000010959 * Handle here documents. Normally we fork off a process to write the
10960 * data to a pipe. If the document is short, we can stuff the data in
10961 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010962 */
10963
Eric Andersenc470f442003-07-28 09:56:35 +000010964static inline int
10965openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010966{
10967 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010968 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010969
Eric Andersen62483552001-07-10 06:09:16 +000010970 if (pipe(pip) < 0)
10971 error("Pipe call failed");
10972 if (redir->type == NHERE) {
10973 len = strlen(redir->nhere.doc->narg.text);
10974 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010975 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010976 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010977 }
Eric Andersencb57d552001-06-28 07:25:16 +000010978 }
Eric Andersenc470f442003-07-28 09:56:35 +000010979 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010980 close(pip[0]);
10981 signal(SIGINT, SIG_IGN);
10982 signal(SIGQUIT, SIG_IGN);
10983 signal(SIGHUP, SIG_IGN);
10984#ifdef SIGTSTP
10985 signal(SIGTSTP, SIG_IGN);
10986#endif
10987 signal(SIGPIPE, SIG_DFL);
10988 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000010989 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010990 else
10991 expandhere(redir->nhere.doc, pip[1]);
10992 _exit(0);
10993 }
Eric Andersenc470f442003-07-28 09:56:35 +000010994out:
Eric Andersen62483552001-07-10 06:09:16 +000010995 close(pip[1]);
10996 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010997}
10998
Eric Andersenc470f442003-07-28 09:56:35 +000010999static int
11000openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011001{
Eric Andersencb57d552001-06-28 07:25:16 +000011002 char *fname;
11003 int f;
11004
11005 switch (redir->nfile.type) {
11006 case NFROM:
11007 fname = redir->nfile.expfname;
11008 if ((f = open(fname, O_RDONLY)) < 0)
11009 goto eopen;
11010 break;
11011 case NFROMTO:
11012 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011013 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011014 goto ecreate;
11015 break;
11016 case NTO:
11017 /* Take care of noclobber mode. */
11018 if (Cflag) {
11019 fname = redir->nfile.expfname;
11020 if ((f = noclobberopen(fname)) < 0)
11021 goto ecreate;
11022 break;
11023 }
Eric Andersenc470f442003-07-28 09:56:35 +000011024 /* FALLTHROUGH */
11025 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011026 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011027 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011028 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011029 break;
11030 case NAPPEND:
11031 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011032 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011033 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011034 break;
11035 default:
11036#ifdef DEBUG
11037 abort();
11038#endif
11039 /* Fall through to eliminate warning. */
11040 case NTOFD:
11041 case NFROMFD:
11042 f = -1;
11043 break;
11044 case NHERE:
11045 case NXHERE:
11046 f = openhere(redir);
11047 break;
11048 }
11049
11050 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011051ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011052 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011053eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011054 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11055}
11056
Eric Andersenc470f442003-07-28 09:56:35 +000011057static inline void
11058dupredirect(union node *redir, int f)
11059{
11060 int fd = redir->nfile.fd;
11061
11062 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11063 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11064 copyfd(redir->ndup.dupfd, fd);
11065 }
11066 return;
11067 }
11068
11069 if (f != fd) {
11070 copyfd(f, fd);
11071 close(f);
11072 }
11073 return;
11074}
Eric Andersencb57d552001-06-28 07:25:16 +000011075
Eric Andersen62483552001-07-10 06:09:16 +000011076/*
11077 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11078 * old file descriptors are stashed away so that the redirection can be
11079 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11080 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011081 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011082 */
11083
Eric Andersenc470f442003-07-28 09:56:35 +000011084static void
11085redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011086{
11087 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011088 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011089 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011090 int fd;
11091 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011092 int *p;
11093 nullredirs++;
11094 if (!redir) {
11095 return;
Eric Andersen62483552001-07-10 06:09:16 +000011096 }
Eric Andersenc470f442003-07-28 09:56:35 +000011097 sv = NULL;
11098 INTOFF;
11099 if (flags & REDIR_PUSH) {
11100 struct redirtab *q;
11101 q = ckmalloc(sizeof (struct redirtab));
11102 q->next = redirlist;
11103 redirlist = q;
11104 q->nullredirs = nullredirs - 1;
11105 for (i = 0 ; i < 10 ; i++)
11106 q->renamed[i] = EMPTY;
11107 nullredirs = 0;
11108 sv = q;
11109 }
11110 n = redir;
11111 do {
Eric Andersen62483552001-07-10 06:09:16 +000011112 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011113 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011114 n->ndup.dupfd == fd)
11115 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011116
Eric Andersen62483552001-07-10 06:09:16 +000011117 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011118 if (fd == newfd)
11119 continue;
11120 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11121 i = fcntl(fd, F_DUPFD, 10);
11122
11123 if (i == -1) {
11124 i = errno;
11125 if (i != EBADF) {
11126 close(newfd);
11127 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011128 error("%d: %m", fd);
11129 /* NOTREACHED */
11130 }
Eric Andersenc470f442003-07-28 09:56:35 +000011131 } else {
11132 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011133 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011134 }
Eric Andersenc470f442003-07-28 09:56:35 +000011135 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011136 close(fd);
11137 }
Eric Andersenc470f442003-07-28 09:56:35 +000011138 dupredirect(n, newfd);
11139 } while ((n = n->nfile.next));
11140 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011141 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11142 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011143}
11144
11145
Eric Andersencb57d552001-06-28 07:25:16 +000011146/*
11147 * Undo the effects of the last redirection.
11148 */
11149
Eric Andersenc470f442003-07-28 09:56:35 +000011150void
11151popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011152{
Eric Andersenc470f442003-07-28 09:56:35 +000011153 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011154 int i;
11155
Eric Andersenc470f442003-07-28 09:56:35 +000011156 if (--nullredirs >= 0)
11157 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011158 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011159 rp = redirlist;
11160 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011161 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011162 if (!drop) {
11163 close(i);
11164 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011165 }
Eric Andersenc470f442003-07-28 09:56:35 +000011166 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011167 }
11168 }
11169 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011170 nullredirs = rp->nullredirs;
11171 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011172 INTON;
11173}
11174
11175/*
Eric Andersenc470f442003-07-28 09:56:35 +000011176 * Undo all redirections. Called on error or interrupt.
11177 */
11178
11179/*
Eric Andersencb57d552001-06-28 07:25:16 +000011180 * Discard all saved file descriptors.
11181 */
11182
Eric Andersenc470f442003-07-28 09:56:35 +000011183void
11184clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011185{
Eric Andersenc470f442003-07-28 09:56:35 +000011186 for (;;) {
11187 nullredirs = 0;
11188 if (!redirlist)
11189 break;
11190 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011191 }
Eric Andersencb57d552001-06-28 07:25:16 +000011192}
11193
11194
Eric Andersencb57d552001-06-28 07:25:16 +000011195/*
11196 * Copy a file descriptor to be >= to. Returns -1
11197 * if the source file descriptor is closed, EMPTY if there are no unused
11198 * file descriptors left.
11199 */
11200
Eric Andersenc470f442003-07-28 09:56:35 +000011201int
11202copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011203{
11204 int newfd;
11205
11206 newfd = fcntl(from, F_DUPFD, to);
11207 if (newfd < 0) {
11208 if (errno == EMFILE)
11209 return EMPTY;
11210 else
Eric Andersen2870d962001-07-02 17:27:21 +000011211 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011212 }
11213 return newfd;
11214}
11215
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011216
Eric Andersenc470f442003-07-28 09:56:35 +000011217int
11218redirectsafe(union node *redir, int flags)
11219{
11220 int err;
11221 volatile int saveint;
11222 struct jmploc *volatile savehandler = handler;
11223 struct jmploc jmploc;
11224
11225 SAVEINT(saveint);
11226 if (!(err = setjmp(jmploc.loc) * 2)) {
11227 handler = &jmploc;
11228 redirect(redir, flags);
11229 }
11230 handler = savehandler;
11231 if (err && exception != EXERROR)
11232 longjmp(handler->loc, 1);
11233 RESTOREINT(saveint);
11234 return err;
11235}
11236
11237/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11238
11239#ifdef DEBUG
11240static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011241static void shcmd(union node *, FILE *);
11242static void sharg(union node *, FILE *);
11243static void indent(int, char *, FILE *);
11244static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011245
11246
Eric Andersenc470f442003-07-28 09:56:35 +000011247void
11248showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011249{
11250 trputs("showtree called\n");
11251 shtree(n, 1, NULL, stdout);
11252}
Eric Andersencb57d552001-06-28 07:25:16 +000011253
Eric Andersenc470f442003-07-28 09:56:35 +000011254
11255static void
11256shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011257{
11258 struct nodelist *lp;
11259 const char *s;
11260
11261 if (n == NULL)
11262 return;
11263
11264 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011265 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011266 case NSEMI:
11267 s = "; ";
11268 goto binop;
11269 case NAND:
11270 s = " && ";
11271 goto binop;
11272 case NOR:
11273 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011274binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011275 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011276 /* if (ind < 0) */
11277 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011278 shtree(n->nbinary.ch2, ind, NULL, fp);
11279 break;
11280 case NCMD:
11281 shcmd(n, fp);
11282 if (ind >= 0)
11283 putc('\n', fp);
11284 break;
11285 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011286 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011287 shcmd(lp->n, fp);
11288 if (lp->next)
11289 fputs(" | ", fp);
11290 }
11291 if (n->npipe.backgnd)
11292 fputs(" &", fp);
11293 if (ind >= 0)
11294 putc('\n', fp);
11295 break;
11296 default:
11297 fprintf(fp, "<node type %d>", n->type);
11298 if (ind >= 0)
11299 putc('\n', fp);
11300 break;
11301 }
11302}
11303
11304
Eric Andersenc470f442003-07-28 09:56:35 +000011305static void
11306shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011307{
11308 union node *np;
11309 int first;
11310 const char *s;
11311 int dftfd;
11312
11313 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011314 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11315 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011316 putchar(' ');
11317 sharg(np, fp);
11318 first = 0;
11319 }
Eric Andersenc470f442003-07-28 09:56:35 +000011320 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11321 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011322 putchar(' ');
11323 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011324 case NTO: s = ">"; dftfd = 1; break;
11325 case NCLOBBER: s = ">|"; dftfd = 1; break;
11326 case NAPPEND: s = ">>"; dftfd = 1; break;
11327 case NTOFD: s = ">&"; dftfd = 1; break;
11328 case NFROM: s = "<"; dftfd = 0; break;
11329 case NFROMFD: s = "<&"; dftfd = 0; break;
11330 case NFROMTO: s = "<>"; dftfd = 0; break;
11331 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011332 }
11333 if (np->nfile.fd != dftfd)
11334 fprintf(fp, "%d", np->nfile.fd);
11335 fputs(s, fp);
11336 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11337 fprintf(fp, "%d", np->ndup.dupfd);
11338 } else {
11339 sharg(np->nfile.fname, fp);
11340 }
11341 first = 0;
11342 }
11343}
11344
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011345
Eric Andersenc470f442003-07-28 09:56:35 +000011346
11347static void
11348sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011349{
Eric Andersencb57d552001-06-28 07:25:16 +000011350 char *p;
11351 struct nodelist *bqlist;
11352 int subtype;
11353
11354 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011355 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011356 abort();
11357 }
11358 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011359 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011360 switch (*p) {
11361 case CTLESC:
11362 putc(*++p, fp);
11363 break;
11364 case CTLVAR:
11365 putc('$', fp);
11366 putc('{', fp);
11367 subtype = *++p;
11368 if (subtype == VSLENGTH)
11369 putc('#', fp);
11370
11371 while (*p != '=')
11372 putc(*p++, fp);
11373
11374 if (subtype & VSNUL)
11375 putc(':', fp);
11376
11377 switch (subtype & VSTYPE) {
11378 case VSNORMAL:
11379 putc('}', fp);
11380 break;
11381 case VSMINUS:
11382 putc('-', fp);
11383 break;
11384 case VSPLUS:
11385 putc('+', fp);
11386 break;
11387 case VSQUESTION:
11388 putc('?', fp);
11389 break;
11390 case VSASSIGN:
11391 putc('=', fp);
11392 break;
11393 case VSTRIMLEFT:
11394 putc('#', fp);
11395 break;
11396 case VSTRIMLEFTMAX:
11397 putc('#', fp);
11398 putc('#', fp);
11399 break;
11400 case VSTRIMRIGHT:
11401 putc('%', fp);
11402 break;
11403 case VSTRIMRIGHTMAX:
11404 putc('%', fp);
11405 putc('%', fp);
11406 break;
11407 case VSLENGTH:
11408 break;
11409 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011410 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011411 }
11412 break;
11413 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011414 putc('}', fp);
11415 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011416 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011417 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011418 putc('$', fp);
11419 putc('(', fp);
11420 shtree(bqlist->n, -1, NULL, fp);
11421 putc(')', fp);
11422 break;
11423 default:
11424 putc(*p, fp);
11425 break;
11426 }
11427 }
11428}
11429
11430
Eric Andersenc470f442003-07-28 09:56:35 +000011431static void
11432indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011433{
11434 int i;
11435
Eric Andersenc470f442003-07-28 09:56:35 +000011436 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011437 if (pfx && i == amount - 1)
11438 fputs(pfx, fp);
11439 putc('\t', fp);
11440 }
11441}
Eric Andersencb57d552001-06-28 07:25:16 +000011442
Eric Andersenc470f442003-07-28 09:56:35 +000011443
11444
11445/*
11446 * Debugging stuff.
11447 */
11448
11449
Eric Andersencb57d552001-06-28 07:25:16 +000011450FILE *tracefile;
11451
Eric Andersencb57d552001-06-28 07:25:16 +000011452
Eric Andersenc470f442003-07-28 09:56:35 +000011453void
11454trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011455{
Eric Andersenc470f442003-07-28 09:56:35 +000011456 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011457 return;
11458 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011459}
11460
Eric Andersenc470f442003-07-28 09:56:35 +000011461void
11462trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011463{
11464 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011465
Eric Andersenc470f442003-07-28 09:56:35 +000011466 if (debug != 1)
11467 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011468 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011469 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011470 va_end(va);
11471}
11472
Eric Andersenc470f442003-07-28 09:56:35 +000011473void
11474tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011475{
Eric Andersenc470f442003-07-28 09:56:35 +000011476 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011477 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011478 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011479}
11480
11481
Eric Andersenc470f442003-07-28 09:56:35 +000011482void
11483trputs(const char *s)
11484{
11485 if (debug != 1)
11486 return;
11487 fputs(s, tracefile);
11488}
11489
11490
11491static void
11492trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011493{
11494 char *p;
11495 char c;
11496
Eric Andersenc470f442003-07-28 09:56:35 +000011497 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011498 return;
11499 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011500 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011501 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011502 case '\n': c = 'n'; goto backslash;
11503 case '\t': c = 't'; goto backslash;
11504 case '\r': c = 'r'; goto backslash;
11505 case '"': c = '"'; goto backslash;
11506 case '\\': c = '\\'; goto backslash;
11507 case CTLESC: c = 'e'; goto backslash;
11508 case CTLVAR: c = 'v'; goto backslash;
11509 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11510 case CTLBACKQ: c = 'q'; goto backslash;
11511 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11512backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011513 putc(c, tracefile);
11514 break;
11515 default:
11516 if (*p >= ' ' && *p <= '~')
11517 putc(*p, tracefile);
11518 else {
11519 putc('\\', tracefile);
11520 putc(*p >> 6 & 03, tracefile);
11521 putc(*p >> 3 & 07, tracefile);
11522 putc(*p & 07, tracefile);
11523 }
11524 break;
11525 }
11526 }
11527 putc('"', tracefile);
11528}
11529
11530
Eric Andersenc470f442003-07-28 09:56:35 +000011531void
11532trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011533{
Eric Andersenc470f442003-07-28 09:56:35 +000011534 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011535 return;
11536 while (*ap) {
11537 trstring(*ap++);
11538 if (*ap)
11539 putc(' ', tracefile);
11540 else
11541 putc('\n', tracefile);
11542 }
Eric Andersencb57d552001-06-28 07:25:16 +000011543}
11544
11545
Eric Andersenc470f442003-07-28 09:56:35 +000011546void
11547opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011548{
Eric Andersencb57d552001-06-28 07:25:16 +000011549 char s[100];
11550#ifdef O_APPEND
11551 int flags;
11552#endif
11553
Eric Andersenc470f442003-07-28 09:56:35 +000011554 if (debug != 1) {
11555 if (tracefile)
11556 fflush(tracefile);
11557 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011558 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011559 }
Eric Andersenc470f442003-07-28 09:56:35 +000011560 scopy("./trace", s);
11561 if (tracefile) {
11562 if (!freopen(s, "a", tracefile)) {
11563 fprintf(stderr, "Can't re-open %s\n", s);
11564 debug = 0;
11565 return;
11566 }
11567 } else {
11568 if ((tracefile = fopen(s, "a")) == NULL) {
11569 fprintf(stderr, "Can't open %s\n", s);
11570 debug = 0;
11571 return;
11572 }
11573 }
Eric Andersencb57d552001-06-28 07:25:16 +000011574#ifdef O_APPEND
11575 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11576 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11577#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011578 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011579 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011580}
Eric Andersenc470f442003-07-28 09:56:35 +000011581#endif /* DEBUG */
11582
11583
11584/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11585
11586/*
11587 * Sigmode records the current value of the signal handlers for the various
11588 * modes. A value of zero means that the current handler is not known.
11589 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11590 */
11591
11592#define S_DFL 1 /* default signal handling (SIG_DFL) */
11593#define S_CATCH 2 /* signal is caught */
11594#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11595#define S_HARD_IGN 4 /* signal is ignored permenantly */
11596#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11597
Eric Andersencb57d552001-06-28 07:25:16 +000011598
11599
11600/*
Eric Andersencb57d552001-06-28 07:25:16 +000011601 * The trap builtin.
11602 */
11603
Eric Andersenc470f442003-07-28 09:56:35 +000011604int
11605trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011606{
11607 char *action;
11608 char **ap;
11609 int signo;
11610
Eric Andersenc470f442003-07-28 09:56:35 +000011611 nextopt(nullstr);
11612 ap = argptr;
11613 if (!*ap) {
11614 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011615 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011616 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011617
Eric Andersenc470f442003-07-28 09:56:35 +000011618 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011619 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011620 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011621 out1fmt("trap -- %s %s\n",
11622 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011623 }
11624 }
11625 return 0;
11626 }
Eric Andersenc470f442003-07-28 09:56:35 +000011627 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011628 action = NULL;
11629 else
11630 action = *ap++;
11631 while (*ap) {
11632 if ((signo = decode_signal(*ap, 0)) < 0)
11633 error("%s: bad trap", *ap);
11634 INTOFF;
11635 if (action) {
11636 if (action[0] == '-' && action[1] == '\0')
11637 action = NULL;
11638 else
Eric Andersenc470f442003-07-28 09:56:35 +000011639 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011640 }
Eric Andersenc470f442003-07-28 09:56:35 +000011641 if (trap[signo])
11642 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011643 trap[signo] = action;
11644 if (signo != 0)
11645 setsignal(signo);
11646 INTON;
11647 ap++;
11648 }
11649 return 0;
11650}
11651
11652
Eric Andersenc470f442003-07-28 09:56:35 +000011653/*
11654 * Clear traps on a fork.
11655 */
11656
11657void
11658clear_traps(void)
11659{
11660 char **tp;
11661
11662 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11663 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11664 INTOFF;
11665 ckfree(*tp);
11666 *tp = NULL;
11667 if (tp != &trap[0])
11668 setsignal(tp - trap);
11669 INTON;
11670 }
11671 }
11672}
11673
11674
Eric Andersencb57d552001-06-28 07:25:16 +000011675/*
11676 * Set the signal handler for the specified signal. The routine figures
11677 * out what it should be set to.
11678 */
11679
Eric Andersenc470f442003-07-28 09:56:35 +000011680void
11681setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011682{
11683 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011684 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011685 struct sigaction act;
11686
11687 if ((t = trap[signo]) == NULL)
11688 action = S_DFL;
11689 else if (*t != '\0')
11690 action = S_CATCH;
11691 else
11692 action = S_IGN;
11693 if (rootshell && action == S_DFL) {
11694 switch (signo) {
11695 case SIGINT:
11696 if (iflag || minusc || sflag == 0)
11697 action = S_CATCH;
11698 break;
11699 case SIGQUIT:
11700#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011701 if (debug)
11702 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011703#endif
11704 /* FALLTHROUGH */
11705 case SIGTERM:
11706 if (iflag)
11707 action = S_IGN;
11708 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011709#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011710 case SIGTSTP:
11711 case SIGTTOU:
11712 if (mflag)
11713 action = S_IGN;
11714 break;
11715#endif
11716 }
11717 }
11718
11719 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011720 tsig = *t;
11721 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011722 /*
11723 * current setting unknown
11724 */
11725 if (sigaction(signo, 0, &act) == -1) {
11726 /*
11727 * Pretend it worked; maybe we should give a warning
11728 * here, but other shells don't. We don't alter
11729 * sigmode, so that we retry every time.
11730 */
11731 return;
11732 }
11733 if (act.sa_handler == SIG_IGN) {
11734 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011735 signo == SIGTTIN || signo == SIGTTOU)) {
11736 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011737 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011738 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011739 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011740 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011741 }
11742 }
Eric Andersenc470f442003-07-28 09:56:35 +000011743 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011744 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011745 switch (action) {
11746 case S_CATCH:
11747 act.sa_handler = onsig;
11748 break;
11749 case S_IGN:
11750 act.sa_handler = SIG_IGN;
11751 break;
11752 default:
11753 act.sa_handler = SIG_DFL;
11754 }
Eric Andersencb57d552001-06-28 07:25:16 +000011755 *t = action;
11756 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011757 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011758 sigaction(signo, &act, 0);
11759}
11760
11761/*
11762 * Ignore a signal.
11763 */
11764
Eric Andersenc470f442003-07-28 09:56:35 +000011765void
11766ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011767{
11768 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11769 signal(signo, SIG_IGN);
11770 }
11771 sigmode[signo - 1] = S_HARD_IGN;
11772}
11773
11774
Eric Andersencb57d552001-06-28 07:25:16 +000011775/*
11776 * Signal handler.
11777 */
11778
Eric Andersenc470f442003-07-28 09:56:35 +000011779void
11780onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011781{
Eric Andersencb57d552001-06-28 07:25:16 +000011782 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011783 pendingsigs = signo;
11784
11785 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11786 if (!suppressint)
11787 onint();
11788 intpending = 1;
11789 }
Eric Andersencb57d552001-06-28 07:25:16 +000011790}
11791
11792
Eric Andersencb57d552001-06-28 07:25:16 +000011793/*
11794 * Called to execute a trap. Perhaps we should avoid entering new trap
11795 * handlers while we are executing a trap handler.
11796 */
11797
Eric Andersenc470f442003-07-28 09:56:35 +000011798void
11799dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011800{
Eric Andersenc470f442003-07-28 09:56:35 +000011801 char *p;
11802 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011803 int savestatus;
11804
Eric Andersenc470f442003-07-28 09:56:35 +000011805 savestatus = exitstatus;
11806 q = gotsig;
Glenn L McGrath2f325a02004-08-06 01:49:04 +000011807 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
Eric Andersenc470f442003-07-28 09:56:35 +000011808 *p = 0;
11809 p = trap[p - q + 1];
11810 if (!p)
11811 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011812 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011813 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011814 }
Eric Andersencb57d552001-06-28 07:25:16 +000011815}
11816
Eric Andersenc470f442003-07-28 09:56:35 +000011817
Eric Andersenc470f442003-07-28 09:56:35 +000011818/*
11819 * Controls whether the shell is interactive or not.
11820 */
11821
Eric Andersenc470f442003-07-28 09:56:35 +000011822void
11823setinteractive(int on)
11824{
11825 static int is_interactive;
11826
11827 if (++on == is_interactive)
11828 return;
11829 is_interactive = on;
11830 setsignal(SIGINT);
11831 setsignal(SIGQUIT);
11832 setsignal(SIGTERM);
11833#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11834 if(is_interactive > 1) {
11835 /* Looks like they want an interactive shell */
11836 static int do_banner;
11837
11838 if(!do_banner) {
11839 out1fmt(
11840 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11841 "Enter 'help' for a list of built-in commands.\n\n");
11842 do_banner++;
11843 }
11844 }
11845#endif
11846}
11847
11848
11849#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11850/*** List the available builtins ***/
11851
11852static int helpcmd(int argc, char **argv)
11853{
11854 int col, i;
11855
11856 out1fmt("\nBuilt-in commands:\n-------------------\n");
11857 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11858 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11859 builtincmd[i].name + 1);
11860 if (col > 60) {
11861 out1fmt("\n");
11862 col = 0;
11863 }
11864 }
11865#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11866 {
11867 extern const struct BB_applet applets[];
11868 extern const size_t NUM_APPLETS;
11869
11870 for (i = 0; i < NUM_APPLETS; i++) {
11871
11872 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11873 if (col > 60) {
11874 out1fmt("\n");
11875 col = 0;
11876 }
11877 }
11878 }
11879#endif
11880 out1fmt("\n\n");
11881 return EXIT_SUCCESS;
11882}
11883#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11884
Eric Andersencb57d552001-06-28 07:25:16 +000011885/*
11886 * Called to exit the shell.
11887 */
11888
Eric Andersenc470f442003-07-28 09:56:35 +000011889void
11890exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011891{
Eric Andersenc470f442003-07-28 09:56:35 +000011892 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011893 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011894 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011895 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011896
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011897 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011898 status = exitstatus;
11899 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011900 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011901 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011902 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011903 if ((p = trap[0]) != NULL && *p != '\0') {
11904 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011905 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011906 }
Eric Andersencb57d552001-06-28 07:25:16 +000011907 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011908 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011909#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11910 if (iflag && rootshell) {
11911 const char *hp = lookupvar("HISTFILE");
11912
11913 if(hp != NULL )
11914 save_history ( hp );
11915 }
11916#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011917out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011918 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011919 /* NOTREACHED */
11920}
11921
11922static int decode_signal(const char *string, int minsig)
11923{
11924 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011925 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011926
Eric Andersen34506362001-08-02 05:02:46 +000011927 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011928}
Eric Andersen34506362001-08-02 05:02:46 +000011929
Eric Andersenc470f442003-07-28 09:56:35 +000011930/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11931
11932static struct var *vartab[VTABSIZE];
11933
11934static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011935static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011936
11937/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011938 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011939 */
11940
Eric Andersenc470f442003-07-28 09:56:35 +000011941
11942#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011943/*
Eric Andersenc470f442003-07-28 09:56:35 +000011944 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011945 */
11946
Eric Andersenc470f442003-07-28 09:56:35 +000011947int
11948setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011949{
Eric Andersenc470f442003-07-28 09:56:35 +000011950 int err;
11951 volatile int saveint;
11952 struct jmploc *volatile savehandler = handler;
11953 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011954
Eric Andersenc470f442003-07-28 09:56:35 +000011955 SAVEINT(saveint);
11956 if (setjmp(jmploc.loc))
11957 err = 1;
11958 else {
11959 handler = &jmploc;
11960 setvar(name, val, flags);
11961 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011962 }
Eric Andersenc470f442003-07-28 09:56:35 +000011963 handler = savehandler;
11964 RESTOREINT(saveint);
11965 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011966}
Eric Andersenc470f442003-07-28 09:56:35 +000011967#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011968
11969/*
11970 * Set the value of a variable. The flags argument is ored with the
11971 * flags of the variable. If val is NULL, the variable is unset.
11972 */
11973
Eric Andersenc470f442003-07-28 09:56:35 +000011974static void
11975setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011976{
Eric Andersenc470f442003-07-28 09:56:35 +000011977 char *p, *q;
11978 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011979 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011980 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011981
Eric Andersenc470f442003-07-28 09:56:35 +000011982 q = endofname(name);
11983 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011984 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011985 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011986 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011987 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011988 if (val == NULL) {
11989 flags |= VUNSET;
11990 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011991 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011992 }
11993 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011994 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
Paul Fox8de331d2005-07-21 12:03:05 +000011995 *p++ = '\0';
11996 if (val) {
11997 p[-1] = '=';
Eric Andersenc470f442003-07-28 09:56:35 +000011998 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011999 }
Eric Andersenc470f442003-07-28 09:56:35 +000012000 *p = '\0';
12001 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012002 INTON;
12003}
12004
12005
Eric Andersencb57d552001-06-28 07:25:16 +000012006/*
12007 * Same as setvar except that the variable and value are passed in
12008 * the first argument as name=value. Since the first argument will
12009 * be actually stored in the table, it should not be a string that
12010 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012011 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012012 */
12013
Eric Andersenc470f442003-07-28 09:56:35 +000012014void
12015setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012016{
12017 struct var *vp, **vpp;
12018
12019 vpp = hashvar(s);
12020 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012021 vp = *findvar(vpp, s);
12022 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012023 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12024 const char *n;
12025
Eric Andersenc470f442003-07-28 09:56:35 +000012026 if (flags & VNOSAVE)
12027 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012028 n = vp->text;
12029 error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012030 }
Eric Andersenc470f442003-07-28 09:56:35 +000012031
12032 if (flags & VNOSET)
12033 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012034
12035 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012036 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012037
Eric Andersenc470f442003-07-28 09:56:35 +000012038 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12039 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012040
Eric Andersenc470f442003-07-28 09:56:35 +000012041 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12042 } else {
12043 if (flags & VNOSET)
12044 return;
12045 /* not found */
12046 vp = ckmalloc(sizeof (*vp));
12047 vp->next = *vpp;
12048 vp->func = NULL;
12049 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012050 }
Eric Andersenc470f442003-07-28 09:56:35 +000012051 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12052 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012053 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012054 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012055}
12056
12057
Eric Andersencb57d552001-06-28 07:25:16 +000012058/*
12059 * Process a linked list of variable assignments.
12060 */
12061
Eric Andersenc470f442003-07-28 09:56:35 +000012062static void
12063listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012064{
Eric Andersenc470f442003-07-28 09:56:35 +000012065 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012066
Eric Andersenc470f442003-07-28 09:56:35 +000012067 if (!lp)
12068 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012069 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012070 do {
12071 setvareq(lp->text, flags);
12072 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012073 INTON;
12074}
12075
12076
Eric Andersencb57d552001-06-28 07:25:16 +000012077/*
12078 * Find the value of a variable. Returns NULL if not set.
12079 */
12080
Eric Andersenc470f442003-07-28 09:56:35 +000012081static char *
12082lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012083{
Eric Andersencb57d552001-06-28 07:25:16 +000012084 struct var *v;
12085
Eric Andersen16767e22004-03-16 05:14:10 +000012086 if ((v = *findvar(hashvar(name), name))) {
12087#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012088 /*
12089 * Dynamic variables are implemented roughly the same way they are
12090 * in bash. Namely, they're "special" so long as they aren't unset.
12091 * As soon as they're unset, they're no longer dynamic, and dynamic
12092 * lookup will no longer happen at that point. -- PFM.
12093 */
Eric Andersen16767e22004-03-16 05:14:10 +000012094 if((v->flags & VDYNAMIC))
12095 (*v->func)(NULL);
12096#endif
12097 if(!(v->flags & VUNSET))
12098 return strchrnul(v->text, '=') + 1;
12099 }
Eric Andersenef02f822004-03-11 13:34:24 +000012100
Eric Andersencb57d552001-06-28 07:25:16 +000012101 return NULL;
12102}
12103
12104
Eric Andersencb57d552001-06-28 07:25:16 +000012105/*
12106 * Search the environment of a builtin command.
12107 */
12108
Eric Andersenc470f442003-07-28 09:56:35 +000012109static char *
12110bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012111{
Eric Andersenc470f442003-07-28 09:56:35 +000012112 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012113
Eric Andersenc470f442003-07-28 09:56:35 +000012114 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012115 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012116 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012117 }
12118 return lookupvar(name);
12119}
12120
12121
Eric Andersencb57d552001-06-28 07:25:16 +000012122/*
Eric Andersenc470f442003-07-28 09:56:35 +000012123 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012124 */
12125
Eric Andersenc470f442003-07-28 09:56:35 +000012126static char **
12127listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012128{
Eric Andersencb57d552001-06-28 07:25:16 +000012129 struct var **vpp;
12130 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012131 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012132 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012133
Eric Andersenc470f442003-07-28 09:56:35 +000012134 STARTSTACKSTR(ep);
12135 vpp = vartab;
12136 mask = on | off;
12137 do {
12138 for (vp = *vpp ; vp ; vp = vp->next)
12139 if ((vp->flags & mask) == on) {
12140 if (ep == stackstrend())
12141 ep = growstackstr();
12142 *ep++ = (char *) vp->text;
12143 }
12144 } while (++vpp < vartab + VTABSIZE);
12145 if (ep == stackstrend())
12146 ep = growstackstr();
12147 if (end)
12148 *end = ep;
12149 *ep++ = NULL;
12150 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012151}
12152
12153
12154/*
Eric Andersenc470f442003-07-28 09:56:35 +000012155 * POSIX requires that 'set' (but not export or readonly) output the
12156 * variables in lexicographic order - by the locale's collating order (sigh).
12157 * Maybe we could keep them in an ordered balanced binary tree
12158 * instead of hashed lists.
12159 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012160 */
12161
Eric Andersenc470f442003-07-28 09:56:35 +000012162static int
12163showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012164{
Eric Andersenc470f442003-07-28 09:56:35 +000012165 const char *sep;
12166 char **ep, **epend;
12167
12168 ep = listvars(on, off, &epend);
12169 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12170
12171 sep = *sep_prefix ? spcstr : sep_prefix;
12172
12173 for (; ep < epend; ep++) {
12174 const char *p;
12175 const char *q;
12176
12177 p = strchrnul(*ep, '=');
12178 q = nullstr;
12179 if (*p)
12180 q = single_quote(++p);
12181
12182 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12183 }
12184
Eric Andersencb57d552001-06-28 07:25:16 +000012185 return 0;
12186}
12187
12188
12189
12190/*
12191 * The export and readonly commands.
12192 */
12193
Eric Andersenc470f442003-07-28 09:56:35 +000012194static int
12195exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012196{
12197 struct var *vp;
12198 char *name;
12199 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012200 char **aptr;
12201 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12202 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012203
Eric Andersenc470f442003-07-28 09:56:35 +000012204 notp = nextopt("p") - 'p';
12205 if (notp && ((name = *(aptr = argptr)))) {
12206 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012207 if ((p = strchr(name, '=')) != NULL) {
12208 p++;
12209 } else {
12210 if ((vp = *findvar(hashvar(name), name))) {
12211 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012212 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012213 }
12214 }
12215 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012216 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012217 } else {
12218 showvars(argv[0], flag, 0);
12219 }
12220 return 0;
12221}
12222
Eric Andersen34506362001-08-02 05:02:46 +000012223
Eric Andersencb57d552001-06-28 07:25:16 +000012224/*
Eric Andersencb57d552001-06-28 07:25:16 +000012225 * Make a variable a local variable. When a variable is made local, it's
12226 * value and flags are saved in a localvar structure. The saved values
12227 * will be restored when the shell function returns. We handle the name
12228 * "-" as a special case.
12229 */
12230
Eric Andersenc470f442003-07-28 09:56:35 +000012231static inline void
12232mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012233{
Eric Andersencb57d552001-06-28 07:25:16 +000012234 struct localvar *lvp;
12235 struct var **vpp;
12236 struct var *vp;
12237
12238 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012239 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012240 if (name[0] == '-' && name[1] == '\0') {
12241 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012242 p = ckmalloc(sizeof(optlist));
12243 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012244 vp = NULL;
12245 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012246 char *eq;
12247
Eric Andersencb57d552001-06-28 07:25:16 +000012248 vpp = hashvar(name);
12249 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012250 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012251 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012252 if (eq)
12253 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012254 else
12255 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012256 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012257 lvp->flags = VUNSET;
12258 } else {
12259 lvp->text = vp->text;
12260 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012261 vp->flags |= VSTRFIXED|VTEXTFIXED;
12262 if (eq)
12263 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012264 }
12265 }
12266 lvp->vp = vp;
12267 lvp->next = localvars;
12268 localvars = lvp;
12269 INTON;
12270}
12271
Eric Andersenc470f442003-07-28 09:56:35 +000012272/*
12273 * The "local" command.
12274 */
12275
12276static int
12277localcmd(int argc, char **argv)
12278{
12279 char *name;
12280
12281 argv = argptr;
12282 while ((name = *argv++) != NULL) {
12283 mklocal(name);
12284 }
12285 return 0;
12286}
12287
12288
Eric Andersencb57d552001-06-28 07:25:16 +000012289/*
12290 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012291 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012292 */
12293
Eric Andersenc470f442003-07-28 09:56:35 +000012294static void
12295poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012296{
Eric Andersencb57d552001-06-28 07:25:16 +000012297 struct localvar *lvp;
12298 struct var *vp;
12299
12300 while ((lvp = localvars) != NULL) {
12301 localvars = lvp->next;
12302 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012303 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12304 if (vp == NULL) { /* $- saved */
12305 memcpy(optlist, lvp->text, sizeof(optlist));
12306 ckfree(lvp->text);
12307 optschanged();
12308 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12309 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012310 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012311 if (vp->func)
12312 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12313 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12314 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012315 vp->flags = lvp->flags;
12316 vp->text = lvp->text;
12317 }
Eric Andersenc470f442003-07-28 09:56:35 +000012318 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012319 }
12320}
12321
12322
Eric Andersencb57d552001-06-28 07:25:16 +000012323/*
12324 * The unset builtin command. We unset the function before we unset the
12325 * variable to allow a function to be unset when there is a readonly variable
12326 * with the same name.
12327 */
12328
Eric Andersenc470f442003-07-28 09:56:35 +000012329int
12330unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012331{
12332 char **ap;
12333 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012334 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012335 int ret = 0;
12336
12337 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012338 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012339 }
Eric Andersencb57d552001-06-28 07:25:16 +000012340
Eric Andersenc470f442003-07-28 09:56:35 +000012341 for (ap = argptr; *ap ; ap++) {
12342 if (flag != 'f') {
12343 i = unsetvar(*ap);
12344 ret |= i;
12345 if (!(i & 2))
12346 continue;
12347 }
12348 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012349 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012350 }
Eric Andersenc470f442003-07-28 09:56:35 +000012351 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012352}
12353
12354
12355/*
12356 * Unset the specified variable.
12357 */
12358
Eric Andersenc470f442003-07-28 09:56:35 +000012359int
12360unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012361{
Eric Andersencb57d552001-06-28 07:25:16 +000012362 struct var **vpp;
12363 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012364 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012365
12366 vpp = findvar(hashvar(s), s);
12367 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012368 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012369 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012370 int flags = vp->flags;
12371
12372 retval = 1;
12373 if (flags & VREADONLY)
12374 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012375#ifdef DYNAMIC_VAR
12376 vp->flags &= ~VDYNAMIC;
12377#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012378 if (flags & VUNSET)
12379 goto ok;
12380 if ((flags & VSTRFIXED) == 0) {
12381 INTOFF;
12382 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12383 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012384 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012385 ckfree(vp);
12386 INTON;
12387 } else {
12388 setvar(s, 0, 0);
12389 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012390 }
Eric Andersenc470f442003-07-28 09:56:35 +000012391ok:
12392 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012393 }
12394
Eric Andersenc470f442003-07-28 09:56:35 +000012395out:
12396 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012397}
12398
12399
12400
12401/*
12402 * Find the appropriate entry in the hash table from the name.
12403 */
12404
Eric Andersenc470f442003-07-28 09:56:35 +000012405static struct var **
12406hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012407{
Eric Andersencb57d552001-06-28 07:25:16 +000012408 unsigned int hashval;
12409
12410 hashval = ((unsigned char) *p) << 4;
12411 while (*p && *p != '=')
12412 hashval += (unsigned char) *p++;
12413 return &vartab[hashval % VTABSIZE];
12414}
12415
12416
12417
12418/*
Eric Andersenc470f442003-07-28 09:56:35 +000012419 * Compares two strings up to the first = or '\0'. The first
12420 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012421 * either '=' or '\0'.
12422 */
12423
Eric Andersenc470f442003-07-28 09:56:35 +000012424int
12425varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012426{
Eric Andersenc470f442003-07-28 09:56:35 +000012427 int c, d;
12428
12429 while ((c = *p) == (d = *q)) {
12430 if (!c || c == '=')
12431 goto out;
12432 p++;
12433 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012434 }
Eric Andersenc470f442003-07-28 09:56:35 +000012435 if (c == '=')
12436 c = 0;
12437 if (d == '=')
12438 d = 0;
12439out:
12440 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012441}
12442
Eric Andersenc470f442003-07-28 09:56:35 +000012443static int
12444vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012445{
Eric Andersenc470f442003-07-28 09:56:35 +000012446 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012447}
12448
Eric Andersenc470f442003-07-28 09:56:35 +000012449static struct var **
12450findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012451{
12452 for (; *vpp; vpp = &(*vpp)->next) {
12453 if (varequal((*vpp)->text, name)) {
12454 break;
12455 }
12456 }
12457 return vpp;
12458}
Eric Andersenc470f442003-07-28 09:56:35 +000012459/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012460
Eric Andersenc470f442003-07-28 09:56:35 +000012461#include <sys/times.h>
12462
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012463static const unsigned char timescmd_str[] = {
12464 ' ', offsetof(struct tms, tms_utime),
12465 '\n', offsetof(struct tms, tms_stime),
12466 ' ', offsetof(struct tms, tms_cutime),
12467 '\n', offsetof(struct tms, tms_cstime),
12468 0
12469};
Eric Andersencb57d552001-06-28 07:25:16 +000012470
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012471static int timescmd(int ac, char **av)
12472{
12473 long int clk_tck, s, t;
12474 const unsigned char *p;
12475 struct tms buf;
12476
12477 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012478 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012479
12480 p = timescmd_str;
12481 do {
12482 t = *(clock_t *)(((char *) &buf) + p[1]);
12483 s = t / clk_tck;
12484 out1fmt("%ldm%ld.%.3lds%c",
12485 s/60, s%60,
12486 ((t - s * clk_tck) * 1000) / clk_tck,
12487 p[0]);
12488 } while (*(p += 2));
12489
Eric Andersencb57d552001-06-28 07:25:16 +000012490 return 0;
12491}
12492
Eric Andersend35c5df2002-01-09 15:37:36 +000012493#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012494static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012495dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012496{
Eric Andersened9ecf72004-06-22 08:29:45 +000012497 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012498 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012499
Eric Andersenc470f442003-07-28 09:56:35 +000012500 INTOFF;
12501 result = arith(s, &errcode);
12502 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012503 if (errcode == -3)
12504 error("exponent less than 0");
12505 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012506 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012507 else if (errcode == -5)
12508 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012509 else
12510 synerror(s);
12511 }
12512 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012513
Eric Andersenc470f442003-07-28 09:56:35 +000012514 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012515}
Eric Andersenc470f442003-07-28 09:56:35 +000012516
12517
12518/*
Eric Andersen90898442003-08-06 11:20:52 +000012519 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12520 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12521 *
12522 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012523 */
Eric Andersen90898442003-08-06 11:20:52 +000012524
Eric Andersenc470f442003-07-28 09:56:35 +000012525static int
Eric Andersen90898442003-08-06 11:20:52 +000012526letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012527{
Eric Andersenc470f442003-07-28 09:56:35 +000012528 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012529 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012530
Eric Andersen90898442003-08-06 11:20:52 +000012531 ap = argv + 1;
12532 if(!*ap)
12533 error("expression expected");
12534 for (ap = argv + 1; *ap; ap++) {
12535 i = dash_arith(*ap);
12536 }
Eric Andersenc470f442003-07-28 09:56:35 +000012537
Eric Andersen90898442003-08-06 11:20:52 +000012538 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012539}
12540#endif /* CONFIG_ASH_MATH_SUPPORT */
12541
12542/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12543
12544/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012545 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012546 */
12547
12548#undef rflag
12549
12550#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012551#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012552typedef enum __rlimit_resource rlim_t;
12553#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012554#endif
12555
12556
Eric Andersenc470f442003-07-28 09:56:35 +000012557/*
12558 * The read builtin. The -e option causes backslashes to escape the
12559 * following character.
12560 *
12561 * This uses unbuffered input, which may be avoidable in some cases.
12562 */
12563
12564static int
12565readcmd(int argc, char **argv)
12566{
12567 char **ap;
12568 int backslash;
12569 char c;
12570 int rflag;
12571 char *prompt;
12572 const char *ifs;
12573 char *p;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012574#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012575 fd_set set;
12576 int timeout;
12577 struct timeval timeout_struct;
12578 struct termios tty, old_tty;
12579#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012580 int startword;
12581 int status;
12582 int i;
12583
12584 rflag = 0;
12585 prompt = NULL;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012586#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012587 timeout = 0;
12588
12589 while ((i = nextopt("p:rt:")) != '\0')
12590#else
12591 while ((i = nextopt("p:r")) != '\0')
12592#endif
12593 {
Eric Andersenc470f442003-07-28 09:56:35 +000012594 if (i == 'p')
12595 prompt = optionarg;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012596 else if (i == 'r')
Eric Andersenc470f442003-07-28 09:56:35 +000012597 rflag = 1;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012598#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012599 else
12600 timeout = atoi(optionarg);
12601#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012602 }
12603 if (prompt && isatty(0)) {
12604 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012605 }
12606 if (*(ap = argptr) == NULL)
12607 error("arg count");
12608 if ((ifs = bltinlookup("IFS")) == NULL)
12609 ifs = defifs;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012610#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012611 c = 0;
12612#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012613 status = 0;
12614 startword = 1;
12615 backslash = 0;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012616
Eric Andersenc470f442003-07-28 09:56:35 +000012617 STARTSTACKSTR(p);
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012618#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012619 if (timeout > 0) {
12620 tcgetattr(0, &tty);
12621 old_tty = tty;
12622
12623 /* cfmakeraw(...) disables too much; we just do this instead. */
12624 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
12625 tcsetattr(0, TCSANOW, &tty);
12626
12627 FD_ZERO (&set);
12628 FD_SET (0, &set);
12629
12630 timeout_struct.tv_sec = timeout;
12631 timeout_struct.tv_usec = 0;
12632
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012633 if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012634 {
12635 read(0, &c, 1);
12636 if(c == '\n' || c == 4) /* Handle newlines and EOF */
12637 i = 0; /* Don't read further... */
12638 else
12639 STPUTC(c, p); /* Keep reading... */
12640 }
12641 tcsetattr(0, TCSANOW, &old_tty);
12642
12643 /* Echo the character so the user knows it was read...
12644 Yes, this can be done by setting the ECHO flag, but that
12645 echoes ^D and other control characters at this state */
12646 if(c != 0)
12647 write(1, &c, 1);
12648
12649 } else
12650 i = 1;
12651
12652 for (;i == 1;)
12653#else
12654 for (;;)
12655#endif
12656 {
Eric Andersenc470f442003-07-28 09:56:35 +000012657 if (read(0, &c, 1) != 1) {
12658 status = 1;
12659 break;
12660 }
12661 if (c == '\0')
12662 continue;
12663 if (backslash) {
12664 backslash = 0;
12665 if (c != '\n')
12666 goto put;
12667 continue;
12668 }
12669 if (!rflag && c == '\\') {
12670 backslash++;
12671 continue;
12672 }
12673 if (c == '\n')
12674 break;
12675 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12676 continue;
12677 }
12678 startword = 0;
12679 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12680 STACKSTRNUL(p);
12681 setvar(*ap, stackblock(), 0);
12682 ap++;
12683 startword = 1;
12684 STARTSTACKSTR(p);
12685 } else {
12686put:
12687 STPUTC(c, p);
12688 }
12689 }
12690 STACKSTRNUL(p);
12691 /* Remove trailing blanks */
12692 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12693 *p = '\0';
12694 setvar(*ap, stackblock(), 0);
12695 while (*++ap != NULL)
12696 setvar(*ap, nullstr, 0);
12697 return status;
12698}
12699
12700
12701static int umaskcmd(int argc, char **argv)
12702{
12703 static const char permuser[3] = "ugo";
12704 static const char permmode[3] = "rwx";
12705 static const short int permmask[] = {
12706 S_IRUSR, S_IWUSR, S_IXUSR,
12707 S_IRGRP, S_IWGRP, S_IXGRP,
12708 S_IROTH, S_IWOTH, S_IXOTH
12709 };
12710
12711 char *ap;
12712 mode_t mask;
12713 int i;
12714 int symbolic_mode = 0;
12715
12716 while (nextopt("S") != '\0') {
12717 symbolic_mode = 1;
12718 }
12719
12720 INTOFF;
12721 mask = umask(0);
12722 umask(mask);
12723 INTON;
12724
12725 if ((ap = *argptr) == NULL) {
12726 if (symbolic_mode) {
12727 char buf[18];
12728 char *p = buf;
12729
12730 for (i = 0; i < 3; i++) {
12731 int j;
12732
12733 *p++ = permuser[i];
12734 *p++ = '=';
12735 for (j = 0; j < 3; j++) {
12736 if ((mask & permmask[3 * i + j]) == 0) {
12737 *p++ = permmode[j];
12738 }
12739 }
12740 *p++ = ',';
12741 }
12742 *--p = 0;
12743 puts(buf);
12744 } else {
12745 out1fmt("%.4o\n", mask);
12746 }
12747 } else {
12748 if (is_digit((unsigned char) *ap)) {
12749 mask = 0;
12750 do {
12751 if (*ap >= '8' || *ap < '0')
12752 error(illnum, argv[1]);
12753 mask = (mask << 3) + (*ap - '0');
12754 } while (*++ap != '\0');
12755 umask(mask);
12756 } else {
12757 mask = ~mask & 0777;
12758 if (!bb_parse_mode(ap, &mask)) {
12759 error("Illegal mode: %s", ap);
12760 }
12761 umask(~mask & 0777);
12762 }
12763 }
12764 return 0;
12765}
12766
12767/*
12768 * ulimit builtin
12769 *
12770 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12771 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12772 * ash by J.T. Conklin.
12773 *
12774 * Public domain.
12775 */
12776
12777struct limits {
12778 const char *name;
12779 int cmd;
12780 int factor; /* multiply by to get rlim_{cur,max} values */
12781 char option;
12782};
12783
12784static const struct limits limits[] = {
12785#ifdef RLIMIT_CPU
12786 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12787#endif
12788#ifdef RLIMIT_FSIZE
12789 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12790#endif
12791#ifdef RLIMIT_DATA
12792 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12793#endif
12794#ifdef RLIMIT_STACK
12795 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12796#endif
12797#ifdef RLIMIT_CORE
12798 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12799#endif
12800#ifdef RLIMIT_RSS
12801 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12802#endif
12803#ifdef RLIMIT_MEMLOCK
12804 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12805#endif
12806#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012807 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012808#endif
12809#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012810 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012811#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012812#ifdef RLIMIT_AS
12813 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012814#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012815#ifdef RLIMIT_LOCKS
12816 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012817#endif
12818 { (char *) 0, 0, 0, '\0' }
12819};
12820
Glenn L McGrath76620622004-01-13 10:19:37 +000012821enum limtype { SOFT = 0x1, HARD = 0x2 };
12822
12823static void printlim(enum limtype how, const struct rlimit *limit,
12824 const struct limits *l)
12825{
12826 rlim_t val;
12827
12828 val = limit->rlim_max;
12829 if (how & SOFT)
12830 val = limit->rlim_cur;
12831
12832 if (val == RLIM_INFINITY)
12833 out1fmt("unlimited\n");
12834 else {
12835 val /= l->factor;
12836 out1fmt("%lld\n", (long long) val);
12837 }
12838}
12839
Eric Andersenc470f442003-07-28 09:56:35 +000012840int
12841ulimitcmd(int argc, char **argv)
12842{
12843 int c;
12844 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012845 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012846 const struct limits *l;
12847 int set, all = 0;
12848 int optc, what;
12849 struct rlimit limit;
12850
12851 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012852 while ((optc = nextopt("HSa"
12853#ifdef RLIMIT_CPU
12854 "t"
12855#endif
12856#ifdef RLIMIT_FSIZE
12857 "f"
12858#endif
12859#ifdef RLIMIT_DATA
12860 "d"
12861#endif
12862#ifdef RLIMIT_STACK
12863 "s"
12864#endif
12865#ifdef RLIMIT_CORE
12866 "c"
12867#endif
12868#ifdef RLIMIT_RSS
12869 "m"
12870#endif
12871#ifdef RLIMIT_MEMLOCK
12872 "l"
12873#endif
12874#ifdef RLIMIT_NPROC
12875 "p"
12876#endif
12877#ifdef RLIMIT_NOFILE
12878 "n"
12879#endif
12880#ifdef RLIMIT_AS
12881 "v"
12882#endif
12883#ifdef RLIMIT_LOCKS
12884 "w"
12885#endif
12886 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012887 switch (optc) {
12888 case 'H':
12889 how = HARD;
12890 break;
12891 case 'S':
12892 how = SOFT;
12893 break;
12894 case 'a':
12895 all = 1;
12896 break;
12897 default:
12898 what = optc;
12899 }
12900
Glenn L McGrath76620622004-01-13 10:19:37 +000012901 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012902 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012903
12904 set = *argptr ? 1 : 0;
12905 if (set) {
12906 char *p = *argptr;
12907
12908 if (all || argptr[1])
12909 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012910 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012911 val = RLIM_INFINITY;
12912 else {
12913 val = (rlim_t) 0;
12914
12915 while ((c = *p++) >= '0' && c <= '9')
12916 {
12917 val = (val * 10) + (long)(c - '0');
12918 if (val < (rlim_t) 0)
12919 break;
12920 }
12921 if (c)
12922 error("bad number");
12923 val *= l->factor;
12924 }
12925 }
12926 if (all) {
12927 for (l = limits; l->name; l++) {
12928 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012929 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012930 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012931 }
12932 return 0;
12933 }
12934
12935 getrlimit(l->cmd, &limit);
12936 if (set) {
12937 if (how & HARD)
12938 limit.rlim_max = val;
12939 if (how & SOFT)
12940 limit.rlim_cur = val;
12941 if (setrlimit(l->cmd, &limit) < 0)
12942 error("error setting limit (%m)");
12943 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012944 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012945 }
12946 return 0;
12947}
12948
Eric Andersen90898442003-08-06 11:20:52 +000012949
12950#ifdef CONFIG_ASH_MATH_SUPPORT
12951
12952/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12953
12954 Permission is hereby granted, free of charge, to any person obtaining
12955 a copy of this software and associated documentation files (the
12956 "Software"), to deal in the Software without restriction, including
12957 without limitation the rights to use, copy, modify, merge, publish,
12958 distribute, sublicense, and/or sell copies of the Software, and to
12959 permit persons to whom the Software is furnished to do so, subject to
12960 the following conditions:
12961
12962 The above copyright notice and this permission notice shall be
12963 included in all copies or substantial portions of the Software.
12964
12965 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12966 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12967 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12968 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12969 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12970 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12971 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12972*/
12973
12974/* This is my infix parser/evaluator. It is optimized for size, intended
12975 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000012976 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000012977 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000012978 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000012979 * be that which POSIX specifies for shells. */
12980
12981/* The code uses a simple two-stack algorithm. See
12982 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000012983 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000012984 * this is based (this code differs in that it applies operators immediately
12985 * to the stack instead of adding them to a queue to end up with an
12986 * expression). */
12987
12988/* To use the routine, call it with an expression string and error return
12989 * pointer */
12990
12991/*
12992 * Aug 24, 2001 Manuel Novoa III
12993 *
12994 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12995 *
12996 * 1) In arith_apply():
12997 * a) Cached values of *numptr and &(numptr[-1]).
12998 * b) Removed redundant test for zero denominator.
12999 *
13000 * 2) In arith():
13001 * a) Eliminated redundant code for processing operator tokens by moving
13002 * to a table-based implementation. Also folded handling of parens
13003 * into the table.
13004 * b) Combined all 3 loops which called arith_apply to reduce generated
13005 * code size at the cost of speed.
13006 *
13007 * 3) The following expressions were treated as valid by the original code:
13008 * 1() , 0! , 1 ( *3 ) .
13009 * These bugs have been fixed by internally enclosing the expression in
13010 * parens and then checking that all binary ops and right parens are
13011 * preceded by a valid expression (NUM_TOKEN).
13012 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013013 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013014 * ctype's isspace() if it is used by another busybox applet or if additional
13015 * whitespace chars should be considered. Look below the "#include"s for a
13016 * precompiler test.
13017 */
13018
13019/*
13020 * Aug 26, 2001 Manuel Novoa III
13021 *
13022 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13023 *
13024 * Merge in Aaron's comments previously posted to the busybox list,
13025 * modified slightly to take account of my changes to the code.
13026 *
13027 */
13028
13029/*
13030 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13031 *
13032 * - allow access to variable,
13033 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13034 * - realize assign syntax (VAR=expr, +=, *= etc)
13035 * - realize exponentiation (** operator)
13036 * - realize comma separated - expr, expr
13037 * - realise ++expr --expr expr++ expr--
13038 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013039 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013040 * - was restored loses XOR operator
13041 * - remove one goto label, added three ;-)
13042 * - protect $((num num)) as true zero expr (Manuel`s error)
13043 * - always use special isspace(), see comment from bash ;-)
13044 */
13045
13046
13047#define arith_isspace(arithval) \
13048 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13049
13050
13051typedef unsigned char operator;
13052
13053/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013054 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013055 * precedence. The ID portion is so that multiple operators can have the
13056 * same precedence, ensuring that the leftmost one is evaluated first.
13057 * Consider * and /. */
13058
13059#define tok_decl(prec,id) (((id)<<5)|(prec))
13060#define PREC(op) ((op) & 0x1F)
13061
13062#define TOK_LPAREN tok_decl(0,0)
13063
13064#define TOK_COMMA tok_decl(1,0)
13065
13066#define TOK_ASSIGN tok_decl(2,0)
13067#define TOK_AND_ASSIGN tok_decl(2,1)
13068#define TOK_OR_ASSIGN tok_decl(2,2)
13069#define TOK_XOR_ASSIGN tok_decl(2,3)
13070#define TOK_PLUS_ASSIGN tok_decl(2,4)
13071#define TOK_MINUS_ASSIGN tok_decl(2,5)
13072#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13073#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13074
13075#define TOK_MUL_ASSIGN tok_decl(3,0)
13076#define TOK_DIV_ASSIGN tok_decl(3,1)
13077#define TOK_REM_ASSIGN tok_decl(3,2)
13078
13079/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13080#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13081
13082/* conditional is right associativity too */
13083#define TOK_CONDITIONAL tok_decl(4,0)
13084#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13085
13086#define TOK_OR tok_decl(5,0)
13087
13088#define TOK_AND tok_decl(6,0)
13089
13090#define TOK_BOR tok_decl(7,0)
13091
13092#define TOK_BXOR tok_decl(8,0)
13093
13094#define TOK_BAND tok_decl(9,0)
13095
13096#define TOK_EQ tok_decl(10,0)
13097#define TOK_NE tok_decl(10,1)
13098
13099#define TOK_LT tok_decl(11,0)
13100#define TOK_GT tok_decl(11,1)
13101#define TOK_GE tok_decl(11,2)
13102#define TOK_LE tok_decl(11,3)
13103
13104#define TOK_LSHIFT tok_decl(12,0)
13105#define TOK_RSHIFT tok_decl(12,1)
13106
13107#define TOK_ADD tok_decl(13,0)
13108#define TOK_SUB tok_decl(13,1)
13109
13110#define TOK_MUL tok_decl(14,0)
13111#define TOK_DIV tok_decl(14,1)
13112#define TOK_REM tok_decl(14,2)
13113
13114/* exponent is right associativity */
13115#define TOK_EXPONENT tok_decl(15,1)
13116
13117/* For now unary operators. */
13118#define UNARYPREC 16
13119#define TOK_BNOT tok_decl(UNARYPREC,0)
13120#define TOK_NOT tok_decl(UNARYPREC,1)
13121
13122#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13123#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13124
13125#define PREC_PRE (UNARYPREC+2)
13126
13127#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13128#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13129
13130#define PREC_POST (UNARYPREC+3)
13131
13132#define TOK_POST_INC tok_decl(PREC_POST, 0)
13133#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13134
13135#define SPEC_PREC (UNARYPREC+4)
13136
13137#define TOK_NUM tok_decl(SPEC_PREC, 0)
13138#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13139
13140#define NUMPTR (*numstackptr)
13141
13142static inline int tok_have_assign(operator op)
13143{
13144 operator prec = PREC(op);
13145
13146 convert_prec_is_assing(prec);
13147 return (prec == PREC(TOK_ASSIGN) ||
13148 prec == PREC_PRE || prec == PREC_POST);
13149}
13150
13151static inline int is_right_associativity(operator prec)
13152{
13153 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13154 prec == PREC(TOK_CONDITIONAL));
13155}
13156
13157
13158typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013159 arith_t val;
13160 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013161 char contidional_second_val_initialized;
13162 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013163 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013164} v_n_t;
13165
13166
13167typedef struct CHK_VAR_RECURSIVE_LOOPED {
13168 const char *var;
13169 struct CHK_VAR_RECURSIVE_LOOPED *next;
13170} chk_var_recursive_looped_t;
13171
13172static chk_var_recursive_looped_t *prev_chk_var_recursive;
13173
13174
13175static int arith_lookup_val(v_n_t *t)
13176{
13177 if(t->var) {
13178 const char * p = lookupvar(t->var);
13179
13180 if(p) {
13181 int errcode;
13182
13183 /* recursive try as expression */
13184 chk_var_recursive_looped_t *cur;
13185 chk_var_recursive_looped_t cur_save;
13186
13187 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13188 if(strcmp(cur->var, t->var) == 0) {
13189 /* expression recursion loop detected */
13190 return -5;
13191 }
13192 }
13193 /* save current lookuped var name */
13194 cur = prev_chk_var_recursive;
13195 cur_save.var = t->var;
13196 cur_save.next = cur;
13197 prev_chk_var_recursive = &cur_save;
13198
13199 t->val = arith (p, &errcode);
13200 /* restore previous ptr after recursiving */
13201 prev_chk_var_recursive = cur;
13202 return errcode;
13203 } else {
13204 /* allow undefined var as 0 */
13205 t->val = 0;
13206 }
13207 }
13208 return 0;
13209}
13210
13211/* "applying" a token means performing it on the top elements on the integer
13212 * stack. For a unary operator it will only change the top element, but a
13213 * binary operator will pop two arguments and push a result */
13214static inline int
13215arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13216{
Eric Andersen90898442003-08-06 11:20:52 +000013217 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013218 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013219 int ret_arith_lookup_val;
13220
13221 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13222 without arguments */
13223 numptr_m1 = NUMPTR - 1;
13224
13225 /* check operand is var with noninteger value */
13226 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13227 if(ret_arith_lookup_val)
13228 return ret_arith_lookup_val;
13229
13230 rez = numptr_m1->val;
13231 if (op == TOK_UMINUS)
13232 rez *= -1;
13233 else if (op == TOK_NOT)
13234 rez = !rez;
13235 else if (op == TOK_BNOT)
13236 rez = ~rez;
13237 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13238 rez++;
13239 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13240 rez--;
13241 else if (op != TOK_UPLUS) {
13242 /* Binary operators */
13243
13244 /* check and binary operators need two arguments */
13245 if (numptr_m1 == numstack) goto err;
13246
13247 /* ... and they pop one */
13248 --NUMPTR;
13249 numptr_val = rez;
13250 if (op == TOK_CONDITIONAL) {
13251 if(! numptr_m1->contidional_second_val_initialized) {
13252 /* protect $((expr1 ? expr2)) without ": expr" */
13253 goto err;
13254 }
13255 rez = numptr_m1->contidional_second_val;
13256 } else if(numptr_m1->contidional_second_val_initialized) {
13257 /* protect $((expr1 : expr2)) without "expr ? " */
13258 goto err;
13259 }
13260 numptr_m1 = NUMPTR - 1;
13261 if(op != TOK_ASSIGN) {
13262 /* check operand is var with noninteger value for not '=' */
13263 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13264 if(ret_arith_lookup_val)
13265 return ret_arith_lookup_val;
13266 }
13267 if (op == TOK_CONDITIONAL) {
13268 numptr_m1->contidional_second_val = rez;
13269 }
13270 rez = numptr_m1->val;
13271 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13272 rez |= numptr_val;
13273 else if (op == TOK_OR)
13274 rez = numptr_val || rez;
13275 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13276 rez &= numptr_val;
13277 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13278 rez ^= numptr_val;
13279 else if (op == TOK_AND)
13280 rez = rez && numptr_val;
13281 else if (op == TOK_EQ)
13282 rez = (rez == numptr_val);
13283 else if (op == TOK_NE)
13284 rez = (rez != numptr_val);
13285 else if (op == TOK_GE)
13286 rez = (rez >= numptr_val);
13287 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13288 rez >>= numptr_val;
13289 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13290 rez <<= numptr_val;
13291 else if (op == TOK_GT)
13292 rez = (rez > numptr_val);
13293 else if (op == TOK_LT)
13294 rez = (rez < numptr_val);
13295 else if (op == TOK_LE)
13296 rez = (rez <= numptr_val);
13297 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13298 rez *= numptr_val;
13299 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13300 rez += numptr_val;
13301 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13302 rez -= numptr_val;
13303 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13304 rez = numptr_val;
13305 else if (op == TOK_CONDITIONAL_SEP) {
13306 if (numptr_m1 == numstack) {
13307 /* protect $((expr : expr)) without "expr ? " */
13308 goto err;
13309 }
13310 numptr_m1->contidional_second_val_initialized = op;
13311 numptr_m1->contidional_second_val = numptr_val;
13312 }
13313 else if (op == TOK_CONDITIONAL) {
13314 rez = rez ?
13315 numptr_val : numptr_m1->contidional_second_val;
13316 }
13317 else if(op == TOK_EXPONENT) {
13318 if(numptr_val < 0)
13319 return -3; /* exponent less than 0 */
13320 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013321 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013322
13323 if(numptr_val)
13324 while(numptr_val--)
13325 c *= rez;
13326 rez = c;
13327 }
13328 }
13329 else if(numptr_val==0) /* zero divisor check */
13330 return -2;
13331 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13332 rez /= numptr_val;
13333 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13334 rez %= numptr_val;
13335 }
13336 if(tok_have_assign(op)) {
13337 char buf[32];
13338
13339 if(numptr_m1->var == NULL) {
13340 /* Hmm, 1=2 ? */
13341 goto err;
13342 }
13343 /* save to shell variable */
Eric Andersenad63cb22004-10-08 09:43:34 +000013344 snprintf(buf, sizeof(buf), "%lld", (long long) rez);
Eric Andersen90898442003-08-06 11:20:52 +000013345 setvar(numptr_m1->var, buf, 0);
13346 /* after saving, make previous value for v++ or v-- */
13347 if(op == TOK_POST_INC)
13348 rez--;
13349 else if(op == TOK_POST_DEC)
13350 rez++;
13351 }
13352 numptr_m1->val = rez;
13353 /* protect geting var value, is number now */
13354 numptr_m1->var = NULL;
13355 return 0;
13356err: return(-1);
13357}
13358
13359/* longest must first */
13360static const char op_tokens[] = {
13361 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13362 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13363 '<','<', 0, TOK_LSHIFT,
13364 '>','>', 0, TOK_RSHIFT,
13365 '|','|', 0, TOK_OR,
13366 '&','&', 0, TOK_AND,
13367 '!','=', 0, TOK_NE,
13368 '<','=', 0, TOK_LE,
13369 '>','=', 0, TOK_GE,
13370 '=','=', 0, TOK_EQ,
13371 '|','=', 0, TOK_OR_ASSIGN,
13372 '&','=', 0, TOK_AND_ASSIGN,
13373 '*','=', 0, TOK_MUL_ASSIGN,
13374 '/','=', 0, TOK_DIV_ASSIGN,
13375 '%','=', 0, TOK_REM_ASSIGN,
13376 '+','=', 0, TOK_PLUS_ASSIGN,
13377 '-','=', 0, TOK_MINUS_ASSIGN,
13378 '-','-', 0, TOK_POST_DEC,
13379 '^','=', 0, TOK_XOR_ASSIGN,
13380 '+','+', 0, TOK_POST_INC,
13381 '*','*', 0, TOK_EXPONENT,
13382 '!', 0, TOK_NOT,
13383 '<', 0, TOK_LT,
13384 '>', 0, TOK_GT,
13385 '=', 0, TOK_ASSIGN,
13386 '|', 0, TOK_BOR,
13387 '&', 0, TOK_BAND,
13388 '*', 0, TOK_MUL,
13389 '/', 0, TOK_DIV,
13390 '%', 0, TOK_REM,
13391 '+', 0, TOK_ADD,
13392 '-', 0, TOK_SUB,
13393 '^', 0, TOK_BXOR,
13394 /* uniq */
13395 '~', 0, TOK_BNOT,
13396 ',', 0, TOK_COMMA,
13397 '?', 0, TOK_CONDITIONAL,
13398 ':', 0, TOK_CONDITIONAL_SEP,
13399 ')', 0, TOK_RPAREN,
13400 '(', 0, TOK_LPAREN,
13401 0
13402};
13403/* ptr to ")" */
13404#define endexpression &op_tokens[sizeof(op_tokens)-7]
13405
13406
Eric Andersened9ecf72004-06-22 08:29:45 +000013407static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013408{
13409 register char arithval; /* Current character under analysis */
13410 operator lasttok, op;
13411 operator prec;
13412
13413 const char *p = endexpression;
13414 int errcode;
13415
13416 size_t datasizes = strlen(expr) + 2;
13417
13418 /* Stack of integers */
13419 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013420 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013421 * the reader. */
13422 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13423 *numstackptr = numstack;
13424 /* Stack of operator tokens */
13425 operator *stack = alloca((datasizes) * sizeof(operator)),
13426 *stackptr = stack;
13427
13428 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13429 *perrcode = errcode = 0;
13430
13431 while(1) {
13432 if ((arithval = *expr) == 0) {
13433 if (p == endexpression) {
13434 /* Null expression. */
13435 return 0;
13436 }
13437
13438 /* This is only reached after all tokens have been extracted from the
13439 * input stream. If there are still tokens on the operator stack, they
13440 * are to be applied in order. At the end, there should be a final
13441 * result on the integer stack */
13442
13443 if (expr != endexpression + 1) {
13444 /* If we haven't done so already, */
13445 /* append a closing right paren */
13446 expr = endexpression;
13447 /* and let the loop process it. */
13448 continue;
13449 }
13450 /* At this point, we're done with the expression. */
13451 if (numstackptr != numstack+1) {
13452 /* ... but if there isn't, it's bad */
13453 err:
13454 return (*perrcode = -1);
13455 }
13456 if(numstack->var) {
13457 /* expression is $((var)) only, lookup now */
13458 errcode = arith_lookup_val(numstack);
13459 }
13460 ret:
13461 *perrcode = errcode;
13462 return numstack->val;
13463 } else {
13464 /* Continue processing the expression. */
13465 if (arith_isspace(arithval)) {
13466 /* Skip whitespace */
13467 goto prologue;
13468 }
13469 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013470 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013471
13472 numstackptr->var = alloca(var_name_size);
13473 safe_strncpy(numstackptr->var, expr, var_name_size);
13474 expr = p;
13475 num:
13476 numstackptr->contidional_second_val_initialized = 0;
13477 numstackptr++;
13478 lasttok = TOK_NUM;
13479 continue;
13480 } else if (is_digit(arithval)) {
13481 numstackptr->var = NULL;
Eric Andersenad63cb22004-10-08 09:43:34 +000013482 numstackptr->val = strtoll(expr, (char **) &expr, 0);
Eric Andersen90898442003-08-06 11:20:52 +000013483 goto num;
13484 }
13485 for(p = op_tokens; ; p++) {
13486 const char *o;
13487
13488 if(*p == 0) {
13489 /* strange operator not found */
13490 goto err;
13491 }
13492 for(o = expr; *p && *o == *p; p++)
13493 o++;
13494 if(! *p) {
13495 /* found */
13496 expr = o - 1;
13497 break;
13498 }
13499 /* skip tail uncompared token */
13500 while(*p)
13501 p++;
13502 /* skip zero delim */
13503 p++;
13504 }
13505 op = p[1];
13506
13507 /* post grammar: a++ reduce to num */
13508 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13509 lasttok = TOK_NUM;
13510
13511 /* Plus and minus are binary (not unary) _only_ if the last
13512 * token was as number, or a right paren (which pretends to be
13513 * a number, since it evaluates to one). Think about it.
13514 * It makes sense. */
13515 if (lasttok != TOK_NUM) {
13516 switch(op) {
13517 case TOK_ADD:
13518 op = TOK_UPLUS;
13519 break;
13520 case TOK_SUB:
13521 op = TOK_UMINUS;
13522 break;
13523 case TOK_POST_INC:
13524 op = TOK_PRE_INC;
13525 break;
13526 case TOK_POST_DEC:
13527 op = TOK_PRE_DEC;
13528 break;
13529 }
13530 }
13531 /* We don't want a unary operator to cause recursive descent on the
13532 * stack, because there can be many in a row and it could cause an
13533 * operator to be evaluated before its argument is pushed onto the
13534 * integer stack. */
13535 /* But for binary operators, "apply" everything on the operator
13536 * stack until we find an operator with a lesser priority than the
13537 * one we have just extracted. */
13538 /* Left paren is given the lowest priority so it will never be
13539 * "applied" in this way.
13540 * if associativity is right and priority eq, applied also skip
13541 */
13542 prec = PREC(op);
13543 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13544 /* not left paren or unary */
13545 if (lasttok != TOK_NUM) {
13546 /* binary op must be preceded by a num */
13547 goto err;
13548 }
13549 while (stackptr != stack) {
13550 if (op == TOK_RPAREN) {
13551 /* The algorithm employed here is simple: while we don't
13552 * hit an open paren nor the bottom of the stack, pop
13553 * tokens and apply them */
13554 if (stackptr[-1] == TOK_LPAREN) {
13555 --stackptr;
13556 /* Any operator directly after a */
13557 lasttok = TOK_NUM;
13558 /* close paren should consider itself binary */
13559 goto prologue;
13560 }
13561 } else {
13562 operator prev_prec = PREC(stackptr[-1]);
13563
13564 convert_prec_is_assing(prec);
13565 convert_prec_is_assing(prev_prec);
13566 if (prev_prec < prec)
13567 break;
13568 /* check right assoc */
13569 if(prev_prec == prec && is_right_associativity(prec))
13570 break;
13571 }
13572 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13573 if(errcode) goto ret;
13574 }
13575 if (op == TOK_RPAREN) {
13576 goto err;
13577 }
13578 }
13579
13580 /* Push this operator to the stack and remember it. */
13581 *stackptr++ = lasttok = op;
13582
13583 prologue:
13584 ++expr;
13585 }
13586 }
13587}
13588#endif /* CONFIG_ASH_MATH_SUPPORT */
13589
13590
Eric Andersenc470f442003-07-28 09:56:35 +000013591#ifdef DEBUG
13592const char *bb_applet_name = "debug stuff usage";
13593int main(int argc, char **argv)
13594{
13595 return ash_main(argc, argv);
13596}
13597#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013598
Eric Andersendf82f612001-06-28 07:46:40 +000013599/*-
13600 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013601 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013602 *
13603 * This code is derived from software contributed to Berkeley by
13604 * Kenneth Almquist.
13605 *
13606 * Redistribution and use in source and binary forms, with or without
13607 * modification, are permitted provided that the following conditions
13608 * are met:
13609 * 1. Redistributions of source code must retain the above copyright
13610 * notice, this list of conditions and the following disclaimer.
13611 * 2. Redistributions in binary form must reproduce the above copyright
13612 * notice, this list of conditions and the following disclaimer in the
13613 * documentation and/or other materials provided with the distribution.
13614 *
Eric Andersen2870d962001-07-02 17:27:21 +000013615 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13616 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013617 *
13618 * 4. Neither the name of the University nor the names of its contributors
13619 * may be used to endorse or promote products derived from this software
13620 * without specific prior written permission.
13621 *
13622 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13623 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13624 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13625 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13626 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13627 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13628 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13629 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13630 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13631 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13632 * SUCH DAMAGE.
13633 */