blob: 57316c9161de5b75af19f51a7aaa12e5b3b9503d [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
Eric Andersen81fe1232003-07-29 06:38:40 +00008 * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9 * was re-ported from NetBSD and debianized.
10 *
11 *
Eric Andersencb57d552001-06-28 07:25:16 +000012 * This code is derived from software contributed to Berkeley by
13 * Kenneth Almquist.
14 *
Eric Andersendf82f612001-06-28 07:46:40 +000015 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000019 *
Eric Andersendf82f612001-06-28 07:46:40 +000020 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
Eric Andersen81fe1232003-07-29 06:38:40 +000029 * Original BSD copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000030 */
31
Eric Andersenc470f442003-07-28 09:56:35 +000032/*
Eric Andersen90898442003-08-06 11:20:52 +000033 * rewrite arith.y to micro stack based cryptic algorithm by
34 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
35 *
Eric Andersenef02f822004-03-11 13:34:24 +000036 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
37 * dynamic variables.
Eric Andersen16767e22004-03-16 05:14:10 +000038 *
39 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be
40 * used in busybox and size optimizations,
41 * rewrote arith (see notes to this), added locale support,
42 * rewrote dynamic variables.
43 *
Eric Andersen90898442003-08-06 11:20:52 +000044 */
45
46
47/*
Eric Andersenc470f442003-07-28 09:56:35 +000048 * The follow should be set to reflect the type of system you have:
49 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
50 * define SYSV if you are running under System V.
51 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
52 * define DEBUG=2 to compile in and turn on debugging.
53 *
54 * When debugging is on, debugging info will be written to ./trace and
55 * a quit signal will generate a core dump.
56 */
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058
Eric Andersenc470f442003-07-28 09:56:35 +000059
Eric Andersen5bb16772001-09-06 18:00:41 +000060#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000061
Eric Andersenc470f442003-07-28 09:56:35 +000062#define PROFILE 0
63
64#ifdef DEBUG
65#define _GNU_SOURCE
66#endif
67
68#include <sys/types.h>
69#include <sys/cdefs.h>
70#include <sys/ioctl.h>
71#include <sys/param.h>
72#include <sys/resource.h>
73#include <sys/stat.h>
74#include <sys/time.h>
75#include <sys/wait.h>
76
77#include <stdio.h>
78#include <stdlib.h>
79#include <string.h>
80#include <unistd.h>
81
82#include <stdarg.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000083#include <stddef.h>
Eric Andersenc470f442003-07-28 09:56:35 +000084#include <assert.h>
Eric Andersencb57d552001-06-28 07:25:16 +000085#include <ctype.h>
86#include <dirent.h>
87#include <errno.h>
88#include <fcntl.h>
89#include <limits.h>
90#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000091#include <setjmp.h>
92#include <signal.h>
Eric Andersenc470f442003-07-28 09:56:35 +000093#include <stdint.h>
Eric Andersencb57d552001-06-28 07:25:16 +000094#include <sysexits.h>
Eric Andersenef02f822004-03-11 13:34:24 +000095#include <time.h>
Eric Andersenc470f442003-07-28 09:56:35 +000096#include <fnmatch.h>
Eric Andersenc470f442003-07-28 09:56:35 +000097
98
Robert Grieblea1a63a2002-06-04 20:10:23 +000099#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +0000100#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +0000101
Eric Andersend35c5df2002-01-09 15:37:36 +0000102#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +0000103#define JOBS 1
104#else
Eric Andersenca162042003-07-29 07:15:17 +0000105#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +0000106#endif
107
108#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000109#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000110#endif
111
Eric Andersen2870d962001-07-02 17:27:21 +0000112#include "cmdedit.h"
113
Eric Andersenc470f442003-07-28 09:56:35 +0000114#ifdef __GLIBC__
115/* glibc sucks */
116static int *dash_errno;
117#undef errno
118#define errno (*dash_errno)
119#endif
120
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000121#if defined(__uClinux__)
122#error "Do not even bother, ash will not run on uClinux"
123#endif
124
Eric Andersenc470f442003-07-28 09:56:35 +0000125#ifdef DEBUG
126#define _DIAGASSERT(assert_expr) assert(assert_expr)
127#else
128#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000129#endif
130
Eric Andersen2870d962001-07-02 17:27:21 +0000131
Eric Andersenc470f442003-07-28 09:56:35 +0000132#ifdef CONFIG_ASH_ALIAS
133/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
134
135#define ALIASINUSE 1
136#define ALIASDEAD 2
137
138struct alias {
139 struct alias *next;
140 char *name;
141 char *val;
142 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000143};
144
Eric Andersenc470f442003-07-28 09:56:35 +0000145static struct alias *lookupalias(const char *, int);
146static int aliascmd(int, char **);
147static int unaliascmd(int, char **);
148static void rmaliases(void);
149static int unalias(const char *);
150static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000151#endif
152
Eric Andersenc470f442003-07-28 09:56:35 +0000153/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
154
155
156static void setpwd(const char *, int);
157
158/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
159
160
161/*
162 * Types of operations (passed to the errmsg routine).
163 */
164
165
166static const char not_found_msg[] = "%s: not found";
167
168
169#define E_OPEN "No such file" /* opening a file */
170#define E_CREAT "Directory nonexistent" /* creating a file */
171#define E_EXEC not_found_msg+4 /* executing a program */
172
173/*
174 * We enclose jmp_buf in a structure so that we can declare pointers to
175 * jump locations. The global variable handler contains the location to
176 * jump to when an exception occurs, and the global variable exception
Eric Andersenaff114c2004-04-14 17:51:38 +0000177 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000178 * exception handlers, the user should save the value of handler on entry
179 * to an inner scope, set handler to point to a jmploc structure for the
180 * inner scope, and restore handler on exit from the scope.
181 */
182
183struct jmploc {
184 jmp_buf loc;
185};
186
187static struct jmploc *handler;
188static int exception;
189static volatile int suppressint;
190static volatile sig_atomic_t intpending;
191
192static int exerrno; /* Last exec error, error for EXEXEC */
193
194/* exceptions */
195#define EXINT 0 /* SIGINT received */
196#define EXERROR 1 /* a generic error */
197#define EXSHELLPROC 2 /* execute a shell procedure */
198#define EXEXEC 3 /* command execution failed */
199#define EXEXIT 4 /* exit the shell */
200#define EXSIG 5 /* trapped signal in wait(1) */
201
202
203/* do we generate EXSIG events */
204static int exsig;
205/* last pending signal */
206static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000207
208/*
209 * These macros allow the user to suspend the handling of interrupt signals
210 * over a period of time. This is similar to SIGHOLD to or sigblock, but
211 * much more efficient and portable. (But hacking the kernel is so much
212 * more fun than worrying about efficiency and portability. :-))
213 */
214
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000215#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
Eric Andersenc470f442003-07-28 09:56:35 +0000216#define INTOFF \
217 ({ \
218 suppressint++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000219 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000220 0; \
221 })
222#define SAVEINT(v) ((v) = suppressint)
223#define RESTOREINT(v) \
224 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000225 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000226 if ((suppressint = (v)) == 0 && intpending) onint(); \
227 0; \
228 })
229#define EXSIGON() \
230 ({ \
231 exsig++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000232 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000233 if (pendingsigs) \
234 exraise(EXSIG); \
235 0; \
236 })
237/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000238
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000239
Eric Andersenc470f442003-07-28 09:56:35 +0000240static void exraise(int) __attribute__((__noreturn__));
241static void onint(void) __attribute__((__noreturn__));
242
243static void error(const char *, ...) __attribute__((__noreturn__));
244static void exerror(int, const char *, ...) __attribute__((__noreturn__));
245
246static void sh_warnx(const char *, ...);
247
248#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
249static void
250inton(void) {
251 if (--suppressint == 0 && intpending) {
252 onint();
253 }
254}
255#define INTON inton()
256static void forceinton(void)
257{
258 suppressint = 0;
259 if (intpending)
260 onint();
261}
Eric Andersen3102ac42001-07-06 04:26:23 +0000262#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000263#else
Eric Andersenc470f442003-07-28 09:56:35 +0000264#define INTON \
265 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000266 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000267 if (--suppressint == 0 && intpending) onint(); \
268 0; \
269 })
270#define FORCEINTON \
271 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000272 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000273 suppressint = 0; \
274 if (intpending) onint(); \
275 0; \
276 })
277#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000278
279/*
Eric Andersenc470f442003-07-28 09:56:35 +0000280 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
281 * so we use _setjmp instead.
Eric Andersen2870d962001-07-02 17:27:21 +0000282 */
Eric Andersen2870d962001-07-02 17:27:21 +0000283
Eric Andersenc470f442003-07-28 09:56:35 +0000284#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
285#define setjmp(jmploc) _setjmp(jmploc)
286#define longjmp(jmploc, val) _longjmp(jmploc, val)
287#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000288
Eric Andersenc470f442003-07-28 09:56:35 +0000289/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000290
291struct strlist {
292 struct strlist *next;
293 char *text;
294};
295
296
297struct arglist {
298 struct strlist *list;
299 struct strlist **lastp;
300};
301
Eric Andersenc470f442003-07-28 09:56:35 +0000302/*
303 * expandarg() flags
304 */
305#define EXP_FULL 0x1 /* perform word splitting & file globbing */
306#define EXP_TILDE 0x2 /* do normal tilde expansion */
307#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
308#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
309#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
310#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
311#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
312#define EXP_WORD 0x80 /* expand word in parameter expansion */
313#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
314
315
316union node;
317static void expandarg(union node *, struct arglist *, int);
318#define rmescapes(p) _rmescapes((p), 0)
319static char *_rmescapes(char *, int);
320static int casematch(union node *, char *);
321
322#ifdef CONFIG_ASH_MATH_SUPPORT
323static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000324#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000325
Eric Andersenc470f442003-07-28 09:56:35 +0000326/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000327
Eric Andersenc470f442003-07-28 09:56:35 +0000328static char *commandname; /* currently executing command */
329static struct strlist *cmdenviron; /* environment for builtin command */
330static int exitstatus; /* exit status of last command */
331static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000332
Eric Andersenc470f442003-07-28 09:56:35 +0000333
334struct backcmd { /* result of evalbackcmd */
335 int fd; /* file descriptor to read from */
336 char *buf; /* buffer */
337 int nleft; /* number of chars in buffer */
338 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000339};
340
Eric Andersen62483552001-07-10 06:09:16 +0000341/*
Eric Andersenc470f442003-07-28 09:56:35 +0000342 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000343 */
Eric Andersenc470f442003-07-28 09:56:35 +0000344
345#define NCMD 0
346#define NPIPE 1
347#define NREDIR 2
348#define NBACKGND 3
349#define NSUBSHELL 4
350#define NAND 5
351#define NOR 6
352#define NSEMI 7
353#define NIF 8
354#define NWHILE 9
355#define NUNTIL 10
356#define NFOR 11
357#define NCASE 12
358#define NCLIST 13
359#define NDEFUN 14
360#define NARG 15
361#define NTO 16
362#define NCLOBBER 17
363#define NFROM 18
364#define NFROMTO 19
365#define NAPPEND 20
366#define NTOFD 21
367#define NFROMFD 22
368#define NHERE 23
369#define NXHERE 24
370#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000371
372
373
Eric Andersenc470f442003-07-28 09:56:35 +0000374struct ncmd {
375 int type;
376 union node *assign;
377 union node *args;
378 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000379};
380
381
Eric Andersenc470f442003-07-28 09:56:35 +0000382struct npipe {
383 int type;
384 int backgnd;
385 struct nodelist *cmdlist;
386};
Eric Andersen62483552001-07-10 06:09:16 +0000387
388
Eric Andersenc470f442003-07-28 09:56:35 +0000389struct nredir {
390 int type;
391 union node *n;
392 union node *redirect;
393};
Eric Andersen62483552001-07-10 06:09:16 +0000394
395
Eric Andersenc470f442003-07-28 09:56:35 +0000396struct nbinary {
397 int type;
398 union node *ch1;
399 union node *ch2;
400};
Eric Andersen2870d962001-07-02 17:27:21 +0000401
Eric Andersen2870d962001-07-02 17:27:21 +0000402
Eric Andersenc470f442003-07-28 09:56:35 +0000403struct nif {
404 int type;
405 union node *test;
406 union node *ifpart;
407 union node *elsepart;
408};
409
410
411struct nfor {
412 int type;
413 union node *args;
414 union node *body;
415 char *var;
416};
417
418
419struct ncase {
420 int type;
421 union node *expr;
422 union node *cases;
423};
424
425
426struct nclist {
427 int type;
428 union node *next;
429 union node *pattern;
430 union node *body;
431};
432
433
434struct narg {
435 int type;
436 union node *next;
437 char *text;
438 struct nodelist *backquote;
439};
440
441
442struct nfile {
443 int type;
444 union node *next;
445 int fd;
446 union node *fname;
447 char *expfname;
448};
449
450
451struct ndup {
452 int type;
453 union node *next;
454 int fd;
455 int dupfd;
456 union node *vname;
457};
458
459
460struct nhere {
461 int type;
462 union node *next;
463 int fd;
464 union node *doc;
465};
466
467
468struct nnot {
469 int type;
470 union node *com;
471};
472
473
474union node {
475 int type;
476 struct ncmd ncmd;
477 struct npipe npipe;
478 struct nredir nredir;
479 struct nbinary nbinary;
480 struct nif nif;
481 struct nfor nfor;
482 struct ncase ncase;
483 struct nclist nclist;
484 struct narg narg;
485 struct nfile nfile;
486 struct ndup ndup;
487 struct nhere nhere;
488 struct nnot nnot;
489};
490
491
492struct nodelist {
493 struct nodelist *next;
494 union node *n;
495};
496
497
498struct funcnode {
499 int count;
500 union node n;
501};
502
503
504static void freefunc(struct funcnode *);
505/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
506
507/* control characters in argument strings */
508#define CTL_FIRST '\201' /* first 'special' character */
509#define CTLESC '\201' /* escape next character */
510#define CTLVAR '\202' /* variable defn */
511#define CTLENDVAR '\203'
512#define CTLBACKQ '\204'
513#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
514/* CTLBACKQ | CTLQUOTE == '\205' */
515#define CTLARI '\206' /* arithmetic expression */
516#define CTLENDARI '\207'
517#define CTLQUOTEMARK '\210'
518#define CTL_LAST '\210' /* last 'special' character */
519
520/* variable substitution byte (follows CTLVAR) */
521#define VSTYPE 0x0f /* type of variable substitution */
522#define VSNUL 0x10 /* colon--treat the empty string as unset */
523#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
524
525/* values of VSTYPE field */
526#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
527#define VSMINUS 0x2 /* ${var-text} */
528#define VSPLUS 0x3 /* ${var+text} */
529#define VSQUESTION 0x4 /* ${var?message} */
530#define VSASSIGN 0x5 /* ${var=text} */
531#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
532#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
533#define VSTRIMLEFT 0x8 /* ${var#pattern} */
534#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
535#define VSLENGTH 0xa /* ${#var} */
536
537/* values of checkkwd variable */
538#define CHKALIAS 0x1
539#define CHKKWD 0x2
540#define CHKNL 0x4
541
542#define IBUFSIZ (BUFSIZ + 1)
543
544/*
545 * NEOF is returned by parsecmd when it encounters an end of file. It
546 * must be distinct from NULL, so we use the address of a variable that
547 * happens to be handy.
548 */
549static int plinno = 1; /* input line number */
550
551/* number of characters left in input buffer */
552static int parsenleft; /* copy of parsefile->nleft */
553static int parselleft; /* copy of parsefile->lleft */
554
555/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000556static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000557
558struct strpush {
559 struct strpush *prev; /* preceding string on stack */
560 char *prevstring;
561 int prevnleft;
562#ifdef CONFIG_ASH_ALIAS
563 struct alias *ap; /* if push was associated with an alias */
564#endif
565 char *string; /* remember the string since it may change */
566};
567
568struct parsefile {
569 struct parsefile *prev; /* preceding file on stack */
570 int linno; /* current line */
571 int fd; /* file descriptor (or -1 if string) */
572 int nleft; /* number of chars left in this line */
573 int lleft; /* number of chars left in this buffer */
574 char *nextc; /* next char in buffer */
575 char *buf; /* input buffer */
576 struct strpush *strpush; /* for pushing strings at this level */
577 struct strpush basestrpush; /* so pushing one is fast */
578};
579
Eric Andersenc470f442003-07-28 09:56:35 +0000580static struct parsefile basepf; /* top level input file */
581static char basebuf[IBUFSIZ]; /* buffer for top level input file */
582static struct parsefile *parsefile = &basepf; /* current input file */
583
584
585static int tokpushback; /* last token pushed back */
586#define NEOF ((union node *)&tokpushback)
587static int parsebackquote; /* nonzero if we are inside backquotes */
588static int doprompt; /* if set, prompt the user */
589static int needprompt; /* true if interactive and at start of line */
590static int lasttoken; /* last token read */
591static char *wordtext; /* text of last word returned by readtoken */
592static int checkkwd;
593static struct nodelist *backquotelist;
594static union node *redirnode;
595static struct heredoc *heredoc;
596static int quoteflag; /* set if (part of) last token was quoted */
597static int startlinno; /* line # where last token started */
598
599static union node *parsecmd(int);
600static void fixredir(union node *, const char *, int);
601static const char *const *findkwd(const char *);
602static char *endofname(const char *);
603
604/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
605
606typedef void *pointer;
607
608static char nullstr[1]; /* zero length string */
609static const char spcstr[] = " ";
610static const char snlfmt[] = "%s\n";
611static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
612static const char illnum[] = "Illegal number: %s";
613static const char homestr[] = "HOME";
614
615#ifdef DEBUG
616#define TRACE(param) trace param
617#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000618#else
Eric Andersenc470f442003-07-28 09:56:35 +0000619#define TRACE(param)
620#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000621#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000622
Eric Andersenc470f442003-07-28 09:56:35 +0000623#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
624#define __builtin_expect(x, expected_value) (x)
625#endif
626
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000627#define xlikely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000628
Eric Andersenc470f442003-07-28 09:56:35 +0000629
630#define TEOF 0
631#define TNL 1
632#define TREDIR 2
633#define TWORD 3
634#define TSEMI 4
635#define TBACKGND 5
636#define TAND 6
637#define TOR 7
638#define TPIPE 8
639#define TLP 9
640#define TRP 10
641#define TENDCASE 11
642#define TENDBQUOTE 12
643#define TNOT 13
644#define TCASE 14
645#define TDO 15
646#define TDONE 16
647#define TELIF 17
648#define TELSE 18
649#define TESAC 19
650#define TFI 20
651#define TFOR 21
652#define TIF 22
653#define TIN 23
654#define TTHEN 24
655#define TUNTIL 25
656#define TWHILE 26
657#define TBEGIN 27
658#define TEND 28
659
660/* first char is indicating which tokens mark the end of a list */
661static const char *const tokname_array[] = {
662 "\1end of file",
663 "\0newline",
664 "\0redirection",
665 "\0word",
666 "\0;",
667 "\0&",
668 "\0&&",
669 "\0||",
670 "\0|",
671 "\0(",
672 "\1)",
673 "\1;;",
674 "\1`",
675#define KWDOFFSET 13
676 /* the following are keywords */
677 "\0!",
678 "\0case",
679 "\1do",
680 "\1done",
681 "\1elif",
682 "\1else",
683 "\1esac",
684 "\1fi",
685 "\0for",
686 "\0if",
687 "\0in",
688 "\1then",
689 "\0until",
690 "\0while",
691 "\0{",
692 "\1}",
693};
694
695static const char *tokname(int tok)
696{
697 static char buf[16];
698
699 if (tok >= TSEMI)
700 buf[0] = '"';
701 sprintf(buf + (tok >= TSEMI), "%s%c",
702 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
703 return buf;
704}
705
706/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
707
708/*
709 * Most machines require the value returned from malloc to be aligned
710 * in some way. The following macro will get this right on many machines.
711 */
712
713#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
714/*
715 * It appears that grabstackstr() will barf with such alignments
716 * because stalloc() will return a string allocated in a new stackblock.
717 */
718#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
719
720/*
721 * This file was generated by the mksyntax program.
722 */
723
724
725/* Syntax classes */
726#define CWORD 0 /* character is nothing special */
727#define CNL 1 /* newline character */
728#define CBACK 2 /* a backslash character */
729#define CSQUOTE 3 /* single quote */
730#define CDQUOTE 4 /* double quote */
731#define CENDQUOTE 5 /* a terminating quote */
732#define CBQUOTE 6 /* backwards single quote */
733#define CVAR 7 /* a dollar sign */
734#define CENDVAR 8 /* a '}' character */
735#define CLP 9 /* a left paren in arithmetic */
736#define CRP 10 /* a right paren in arithmetic */
737#define CENDFILE 11 /* end of file */
738#define CCTL 12 /* like CWORD, except it must be escaped */
739#define CSPCL 13 /* these terminate a word */
740#define CIGN 14 /* character should be ignored */
741
742#ifdef CONFIG_ASH_ALIAS
743#define SYNBASE 130
744#define PEOF -130
745#define PEOA -129
746#define PEOA_OR_PEOF PEOA
747#else
748#define SYNBASE 129
749#define PEOF -129
750#define PEOA_OR_PEOF PEOF
751#endif
752
753#define is_digit(c) ((unsigned)((c) - '0') <= 9)
754#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
755#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
756
757/*
758 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
759 * (assuming ascii char codes, as the original implementation did)
760 */
761#define is_special(c) \
762 ( (((unsigned int)c) - 33 < 32) \
763 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
764
765#define digit_val(c) ((c) - '0')
766
767/*
768 * This file was generated by the mksyntax program.
769 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000770
Eric Andersend35c5df2002-01-09 15:37:36 +0000771#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000772#define USE_SIT_FUNCTION
773#endif
774
775/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000776#define BASESYNTAX 0 /* not in quotes */
777#define DQSYNTAX 1 /* in double quotes */
778#define SQSYNTAX 2 /* in single quotes */
779#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000780
Eric Andersenc470f442003-07-28 09:56:35 +0000781#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000782static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000783#ifdef CONFIG_ASH_ALIAS
784 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
785#endif
786 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
787 {CNL, CNL, CNL, CNL}, /* 2, \n */
788 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
789 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
790 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
791 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
792 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
793 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
794 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
795 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
796 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000797#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000798 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
799 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
800 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000801#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000802};
Eric Andersenc470f442003-07-28 09:56:35 +0000803#else
804static const char S_I_T[][3] = {
805#ifdef CONFIG_ASH_ALIAS
806 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
807#endif
808 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
809 {CNL, CNL, CNL}, /* 2, \n */
810 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
811 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
812 {CVAR, CVAR, CWORD}, /* 5, $ */
813 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
814 {CSPCL, CWORD, CWORD}, /* 7, ( */
815 {CSPCL, CWORD, CWORD}, /* 8, ) */
816 {CBACK, CBACK, CCTL}, /* 9, \ */
817 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
818 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
819#ifndef USE_SIT_FUNCTION
820 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
821 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
822 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
823#endif
824};
825#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000826
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000827#ifdef USE_SIT_FUNCTION
828
829#define U_C(c) ((unsigned char)(c))
830
831static int SIT(int c, int syntax)
832{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000833 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000834#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000835 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000836 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
837 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
838 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
839 11, 3 /* "}~" */
840 };
841#else
842 static const char syntax_index_table[] = {
843 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
844 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
845 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
846 10, 2 /* "}~" */
847 };
848#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000849 const char *s;
850 int indx;
851
Eric Andersenc470f442003-07-28 09:56:35 +0000852 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000853 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000854#ifdef CONFIG_ASH_ALIAS
855 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000856 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000857 else
858#endif
859 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
860 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000861 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000862 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000863 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000864 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000865 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000866 }
867 return S_I_T[indx][syntax];
868}
869
Eric Andersenc470f442003-07-28 09:56:35 +0000870#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000871
872#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
873
Eric Andersenc470f442003-07-28 09:56:35 +0000874#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000875#define CSPCL_CIGN_CIGN_CIGN 0
876#define CSPCL_CWORD_CWORD_CWORD 1
877#define CNL_CNL_CNL_CNL 2
878#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000879#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000880#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000881#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000882#define CSPCL_CWORD_CWORD_CLP 7
883#define CSPCL_CWORD_CWORD_CRP 8
884#define CBACK_CBACK_CCTL_CBACK 9
885#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
886#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
887#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
888#define CWORD_CWORD_CWORD_CWORD 13
889#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000890#else
891#define CSPCL_CWORD_CWORD_CWORD 0
892#define CNL_CNL_CNL_CNL 1
893#define CWORD_CCTL_CCTL_CWORD 2
894#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
895#define CVAR_CVAR_CWORD_CVAR 4
896#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
897#define CSPCL_CWORD_CWORD_CLP 6
898#define CSPCL_CWORD_CWORD_CRP 7
899#define CBACK_CBACK_CCTL_CBACK 8
900#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
901#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
902#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
903#define CWORD_CWORD_CWORD_CWORD 12
904#define CCTL_CCTL_CCTL_CCTL 13
905#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000906
907static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000908 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000909 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
910#ifdef CONFIG_ASH_ALIAS
911 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
912#endif
913 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
914 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
915 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
916 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
917 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
918 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
919 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
920 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
921 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000922 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
923 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
924 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
925 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
926 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
927 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
928 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
929 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
930 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
931 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
932 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
933 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
934 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
935 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
936 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
937 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
938 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
939 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
940 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
941 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
942 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
943 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
944 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
945 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
946 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
947 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
948 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
949 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
950 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
951 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
952 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
953 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
954 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
955 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
956 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
957 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
958 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
959 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
960 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
961 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
962 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
963 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
964 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
965 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
966 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
967 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
968 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
969 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
970 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
971 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
972 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
973 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
974 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
975 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
976 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
977 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
978 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
979 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
980 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
981 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
982 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
983 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
984 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
985 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
986 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
987 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
988 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
989 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
990 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
991 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
992 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
993 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
994 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
995 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
996 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
997 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
998 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
999 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1051 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1052 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1053 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1054 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1055 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1056 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1057 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1058 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1059 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1060 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1061 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1062 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1063 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1064 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1065 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1066 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1067 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1068 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1069 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1070 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1071 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1072 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1073 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001075 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001076 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1077 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1078 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001080 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001081 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1082 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1083 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1084 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1086 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1087 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1088 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1089 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1100 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1101 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1102 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1103 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1104 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1105 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1133 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1134 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1135 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1138 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1143 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1144 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1145 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1146 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1147 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1148 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1149 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1150 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1151 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1152 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1153 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1154 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1155 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1156 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1157 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1158 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1159 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1160 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1161 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1162 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1163 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1164 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1165 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1166 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1167 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1168 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001169};
1170
Eric Andersenc470f442003-07-28 09:56:35 +00001171#endif /* USE_SIT_FUNCTION */
1172
1173/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001174
Eric Andersen2870d962001-07-02 17:27:21 +00001175
Eric Andersenc470f442003-07-28 09:56:35 +00001176#define ATABSIZE 39
1177
1178static int funcblocksize; /* size of structures in function */
1179static int funcstringsize; /* size of strings in node */
1180static pointer funcblock; /* block to allocate function from */
1181static char *funcstring; /* block to allocate strings from */
1182
1183static const short nodesize[26] = {
1184 SHELL_ALIGN(sizeof (struct ncmd)),
1185 SHELL_ALIGN(sizeof (struct npipe)),
1186 SHELL_ALIGN(sizeof (struct nredir)),
1187 SHELL_ALIGN(sizeof (struct nredir)),
1188 SHELL_ALIGN(sizeof (struct nredir)),
1189 SHELL_ALIGN(sizeof (struct nbinary)),
1190 SHELL_ALIGN(sizeof (struct nbinary)),
1191 SHELL_ALIGN(sizeof (struct nbinary)),
1192 SHELL_ALIGN(sizeof (struct nif)),
1193 SHELL_ALIGN(sizeof (struct nbinary)),
1194 SHELL_ALIGN(sizeof (struct nbinary)),
1195 SHELL_ALIGN(sizeof (struct nfor)),
1196 SHELL_ALIGN(sizeof (struct ncase)),
1197 SHELL_ALIGN(sizeof (struct nclist)),
1198 SHELL_ALIGN(sizeof (struct narg)),
1199 SHELL_ALIGN(sizeof (struct narg)),
1200 SHELL_ALIGN(sizeof (struct nfile)),
1201 SHELL_ALIGN(sizeof (struct nfile)),
1202 SHELL_ALIGN(sizeof (struct nfile)),
1203 SHELL_ALIGN(sizeof (struct nfile)),
1204 SHELL_ALIGN(sizeof (struct nfile)),
1205 SHELL_ALIGN(sizeof (struct ndup)),
1206 SHELL_ALIGN(sizeof (struct ndup)),
1207 SHELL_ALIGN(sizeof (struct nhere)),
1208 SHELL_ALIGN(sizeof (struct nhere)),
1209 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001210};
1211
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001212
Eric Andersenc470f442003-07-28 09:56:35 +00001213static void calcsize(union node *);
1214static void sizenodelist(struct nodelist *);
1215static union node *copynode(union node *);
1216static struct nodelist *copynodelist(struct nodelist *);
1217static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001218
1219
Eric Andersen2870d962001-07-02 17:27:21 +00001220
Glenn L McGrath76620622004-01-13 10:19:37 +00001221static void evalstring(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001222union node; /* BLETCH for ansi C */
1223static void evaltree(union node *, int);
1224static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001225
Eric Andersenc470f442003-07-28 09:56:35 +00001226/* in_function returns nonzero if we are currently evaluating a function */
1227#define in_function() funcnest
1228static int evalskip; /* set if we are skipping commands */
1229static int skipcount; /* number of levels to skip */
1230static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001231
1232/* reasons for skipping commands (see comment on breakcmd routine) */
1233#define SKIPBREAK 1
1234#define SKIPCONT 2
1235#define SKIPFUNC 3
1236#define SKIPFILE 4
1237
Eric Andersenc470f442003-07-28 09:56:35 +00001238/*
1239 * This file was generated by the mkbuiltins program.
1240 */
Eric Andersen2870d962001-07-02 17:27:21 +00001241
Eric Andersenc470f442003-07-28 09:56:35 +00001242#ifdef JOBS
1243static int bgcmd(int, char **);
1244#endif
1245static int breakcmd(int, char **);
1246static int cdcmd(int, char **);
1247#ifdef CONFIG_ASH_CMDCMD
1248static int commandcmd(int, char **);
1249#endif
1250static int dotcmd(int, char **);
1251static int evalcmd(int, char **);
1252static int execcmd(int, char **);
1253static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001254static int exportcmd(int, char **);
1255static int falsecmd(int, char **);
1256#ifdef JOBS
1257static int fgcmd(int, char **);
1258#endif
1259#ifdef CONFIG_ASH_GETOPTS
1260static int getoptscmd(int, char **);
1261#endif
1262static int hashcmd(int, char **);
1263#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1264static int helpcmd(int argc, char **argv);
1265#endif
1266#ifdef JOBS
1267static int jobscmd(int, char **);
1268#endif
Eric Andersen90898442003-08-06 11:20:52 +00001269#ifdef CONFIG_ASH_MATH_SUPPORT
1270static int letcmd(int, char **);
1271#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001272static int localcmd(int, char **);
1273static int pwdcmd(int, char **);
1274static int readcmd(int, char **);
1275static int returncmd(int, char **);
1276static int setcmd(int, char **);
1277static int shiftcmd(int, char **);
1278static int timescmd(int, char **);
1279static int trapcmd(int, char **);
1280static int truecmd(int, char **);
1281static int typecmd(int, char **);
1282static int umaskcmd(int, char **);
1283static int unsetcmd(int, char **);
1284static int waitcmd(int, char **);
1285static int ulimitcmd(int, char **);
1286#ifdef JOBS
1287static int killcmd(int, char **);
1288#endif
1289
1290/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1291
1292#ifdef CONFIG_ASH_MAIL
1293static void chkmail(void);
1294static void changemail(const char *);
1295#endif
1296
1297/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1298
1299/* values of cmdtype */
1300#define CMDUNKNOWN -1 /* no entry in table for command */
1301#define CMDNORMAL 0 /* command is an executable program */
1302#define CMDFUNCTION 1 /* command is a shell function */
1303#define CMDBUILTIN 2 /* command is a shell builtin */
1304
1305struct builtincmd {
1306 const char *name;
1307 int (*builtin)(int, char **);
1308 /* unsigned flags; */
1309};
1310
1311#ifdef CONFIG_ASH_CMDCMD
1312# ifdef JOBS
1313# ifdef CONFIG_ASH_ALIAS
1314# define COMMANDCMD (builtincmd + 7)
1315# define EXECCMD (builtincmd + 10)
1316# else
1317# define COMMANDCMD (builtincmd + 6)
1318# define EXECCMD (builtincmd + 9)
1319# endif
1320# else /* ! JOBS */
1321# ifdef CONFIG_ASH_ALIAS
1322# define COMMANDCMD (builtincmd + 6)
1323# define EXECCMD (builtincmd + 9)
1324# else
1325# define COMMANDCMD (builtincmd + 5)
1326# define EXECCMD (builtincmd + 8)
1327# endif
1328# endif /* JOBS */
1329#else /* ! CONFIG_ASH_CMDCMD */
1330# ifdef JOBS
1331# ifdef CONFIG_ASH_ALIAS
1332# define EXECCMD (builtincmd + 9)
1333# else
1334# define EXECCMD (builtincmd + 8)
1335# endif
1336# else /* ! JOBS */
1337# ifdef CONFIG_ASH_ALIAS
1338# define EXECCMD (builtincmd + 8)
1339# else
1340# define EXECCMD (builtincmd + 7)
1341# endif
1342# endif /* JOBS */
1343#endif /* CONFIG_ASH_CMDCMD */
1344
1345#define BUILTIN_NOSPEC "0"
1346#define BUILTIN_SPECIAL "1"
1347#define BUILTIN_REGULAR "2"
1348#define BUILTIN_SPEC_REG "3"
1349#define BUILTIN_ASSIGN "4"
1350#define BUILTIN_SPEC_ASSG "5"
1351#define BUILTIN_REG_ASSG "6"
1352#define BUILTIN_SPEC_REG_ASSG "7"
1353
1354#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1355#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1356
1357static const struct builtincmd builtincmd[] = {
1358 { BUILTIN_SPEC_REG ".", dotcmd },
1359 { BUILTIN_SPEC_REG ":", truecmd },
1360#ifdef CONFIG_ASH_ALIAS
1361 { BUILTIN_REG_ASSG "alias", aliascmd },
1362#endif
1363#ifdef JOBS
1364 { BUILTIN_REGULAR "bg", bgcmd },
1365#endif
1366 { BUILTIN_SPEC_REG "break", breakcmd },
1367 { BUILTIN_REGULAR "cd", cdcmd },
1368 { BUILTIN_NOSPEC "chdir", cdcmd },
1369#ifdef CONFIG_ASH_CMDCMD
1370 { BUILTIN_REGULAR "command", commandcmd },
1371#endif
1372 { BUILTIN_SPEC_REG "continue", breakcmd },
1373 { BUILTIN_SPEC_REG "eval", evalcmd },
1374 { BUILTIN_SPEC_REG "exec", execcmd },
1375 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001376 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1377 { BUILTIN_REGULAR "false", falsecmd },
1378#ifdef JOBS
1379 { BUILTIN_REGULAR "fg", fgcmd },
1380#endif
1381#ifdef CONFIG_ASH_GETOPTS
1382 { BUILTIN_REGULAR "getopts", getoptscmd },
1383#endif
1384 { BUILTIN_NOSPEC "hash", hashcmd },
1385#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1386 { BUILTIN_NOSPEC "help", helpcmd },
1387#endif
1388#ifdef JOBS
1389 { BUILTIN_REGULAR "jobs", jobscmd },
1390 { BUILTIN_REGULAR "kill", killcmd },
1391#endif
1392#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001393 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001394#endif
1395 { BUILTIN_ASSIGN "local", localcmd },
1396 { BUILTIN_NOSPEC "pwd", pwdcmd },
1397 { BUILTIN_REGULAR "read", readcmd },
1398 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1399 { BUILTIN_SPEC_REG "return", returncmd },
1400 { BUILTIN_SPEC_REG "set", setcmd },
1401 { BUILTIN_SPEC_REG "shift", shiftcmd },
1402 { BUILTIN_SPEC_REG "times", timescmd },
1403 { BUILTIN_SPEC_REG "trap", trapcmd },
1404 { BUILTIN_REGULAR "true", truecmd },
1405 { BUILTIN_NOSPEC "type", typecmd },
1406 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1407 { BUILTIN_REGULAR "umask", umaskcmd },
1408#ifdef CONFIG_ASH_ALIAS
1409 { BUILTIN_REGULAR "unalias", unaliascmd },
1410#endif
1411 { BUILTIN_SPEC_REG "unset", unsetcmd },
1412 { BUILTIN_REGULAR "wait", waitcmd },
1413};
1414
1415#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1416
1417
1418
1419struct cmdentry {
1420 int cmdtype;
1421 union param {
1422 int index;
1423 const struct builtincmd *cmd;
1424 struct funcnode *func;
1425 } u;
1426};
1427
1428
1429/* action to find_command() */
1430#define DO_ERR 0x01 /* prints errors */
1431#define DO_ABS 0x02 /* checks absolute paths */
1432#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1433#define DO_ALTPATH 0x08 /* using alternate path */
1434#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1435
1436static const char *pathopt; /* set by padvance */
1437
1438static void shellexec(char **, const char *, int)
1439 __attribute__((__noreturn__));
1440static char *padvance(const char **, const char *);
1441static void find_command(char *, struct cmdentry *, int, const char *);
1442static struct builtincmd *find_builtin(const char *);
1443static void hashcd(void);
1444static void changepath(const char *);
1445static void defun(char *, union node *);
1446static void unsetfunc(const char *);
1447
Eric Andersened9ecf72004-06-22 08:29:45 +00001448#ifdef CONFIG_ASH_MATH_SUPPORT_64
1449typedef int64_t arith_t;
1450#else
1451typedef long arith_t;
1452#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001453
1454#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001455static arith_t dash_arith(const char *);
1456static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001457#endif
1458
Eric Andersen16767e22004-03-16 05:14:10 +00001459#ifdef CONFIG_ASH_RANDOM_SUPPORT
1460static unsigned long rseed;
1461static void change_random(const char *);
1462# ifndef DYNAMIC_VAR
1463# define DYNAMIC_VAR
1464# endif
1465#endif
1466
Eric Andersenc470f442003-07-28 09:56:35 +00001467/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1468
1469static void reset(void);
1470
1471/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001472
1473/*
1474 * Shell variables.
1475 */
1476
1477/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001478#define VEXPORT 0x01 /* variable is exported */
1479#define VREADONLY 0x02 /* variable cannot be modified */
1480#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1481#define VTEXTFIXED 0x08 /* text is statically allocated */
1482#define VSTACK 0x10 /* text is allocated on the stack */
1483#define VUNSET 0x20 /* the variable is not set */
1484#define VNOFUNC 0x40 /* don't call the callback function */
1485#define VNOSET 0x80 /* do not set variable - just readonly test */
1486#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001487#ifdef DYNAMIC_VAR
1488# define VDYNAMIC 0x200 /* dynamic variable */
1489# else
1490# define VDYNAMIC 0
1491#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001492
1493struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001494 struct var *next; /* next entry in hash list */
1495 int flags; /* flags are defined above */
1496 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001497 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001498 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001499};
1500
1501struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001502 struct localvar *next; /* next local variable in list */
1503 struct var *vp; /* the variable that was made local */
1504 int flags; /* saved flags */
1505 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001506};
1507
1508
Eric Andersen2870d962001-07-02 17:27:21 +00001509static struct localvar *localvars;
1510
Eric Andersenc470f442003-07-28 09:56:35 +00001511/*
1512 * Shell variables.
1513 */
1514
1515#ifdef CONFIG_ASH_GETOPTS
1516static void getoptsreset(const char *);
1517#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001518
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001519#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001520#include <locale.h>
1521static void change_lc_all(const char *value);
1522static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001523#endif
1524
Eric Andersenef02f822004-03-11 13:34:24 +00001525
Eric Andersen2870d962001-07-02 17:27:21 +00001526#define VTABSIZE 39
1527
Eric Andersen90898442003-08-06 11:20:52 +00001528static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001529#ifdef IFS_BROKEN
1530static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001531#define defifs (defifsvar + 4)
1532#else
Eric Andersenc470f442003-07-28 09:56:35 +00001533static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001534#endif
1535
Eric Andersenc470f442003-07-28 09:56:35 +00001536
1537static struct var varinit[] = {
1538#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001539 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001540#else
Eric Andersen16767e22004-03-16 05:14:10 +00001541 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001542#endif
1543
1544#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001545 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1546 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001547#endif
1548
Eric Andersen16767e22004-03-16 05:14:10 +00001549 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1550 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1551 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1552 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001553#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001554 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1555#endif
1556#ifdef CONFIG_ASH_RANDOM_SUPPORT
1557 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001558#endif
1559#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001560 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1561 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001562#endif
1563#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001564 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001565#endif
1566};
1567
1568#define vifs varinit[0]
1569#ifdef CONFIG_ASH_MAIL
1570#define vmail (&vifs)[1]
1571#define vmpath (&vmail)[1]
1572#else
1573#define vmpath vifs
1574#endif
1575#define vpath (&vmpath)[1]
1576#define vps1 (&vpath)[1]
1577#define vps2 (&vps1)[1]
1578#define vps4 (&vps2)[1]
1579#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001580#ifdef CONFIG_ASH_GETOPTS
1581#define vrandom (&voptind)[1]
1582#else
1583#define vrandom (&vps4)[1]
1584#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001585#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001586
1587/*
1588 * The following macros access the values of the above variables.
1589 * They have to skip over the name. They return the null string
1590 * for unset variables.
1591 */
1592
1593#define ifsval() (vifs.text + 4)
1594#define ifsset() ((vifs.flags & VUNSET) == 0)
1595#define mailval() (vmail.text + 5)
1596#define mpathval() (vmpath.text + 9)
1597#define pathval() (vpath.text + 5)
1598#define ps1val() (vps1.text + 4)
1599#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001600#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001601#define optindval() (voptind.text + 7)
1602
1603#define mpathset() ((vmpath.flags & VUNSET) == 0)
1604
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001605static void setvar(const char *, const char *, int);
1606static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001607static void listsetvar(struct strlist *, int);
1608static char *lookupvar(const char *);
1609static char *bltinlookup(const char *);
1610static char **listvars(int, int, char ***);
1611#define environment() listvars(VEXPORT, VUNSET, 0)
1612static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001613static void poplocalvars(void);
1614static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001615#ifdef CONFIG_ASH_GETOPTS
1616static int setvarsafe(const char *, const char *, int);
1617#endif
1618static int varcmp(const char *, const char *);
1619static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001620
1621
Eric Andersenc470f442003-07-28 09:56:35 +00001622static inline int varequal(const char *a, const char *b) {
1623 return !varcmp(a, b);
1624}
Eric Andersen2870d962001-07-02 17:27:21 +00001625
1626
Eric Andersenc470f442003-07-28 09:56:35 +00001627static int loopnest; /* current loop nesting level */
1628
Eric Andersenc470f442003-07-28 09:56:35 +00001629/*
1630 * The parsefile structure pointed to by the global variable parsefile
1631 * contains information about the current file being read.
1632 */
1633
1634
1635struct redirtab {
1636 struct redirtab *next;
1637 int renamed[10];
1638 int nullredirs;
1639};
1640
1641static struct redirtab *redirlist;
1642static int nullredirs;
1643
1644extern char **environ;
1645
1646/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1647
1648
1649static void outstr(const char *, FILE *);
1650static void outcslow(int, FILE *);
1651static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001652static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001653static int out1fmt(const char *, ...)
1654 __attribute__((__format__(__printf__,1,2)));
1655static int fmtstr(char *, size_t, const char *, ...)
1656 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001657
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001658static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001659
Eric Andersenc470f442003-07-28 09:56:35 +00001660
1661static void out1str(const char *p)
1662{
1663 outstr(p, stdout);
1664}
1665
1666static void out2str(const char *p)
1667{
1668 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001669 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001670}
1671
1672/*
1673 * Initialization code.
1674 */
1675
1676/*
1677 * This routine initializes the builtin variables.
1678 */
1679
1680static inline void
1681initvar(void)
1682{
1683 struct var *vp;
1684 struct var *end;
1685 struct var **vpp;
1686
1687 /*
1688 * PS1 depends on uid
1689 */
1690#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1691 vps1.text = "PS1=\\w \\$ ";
1692#else
1693 if (!geteuid())
1694 vps1.text = "PS1=# ";
1695#endif
1696 vp = varinit;
1697 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1698 do {
1699 vpp = hashvar(vp->text);
1700 vp->next = *vpp;
1701 *vpp = vp;
1702 } while (++vp < end);
1703}
1704
1705static inline void
1706init(void)
1707{
1708
1709 /* from input.c: */
1710 {
1711 basepf.nextc = basepf.buf = basebuf;
1712 }
1713
1714 /* from trap.c: */
1715 {
1716 signal(SIGCHLD, SIG_DFL);
1717 }
1718
1719 /* from var.c: */
1720 {
1721 char **envp;
1722 char ppid[32];
1723
1724 initvar();
1725 for (envp = environ ; *envp ; envp++) {
1726 if (strchr(*envp, '=')) {
1727 setvareq(*envp, VEXPORT|VTEXTFIXED);
1728 }
1729 }
1730
1731 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1732 setvar("PPID", ppid, 0);
1733 setpwd(0, 0);
1734 }
1735}
1736
1737/* PEOF (the end of file marker) */
1738
1739/*
1740 * The input line number. Input.c just defines this variable, and saves
1741 * and restores it when files are pushed and popped. The user of this
1742 * package must set its value.
1743 */
1744
1745static int pgetc(void);
1746static int pgetc2(void);
1747static int preadbuffer(void);
1748static void pungetc(void);
1749static void pushstring(char *, void *);
1750static void popstring(void);
1751static void setinputfile(const char *, int);
1752static void setinputfd(int, int);
1753static void setinputstring(char *);
1754static void popfile(void);
1755static void popallfiles(void);
1756static void closescript(void);
1757
1758
1759/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1760
1761
1762/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1763#define FORK_FG 0
1764#define FORK_BG 1
1765#define FORK_NOJOB 2
1766
1767/* mode flags for showjob(s) */
1768#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1769#define SHOW_PID 0x04 /* include process pid */
1770#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1771
1772
1773/*
1774 * A job structure contains information about a job. A job is either a
1775 * single process or a set of processes contained in a pipeline. In the
1776 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1777 * array of pids.
1778 */
1779
1780struct procstat {
1781 pid_t pid; /* process id */
1782 int status; /* last process status from wait() */
1783 char *cmd; /* text of command being run */
1784};
1785
1786struct job {
1787 struct procstat ps0; /* status of process */
1788 struct procstat *ps; /* status or processes when more than one */
1789#if JOBS
1790 int stopstatus; /* status of a stopped job */
1791#endif
1792 uint32_t
1793 nprocs: 16, /* number of processes */
1794 state: 8,
1795#define JOBRUNNING 0 /* at least one proc running */
1796#define JOBSTOPPED 1 /* all procs are stopped */
1797#define JOBDONE 2 /* all procs are completed */
1798#if JOBS
1799 sigint: 1, /* job was killed by SIGINT */
1800 jobctl: 1, /* job running under job control */
1801#endif
1802 waited: 1, /* true if this entry has been waited for */
1803 used: 1, /* true if this entry is in used */
1804 changed: 1; /* true if status has changed */
1805 struct job *prev_job; /* previous job */
1806};
1807
1808static pid_t backgndpid; /* pid of last background process */
1809static int job_warning; /* user was warned about stopped jobs */
1810#if JOBS
1811static int jobctl; /* true if doing job control */
1812#endif
1813
1814static struct job *makejob(union node *, int);
1815static int forkshell(struct job *, union node *, int);
1816static int waitforjob(struct job *);
1817static int stoppedjobs(void);
1818
1819#if ! JOBS
1820#define setjobctl(on) /* do nothing */
1821#else
1822static void setjobctl(int);
1823static void showjobs(FILE *, int);
1824#endif
1825
1826/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1827
1828
1829/* pid of main shell */
1830static int rootpid;
1831/* true if we aren't a child of the main shell */
1832static int rootshell;
1833
1834static void readcmdfile(char *);
1835static void cmdloop(int);
1836
1837/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1838
1839
1840struct stackmark {
1841 struct stack_block *stackp;
1842 char *stacknxt;
1843 size_t stacknleft;
1844 struct stackmark *marknext;
1845};
1846
1847/* minimum size of a block */
1848#define MINSIZE SHELL_ALIGN(504)
1849
1850struct stack_block {
1851 struct stack_block *prev;
1852 char space[MINSIZE];
1853};
1854
1855static struct stack_block stackbase;
1856static struct stack_block *stackp = &stackbase;
1857static struct stackmark *markp;
1858static char *stacknxt = stackbase.space;
1859static size_t stacknleft = MINSIZE;
1860static char *sstrend = stackbase.space + MINSIZE;
1861static int herefd = -1;
1862
1863
1864static pointer ckmalloc(size_t);
1865static pointer ckrealloc(pointer, size_t);
1866static char *savestr(const char *);
1867static pointer stalloc(size_t);
1868static void stunalloc(pointer);
1869static void setstackmark(struct stackmark *);
1870static void popstackmark(struct stackmark *);
1871static void growstackblock(void);
1872static void *growstackstr(void);
1873static char *makestrspace(size_t, char *);
1874static char *stnputs(const char *, size_t, char *);
1875static char *stputs(const char *, char *);
1876
1877
1878static inline char *_STPUTC(char c, char *p) {
1879 if (p == sstrend)
1880 p = growstackstr();
1881 *p++ = c;
1882 return p;
1883}
1884
1885#define stackblock() ((void *)stacknxt)
1886#define stackblocksize() stacknleft
1887#define STARTSTACKSTR(p) ((p) = stackblock())
1888#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1889#define CHECKSTRSPACE(n, p) \
1890 ({ \
1891 char *q = (p); \
1892 size_t l = (n); \
1893 size_t m = sstrend - q; \
1894 if (l > m) \
1895 (p) = makestrspace(l, q); \
1896 0; \
1897 })
1898#define USTPUTC(c, p) (*p++ = (c))
1899#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1900#define STUNPUTC(p) (--p)
1901#define STTOPC(p) p[-1]
1902#define STADJUST(amount, p) (p += (amount))
1903
1904#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1905#define ungrabstackstr(s, p) stunalloc((s))
1906#define stackstrend() ((void *)sstrend)
1907
1908#define ckfree(p) free((pointer)(p))
1909
1910/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1911
1912
1913#define DOLATSTRLEN 4
1914
1915static char *prefix(const char *, const char *);
1916static int number(const char *);
1917static int is_number(const char *);
1918static char *single_quote(const char *);
1919static char *sstrdup(const char *);
1920
1921#define equal(s1, s2) (strcmp(s1, s2) == 0)
1922#define scopy(s1, s2) ((void)strcpy(s2, s1))
1923
1924/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1925
1926struct shparam {
1927 int nparam; /* # of positional parameters (without $0) */
1928 unsigned char malloc; /* if parameter list dynamically allocated */
1929 char **p; /* parameter list */
1930#ifdef CONFIG_ASH_GETOPTS
1931 int optind; /* next parameter to be processed by getopts */
1932 int optoff; /* used by getopts */
1933#endif
1934};
1935
1936
1937#define eflag optlist[0]
1938#define fflag optlist[1]
1939#define Iflag optlist[2]
1940#define iflag optlist[3]
1941#define mflag optlist[4]
1942#define nflag optlist[5]
1943#define sflag optlist[6]
1944#define xflag optlist[7]
1945#define vflag optlist[8]
1946#define Cflag optlist[9]
1947#define aflag optlist[10]
1948#define bflag optlist[11]
1949#define uflag optlist[12]
1950#define qflag optlist[13]
1951
1952#ifdef DEBUG
1953#define nolog optlist[14]
1954#define debug optlist[15]
1955#define NOPTS 16
1956#else
1957#define NOPTS 14
1958#endif
1959
1960/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1961
1962
1963static const char *const optletters_optnames[NOPTS] = {
1964 "e" "errexit",
1965 "f" "noglob",
1966 "I" "ignoreeof",
1967 "i" "interactive",
1968 "m" "monitor",
1969 "n" "noexec",
1970 "s" "stdin",
1971 "x" "xtrace",
1972 "v" "verbose",
1973 "C" "noclobber",
1974 "a" "allexport",
1975 "b" "notify",
1976 "u" "nounset",
1977 "q" "quietprofile",
1978#ifdef DEBUG
1979 "\0" "nolog",
1980 "\0" "debug",
1981#endif
1982};
1983
1984#define optletters(n) optletters_optnames[(n)][0]
1985#define optnames(n) (&optletters_optnames[(n)][1])
1986
1987
1988static char optlist[NOPTS];
1989
1990
1991static char *arg0; /* value of $0 */
1992static struct shparam shellparam; /* $@ current positional parameters */
1993static char **argptr; /* argument list for builtin commands */
1994static char *optionarg; /* set by nextopt (like getopt) */
1995static char *optptr; /* used by nextopt */
1996
1997static char *minusc; /* argument to -c option */
1998
1999
2000static void procargs(int, char **);
2001static void optschanged(void);
2002static void setparam(char **);
2003static void freeparam(volatile struct shparam *);
2004static int shiftcmd(int, char **);
2005static int setcmd(int, char **);
2006static int nextopt(const char *);
2007
2008/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
2009
2010/* flags passed to redirect */
2011#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002012#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00002013
2014union node;
2015static void redirect(union node *, int);
2016static void popredir(int);
2017static void clearredir(int);
2018static int copyfd(int, int);
2019static int redirectsafe(union node *, int);
2020
2021/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2022
2023
2024#ifdef DEBUG
2025static void showtree(union node *);
2026static void trace(const char *, ...);
2027static void tracev(const char *, va_list);
2028static void trargs(char **);
2029static void trputc(int);
2030static void trputs(const char *);
2031static void opentrace(void);
2032#endif
2033
2034/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2035
2036
2037/* trap handler commands */
2038static char *trap[NSIG];
2039/* current value of signal */
2040static char sigmode[NSIG - 1];
2041/* indicates specified signal received */
2042static char gotsig[NSIG - 1];
2043
2044static void clear_traps(void);
2045static void setsignal(int);
2046static void ignoresig(int);
2047static void onsig(int);
2048static void dotrap(void);
2049static void setinteractive(int);
2050static void exitshell(void) __attribute__((__noreturn__));
2051static int decode_signal(const char *, int);
2052
2053/*
2054 * This routine is called when an error or an interrupt occurs in an
2055 * interactive shell and control is returned to the main command loop.
2056 */
2057
2058static void
2059reset(void)
2060{
2061 /* from eval.c: */
2062 {
2063 evalskip = 0;
2064 loopnest = 0;
2065 funcnest = 0;
2066 }
2067
2068 /* from input.c: */
2069 {
2070 parselleft = parsenleft = 0; /* clear input buffer */
2071 popallfiles();
2072 }
2073
2074 /* from parser.c: */
2075 {
2076 tokpushback = 0;
2077 checkkwd = 0;
2078 }
2079
2080 /* from redir.c: */
2081 {
2082 clearredir(0);
2083 }
2084
2085}
2086
2087#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002088static struct alias *atab[ATABSIZE];
2089
Eric Andersenc470f442003-07-28 09:56:35 +00002090static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002091static struct alias *freealias(struct alias *);
2092static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002093
Eric Andersenc470f442003-07-28 09:56:35 +00002094static void
2095setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002096{
2097 struct alias *ap, **app;
2098
2099 app = __lookupalias(name);
2100 ap = *app;
2101 INTOFF;
2102 if (ap) {
2103 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002104 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002105 }
Eric Andersenc470f442003-07-28 09:56:35 +00002106 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002107 ap->flag &= ~ALIASDEAD;
2108 } else {
2109 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002110 ap = ckmalloc(sizeof (struct alias));
2111 ap->name = savestr(name);
2112 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002113 ap->flag = 0;
2114 ap->next = 0;
2115 *app = ap;
2116 }
2117 INTON;
2118}
2119
Eric Andersenc470f442003-07-28 09:56:35 +00002120static int
2121unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002122{
Eric Andersencb57d552001-06-28 07:25:16 +00002123 struct alias **app;
2124
2125 app = __lookupalias(name);
2126
2127 if (*app) {
2128 INTOFF;
2129 *app = freealias(*app);
2130 INTON;
2131 return (0);
2132 }
2133
2134 return (1);
2135}
2136
Eric Andersenc470f442003-07-28 09:56:35 +00002137static void
2138rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002139{
Eric Andersencb57d552001-06-28 07:25:16 +00002140 struct alias *ap, **app;
2141 int i;
2142
2143 INTOFF;
2144 for (i = 0; i < ATABSIZE; i++) {
2145 app = &atab[i];
2146 for (ap = *app; ap; ap = *app) {
2147 *app = freealias(*app);
2148 if (ap == *app) {
2149 app = &ap->next;
2150 }
2151 }
2152 }
2153 INTON;
2154}
2155
Eric Andersenc470f442003-07-28 09:56:35 +00002156static struct alias *
2157lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002158{
Eric Andersenc470f442003-07-28 09:56:35 +00002159 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002160
Eric Andersenc470f442003-07-28 09:56:35 +00002161 if (check && ap && (ap->flag & ALIASINUSE))
2162 return (NULL);
2163 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002164}
2165
Eric Andersencb57d552001-06-28 07:25:16 +00002166/*
2167 * TODO - sort output
2168 */
Eric Andersenc470f442003-07-28 09:56:35 +00002169static int
2170aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002171{
2172 char *n, *v;
2173 int ret = 0;
2174 struct alias *ap;
2175
2176 if (argc == 1) {
2177 int i;
2178
2179 for (i = 0; i < ATABSIZE; i++)
2180 for (ap = atab[i]; ap; ap = ap->next) {
2181 printalias(ap);
2182 }
2183 return (0);
2184 }
2185 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002186 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002187 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002188 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002189 ret = 1;
2190 } else
2191 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002192 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002193 *v++ = '\0';
2194 setalias(n, v);
2195 }
2196 }
2197
2198 return (ret);
2199}
2200
Eric Andersenc470f442003-07-28 09:56:35 +00002201static int
2202unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002203{
2204 int i;
2205
2206 while ((i = nextopt("a")) != '\0') {
2207 if (i == 'a') {
2208 rmaliases();
2209 return (0);
2210 }
2211 }
2212 for (i = 0; *argptr; argptr++) {
2213 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002214 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002215 i = 1;
2216 }
2217 }
2218
2219 return (i);
2220}
2221
Eric Andersenc470f442003-07-28 09:56:35 +00002222static struct alias *
2223freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002224 struct alias *next;
2225
2226 if (ap->flag & ALIASINUSE) {
2227 ap->flag |= ALIASDEAD;
2228 return ap;
2229 }
2230
2231 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002232 ckfree(ap->name);
2233 ckfree(ap->val);
2234 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002235 return next;
2236}
2237
Eric Andersenc470f442003-07-28 09:56:35 +00002238static void
2239printalias(const struct alias *ap) {
2240 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2241}
Eric Andersencb57d552001-06-28 07:25:16 +00002242
Eric Andersenc470f442003-07-28 09:56:35 +00002243static struct alias **
2244__lookupalias(const char *name) {
2245 unsigned int hashval;
2246 struct alias **app;
2247 const char *p;
2248 unsigned int ch;
2249
2250 p = name;
2251
2252 ch = (unsigned char)*p;
2253 hashval = ch << 4;
2254 while (ch) {
2255 hashval += ch;
2256 ch = (unsigned char)*++p;
2257 }
2258 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002259
2260 for (; *app; app = &(*app)->next) {
2261 if (equal(name, (*app)->name)) {
2262 break;
2263 }
2264 }
2265
2266 return app;
2267}
Eric Andersenc470f442003-07-28 09:56:35 +00002268#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002269
Eric Andersencb57d552001-06-28 07:25:16 +00002270
Eric Andersenc470f442003-07-28 09:56:35 +00002271/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00002272
Eric Andersencb57d552001-06-28 07:25:16 +00002273/*
Eric Andersenc470f442003-07-28 09:56:35 +00002274 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002275 */
2276
Eric Andersenc470f442003-07-28 09:56:35 +00002277#define CD_PHYSICAL 1
2278#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002279
Eric Andersenc470f442003-07-28 09:56:35 +00002280static int docd(const char *, int);
2281static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002282
Eric Andersenc470f442003-07-28 09:56:35 +00002283static char *curdir = nullstr; /* current working directory */
2284static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002285
Eric Andersenc470f442003-07-28 09:56:35 +00002286static int
2287cdopt(void)
2288{
2289 int flags = 0;
2290 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002291
Eric Andersenc470f442003-07-28 09:56:35 +00002292 j = 'L';
2293 while ((i = nextopt("LP"))) {
2294 if (i != j) {
2295 flags ^= CD_PHYSICAL;
2296 j = i;
2297 }
2298 }
Eric Andersencb57d552001-06-28 07:25:16 +00002299
Eric Andersenc470f442003-07-28 09:56:35 +00002300 return flags;
2301}
Eric Andersen2870d962001-07-02 17:27:21 +00002302
Eric Andersenc470f442003-07-28 09:56:35 +00002303static int
2304cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002305{
2306 const char *dest;
2307 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002308 const char *p;
2309 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002310 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002311 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002312
Eric Andersenc470f442003-07-28 09:56:35 +00002313 flags = cdopt();
2314 dest = *argptr;
2315 if (!dest)
2316 dest = bltinlookup(homestr);
2317 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002318 dest = bltinlookup("OLDPWD");
Eric Andersenc00e11d2004-10-08 08:14:58 +00002319 if ( !dest ) goto out;
Eric Andersenc470f442003-07-28 09:56:35 +00002320 flags |= CD_PRINT;
2321 goto step7;
Eric Andersencb57d552001-06-28 07:25:16 +00002322 }
Eric Andersenc470f442003-07-28 09:56:35 +00002323 if (!dest)
2324 dest = nullstr;
2325 if (*dest == '/')
2326 goto step7;
2327 if (*dest == '.') {
2328 c = dest[1];
2329dotdot:
2330 switch (c) {
2331 case '\0':
2332 case '/':
2333 goto step6;
2334 case '.':
2335 c = dest[2];
2336 if (c != '.')
2337 goto dotdot;
2338 }
2339 }
2340 if (!*dest)
2341 dest = ".";
2342 if (!(path = bltinlookup("CDPATH"))) {
2343step6:
2344step7:
2345 p = dest;
2346 goto docd;
2347 }
2348 do {
2349 c = *path;
2350 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002351 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002352 if (c && c != ':')
2353 flags |= CD_PRINT;
2354docd:
2355 if (!docd(p, flags))
2356 goto out;
2357 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002358 }
Eric Andersenc470f442003-07-28 09:56:35 +00002359 } while (path);
Eric Andersencb57d552001-06-28 07:25:16 +00002360 error("can't cd to %s", dest);
2361 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002362out:
2363 if (flags & CD_PRINT)
2364 out1fmt(snlfmt, curdir);
2365 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002366}
2367
2368
2369/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002370 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002371 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002372 */
2373
Eric Andersenc470f442003-07-28 09:56:35 +00002374static inline const char *
2375updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002376{
Eric Andersenc470f442003-07-28 09:56:35 +00002377 char *new;
2378 char *p;
2379 char *cdcomppath;
2380 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002381
Eric Andersenc470f442003-07-28 09:56:35 +00002382 cdcomppath = sstrdup(dir);
2383 STARTSTACKSTR(new);
2384 if (*dir != '/') {
2385 if (curdir == nullstr)
2386 return 0;
2387 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002388 }
Eric Andersenc470f442003-07-28 09:56:35 +00002389 new = makestrspace(strlen(dir) + 2, new);
2390 lim = stackblock() + 1;
2391 if (*dir != '/') {
2392 if (new[-1] != '/')
2393 USTPUTC('/', new);
2394 if (new > lim && *lim == '/')
2395 lim++;
2396 } else {
2397 USTPUTC('/', new);
2398 cdcomppath++;
2399 if (dir[1] == '/' && dir[2] != '/') {
2400 USTPUTC('/', new);
2401 cdcomppath++;
2402 lim++;
2403 }
2404 }
2405 p = strtok(cdcomppath, "/");
2406 while (p) {
2407 switch(*p) {
2408 case '.':
2409 if (p[1] == '.' && p[2] == '\0') {
2410 while (new > lim) {
2411 STUNPUTC(new);
2412 if (new[-1] == '/')
2413 break;
2414 }
2415 break;
2416 } else if (p[1] == '\0')
2417 break;
2418 /* fall through */
2419 default:
2420 new = stputs(p, new);
2421 USTPUTC('/', new);
2422 }
2423 p = strtok(0, "/");
2424 }
2425 if (new > lim)
2426 STUNPUTC(new);
2427 *new = 0;
2428 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002429}
2430
2431/*
Eric Andersenc470f442003-07-28 09:56:35 +00002432 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2433 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002434 */
2435
Eric Andersenc470f442003-07-28 09:56:35 +00002436static int
2437docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002438{
Eric Andersenc470f442003-07-28 09:56:35 +00002439 const char *dir = 0;
2440 int err;
2441
2442 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2443
Eric Andersencb57d552001-06-28 07:25:16 +00002444 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002445 if (!(flags & CD_PHYSICAL)) {
2446 dir = updatepwd(dest);
2447 if (dir)
2448 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002449 }
Eric Andersenc470f442003-07-28 09:56:35 +00002450 err = chdir(dest);
2451 if (err)
2452 goto out;
2453 setpwd(dir, 1);
2454 hashcd();
2455out:
Eric Andersencb57d552001-06-28 07:25:16 +00002456 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002457 return err;
2458}
2459
2460/*
2461 * Find out what the current directory is. If we already know the current
2462 * directory, this routine returns immediately.
2463 */
2464static inline char *
2465getpwd(void)
2466{
2467 char *dir = getcwd(0, 0);
2468 return dir ? dir : nullstr;
2469}
2470
2471static int
2472pwdcmd(int argc, char **argv)
2473{
2474 int flags;
2475 const char *dir = curdir;
2476
2477 flags = cdopt();
2478 if (flags) {
2479 if (physdir == nullstr)
2480 setpwd(dir, 0);
2481 dir = physdir;
2482 }
2483 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002484 return 0;
2485}
2486
Eric Andersenc470f442003-07-28 09:56:35 +00002487static void
2488setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002489{
Eric Andersenc470f442003-07-28 09:56:35 +00002490 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002491
Eric Andersenc470f442003-07-28 09:56:35 +00002492 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002493
Eric Andersencb57d552001-06-28 07:25:16 +00002494 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002495 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002496 }
2497 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002498 if (physdir != nullstr) {
2499 if (physdir != oldcur)
2500 free(physdir);
2501 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002502 }
Eric Andersenc470f442003-07-28 09:56:35 +00002503 if (oldcur == val || !val) {
2504 char *s = getpwd();
2505 physdir = s;
2506 if (!val)
2507 dir = s;
2508 } else
2509 dir = savestr(val);
2510 if (oldcur != dir && oldcur != nullstr) {
2511 free(oldcur);
2512 }
2513 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002514 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002515 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002516}
2517
Eric Andersenc470f442003-07-28 09:56:35 +00002518/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2519
Eric Andersencb57d552001-06-28 07:25:16 +00002520/*
2521 * Errors and exceptions.
2522 */
2523
2524/*
2525 * Code to handle exceptions in C.
2526 */
2527
Eric Andersen2870d962001-07-02 17:27:21 +00002528
Eric Andersencb57d552001-06-28 07:25:16 +00002529
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002530static void exverror(int, const char *, va_list)
Eric Andersenc470f442003-07-28 09:56:35 +00002531 __attribute__((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00002532
2533/*
2534 * Called to raise an exception. Since C doesn't include exceptions, we
2535 * just do a longjmp to the exception handler. The type of exception is
2536 * stored in the global variable "exception".
2537 */
2538
Eric Andersenc470f442003-07-28 09:56:35 +00002539static void
2540exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002541{
2542#ifdef DEBUG
2543 if (handler == NULL)
2544 abort();
2545#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002546 INTOFF;
2547
Eric Andersencb57d552001-06-28 07:25:16 +00002548 exception = e;
2549 longjmp(handler->loc, 1);
2550}
2551
2552
2553/*
2554 * Called from trap.c when a SIGINT is received. (If the user specifies
2555 * that SIGINT is to be trapped or ignored using the trap builtin, then
2556 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002557 * are held using the INTOFF macro. (The test for iflag is just
2558 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002559 */
2560
Eric Andersenc470f442003-07-28 09:56:35 +00002561static void
2562onint(void) {
2563 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002564
Eric Andersencb57d552001-06-28 07:25:16 +00002565 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002566 sigsetmask(0);
2567 i = EXSIG;
2568 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2569 if (!(rootshell && iflag)) {
2570 signal(SIGINT, SIG_DFL);
2571 raise(SIGINT);
2572 }
2573 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002574 }
Eric Andersenc470f442003-07-28 09:56:35 +00002575 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002576 /* NOTREACHED */
2577}
2578
Eric Andersenc470f442003-07-28 09:56:35 +00002579static void
2580exvwarning(const char *msg, va_list ap)
2581{
2582 FILE *errs;
2583 const char *name;
2584 const char *fmt;
Eric Andersencb57d552001-06-28 07:25:16 +00002585
Eric Andersenc470f442003-07-28 09:56:35 +00002586 errs = stderr;
2587 name = arg0;
2588 fmt = "%s: ";
2589 if (commandname) {
2590 name = commandname;
2591 fmt = "%s: %d: ";
2592 }
2593 fprintf(errs, fmt, name, startlinno);
2594 vfprintf(errs, msg, ap);
2595 outcslow('\n', errs);
2596}
Eric Andersen2870d962001-07-02 17:27:21 +00002597
Eric Andersencb57d552001-06-28 07:25:16 +00002598/*
Eric Andersenc470f442003-07-28 09:56:35 +00002599 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002600 * is not NULL then error prints an error message using printf style
2601 * formatting. It then raises the error exception.
2602 */
Eric Andersenc470f442003-07-28 09:56:35 +00002603static void
2604exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002605{
Eric Andersencb57d552001-06-28 07:25:16 +00002606#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002607 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002608 TRACE(("exverror(%d, \"", cond));
2609 TRACEV((msg, ap));
2610 TRACE(("\") pid=%d\n", getpid()));
2611 } else
2612 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2613 if (msg)
2614#endif
2615 exvwarning(msg, ap);
2616
2617 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002618 exraise(cond);
2619 /* NOTREACHED */
2620}
2621
2622
Eric Andersenc470f442003-07-28 09:56:35 +00002623static void
2624error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002625{
Eric Andersencb57d552001-06-28 07:25:16 +00002626 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002627
Eric Andersencb57d552001-06-28 07:25:16 +00002628 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002629 exverror(EXERROR, msg, ap);
2630 /* NOTREACHED */
2631 va_end(ap);
2632}
2633
2634
Eric Andersenc470f442003-07-28 09:56:35 +00002635static void
2636exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002637{
Eric Andersencb57d552001-06-28 07:25:16 +00002638 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002639
Eric Andersencb57d552001-06-28 07:25:16 +00002640 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002641 exverror(cond, msg, ap);
2642 /* NOTREACHED */
2643 va_end(ap);
2644}
2645
Eric Andersencb57d552001-06-28 07:25:16 +00002646/*
Eric Andersenc470f442003-07-28 09:56:35 +00002647 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002648 */
2649
Eric Andersenc470f442003-07-28 09:56:35 +00002650static void
2651sh_warnx(const char *fmt, ...)
2652{
2653 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002654
Eric Andersenc470f442003-07-28 09:56:35 +00002655 va_start(ap, fmt);
2656 exvwarning(fmt, ap);
2657 va_end(ap);
2658}
Eric Andersen2870d962001-07-02 17:27:21 +00002659
Eric Andersencb57d552001-06-28 07:25:16 +00002660
2661/*
2662 * Return a string describing an error. The returned string may be a
2663 * pointer to a static buffer that will be overwritten on the next call.
2664 * Action describes the operation that got the error.
2665 */
2666
Eric Andersenc470f442003-07-28 09:56:35 +00002667static const char *
2668errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002669{
Eric Andersenc470f442003-07-28 09:56:35 +00002670 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002671
Eric Andersenc470f442003-07-28 09:56:35 +00002672 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002673 }
Eric Andersenc470f442003-07-28 09:56:35 +00002674 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002675}
2676
2677
Eric Andersenc470f442003-07-28 09:56:35 +00002678/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2679
2680/*
2681 * Evaluate a command.
2682 */
Eric Andersencb57d552001-06-28 07:25:16 +00002683
2684/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002685#define EV_EXIT 01 /* exit after evaluating tree */
2686#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2687#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002688
2689
Eric Andersenc470f442003-07-28 09:56:35 +00002690static void evalloop(union node *, int);
2691static void evalfor(union node *, int);
2692static void evalcase(union node *, int);
2693static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002694static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002695static void evalpipe(union node *, int);
2696static void evalcommand(union node *, int);
2697static int evalbltin(const struct builtincmd *, int, char **);
2698static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002699static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002700static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002701
Eric Andersenc470f442003-07-28 09:56:35 +00002702
2703static const struct builtincmd bltin = {
2704 "\0\0", bltincmd
2705};
2706
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002707
Eric Andersencb57d552001-06-28 07:25:16 +00002708/*
2709 * Called to reset things after an exception.
2710 */
2711
Eric Andersencb57d552001-06-28 07:25:16 +00002712/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002713 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002714 */
2715
Eric Andersenc470f442003-07-28 09:56:35 +00002716static int
2717evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002718{
Eric Andersen2870d962001-07-02 17:27:21 +00002719 char *p;
2720 char *concat;
2721 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002722
Eric Andersen2870d962001-07-02 17:27:21 +00002723 if (argc > 1) {
2724 p = argv[1];
2725 if (argc > 2) {
2726 STARTSTACKSTR(concat);
2727 ap = argv + 2;
2728 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002729 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002730 if ((p = *ap++) == NULL)
2731 break;
2732 STPUTC(' ', concat);
2733 }
2734 STPUTC('\0', concat);
2735 p = grabstackstr(concat);
2736 }
Glenn L McGrath76620622004-01-13 10:19:37 +00002737 evalstring(p);
Eric Andersen2870d962001-07-02 17:27:21 +00002738 }
2739 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002740}
2741
Eric Andersenc470f442003-07-28 09:56:35 +00002742
Eric Andersencb57d552001-06-28 07:25:16 +00002743/*
2744 * Execute a command or commands contained in a string.
2745 */
2746
Eric Andersenc470f442003-07-28 09:56:35 +00002747static void
Glenn L McGrath76620622004-01-13 10:19:37 +00002748evalstring(char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00002749{
Eric Andersencb57d552001-06-28 07:25:16 +00002750 union node *n;
2751 struct stackmark smark;
2752
2753 setstackmark(&smark);
2754 setinputstring(s);
Eric Andersenc470f442003-07-28 09:56:35 +00002755
Eric Andersencb57d552001-06-28 07:25:16 +00002756 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002757 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002758 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002759 if (evalskip)
2760 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002761 }
2762 popfile();
2763 popstackmark(&smark);
2764}
2765
Eric Andersenc470f442003-07-28 09:56:35 +00002766
Eric Andersen62483552001-07-10 06:09:16 +00002767
2768/*
Eric Andersenc470f442003-07-28 09:56:35 +00002769 * Evaluate a parse tree. The value is left in the global variable
2770 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002771 */
2772
Eric Andersenc470f442003-07-28 09:56:35 +00002773static void
2774evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002775{
Eric Andersenc470f442003-07-28 09:56:35 +00002776 int checkexit = 0;
2777 void (*evalfn)(union node *, int);
2778 unsigned isor;
2779 int status;
2780 if (n == NULL) {
2781 TRACE(("evaltree(NULL) called\n"));
2782 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002783 }
Eric Andersenc470f442003-07-28 09:56:35 +00002784 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2785 getpid(), n, n->type, flags));
2786 switch (n->type) {
2787 default:
2788#ifdef DEBUG
2789 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002790 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002791 break;
2792#endif
2793 case NNOT:
2794 evaltree(n->nnot.com, EV_TESTED);
2795 status = !exitstatus;
2796 goto setstatus;
2797 case NREDIR:
2798 expredir(n->nredir.redirect);
2799 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2800 if (!status) {
2801 evaltree(n->nredir.n, flags & EV_TESTED);
2802 status = exitstatus;
2803 }
2804 popredir(0);
2805 goto setstatus;
2806 case NCMD:
2807 evalfn = evalcommand;
2808checkexit:
2809 if (eflag && !(flags & EV_TESTED))
2810 checkexit = ~0;
2811 goto calleval;
2812 case NFOR:
2813 evalfn = evalfor;
2814 goto calleval;
2815 case NWHILE:
2816 case NUNTIL:
2817 evalfn = evalloop;
2818 goto calleval;
2819 case NSUBSHELL:
2820 case NBACKGND:
2821 evalfn = evalsubshell;
2822 goto calleval;
2823 case NPIPE:
2824 evalfn = evalpipe;
2825 goto checkexit;
2826 case NCASE:
2827 evalfn = evalcase;
2828 goto calleval;
2829 case NAND:
2830 case NOR:
2831 case NSEMI:
2832#if NAND + 1 != NOR
2833#error NAND + 1 != NOR
2834#endif
2835#if NOR + 1 != NSEMI
2836#error NOR + 1 != NSEMI
2837#endif
2838 isor = n->type - NAND;
2839 evaltree(
2840 n->nbinary.ch1,
2841 (flags | ((isor >> 1) - 1)) & EV_TESTED
2842 );
2843 if (!exitstatus == isor)
2844 break;
2845 if (!evalskip) {
2846 n = n->nbinary.ch2;
2847evaln:
2848 evalfn = evaltree;
2849calleval:
2850 evalfn(n, flags);
2851 break;
2852 }
2853 break;
2854 case NIF:
2855 evaltree(n->nif.test, EV_TESTED);
2856 if (evalskip)
2857 break;
2858 if (exitstatus == 0) {
2859 n = n->nif.ifpart;
2860 goto evaln;
2861 } else if (n->nif.elsepart) {
2862 n = n->nif.elsepart;
2863 goto evaln;
2864 }
2865 goto success;
2866 case NDEFUN:
2867 defun(n->narg.text, n->narg.next);
2868success:
2869 status = 0;
2870setstatus:
2871 exitstatus = status;
2872 break;
2873 }
2874out:
2875 if (pendingsigs)
2876 dotrap();
2877 if (flags & EV_EXIT || checkexit & exitstatus)
2878 exraise(EXEXIT);
Eric Andersen62483552001-07-10 06:09:16 +00002879}
2880
Eric Andersenc470f442003-07-28 09:56:35 +00002881
2882#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2883static
2884#endif
2885void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2886
2887
2888static void
2889evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002890{
2891 int status;
2892
2893 loopnest++;
2894 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002895 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002896 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002897 int i;
2898
Eric Andersencb57d552001-06-28 07:25:16 +00002899 evaltree(n->nbinary.ch1, EV_TESTED);
2900 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002901skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002902 evalskip = 0;
2903 continue;
2904 }
2905 if (evalskip == SKIPBREAK && --skipcount <= 0)
2906 evalskip = 0;
2907 break;
2908 }
Eric Andersenc470f442003-07-28 09:56:35 +00002909 i = exitstatus;
2910 if (n->type != NWHILE)
2911 i = !i;
2912 if (i != 0)
2913 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002914 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002915 status = exitstatus;
2916 if (evalskip)
2917 goto skipping;
2918 }
2919 loopnest--;
2920 exitstatus = status;
2921}
2922
Eric Andersenc470f442003-07-28 09:56:35 +00002923
2924
2925static void
2926evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002927{
2928 struct arglist arglist;
2929 union node *argp;
2930 struct strlist *sp;
2931 struct stackmark smark;
2932
2933 setstackmark(&smark);
2934 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002935 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002936 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002937 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002938 if (evalskip)
2939 goto out;
2940 }
2941 *arglist.lastp = NULL;
2942
2943 exitstatus = 0;
2944 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002945 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002946 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002947 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002948 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002949 if (evalskip) {
2950 if (evalskip == SKIPCONT && --skipcount <= 0) {
2951 evalskip = 0;
2952 continue;
2953 }
2954 if (evalskip == SKIPBREAK && --skipcount <= 0)
2955 evalskip = 0;
2956 break;
2957 }
2958 }
2959 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002960out:
Eric Andersencb57d552001-06-28 07:25:16 +00002961 popstackmark(&smark);
2962}
2963
Eric Andersenc470f442003-07-28 09:56:35 +00002964
2965
2966static void
2967evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002968{
2969 union node *cp;
2970 union node *patp;
2971 struct arglist arglist;
2972 struct stackmark smark;
2973
2974 setstackmark(&smark);
2975 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002976 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002977 exitstatus = 0;
2978 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2979 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002980 if (casematch(patp, arglist.list->text)) {
2981 if (evalskip == 0) {
2982 evaltree(cp->nclist.body, flags);
2983 }
2984 goto out;
2985 }
2986 }
2987 }
Eric Andersenc470f442003-07-28 09:56:35 +00002988out:
Eric Andersencb57d552001-06-28 07:25:16 +00002989 popstackmark(&smark);
2990}
2991
Eric Andersenc470f442003-07-28 09:56:35 +00002992
2993
2994/*
2995 * Kick off a subshell to evaluate a tree.
2996 */
2997
2998static void
2999evalsubshell(union node *n, int flags)
3000{
3001 struct job *jp;
3002 int backgnd = (n->type == NBACKGND);
3003 int status;
3004
3005 expredir(n->nredir.redirect);
3006 if (!backgnd && flags & EV_EXIT && !trap[0])
3007 goto nofork;
3008 INTOFF;
3009 jp = makejob(n, 1);
3010 if (forkshell(jp, n, backgnd) == 0) {
3011 INTON;
3012 flags |= EV_EXIT;
3013 if (backgnd)
3014 flags &=~ EV_TESTED;
3015nofork:
3016 redirect(n->nredir.redirect, 0);
3017 evaltreenr(n->nredir.n, flags);
3018 /* never returns */
3019 }
3020 status = 0;
3021 if (! backgnd)
3022 status = waitforjob(jp);
3023 exitstatus = status;
3024 INTON;
3025}
3026
3027
3028
3029/*
3030 * Compute the names of the files in a redirection list.
3031 */
3032
3033static void
3034expredir(union node *n)
3035{
3036 union node *redir;
3037
3038 for (redir = n ; redir ; redir = redir->nfile.next) {
3039 struct arglist fn;
3040 fn.lastp = &fn.list;
3041 switch (redir->type) {
3042 case NFROMTO:
3043 case NFROM:
3044 case NTO:
3045 case NCLOBBER:
3046 case NAPPEND:
3047 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3048 redir->nfile.expfname = fn.list->text;
3049 break;
3050 case NFROMFD:
3051 case NTOFD:
3052 if (redir->ndup.vname) {
3053 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3054 fixredir(redir, fn.list->text, 1);
3055 }
3056 break;
3057 }
3058 }
3059}
3060
3061
3062
Eric Andersencb57d552001-06-28 07:25:16 +00003063/*
Eric Andersencb57d552001-06-28 07:25:16 +00003064 * Evaluate a pipeline. All the processes in the pipeline are children
3065 * of the process creating the pipeline. (This differs from some versions
3066 * of the shell, which make the last process in a pipeline the parent
3067 * of all the rest.)
3068 */
3069
Eric Andersenc470f442003-07-28 09:56:35 +00003070static void
3071evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003072{
3073 struct job *jp;
3074 struct nodelist *lp;
3075 int pipelen;
3076 int prevfd;
3077 int pip[2];
3078
Eric Andersenc470f442003-07-28 09:56:35 +00003079 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003080 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003081 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003082 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003083 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003084 INTOFF;
3085 jp = makejob(n, pipelen);
3086 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003087 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003088 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003089 pip[1] = -1;
3090 if (lp->next) {
3091 if (pipe(pip) < 0) {
3092 close(prevfd);
3093 error("Pipe call failed");
3094 }
3095 }
3096 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3097 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003098 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003099 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003100 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003101 if (prevfd > 0) {
3102 dup2(prevfd, 0);
3103 close(prevfd);
3104 }
3105 if (pip[1] > 1) {
3106 dup2(pip[1], 1);
3107 close(pip[1]);
3108 }
Eric Andersenc470f442003-07-28 09:56:35 +00003109 evaltreenr(lp->n, flags);
3110 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003111 }
3112 if (prevfd >= 0)
3113 close(prevfd);
3114 prevfd = pip[0];
3115 close(pip[1]);
3116 }
Eric Andersencb57d552001-06-28 07:25:16 +00003117 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003118 exitstatus = waitforjob(jp);
3119 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003120 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003121 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003122}
3123
Eric Andersen62483552001-07-10 06:09:16 +00003124
3125
3126/*
3127 * Execute a command inside back quotes. If it's a builtin command, we
3128 * want to save its output in a block obtained from malloc. Otherwise
3129 * we fork off a subprocess and get the output of the command via a pipe.
3130 * Should be called with interrupts off.
3131 */
3132
Eric Andersenc470f442003-07-28 09:56:35 +00003133static void
3134evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003135{
Eric Andersenc470f442003-07-28 09:56:35 +00003136 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003137
Eric Andersen62483552001-07-10 06:09:16 +00003138 result->fd = -1;
3139 result->buf = NULL;
3140 result->nleft = 0;
3141 result->jp = NULL;
3142 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003143 goto out;
3144 }
Eric Andersenc470f442003-07-28 09:56:35 +00003145
3146 saveherefd = herefd;
3147 herefd = -1;
3148
3149 {
3150 int pip[2];
3151 struct job *jp;
3152
3153 if (pipe(pip) < 0)
3154 error("Pipe call failed");
3155 jp = makejob(n, 1);
3156 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3157 FORCEINTON;
3158 close(pip[0]);
3159 if (pip[1] != 1) {
3160 close(1);
3161 copyfd(pip[1], 1);
3162 close(pip[1]);
3163 }
3164 eflag = 0;
3165 evaltreenr(n, EV_EXIT);
3166 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003167 }
Eric Andersenc470f442003-07-28 09:56:35 +00003168 close(pip[1]);
3169 result->fd = pip[0];
3170 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003171 }
Eric Andersenc470f442003-07-28 09:56:35 +00003172 herefd = saveherefd;
3173out:
Eric Andersen62483552001-07-10 06:09:16 +00003174 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003175 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003176}
3177
Eric Andersenc470f442003-07-28 09:56:35 +00003178#ifdef CONFIG_ASH_CMDCMD
3179static inline char **
3180parse_command_args(char **argv, const char **path)
3181{
3182 char *cp, c;
3183
3184 for (;;) {
3185 cp = *++argv;
3186 if (!cp)
3187 return 0;
3188 if (*cp++ != '-')
3189 break;
3190 if (!(c = *cp++))
3191 break;
3192 if (c == '-' && !*cp) {
3193 argv++;
3194 break;
3195 }
3196 do {
3197 switch (c) {
3198 case 'p':
3199 *path = defpath;
3200 break;
3201 default:
3202 /* run 'typecmd' for other options */
3203 return 0;
3204 }
3205 } while ((c = *cp++));
3206 }
3207 return argv;
3208}
3209#endif
3210
3211
Eric Andersen62483552001-07-10 06:09:16 +00003212
3213/*
3214 * Execute a simple command.
3215 */
Eric Andersencb57d552001-06-28 07:25:16 +00003216
Eric Andersenc470f442003-07-28 09:56:35 +00003217static void
3218evalcommand(union node *cmd, int flags)
3219{
3220 struct stackmark smark;
3221 union node *argp;
3222 struct arglist arglist;
3223 struct arglist varlist;
3224 char **argv;
3225 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003226 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003227 struct cmdentry cmdentry;
3228 struct job *jp;
3229 char *lastarg;
3230 const char *path;
3231 int spclbltin;
3232 int cmd_is_exec;
3233 int status;
3234 char **nargv;
3235
3236 /* First expand the arguments. */
3237 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3238 setstackmark(&smark);
3239 back_exitstatus = 0;
3240
3241 cmdentry.cmdtype = CMDBUILTIN;
3242 cmdentry.u.cmd = &bltin;
3243 varlist.lastp = &varlist.list;
3244 *varlist.lastp = NULL;
3245 arglist.lastp = &arglist.list;
3246 *arglist.lastp = NULL;
3247
3248 argc = 0;
3249 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3250 struct strlist **spp;
3251
3252 spp = arglist.lastp;
3253 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3254 for (sp = *spp; sp; sp = sp->next)
3255 argc++;
3256 }
3257
3258 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3259 for (sp = arglist.list ; sp ; sp = sp->next) {
3260 TRACE(("evalcommand arg: %s\n", sp->text));
3261 *nargv++ = sp->text;
3262 }
3263 *nargv = NULL;
3264
3265 lastarg = NULL;
3266 if (iflag && funcnest == 0 && argc > 0)
3267 lastarg = nargv[-1];
3268
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003269 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003270 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003271 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003272
3273 path = vpath.text;
3274 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3275 struct strlist **spp;
3276 char *p;
3277
3278 spp = varlist.lastp;
3279 expandarg(argp, &varlist, EXP_VARTILDE);
3280
3281 /*
3282 * Modify the command lookup path, if a PATH= assignment
3283 * is present
3284 */
3285 p = (*spp)->text;
3286 if (varequal(p, path))
3287 path = p;
3288 }
3289
3290 /* Print the command if xflag is set. */
3291 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003292 int n;
3293 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003294
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003295 p++;
3296 dprintf(preverrout_fd, p, ps4val());
3297
3298 sp = varlist.list;
3299 for(n = 0; n < 2; n++) {
3300 while (sp) {
3301 dprintf(preverrout_fd, p, sp->text);
3302 sp = sp->next;
3303 if(*p == '%') {
3304 p--;
3305 }
3306 }
3307 sp = arglist.list;
3308 }
Eric Andersen16767e22004-03-16 05:14:10 +00003309 bb_full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003310 }
3311
3312 cmd_is_exec = 0;
3313 spclbltin = -1;
3314
3315 /* Now locate the command. */
3316 if (argc) {
3317 const char *oldpath;
3318 int cmd_flag = DO_ERR;
3319
3320 path += 5;
3321 oldpath = path;
3322 for (;;) {
3323 find_command(argv[0], &cmdentry, cmd_flag, path);
3324 if (cmdentry.cmdtype == CMDUNKNOWN) {
3325 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003326 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003327 goto bail;
3328 }
3329
3330 /* implement bltin and command here */
3331 if (cmdentry.cmdtype != CMDBUILTIN)
3332 break;
3333 if (spclbltin < 0)
3334 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3335 if (cmdentry.u.cmd == EXECCMD)
3336 cmd_is_exec++;
3337#ifdef CONFIG_ASH_CMDCMD
3338 if (cmdentry.u.cmd == COMMANDCMD) {
3339
3340 path = oldpath;
3341 nargv = parse_command_args(argv, &path);
3342 if (!nargv)
3343 break;
3344 argc -= nargv - argv;
3345 argv = nargv;
3346 cmd_flag |= DO_NOFUNC;
3347 } else
3348#endif
3349 break;
3350 }
3351 }
3352
3353 if (status) {
3354 /* We have a redirection error. */
3355 if (spclbltin > 0)
3356 exraise(EXERROR);
3357bail:
3358 exitstatus = status;
3359 goto out;
3360 }
3361
3362 /* Execute the command. */
3363 switch (cmdentry.cmdtype) {
3364 default:
3365 /* Fork off a child process if necessary. */
3366 if (!(flags & EV_EXIT) || trap[0]) {
3367 INTOFF;
3368 jp = makejob(cmd, 1);
3369 if (forkshell(jp, cmd, FORK_FG) != 0) {
3370 exitstatus = waitforjob(jp);
3371 INTON;
3372 break;
3373 }
3374 FORCEINTON;
3375 }
3376 listsetvar(varlist.list, VEXPORT|VSTACK);
3377 shellexec(argv, path, cmdentry.u.index);
3378 /* NOTREACHED */
3379
3380 case CMDBUILTIN:
3381 cmdenviron = varlist.list;
3382 if (cmdenviron) {
3383 struct strlist *list = cmdenviron;
3384 int i = VNOSET;
3385 if (spclbltin > 0 || argc == 0) {
3386 i = 0;
3387 if (cmd_is_exec && argc > 1)
3388 i = VEXPORT;
3389 }
3390 listsetvar(list, i);
3391 }
3392 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3393 int exit_status;
3394 int i, j;
3395
3396 i = exception;
3397 if (i == EXEXIT)
3398 goto raise;
3399
3400 exit_status = 2;
3401 j = 0;
3402 if (i == EXINT)
3403 j = SIGINT;
3404 if (i == EXSIG)
3405 j = pendingsigs;
3406 if (j)
3407 exit_status = j + 128;
3408 exitstatus = exit_status;
3409
3410 if (i == EXINT || spclbltin > 0) {
3411raise:
3412 longjmp(handler->loc, 1);
3413 }
3414 FORCEINTON;
3415 }
3416 break;
3417
3418 case CMDFUNCTION:
3419 listsetvar(varlist.list, 0);
3420 if (evalfun(cmdentry.u.func, argc, argv, flags))
3421 goto raise;
3422 break;
3423 }
3424
3425out:
3426 popredir(cmd_is_exec);
3427 if (lastarg)
3428 /* dsl: I think this is intended to be used to support
3429 * '_' in 'vi' command mode during line editing...
3430 * However I implemented that within libedit itself.
3431 */
3432 setvar("_", lastarg, 0);
3433 popstackmark(&smark);
3434}
3435
3436static int
3437evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3438 char *volatile savecmdname;
3439 struct jmploc *volatile savehandler;
3440 struct jmploc jmploc;
3441 int i;
3442
3443 savecmdname = commandname;
3444 if ((i = setjmp(jmploc.loc)))
3445 goto cmddone;
3446 savehandler = handler;
3447 handler = &jmploc;
3448 commandname = argv[0];
3449 argptr = argv + 1;
3450 optptr = NULL; /* initialize nextopt */
3451 exitstatus = (*cmd->builtin)(argc, argv);
3452 flushall();
3453cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003454 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003455 commandname = savecmdname;
3456 exsig = 0;
3457 handler = savehandler;
3458
3459 return i;
3460}
3461
3462static int
3463evalfun(struct funcnode *func, int argc, char **argv, int flags)
3464{
3465 volatile struct shparam saveparam;
3466 struct localvar *volatile savelocalvars;
3467 struct jmploc *volatile savehandler;
3468 struct jmploc jmploc;
3469 int e;
3470
3471 saveparam = shellparam;
3472 savelocalvars = localvars;
3473 if ((e = setjmp(jmploc.loc))) {
3474 goto funcdone;
3475 }
3476 INTOFF;
3477 savehandler = handler;
3478 handler = &jmploc;
3479 localvars = NULL;
3480 shellparam.malloc = 0;
3481 func->count++;
3482 INTON;
3483 shellparam.nparam = argc - 1;
3484 shellparam.p = argv + 1;
3485#ifdef CONFIG_ASH_GETOPTS
3486 shellparam.optind = 1;
3487 shellparam.optoff = -1;
3488#endif
3489 funcnest++;
3490 evaltree(&func->n, flags & EV_TESTED);
3491 funcnest--;
3492funcdone:
3493 INTOFF;
3494 freefunc(func);
3495 poplocalvars();
3496 localvars = savelocalvars;
3497 freeparam(&shellparam);
3498 shellparam = saveparam;
3499 handler = savehandler;
3500 INTON;
3501 if (evalskip == SKIPFUNC) {
3502 evalskip = 0;
3503 skipcount = 0;
3504 }
3505 return e;
3506}
3507
3508
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003509static inline int
3510goodname(const char *p)
3511{
3512 return !*endofname(p);
3513}
3514
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003515/*
3516 * Search for a command. This is called before we fork so that the
3517 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003518 * the child. The check for "goodname" is an overly conservative
3519 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003520 */
3521
Eric Andersenc470f442003-07-28 09:56:35 +00003522static void
3523prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003524{
3525 struct cmdentry entry;
3526
3527 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003528 if (goodname(n->ncmd.args->narg.text))
3529 find_command(n->ncmd.args->narg.text, &entry, 0,
3530 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003531}
3532
Eric Andersencb57d552001-06-28 07:25:16 +00003533
Eric Andersenc470f442003-07-28 09:56:35 +00003534
Eric Andersencb57d552001-06-28 07:25:16 +00003535/*
3536 * Builtin commands. Builtin commands whose functions are closely
3537 * tied to evaluation are implemented here.
3538 */
3539
3540/*
Eric Andersenc470f442003-07-28 09:56:35 +00003541 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003542 */
3543
Eric Andersenc470f442003-07-28 09:56:35 +00003544static int
3545bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003546{
3547 /*
3548 * Preserve exitstatus of a previous possible redirection
3549 * as POSIX mandates
3550 */
Eric Andersenc470f442003-07-28 09:56:35 +00003551 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003552}
3553
3554
3555/*
3556 * Handle break and continue commands. Break, continue, and return are
3557 * all handled by setting the evalskip flag. The evaluation routines
3558 * above all check this flag, and if it is set they start skipping
3559 * commands rather than executing them. The variable skipcount is
3560 * the number of loops to break/continue, or the number of function
3561 * levels to return. (The latter is always 1.) It should probably
3562 * be an error to break out of more loops than exist, but it isn't
3563 * in the standard shell so we don't make it one here.
3564 */
3565
Eric Andersenc470f442003-07-28 09:56:35 +00003566static int
3567breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003568{
3569 int n = argc > 1 ? number(argv[1]) : 1;
3570
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003571 if (n <= 0)
Eric Andersenc470f442003-07-28 09:56:35 +00003572 error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003573 if (n > loopnest)
3574 n = loopnest;
3575 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003576 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003577 skipcount = n;
3578 }
3579 return 0;
3580}
3581
3582
3583/*
3584 * The return command.
3585 */
3586
Eric Andersenc470f442003-07-28 09:56:35 +00003587static int
3588returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003589{
Eric Andersenc470f442003-07-28 09:56:35 +00003590 int ret = argc > 1 ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003591
3592 if (funcnest) {
3593 evalskip = SKIPFUNC;
3594 skipcount = 1;
3595 return ret;
Eric Andersenc470f442003-07-28 09:56:35 +00003596 }
3597 else {
Eric Andersencb57d552001-06-28 07:25:16 +00003598 /* Do what ksh does; skip the rest of the file */
3599 evalskip = SKIPFILE;
3600 skipcount = 1;
3601 return ret;
3602 }
3603}
3604
3605
Eric Andersenc470f442003-07-28 09:56:35 +00003606static int
3607falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003608{
3609 return 1;
3610}
3611
Eric Andersenc470f442003-07-28 09:56:35 +00003612
3613static int
3614truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003615{
3616 return 0;
3617}
Eric Andersen2870d962001-07-02 17:27:21 +00003618
Eric Andersencb57d552001-06-28 07:25:16 +00003619
Eric Andersenc470f442003-07-28 09:56:35 +00003620static int
3621execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003622{
3623 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003624 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003625 mflag = 0;
3626 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003627 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003628 }
3629 return 0;
3630}
3631
Eric Andersenc470f442003-07-28 09:56:35 +00003632
Eric Andersenc470f442003-07-28 09:56:35 +00003633/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3634
3635/*
3636 * When commands are first encountered, they are entered in a hash table.
3637 * This ensures that a full path search will not have to be done for them
3638 * on each invocation.
3639 *
3640 * We should investigate converting to a linear search, even though that
3641 * would make the command name "hash" a misnomer.
3642 */
3643
3644#define CMDTABLESIZE 31 /* should be prime */
3645#define ARB 1 /* actual size determined at run time */
3646
3647
3648
3649struct tblentry {
3650 struct tblentry *next; /* next entry in hash chain */
3651 union param param; /* definition of builtin function */
3652 short cmdtype; /* index identifying command */
3653 char rehash; /* if set, cd done since entry created */
3654 char cmdname[ARB]; /* name of command */
3655};
3656
3657
3658static struct tblentry *cmdtable[CMDTABLESIZE];
3659static int builtinloc = -1; /* index in path of %builtin, or -1 */
3660
3661
3662static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003663static void clearcmdentry(int);
3664static struct tblentry *cmdlookup(const char *, int);
3665static void delete_cmd_entry(void);
3666
Eric Andersencb57d552001-06-28 07:25:16 +00003667
3668/*
3669 * Exec a program. Never returns. If you change this routine, you may
3670 * have to change the find_command routine as well.
3671 */
3672
Eric Andersenc470f442003-07-28 09:56:35 +00003673static void
3674shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003675{
3676 char *cmdname;
3677 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003678 char **envp;
Eric Andersencb57d552001-06-28 07:25:16 +00003679
Eric Andersenc470f442003-07-28 09:56:35 +00003680 clearredir(1);
3681 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003682 if (strchr(argv[0], '/') != NULL
3683#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3684 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003685#endif
3686 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003687 tryexec(argv[0], argv, envp);
3688 e = errno;
3689 } else {
3690 e = ENOENT;
3691 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3692 if (--idx < 0 && pathopt == NULL) {
3693 tryexec(cmdname, argv, envp);
3694 if (errno != ENOENT && errno != ENOTDIR)
3695 e = errno;
3696 }
3697 stunalloc(cmdname);
3698 }
3699 }
3700
3701 /* Map to POSIX errors */
3702 switch (e) {
3703 case EACCES:
3704 exerrno = 126;
3705 break;
3706 case ENOENT:
3707 exerrno = 127;
3708 break;
3709 default:
3710 exerrno = 2;
3711 break;
3712 }
Eric Andersenc470f442003-07-28 09:56:35 +00003713 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3714 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003715 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3716 /* NOTREACHED */
3717}
3718
Eric Andersen2870d962001-07-02 17:27:21 +00003719
Eric Andersenc470f442003-07-28 09:56:35 +00003720static void
3721tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003722{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003723 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003724#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003725 if(find_applet_by_name(cmd) != NULL) {
3726 /* re-exec ourselves with the new arguments */
3727 execve("/proc/self/exe",argv,envp);
3728 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3729 execve("/bin/busybox",argv,envp);
3730 /* If they called chroot or otherwise made the binary no longer
3731 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003732 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003733#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003734
3735repeat:
3736#ifdef SYSV
3737 do {
3738 execve(cmd, argv, envp);
3739 } while (errno == EINTR);
3740#else
Eric Andersencb57d552001-06-28 07:25:16 +00003741 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003742#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003743 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003744 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003745 } else if (errno == ENOEXEC) {
3746 char **ap;
3747 char **new;
3748
Eric Andersenc470f442003-07-28 09:56:35 +00003749 for (ap = argv; *ap; ap++)
3750 ;
3751 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003752 ap[1] = cmd;
3753 *ap = cmd = (char *)DEFAULT_SHELL;
3754 ap += 2;
3755 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003756 while ((*ap++ = *argv++))
3757 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003758 argv = new;
3759 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003760 }
Eric Andersencb57d552001-06-28 07:25:16 +00003761}
3762
Eric Andersenc470f442003-07-28 09:56:35 +00003763
Eric Andersencb57d552001-06-28 07:25:16 +00003764
3765/*
3766 * Do a path search. The variable path (passed by reference) should be
3767 * set to the start of the path before the first call; padvance will update
3768 * this value as it proceeds. Successive calls to padvance will return
3769 * the possible path expansions in sequence. If an option (indicated by
3770 * a percent sign) appears in the path entry then the global variable
3771 * pathopt will be set to point to it; otherwise pathopt will be set to
3772 * NULL.
3773 */
3774
Eric Andersenc470f442003-07-28 09:56:35 +00003775static char *
3776padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003777{
Eric Andersencb57d552001-06-28 07:25:16 +00003778 const char *p;
3779 char *q;
3780 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003781 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003782
3783 if (*path == NULL)
3784 return NULL;
3785 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003786 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3787 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003788 while (stackblocksize() < len)
3789 growstackblock();
3790 q = stackblock();
3791 if (p != start) {
3792 memcpy(q, start, p - start);
3793 q += p - start;
3794 *q++ = '/';
3795 }
3796 strcpy(q, name);
3797 pathopt = NULL;
3798 if (*p == '%') {
3799 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003800 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003801 }
3802 if (*p == ':')
3803 *path = p + 1;
3804 else
3805 *path = NULL;
3806 return stalloc(len);
3807}
3808
3809
Eric Andersencb57d552001-06-28 07:25:16 +00003810/*** Command hashing code ***/
3811
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003812static void
3813printentry(struct tblentry *cmdp)
3814{
3815 int idx;
3816 const char *path;
3817 char *name;
3818
3819 idx = cmdp->param.index;
3820 path = pathval();
3821 do {
3822 name = padvance(&path, cmdp->cmdname);
3823 stunalloc(name);
3824 } while (--idx >= 0);
3825 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3826}
3827
Eric Andersenc470f442003-07-28 09:56:35 +00003828
3829static int
3830hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003831{
3832 struct tblentry **pp;
3833 struct tblentry *cmdp;
3834 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003835 struct cmdentry entry;
3836 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003837
Eric Andersenc470f442003-07-28 09:56:35 +00003838 while ((c = nextopt("r")) != '\0') {
3839 clearcmdentry(0);
3840 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003841 }
3842 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003843 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3844 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3845 if (cmdp->cmdtype == CMDNORMAL)
3846 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003847 }
3848 }
3849 return 0;
3850 }
3851 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003852 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003853 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003854 && (cmdp->cmdtype == CMDNORMAL
3855 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003856 delete_cmd_entry();
3857 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003858 if (entry.cmdtype == CMDUNKNOWN)
3859 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003860 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003861 }
3862 return c;
3863}
3864
Eric Andersenc470f442003-07-28 09:56:35 +00003865
Eric Andersencb57d552001-06-28 07:25:16 +00003866/*
3867 * Resolve a command name. If you change this routine, you may have to
3868 * change the shellexec routine as well.
3869 */
3870
3871static void
Eric Andersenc470f442003-07-28 09:56:35 +00003872find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003873{
3874 struct tblentry *cmdp;
3875 int idx;
3876 int prev;
3877 char *fullname;
3878 struct stat statb;
3879 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003880 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003881 struct builtincmd *bcmd;
3882
Eric Andersenc470f442003-07-28 09:56:35 +00003883 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003884 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003885 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003886 if (act & DO_ABS) {
3887 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003888#ifdef SYSV
3889 if (errno == EINTR)
3890 continue;
3891#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003892 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003893 return;
3894 }
Eric Andersencb57d552001-06-28 07:25:16 +00003895 }
3896 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003897 return;
3898 }
3899
Eric Andersenbf8bf102002-09-17 08:41:08 +00003900#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3901 if (find_applet_by_name(name)) {
3902 entry->cmdtype = CMDNORMAL;
3903 entry->u.index = -1;
3904 return;
3905 }
3906#endif
3907
Eric Andersenc470f442003-07-28 09:56:35 +00003908 updatetbl = (path == pathval());
3909 if (!updatetbl) {
3910 act |= DO_ALTPATH;
3911 if (strstr(path, "%builtin") != NULL)
3912 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003913 }
3914
Eric Andersenc470f442003-07-28 09:56:35 +00003915 /* If name is in the table, check answer will be ok */
3916 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3917 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003918
Eric Andersenc470f442003-07-28 09:56:35 +00003919 switch (cmdp->cmdtype) {
3920 default:
3921#if DEBUG
3922 abort();
3923#endif
3924 case CMDNORMAL:
3925 bit = DO_ALTPATH;
3926 break;
3927 case CMDFUNCTION:
3928 bit = DO_NOFUNC;
3929 break;
3930 case CMDBUILTIN:
3931 bit = DO_ALTBLTIN;
3932 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003933 }
Eric Andersenc470f442003-07-28 09:56:35 +00003934 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003935 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003936 cmdp = NULL;
3937 } else if (cmdp->rehash == 0)
3938 /* if not invalidated by cd, we're done */
3939 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003940 }
3941
3942 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003943 bcmd = find_builtin(name);
3944 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3945 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3946 )))
3947 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003948
3949 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003950 prev = -1; /* where to start */
3951 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003952 if (cmdp->cmdtype == CMDBUILTIN)
3953 prev = builtinloc;
3954 else
3955 prev = cmdp->param.index;
3956 }
3957
3958 e = ENOENT;
3959 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003960loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003961 while ((fullname = padvance(&path, name)) != NULL) {
3962 stunalloc(fullname);
3963 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003964 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003965 if (prefix(pathopt, "builtin")) {
3966 if (bcmd)
3967 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003968 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003969 } else if (!(act & DO_NOFUNC) &&
3970 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003971 /* handled below */
3972 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003973 /* ignore unimplemented options */
3974 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003975 }
3976 }
3977 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003978 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003979 if (idx < prev)
3980 continue;
3981 TRACE(("searchexec \"%s\": no change\n", name));
3982 goto success;
3983 }
3984 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003985#ifdef SYSV
3986 if (errno == EINTR)
3987 continue;
3988#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003989 if (errno != ENOENT && errno != ENOTDIR)
3990 e = errno;
3991 goto loop;
3992 }
Eric Andersenc470f442003-07-28 09:56:35 +00003993 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003994 if (!S_ISREG(statb.st_mode))
3995 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003996 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003997 stalloc(strlen(fullname) + 1);
3998 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00003999 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4000 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004001 error("%s not defined in %s", name, fullname);
4002 stunalloc(fullname);
4003 goto success;
4004 }
Eric Andersencb57d552001-06-28 07:25:16 +00004005 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004006 if (!updatetbl) {
4007 entry->cmdtype = CMDNORMAL;
4008 entry->u.index = idx;
4009 return;
4010 }
4011 INTOFF;
4012 cmdp = cmdlookup(name, 1);
4013 cmdp->cmdtype = CMDNORMAL;
4014 cmdp->param.index = idx;
4015 INTON;
4016 goto success;
4017 }
4018
4019 /* We failed. If there was an entry for this command, delete it */
4020 if (cmdp && updatetbl)
4021 delete_cmd_entry();
4022 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004023 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004024 entry->cmdtype = CMDUNKNOWN;
4025 return;
4026
Eric Andersenc470f442003-07-28 09:56:35 +00004027builtin_success:
4028 if (!updatetbl) {
4029 entry->cmdtype = CMDBUILTIN;
4030 entry->u.cmd = bcmd;
4031 return;
4032 }
4033 INTOFF;
4034 cmdp = cmdlookup(name, 1);
4035 cmdp->cmdtype = CMDBUILTIN;
4036 cmdp->param.cmd = bcmd;
4037 INTON;
4038success:
Eric Andersencb57d552001-06-28 07:25:16 +00004039 cmdp->rehash = 0;
4040 entry->cmdtype = cmdp->cmdtype;
4041 entry->u = cmdp->param;
4042}
4043
4044
Eric Andersenc470f442003-07-28 09:56:35 +00004045/*
4046 * Wrapper around strcmp for qsort/bsearch/...
4047 */
4048static int pstrcmp(const void *a, const void *b)
4049{
4050 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4051}
Eric Andersencb57d552001-06-28 07:25:16 +00004052
4053/*
4054 * Search the table of builtin commands.
4055 */
4056
Eric Andersenc470f442003-07-28 09:56:35 +00004057static struct builtincmd *
4058find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004059{
4060 struct builtincmd *bp;
4061
Eric Andersenc470f442003-07-28 09:56:35 +00004062 bp = bsearch(
4063 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4064 pstrcmp
4065 );
Eric Andersencb57d552001-06-28 07:25:16 +00004066 return bp;
4067}
4068
4069
Eric Andersenc470f442003-07-28 09:56:35 +00004070
Eric Andersencb57d552001-06-28 07:25:16 +00004071/*
4072 * Called when a cd is done. Marks all commands so the next time they
4073 * are executed they will be rehashed.
4074 */
4075
Eric Andersenc470f442003-07-28 09:56:35 +00004076static void
4077hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004078{
Eric Andersencb57d552001-06-28 07:25:16 +00004079 struct tblentry **pp;
4080 struct tblentry *cmdp;
4081
Eric Andersenc470f442003-07-28 09:56:35 +00004082 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4083 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4084 if (cmdp->cmdtype == CMDNORMAL || (
4085 cmdp->cmdtype == CMDBUILTIN &&
4086 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4087 builtinloc > 0
4088 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004089 cmdp->rehash = 1;
4090 }
4091 }
4092}
4093
4094
4095
4096/*
Eric Andersenc470f442003-07-28 09:56:35 +00004097 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004098 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004099 * pathval() still returns the old value at this point.
4100 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004101 */
4102
Eric Andersenc470f442003-07-28 09:56:35 +00004103static void
4104changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004105{
Eric Andersenc470f442003-07-28 09:56:35 +00004106 const char *old, *new;
4107 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004108 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004109 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004110
Eric Andersenc470f442003-07-28 09:56:35 +00004111 old = pathval();
4112 new = newval;
4113 firstchange = 9999; /* assume no change */
4114 idx = 0;
4115 idx_bltin = -1;
4116 for (;;) {
4117 if (*old != *new) {
4118 firstchange = idx;
4119 if ((*old == '\0' && *new == ':')
4120 || (*old == ':' && *new == '\0'))
4121 firstchange++;
4122 old = new; /* ignore subsequent differences */
4123 }
4124 if (*new == '\0')
4125 break;
4126 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4127 idx_bltin = idx;
4128 if (*new == ':') {
4129 idx++;
4130 }
4131 new++, old++;
4132 }
4133 if (builtinloc < 0 && idx_bltin >= 0)
4134 builtinloc = idx_bltin; /* zap builtins */
4135 if (builtinloc >= 0 && idx_bltin < 0)
4136 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004137 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004138 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004139}
4140
4141
4142/*
4143 * Clear out command entries. The argument specifies the first entry in
4144 * PATH which has changed.
4145 */
4146
Eric Andersenc470f442003-07-28 09:56:35 +00004147static void
4148clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004149{
4150 struct tblentry **tblp;
4151 struct tblentry **pp;
4152 struct tblentry *cmdp;
4153
4154 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004155 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004156 pp = tblp;
4157 while ((cmdp = *pp) != NULL) {
4158 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004159 cmdp->param.index >= firstchange)
4160 || (cmdp->cmdtype == CMDBUILTIN &&
4161 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004162 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004163 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004164 } else {
4165 pp = &cmdp->next;
4166 }
4167 }
4168 }
4169 INTON;
4170}
4171
4172
Eric Andersenc470f442003-07-28 09:56:35 +00004173
Eric Andersencb57d552001-06-28 07:25:16 +00004174/*
Eric Andersencb57d552001-06-28 07:25:16 +00004175 * Locate a command in the command hash table. If "add" is nonzero,
4176 * add the command to the table if it is not already present. The
4177 * variable "lastcmdentry" is set to point to the address of the link
4178 * pointing to the entry, so that delete_cmd_entry can delete the
4179 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004180 *
4181 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004182 */
4183
Eric Andersen2870d962001-07-02 17:27:21 +00004184static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004185
Eric Andersenc470f442003-07-28 09:56:35 +00004186
4187static struct tblentry *
4188cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004189{
Eric Andersenc470f442003-07-28 09:56:35 +00004190 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004191 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004192 struct tblentry *cmdp;
4193 struct tblentry **pp;
4194
4195 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004196 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004197 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004198 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004199 hashval &= 0x7FFF;
4200 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004201 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004202 if (equal(cmdp->cmdname, name))
4203 break;
4204 pp = &cmdp->next;
4205 }
4206 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004207 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4208 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004209 cmdp->next = NULL;
4210 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004211 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004212 }
4213 lastcmdentry = pp;
4214 return cmdp;
4215}
4216
4217/*
4218 * Delete the command entry returned on the last lookup.
4219 */
4220
Eric Andersenc470f442003-07-28 09:56:35 +00004221static void
4222delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004223{
Eric Andersencb57d552001-06-28 07:25:16 +00004224 struct tblentry *cmdp;
4225
4226 INTOFF;
4227 cmdp = *lastcmdentry;
4228 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004229 if (cmdp->cmdtype == CMDFUNCTION)
4230 freefunc(cmdp->param.func);
4231 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004232 INTON;
4233}
4234
4235
Eric Andersenc470f442003-07-28 09:56:35 +00004236/*
4237 * Add a new command entry, replacing any existing command entry for
4238 * the same name - except special builtins.
4239 */
Eric Andersencb57d552001-06-28 07:25:16 +00004240
Eric Andersenc470f442003-07-28 09:56:35 +00004241static inline void
4242addcmdentry(char *name, struct cmdentry *entry)
4243{
4244 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004245
Eric Andersenc470f442003-07-28 09:56:35 +00004246 cmdp = cmdlookup(name, 1);
4247 if (cmdp->cmdtype == CMDFUNCTION) {
4248 freefunc(cmdp->param.func);
4249 }
4250 cmdp->cmdtype = entry->cmdtype;
4251 cmdp->param = entry->u;
4252 cmdp->rehash = 0;
4253}
Eric Andersencb57d552001-06-28 07:25:16 +00004254
Eric Andersenc470f442003-07-28 09:56:35 +00004255/*
4256 * Make a copy of a parse tree.
4257 */
Eric Andersencb57d552001-06-28 07:25:16 +00004258
Eric Andersenc470f442003-07-28 09:56:35 +00004259static inline struct funcnode *
4260copyfunc(union node *n)
4261{
4262 struct funcnode *f;
4263 size_t blocksize;
4264
4265 funcblocksize = offsetof(struct funcnode, n);
4266 funcstringsize = 0;
4267 calcsize(n);
4268 blocksize = funcblocksize;
4269 f = ckmalloc(blocksize + funcstringsize);
4270 funcblock = (char *) f + offsetof(struct funcnode, n);
4271 funcstring = (char *) f + blocksize;
4272 copynode(n);
4273 f->count = 0;
4274 return f;
4275}
4276
4277/*
4278 * Define a shell function.
4279 */
4280
4281static void
4282defun(char *name, union node *func)
4283{
4284 struct cmdentry entry;
4285
4286 INTOFF;
4287 entry.cmdtype = CMDFUNCTION;
4288 entry.u.func = copyfunc(func);
4289 addcmdentry(name, &entry);
4290 INTON;
4291}
Eric Andersencb57d552001-06-28 07:25:16 +00004292
4293
4294/*
4295 * Delete a function if it exists.
4296 */
4297
Eric Andersenc470f442003-07-28 09:56:35 +00004298static void
4299unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004300{
Eric Andersencb57d552001-06-28 07:25:16 +00004301 struct tblentry *cmdp;
4302
Eric Andersenc470f442003-07-28 09:56:35 +00004303 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4304 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004305 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004306}
4307
Eric Andersen2870d962001-07-02 17:27:21 +00004308/*
Eric Andersencb57d552001-06-28 07:25:16 +00004309 * Locate and print what a word is...
4310 */
4311
Eric Andersenc470f442003-07-28 09:56:35 +00004312
4313#ifdef CONFIG_ASH_CMDCMD
4314static int
4315describe_command(char *command, int describe_command_verbose)
4316#else
4317#define describe_command_verbose 1
4318static int
4319describe_command(char *command)
4320#endif
4321{
4322 struct cmdentry entry;
4323 struct tblentry *cmdp;
4324#ifdef CONFIG_ASH_ALIAS
4325 const struct alias *ap;
4326#endif
4327 const char *path = pathval();
4328
4329 if (describe_command_verbose) {
4330 out1str(command);
4331 }
4332
4333 /* First look at the keywords */
4334 if (findkwd(command)) {
4335 out1str(describe_command_verbose ? " is a shell keyword" : command);
4336 goto out;
4337 }
4338
4339#ifdef CONFIG_ASH_ALIAS
4340 /* Then look at the aliases */
4341 if ((ap = lookupalias(command, 0)) != NULL) {
4342 if (describe_command_verbose) {
4343 out1fmt(" is an alias for %s", ap->val);
4344 } else {
4345 out1str("alias ");
4346 printalias(ap);
4347 return 0;
4348 }
4349 goto out;
4350 }
4351#endif
4352 /* Then check if it is a tracked alias */
4353 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4354 entry.cmdtype = cmdp->cmdtype;
4355 entry.u = cmdp->param;
4356 } else {
4357 /* Finally use brute force */
4358 find_command(command, &entry, DO_ABS, path);
4359 }
4360
4361 switch (entry.cmdtype) {
4362 case CMDNORMAL: {
4363 int j = entry.u.index;
4364 char *p;
4365 if (j == -1) {
4366 p = command;
4367 } else {
4368 do {
4369 p = padvance(&path, command);
4370 stunalloc(p);
4371 } while (--j >= 0);
4372 }
4373 if (describe_command_verbose) {
4374 out1fmt(" is%s %s",
4375 (cmdp ? " a tracked alias for" : nullstr), p
4376 );
4377 } else {
4378 out1str(p);
4379 }
4380 break;
4381 }
4382
4383 case CMDFUNCTION:
4384 if (describe_command_verbose) {
4385 out1str(" is a shell function");
4386 } else {
4387 out1str(command);
4388 }
4389 break;
4390
4391 case CMDBUILTIN:
4392 if (describe_command_verbose) {
4393 out1fmt(" is a %sshell builtin",
4394 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4395 "special " : nullstr
4396 );
4397 } else {
4398 out1str(command);
4399 }
4400 break;
4401
4402 default:
4403 if (describe_command_verbose) {
4404 out1str(": not found\n");
4405 }
4406 return 127;
4407 }
4408
4409out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004410 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004411 return 0;
4412}
4413
4414static int
4415typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004416{
4417 int i;
4418 int err = 0;
4419
4420 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004421#ifdef CONFIG_ASH_CMDCMD
4422 err |= describe_command(argv[i], 1);
4423#else
4424 err |= describe_command(argv[i]);
4425#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004426 }
4427 return err;
4428}
4429
Eric Andersend35c5df2002-01-09 15:37:36 +00004430#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004431static int
4432commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004433{
4434 int c;
4435 int default_path = 0;
4436 int verify_only = 0;
4437 int verbose_verify_only = 0;
4438
4439 while ((c = nextopt("pvV")) != '\0')
4440 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004441 default:
4442#ifdef DEBUG
4443 fprintf(stderr,
4444"command: nextopt returned character code 0%o\n", c);
4445 return EX_SOFTWARE;
4446#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004447 case 'p':
4448 default_path = 1;
4449 break;
4450 case 'v':
4451 verify_only = 1;
4452 break;
4453 case 'V':
4454 verbose_verify_only = 1;
4455 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004456 }
4457
Eric Andersenc470f442003-07-28 09:56:35 +00004458 if (default_path + verify_only + verbose_verify_only > 1 ||
4459 !*argptr) {
4460 fprintf(stderr,
4461 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004462 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004463 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004464 }
4465
Eric Andersencb57d552001-06-28 07:25:16 +00004466 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004467 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004468 }
Eric Andersencb57d552001-06-28 07:25:16 +00004469
4470 return 0;
4471}
Eric Andersen2870d962001-07-02 17:27:21 +00004472#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004473
Eric Andersenc470f442003-07-28 09:56:35 +00004474/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004475
Eric Andersencb57d552001-06-28 07:25:16 +00004476/*
4477 * Routines to expand arguments to commands. We have to deal with
4478 * backquotes, shell variables, and file metacharacters.
4479 */
Eric Andersenc470f442003-07-28 09:56:35 +00004480
Eric Andersencb57d552001-06-28 07:25:16 +00004481/*
4482 * _rmescape() flags
4483 */
Eric Andersenc470f442003-07-28 09:56:35 +00004484#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4485#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4486#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4487#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4488#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004489
4490/*
4491 * Structure specifying which parts of the string should be searched
4492 * for IFS characters.
4493 */
4494
4495struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004496 struct ifsregion *next; /* next region in list */
4497 int begoff; /* offset of start of region */
4498 int endoff; /* offset of end of region */
4499 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004500};
4501
Eric Andersenc470f442003-07-28 09:56:35 +00004502/* output of current string */
4503static char *expdest;
4504/* list of back quote expressions */
4505static struct nodelist *argbackq;
4506/* first struct in list of ifs regions */
4507static struct ifsregion ifsfirst;
4508/* last struct in list */
4509static struct ifsregion *ifslastp;
4510/* holds expanded arg list */
4511static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004512
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004513static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004514static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004515static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004516static const char *subevalvar(char *, char *, int, int, int, int, int);
4517static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004518static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004519static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004520static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004521static void recordregion(int, int, int);
4522static void removerecordregions(int);
4523static void ifsbreakup(char *, struct arglist *);
4524static void ifsfree(void);
4525static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004526static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004527
Eric Andersened9ecf72004-06-22 08:29:45 +00004528static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004529static size_t esclen(const char *, const char *);
4530static char *scanleft(char *, char *, char *, char *, int, int);
4531static char *scanright(char *, char *, char *, char *, int, int);
4532static void varunset(const char *, const char *, const char *, int)
4533 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004534
Eric Andersenc470f442003-07-28 09:56:35 +00004535
4536#define pmatch(a, b) !fnmatch((a), (b), 0)
4537/*
Eric Andersen90898442003-08-06 11:20:52 +00004538 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004539 *
4540 * Returns an stalloced string.
4541 */
4542
4543static inline char *
4544preglob(const char *pattern, int quoted, int flag) {
4545 flag |= RMESCAPE_GLOB;
4546 if (quoted) {
4547 flag |= RMESCAPE_QUOTED;
4548 }
4549 return _rmescapes((char *)pattern, flag);
4550}
4551
4552
4553static size_t
4554esclen(const char *start, const char *p) {
4555 size_t esc = 0;
4556
4557 while (p > start && *--p == CTLESC) {
4558 esc++;
4559 }
4560 return esc;
4561}
4562
Eric Andersencb57d552001-06-28 07:25:16 +00004563
4564/*
4565 * Expand shell variables and backquotes inside a here document.
4566 */
4567
Eric Andersenc470f442003-07-28 09:56:35 +00004568static inline void
4569expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004570{
Eric Andersencb57d552001-06-28 07:25:16 +00004571 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004572 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004573 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004574}
4575
4576
4577/*
4578 * Perform variable substitution and command substitution on an argument,
4579 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4580 * perform splitting and file name expansion. When arglist is NULL, perform
4581 * here document expansion.
4582 */
4583
Eric Andersenc470f442003-07-28 09:56:35 +00004584void
4585expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004586{
4587 struct strlist *sp;
4588 char *p;
4589
4590 argbackq = arg->narg.backquote;
4591 STARTSTACKSTR(expdest);
4592 ifsfirst.next = NULL;
4593 ifslastp = NULL;
4594 argstr(arg->narg.text, flag);
4595 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004596 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004597 }
4598 STPUTC('\0', expdest);
4599 p = grabstackstr(expdest);
4600 exparg.lastp = &exparg.list;
4601 /*
4602 * TODO - EXP_REDIR
4603 */
4604 if (flag & EXP_FULL) {
4605 ifsbreakup(p, &exparg);
4606 *exparg.lastp = NULL;
4607 exparg.lastp = &exparg.list;
4608 expandmeta(exparg.list, flag);
4609 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004610 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004611 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004612 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004613 sp->text = p;
4614 *exparg.lastp = sp;
4615 exparg.lastp = &sp->next;
4616 }
Eric Andersenc470f442003-07-28 09:56:35 +00004617 if (ifsfirst.next)
4618 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004619 *exparg.lastp = NULL;
4620 if (exparg.list) {
4621 *arglist->lastp = exparg.list;
4622 arglist->lastp = exparg.lastp;
4623 }
4624}
4625
4626
Eric Andersenc470f442003-07-28 09:56:35 +00004627/*
4628 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4629 * characters to allow for further processing. Otherwise treat
4630 * $@ like $* since no splitting will be performed.
4631 */
4632
4633static void
4634argstr(char *p, int flag)
4635{
4636 static const char spclchars[] = {
4637 '=',
4638 ':',
4639 CTLQUOTEMARK,
4640 CTLENDVAR,
4641 CTLESC,
4642 CTLVAR,
4643 CTLBACKQ,
4644 CTLBACKQ | CTLQUOTE,
4645#ifdef CONFIG_ASH_MATH_SUPPORT
4646 CTLENDARI,
4647#endif
4648 0
4649 };
4650 const char *reject = spclchars;
4651 int c;
4652 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4653 int breakall = flag & EXP_WORD;
4654 int inquotes;
4655 size_t length;
4656 int startloc;
4657
4658 if (!(flag & EXP_VARTILDE)) {
4659 reject += 2;
4660 } else if (flag & EXP_VARTILDE2) {
4661 reject++;
4662 }
4663 inquotes = 0;
4664 length = 0;
4665 if (flag & EXP_TILDE) {
4666 char *q;
4667
4668 flag &= ~EXP_TILDE;
4669tilde:
4670 q = p;
4671 if (*q == CTLESC && (flag & EXP_QWORD))
4672 q++;
4673 if (*q == '~')
4674 p = exptilde(p, q, flag);
4675 }
4676start:
4677 startloc = expdest - (char *)stackblock();
4678 for (;;) {
4679 length += strcspn(p + length, reject);
4680 c = p[length];
4681 if (c && (!(c & 0x80)
4682#ifdef CONFIG_ASH_MATH_SUPPORT
4683 || c == CTLENDARI
4684#endif
4685 )) {
4686 /* c == '=' || c == ':' || c == CTLENDARI */
4687 length++;
4688 }
4689 if (length > 0) {
4690 int newloc;
4691 expdest = stnputs(p, length, expdest);
4692 newloc = expdest - (char *)stackblock();
4693 if (breakall && !inquotes && newloc > startloc) {
4694 recordregion(startloc, newloc, 0);
4695 }
4696 startloc = newloc;
4697 }
4698 p += length + 1;
4699 length = 0;
4700
4701 switch (c) {
4702 case '\0':
4703 goto breakloop;
4704 case '=':
4705 if (flag & EXP_VARTILDE2) {
4706 p--;
4707 continue;
4708 }
4709 flag |= EXP_VARTILDE2;
4710 reject++;
4711 /* fall through */
4712 case ':':
4713 /*
4714 * sort of a hack - expand tildes in variable
4715 * assignments (after the first '=' and after ':'s).
4716 */
4717 if (*--p == '~') {
4718 goto tilde;
4719 }
4720 continue;
4721 }
4722
4723 switch (c) {
4724 case CTLENDVAR: /* ??? */
4725 goto breakloop;
4726 case CTLQUOTEMARK:
4727 /* "$@" syntax adherence hack */
4728 if (
4729 !inquotes &&
4730 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4731 (p[4] == CTLQUOTEMARK || (
4732 p[4] == CTLENDVAR &&
4733 p[5] == CTLQUOTEMARK
4734 ))
4735 ) {
4736 p = evalvar(p + 1, flag) + 1;
4737 goto start;
4738 }
4739 inquotes = !inquotes;
4740addquote:
4741 if (quotes) {
4742 p--;
4743 length++;
4744 startloc++;
4745 }
4746 break;
4747 case CTLESC:
4748 startloc++;
4749 length++;
4750 goto addquote;
4751 case CTLVAR:
4752 p = evalvar(p, flag);
4753 goto start;
4754 case CTLBACKQ:
4755 c = 0;
4756 case CTLBACKQ|CTLQUOTE:
4757 expbackq(argbackq->n, c, quotes);
4758 argbackq = argbackq->next;
4759 goto start;
4760#ifdef CONFIG_ASH_MATH_SUPPORT
4761 case CTLENDARI:
4762 p--;
4763 expari(quotes);
4764 goto start;
4765#endif
4766 }
4767 }
4768breakloop:
4769 ;
4770}
4771
4772static char *
4773exptilde(char *startp, char *p, int flag)
4774{
4775 char c;
4776 char *name;
4777 struct passwd *pw;
4778 const char *home;
4779 int quotes = flag & (EXP_FULL | EXP_CASE);
4780 int startloc;
4781
4782 name = p + 1;
4783
4784 while ((c = *++p) != '\0') {
4785 switch(c) {
4786 case CTLESC:
4787 return (startp);
4788 case CTLQUOTEMARK:
4789 return (startp);
4790 case ':':
4791 if (flag & EXP_VARTILDE)
4792 goto done;
4793 break;
4794 case '/':
4795 case CTLENDVAR:
4796 goto done;
4797 }
4798 }
4799done:
4800 *p = '\0';
4801 if (*name == '\0') {
4802 if ((home = lookupvar(homestr)) == NULL)
4803 goto lose;
4804 } else {
4805 if ((pw = getpwnam(name)) == NULL)
4806 goto lose;
4807 home = pw->pw_dir;
4808 }
4809 if (*home == '\0')
4810 goto lose;
4811 *p = c;
4812 startloc = expdest - (char *)stackblock();
4813 strtodest(home, SQSYNTAX, quotes);
4814 recordregion(startloc, expdest - (char *)stackblock(), 0);
4815 return (p);
4816lose:
4817 *p = c;
4818 return (startp);
4819}
4820
4821
4822static void
4823removerecordregions(int endoff)
4824{
4825 if (ifslastp == NULL)
4826 return;
4827
4828 if (ifsfirst.endoff > endoff) {
4829 while (ifsfirst.next != NULL) {
4830 struct ifsregion *ifsp;
4831 INTOFF;
4832 ifsp = ifsfirst.next->next;
4833 ckfree(ifsfirst.next);
4834 ifsfirst.next = ifsp;
4835 INTON;
4836 }
4837 if (ifsfirst.begoff > endoff)
4838 ifslastp = NULL;
4839 else {
4840 ifslastp = &ifsfirst;
4841 ifsfirst.endoff = endoff;
4842 }
4843 return;
4844 }
4845
4846 ifslastp = &ifsfirst;
4847 while (ifslastp->next && ifslastp->next->begoff < endoff)
4848 ifslastp=ifslastp->next;
4849 while (ifslastp->next != NULL) {
4850 struct ifsregion *ifsp;
4851 INTOFF;
4852 ifsp = ifslastp->next->next;
4853 ckfree(ifslastp->next);
4854 ifslastp->next = ifsp;
4855 INTON;
4856 }
4857 if (ifslastp->endoff > endoff)
4858 ifslastp->endoff = endoff;
4859}
4860
4861
4862#ifdef CONFIG_ASH_MATH_SUPPORT
4863/*
4864 * Expand arithmetic expression. Backup to start of expression,
4865 * evaluate, place result in (backed up) result, adjust string position.
4866 */
4867void
4868expari(int quotes)
4869{
4870 char *p, *start;
4871 int begoff;
4872 int flag;
4873 int len;
4874
4875 /* ifsfree(); */
4876
4877 /*
4878 * This routine is slightly over-complicated for
4879 * efficiency. Next we scan backwards looking for the
4880 * start of arithmetic.
4881 */
4882 start = stackblock();
4883 p = expdest - 1;
4884 *p = '\0';
4885 p--;
4886 do {
4887 int esc;
4888
4889 while (*p != CTLARI) {
4890 p--;
4891#ifdef DEBUG
4892 if (p < start) {
4893 error("missing CTLARI (shouldn't happen)");
4894 }
4895#endif
4896 }
4897
4898 esc = esclen(start, p);
4899 if (!(esc % 2)) {
4900 break;
4901 }
4902
4903 p -= esc + 1;
4904 } while (1);
4905
4906 begoff = p - start;
4907
4908 removerecordregions(begoff);
4909
4910 flag = p[1];
4911
4912 expdest = p;
4913
4914 if (quotes)
4915 rmescapes(p + 2);
4916
4917 len = cvtnum(dash_arith(p + 2));
4918
4919 if (flag != '"')
4920 recordregion(begoff, begoff + len, 0);
4921}
4922#endif
4923
4924/*
4925 * Expand stuff in backwards quotes.
4926 */
4927
4928static void
4929expbackq(union node *cmd, int quoted, int quotes)
4930{
4931 struct backcmd in;
4932 int i;
4933 char buf[128];
4934 char *p;
4935 char *dest;
4936 int startloc;
4937 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4938 struct stackmark smark;
4939
4940 INTOFF;
4941 setstackmark(&smark);
4942 dest = expdest;
4943 startloc = dest - (char *)stackblock();
4944 grabstackstr(dest);
4945 evalbackcmd(cmd, (struct backcmd *) &in);
4946 popstackmark(&smark);
4947
4948 p = in.buf;
4949 i = in.nleft;
4950 if (i == 0)
4951 goto read;
4952 for (;;) {
4953 memtodest(p, i, syntax, quotes);
4954read:
4955 if (in.fd < 0)
4956 break;
4957 i = safe_read(in.fd, buf, sizeof buf);
4958 TRACE(("expbackq: read returns %d\n", i));
4959 if (i <= 0)
4960 break;
4961 p = buf;
4962 }
4963
4964 if (in.buf)
4965 ckfree(in.buf);
4966 if (in.fd >= 0) {
4967 close(in.fd);
4968 back_exitstatus = waitforjob(in.jp);
4969 }
4970 INTON;
4971
4972 /* Eat all trailing newlines */
4973 dest = expdest;
4974 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4975 STUNPUTC(dest);
4976 expdest = dest;
4977
4978 if (quoted == 0)
4979 recordregion(startloc, dest - (char *)stackblock(), 0);
4980 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4981 (dest - (char *)stackblock()) - startloc,
4982 (dest - (char *)stackblock()) - startloc,
4983 stackblock() + startloc));
4984}
4985
4986
4987static char *
Eric Andersen90898442003-08-06 11:20:52 +00004988scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4989 int zero)
4990{
Eric Andersenc470f442003-07-28 09:56:35 +00004991 char *loc;
4992 char *loc2;
4993 char c;
4994
4995 loc = startp;
4996 loc2 = rmesc;
4997 do {
4998 int match;
4999 const char *s = loc2;
5000 c = *loc2;
5001 if (zero) {
5002 *loc2 = '\0';
5003 s = rmesc;
5004 }
5005 match = pmatch(str, s);
5006 *loc2 = c;
5007 if (match)
5008 return loc;
5009 if (quotes && *loc == CTLESC)
5010 loc++;
5011 loc++;
5012 loc2++;
5013 } while (c);
5014 return 0;
5015}
5016
5017
5018static char *
Eric Andersen90898442003-08-06 11:20:52 +00005019scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5020 int zero)
5021{
Eric Andersenc470f442003-07-28 09:56:35 +00005022 int esc = 0;
5023 char *loc;
5024 char *loc2;
5025
5026 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5027 int match;
5028 char c = *loc2;
5029 const char *s = loc2;
5030 if (zero) {
5031 *loc2 = '\0';
5032 s = rmesc;
5033 }
5034 match = pmatch(str, s);
5035 *loc2 = c;
5036 if (match)
5037 return loc;
5038 loc--;
5039 if (quotes) {
5040 if (--esc < 0) {
5041 esc = esclen(startp, loc);
5042 }
5043 if (esc % 2) {
5044 esc--;
5045 loc--;
5046 }
5047 }
5048 }
5049 return 0;
5050}
5051
5052static const char *
5053subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5054{
5055 char *startp;
5056 char *loc;
5057 int saveherefd = herefd;
5058 struct nodelist *saveargbackq = argbackq;
5059 int amount;
5060 char *rmesc, *rmescend;
5061 int zero;
5062 char *(*scan)(char *, char *, char *, char *, int , int);
5063
5064 herefd = -1;
5065 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5066 STPUTC('\0', expdest);
5067 herefd = saveherefd;
5068 argbackq = saveargbackq;
5069 startp = stackblock() + startloc;
5070
5071 switch (subtype) {
5072 case VSASSIGN:
5073 setvar(str, startp, 0);
5074 amount = startp - expdest;
5075 STADJUST(amount, expdest);
5076 return startp;
5077
5078 case VSQUESTION:
5079 varunset(p, str, startp, varflags);
5080 /* NOTREACHED */
5081 }
5082
5083 subtype -= VSTRIMRIGHT;
5084#ifdef DEBUG
5085 if (subtype < 0 || subtype > 3)
5086 abort();
5087#endif
5088
5089 rmesc = startp;
5090 rmescend = stackblock() + strloc;
5091 if (quotes) {
5092 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5093 if (rmesc != startp) {
5094 rmescend = expdest;
5095 startp = stackblock() + startloc;
5096 }
5097 }
5098 rmescend--;
5099 str = stackblock() + strloc;
5100 preglob(str, varflags & VSQUOTE, 0);
5101
5102 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5103 zero = subtype >> 1;
5104 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5105 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5106
5107 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5108 if (loc) {
5109 if (zero) {
5110 memmove(startp, loc, str - loc);
5111 loc = startp + (str - loc) - 1;
5112 }
5113 *loc = '\0';
5114 amount = loc - expdest;
5115 STADJUST(amount, expdest);
5116 }
5117 return loc;
5118}
5119
5120
Eric Andersen62483552001-07-10 06:09:16 +00005121/*
5122 * Expand a variable, and return a pointer to the next character in the
5123 * input string.
5124 */
Eric Andersenc470f442003-07-28 09:56:35 +00005125static char *
5126evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005127{
5128 int subtype;
5129 int varflags;
5130 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005131 int patloc;
5132 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005133 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005134 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005135 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005136 int quotes;
5137 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005138
Eric Andersenc470f442003-07-28 09:56:35 +00005139 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005140 varflags = *p++;
5141 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005142 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005143 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005144 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005145 startloc = expdest - (char *)stackblock();
5146 p = strchr(p, '=') + 1;
5147
Eric Andersenc470f442003-07-28 09:56:35 +00005148again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005149 varlen = varvalue(var, varflags, flag);
5150 if (varflags & VSNUL)
5151 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005152
Glenn L McGrath76620622004-01-13 10:19:37 +00005153 if (subtype == VSPLUS) {
5154 varlen = -1 - varlen;
5155 goto vsplus;
5156 }
Eric Andersen62483552001-07-10 06:09:16 +00005157
Eric Andersenc470f442003-07-28 09:56:35 +00005158 if (subtype == VSMINUS) {
5159vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005160 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005161 argstr(
5162 p, flag | EXP_TILDE |
5163 (quoted ? EXP_QWORD : EXP_WORD)
5164 );
5165 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005166 }
5167 if (easy)
5168 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005169 goto end;
5170 }
Eric Andersen62483552001-07-10 06:09:16 +00005171
Eric Andersenc470f442003-07-28 09:56:35 +00005172 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005173 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005174 if (subevalvar(p, var, 0, subtype, startloc,
5175 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005176 varflags &= ~VSNUL;
5177 /*
5178 * Remove any recorded regions beyond
5179 * start of variable
5180 */
5181 removerecordregions(startloc);
5182 goto again;
5183 }
Eric Andersenc470f442003-07-28 09:56:35 +00005184 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005185 }
5186 if (easy)
5187 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005188 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005189 }
5190
Glenn L McGrath76620622004-01-13 10:19:37 +00005191 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005192 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005193
Eric Andersenc470f442003-07-28 09:56:35 +00005194 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005195 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005196 goto record;
5197 }
5198
5199 if (subtype == VSNORMAL) {
5200 if (!easy)
5201 goto end;
5202record:
5203 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5204 goto end;
5205 }
5206
5207#ifdef DEBUG
5208 switch (subtype) {
5209 case VSTRIMLEFT:
5210 case VSTRIMLEFTMAX:
5211 case VSTRIMRIGHT:
5212 case VSTRIMRIGHTMAX:
5213 break;
5214 default:
5215 abort();
5216 }
5217#endif
5218
Glenn L McGrath76620622004-01-13 10:19:37 +00005219 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005220 /*
5221 * Terminate the string and start recording the pattern
5222 * right after it
5223 */
5224 STPUTC('\0', expdest);
5225 patloc = expdest - (char *)stackblock();
5226 if (subevalvar(p, NULL, patloc, subtype,
5227 startloc, varflags, quotes) == 0) {
5228 int amount = expdest - (
5229 (char *)stackblock() + patloc - 1
5230 );
5231 STADJUST(-amount, expdest);
5232 }
5233 /* Remove any recorded regions beyond start of variable */
5234 removerecordregions(startloc);
5235 goto record;
5236 }
5237
5238end:
5239 if (subtype != VSNORMAL) { /* skip to end of alternative */
5240 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005241 for (;;) {
5242 if ((c = *p++) == CTLESC)
5243 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005244 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005245 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005246 argbackq = argbackq->next;
5247 } else if (c == CTLVAR) {
5248 if ((*p++ & VSTYPE) != VSNORMAL)
5249 nesting++;
5250 } else if (c == CTLENDVAR) {
5251 if (--nesting == 0)
5252 break;
5253 }
5254 }
5255 }
5256 return p;
5257}
5258
Eric Andersencb57d552001-06-28 07:25:16 +00005259
Eric Andersencb57d552001-06-28 07:25:16 +00005260/*
5261 * Put a string on the stack.
5262 */
5263
Eric Andersenc470f442003-07-28 09:56:35 +00005264static void
5265memtodest(const char *p, size_t len, int syntax, int quotes) {
5266 char *q = expdest;
5267
5268 q = makestrspace(len * 2, q);
5269
5270 while (len--) {
5271 int c = *p++;
5272 if (!c)
5273 continue;
5274 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5275 USTPUTC(CTLESC, q);
5276 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005277 }
Eric Andersenc470f442003-07-28 09:56:35 +00005278
5279 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005280}
5281
Eric Andersenc470f442003-07-28 09:56:35 +00005282
5283static void
5284strtodest(const char *p, int syntax, int quotes)
5285{
5286 memtodest(p, strlen(p), syntax, quotes);
5287}
5288
5289
Eric Andersencb57d552001-06-28 07:25:16 +00005290/*
5291 * Add the value of a specialized variable to the stack string.
5292 */
5293
Glenn L McGrath76620622004-01-13 10:19:37 +00005294static ssize_t
5295varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005296{
5297 int num;
5298 char *p;
5299 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005300 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005301 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005302 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005303 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005304 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005305 int quoted = varflags & VSQUOTE;
5306 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005307 int quotes = flags & (EXP_FULL | EXP_CASE);
5308
Glenn L McGrath76620622004-01-13 10:19:37 +00005309 if (quoted && (flags & EXP_FULL))
5310 sep = 1 << CHAR_BIT;
5311
Eric Andersencb57d552001-06-28 07:25:16 +00005312 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5313 switch (*name) {
5314 case '$':
5315 num = rootpid;
5316 goto numvar;
5317 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005318 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005319 goto numvar;
5320 case '#':
5321 num = shellparam.nparam;
5322 goto numvar;
5323 case '!':
5324 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005325 if (num == 0)
5326 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005327numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005328 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005329 break;
5330 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005331 p = makestrspace(NOPTS, expdest);
5332 for (i = NOPTS - 1; i >= 0; i--) {
5333 if (optlist[i]) {
5334 USTPUTC(optletters(i), p);
5335 len++;
5336 }
Eric Andersencb57d552001-06-28 07:25:16 +00005337 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005338 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005339 break;
5340 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005341 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005342 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005343 /* fall through */
5344 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005345 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005346 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5347 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005348param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005349 if (!(ap = shellparam.p))
5350 return -1;
5351 while ((p = *ap++)) {
5352 size_t partlen;
5353
5354 partlen = strlen(p);
5355
5356 len += partlen;
5357 if (len > partlen && sep) {
5358 char *q;
5359
5360 len++;
5361 if (subtype == VSPLUS || subtype == VSLENGTH) {
5362 continue;
5363 }
5364 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005365 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005366 STPUTC(CTLESC, q);
5367 STPUTC(sep, q);
5368 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005369 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005370
5371 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5372 memtodest(p, partlen, syntax, quotes);
Eric Andersencb57d552001-06-28 07:25:16 +00005373 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005374 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005375 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005376 case '1':
5377 case '2':
5378 case '3':
5379 case '4':
5380 case '5':
5381 case '6':
5382 case '7':
5383 case '8':
5384 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005385 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005386 if (num < 0 || num > shellparam.nparam)
5387 return -1;
5388 p = num ? shellparam.p[num - 1] : arg0;
5389 goto value;
5390 default:
5391 p = lookupvar(name);
5392value:
5393 if (!p)
5394 return -1;
5395
5396 len = strlen(p);
5397 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5398 memtodest(p, len, syntax, quotes);
5399 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005400 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005401
5402 if (subtype == VSPLUS || subtype == VSLENGTH)
5403 STADJUST(-len, expdest);
5404 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005405}
5406
5407
Eric Andersencb57d552001-06-28 07:25:16 +00005408/*
5409 * Record the fact that we have to scan this region of the
5410 * string for IFS characters.
5411 */
5412
Eric Andersenc470f442003-07-28 09:56:35 +00005413static void
5414recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005415{
5416 struct ifsregion *ifsp;
5417
5418 if (ifslastp == NULL) {
5419 ifsp = &ifsfirst;
5420 } else {
5421 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005422 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005423 ifsp->next = NULL;
5424 ifslastp->next = ifsp;
5425 INTON;
5426 }
5427 ifslastp = ifsp;
5428 ifslastp->begoff = start;
5429 ifslastp->endoff = end;
5430 ifslastp->nulonly = nulonly;
5431}
5432
5433
Eric Andersencb57d552001-06-28 07:25:16 +00005434/*
5435 * Break the argument string into pieces based upon IFS and add the
5436 * strings to the argument list. The regions of the string to be
5437 * searched for IFS characters have been stored by recordregion.
5438 */
Eric Andersenc470f442003-07-28 09:56:35 +00005439static void
5440ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005441{
Eric Andersencb57d552001-06-28 07:25:16 +00005442 struct ifsregion *ifsp;
5443 struct strlist *sp;
5444 char *start;
5445 char *p;
5446 char *q;
5447 const char *ifs, *realifs;
5448 int ifsspc;
5449 int nulonly;
5450
5451
5452 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005453 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005454 ifsspc = 0;
5455 nulonly = 0;
5456 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005457 ifsp = &ifsfirst;
5458 do {
5459 p = string + ifsp->begoff;
5460 nulonly = ifsp->nulonly;
5461 ifs = nulonly ? nullstr : realifs;
5462 ifsspc = 0;
5463 while (p < string + ifsp->endoff) {
5464 q = p;
5465 if (*p == CTLESC)
5466 p++;
5467 if (strchr(ifs, *p)) {
5468 if (!nulonly)
5469 ifsspc = (strchr(defifs, *p) != NULL);
5470 /* Ignore IFS whitespace at start */
5471 if (q == start && ifsspc) {
5472 p++;
5473 start = p;
5474 continue;
5475 }
5476 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005477 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005478 sp->text = start;
5479 *arglist->lastp = sp;
5480 arglist->lastp = &sp->next;
5481 p++;
5482 if (!nulonly) {
5483 for (;;) {
5484 if (p >= string + ifsp->endoff) {
5485 break;
5486 }
5487 q = p;
5488 if (*p == CTLESC)
5489 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005490 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005491 p = q;
5492 break;
5493 } else if (strchr(defifs, *p) == NULL) {
5494 if (ifsspc) {
5495 p++;
5496 ifsspc = 0;
5497 } else {
5498 p = q;
5499 break;
5500 }
5501 } else
5502 p++;
5503 }
5504 }
5505 start = p;
5506 } else
5507 p++;
5508 }
5509 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005510 if (nulonly)
5511 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005512 }
5513
Eric Andersenc470f442003-07-28 09:56:35 +00005514 if (!*start)
5515 return;
5516
5517add:
5518 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005519 sp->text = start;
5520 *arglist->lastp = sp;
5521 arglist->lastp = &sp->next;
5522}
5523
Eric Andersenc470f442003-07-28 09:56:35 +00005524static void
5525ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005526{
Eric Andersenc470f442003-07-28 09:56:35 +00005527 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005528
Eric Andersenc470f442003-07-28 09:56:35 +00005529 INTOFF;
5530 p = ifsfirst.next;
5531 do {
5532 struct ifsregion *ifsp;
5533 ifsp = p->next;
5534 ckfree(p);
5535 p = ifsp;
5536 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005537 ifslastp = NULL;
5538 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005539 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005540}
5541
Eric Andersen90898442003-08-06 11:20:52 +00005542static void expmeta(char *, char *);
5543static struct strlist *expsort(struct strlist *);
5544static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005545
Eric Andersen90898442003-08-06 11:20:52 +00005546static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005547
Eric Andersencb57d552001-06-28 07:25:16 +00005548
Eric Andersenc470f442003-07-28 09:56:35 +00005549static void
Eric Andersen90898442003-08-06 11:20:52 +00005550expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005551{
Eric Andersen90898442003-08-06 11:20:52 +00005552 static const char metachars[] = {
5553 '*', '?', '[', 0
5554 };
Eric Andersencb57d552001-06-28 07:25:16 +00005555 /* TODO - EXP_REDIR */
5556
5557 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005558 struct strlist **savelastp;
5559 struct strlist *sp;
5560 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005561
Eric Andersencb57d552001-06-28 07:25:16 +00005562 if (fflag)
5563 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005564 if (!strpbrk(str->text, metachars))
5565 goto nometa;
5566 savelastp = exparg.lastp;
5567
Eric Andersencb57d552001-06-28 07:25:16 +00005568 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005569 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005570 {
5571 int i = strlen(str->text);
5572 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5573 }
5574
5575 expmeta(expdir, p);
5576 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005577 if (p != str->text)
5578 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005579 INTON;
5580 if (exparg.lastp == savelastp) {
5581 /*
5582 * no matches
5583 */
Eric Andersenc470f442003-07-28 09:56:35 +00005584nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005585 *exparg.lastp = str;
5586 rmescapes(str->text);
5587 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005588 } else {
5589 *exparg.lastp = NULL;
5590 *savelastp = sp = expsort(*savelastp);
5591 while (sp->next != NULL)
5592 sp = sp->next;
5593 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005594 }
5595 str = str->next;
5596 }
5597}
5598
Eric Andersencb57d552001-06-28 07:25:16 +00005599/*
Eric Andersenc470f442003-07-28 09:56:35 +00005600 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005601 */
5602
Eric Andersenc470f442003-07-28 09:56:35 +00005603static void
Eric Andersen90898442003-08-06 11:20:52 +00005604addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005605{
Eric Andersencb57d552001-06-28 07:25:16 +00005606 struct strlist *sp;
5607
Eric Andersenc470f442003-07-28 09:56:35 +00005608 sp = (struct strlist *)stalloc(sizeof *sp);
5609 sp->text = sstrdup(name);
5610 *exparg.lastp = sp;
5611 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005612}
5613
5614
Eric Andersencb57d552001-06-28 07:25:16 +00005615/*
Eric Andersen90898442003-08-06 11:20:52 +00005616 * Do metacharacter (i.e. *, ?, [...]) expansion.
5617 */
5618
5619static void
5620expmeta(char *enddir, char *name)
5621{
5622 char *p;
5623 const char *cp;
5624 char *start;
5625 char *endname;
5626 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005627 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005628 DIR *dirp;
5629 struct dirent *dp;
5630 int atend;
5631 int matchdot;
5632
5633 metaflag = 0;
5634 start = name;
5635 for (p = name; *p; p++) {
5636 if (*p == '*' || *p == '?')
5637 metaflag = 1;
5638 else if (*p == '[') {
5639 char *q = p + 1;
5640 if (*q == '!')
5641 q++;
5642 for (;;) {
5643 if (*q == '\\')
5644 q++;
5645 if (*q == '/' || *q == '\0')
5646 break;
5647 if (*++q == ']') {
5648 metaflag = 1;
5649 break;
5650 }
5651 }
5652 } else if (*p == '\\')
5653 p++;
5654 else if (*p == '/') {
5655 if (metaflag)
5656 goto out;
5657 start = p + 1;
5658 }
5659 }
5660out:
5661 if (metaflag == 0) { /* we've reached the end of the file name */
5662 if (enddir != expdir)
5663 metaflag++;
5664 p = name;
5665 do {
5666 if (*p == '\\')
5667 p++;
5668 *enddir++ = *p;
5669 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005670 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005671 addfname(expdir);
5672 return;
5673 }
5674 endname = p;
5675 if (name < start) {
5676 p = name;
5677 do {
5678 if (*p == '\\')
5679 p++;
5680 *enddir++ = *p++;
5681 } while (p < start);
5682 }
5683 if (enddir == expdir) {
5684 cp = ".";
5685 } else if (enddir == expdir + 1 && *expdir == '/') {
5686 cp = "/";
5687 } else {
5688 cp = expdir;
5689 enddir[-1] = '\0';
5690 }
5691 if ((dirp = opendir(cp)) == NULL)
5692 return;
5693 if (enddir != expdir)
5694 enddir[-1] = '/';
5695 if (*endname == 0) {
5696 atend = 1;
5697 } else {
5698 atend = 0;
5699 *endname++ = '\0';
5700 }
5701 matchdot = 0;
5702 p = start;
5703 if (*p == '\\')
5704 p++;
5705 if (*p == '.')
5706 matchdot++;
5707 while (! intpending && (dp = readdir(dirp)) != NULL) {
5708 if (dp->d_name[0] == '.' && ! matchdot)
5709 continue;
5710 if (pmatch(start, dp->d_name)) {
5711 if (atend) {
5712 scopy(dp->d_name, enddir);
5713 addfname(expdir);
5714 } else {
5715 for (p = enddir, cp = dp->d_name;
5716 (*p++ = *cp++) != '\0';)
5717 continue;
5718 p[-1] = '/';
5719 expmeta(p, endname);
5720 }
5721 }
5722 }
5723 closedir(dirp);
5724 if (! atend)
5725 endname[-1] = '/';
5726}
5727
5728/*
5729 * Sort the results of file name expansion. It calculates the number of
5730 * strings to sort and then calls msort (short for merge sort) to do the
5731 * work.
5732 */
5733
5734static struct strlist *
5735expsort(struct strlist *str)
5736{
5737 int len;
5738 struct strlist *sp;
5739
5740 len = 0;
5741 for (sp = str ; sp ; sp = sp->next)
5742 len++;
5743 return msort(str, len);
5744}
5745
5746
5747static struct strlist *
5748msort(struct strlist *list, int len)
5749{
5750 struct strlist *p, *q = NULL;
5751 struct strlist **lpp;
5752 int half;
5753 int n;
5754
5755 if (len <= 1)
5756 return list;
5757 half = len >> 1;
5758 p = list;
5759 for (n = half ; --n >= 0 ; ) {
5760 q = p;
5761 p = p->next;
5762 }
5763 q->next = NULL; /* terminate first half of list */
5764 q = msort(list, half); /* sort first half of list */
5765 p = msort(p, len - half); /* sort second half */
5766 lpp = &list;
5767 for (;;) {
5768#ifdef CONFIG_LOCALE_SUPPORT
5769 if (strcoll(p->text, q->text) < 0)
5770#else
5771 if (strcmp(p->text, q->text) < 0)
5772#endif
5773 {
5774 *lpp = p;
5775 lpp = &p->next;
5776 if ((p = *lpp) == NULL) {
5777 *lpp = q;
5778 break;
5779 }
5780 } else {
5781 *lpp = q;
5782 lpp = &q->next;
5783 if ((q = *lpp) == NULL) {
5784 *lpp = p;
5785 break;
5786 }
5787 }
5788 }
5789 return list;
5790}
5791
5792
5793/*
Eric Andersencb57d552001-06-28 07:25:16 +00005794 * Returns true if the pattern matches the string.
5795 */
5796
Eric Andersenc470f442003-07-28 09:56:35 +00005797static inline int
5798patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005799{
Eric Andersenc470f442003-07-28 09:56:35 +00005800 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005801}
5802
5803
Eric Andersencb57d552001-06-28 07:25:16 +00005804/*
5805 * Remove any CTLESC characters from a string.
5806 */
5807
Eric Andersenc470f442003-07-28 09:56:35 +00005808static char *
5809_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005810{
5811 char *p, *q, *r;
5812 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005813 unsigned inquotes;
5814 int notescaped;
5815 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005816
5817 p = strpbrk(str, qchars);
5818 if (!p) {
5819 return str;
5820 }
5821 q = p;
5822 r = str;
5823 if (flag & RMESCAPE_ALLOC) {
5824 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005825 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005826
Eric Andersenc470f442003-07-28 09:56:35 +00005827 if (flag & RMESCAPE_GROW) {
5828 r = makestrspace(fulllen, expdest);
5829 } else if (flag & RMESCAPE_HEAP) {
5830 r = ckmalloc(fulllen);
5831 } else {
5832 r = stalloc(fulllen);
5833 }
5834 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005835 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005836 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005837 }
5838 }
Eric Andersenc470f442003-07-28 09:56:35 +00005839 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5840 globbing = flag & RMESCAPE_GLOB;
5841 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005842 while (*p) {
5843 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005844 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005845 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005846 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005847 continue;
5848 }
Eric Andersenc470f442003-07-28 09:56:35 +00005849 if (*p == '\\') {
5850 /* naked back slash */
5851 notescaped = 0;
5852 goto copy;
5853 }
Eric Andersencb57d552001-06-28 07:25:16 +00005854 if (*p == CTLESC) {
5855 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005856 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005857 *q++ = '\\';
5858 }
5859 }
Eric Andersenc470f442003-07-28 09:56:35 +00005860 notescaped = globbing;
5861copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005862 *q++ = *p++;
5863 }
5864 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005865 if (flag & RMESCAPE_GROW) {
5866 expdest = r;
5867 STADJUST(q - r + 1, expdest);
5868 }
Eric Andersencb57d552001-06-28 07:25:16 +00005869 return r;
5870}
Eric Andersencb57d552001-06-28 07:25:16 +00005871
5872
Eric Andersencb57d552001-06-28 07:25:16 +00005873/*
5874 * See if a pattern matches in a case statement.
5875 */
5876
Eric Andersenc470f442003-07-28 09:56:35 +00005877int
5878casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005879{
Eric Andersencb57d552001-06-28 07:25:16 +00005880 struct stackmark smark;
5881 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005882
5883 setstackmark(&smark);
5884 argbackq = pattern->narg.backquote;
5885 STARTSTACKSTR(expdest);
5886 ifslastp = NULL;
5887 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005888 STACKSTRNUL(expdest);
5889 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005890 popstackmark(&smark);
5891 return result;
5892}
5893
5894/*
5895 * Our own itoa().
5896 */
5897
Eric Andersenc470f442003-07-28 09:56:35 +00005898static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005899cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005900{
Eric Andersencb57d552001-06-28 07:25:16 +00005901 int len;
5902
Eric Andersenc470f442003-07-28 09:56:35 +00005903 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005904#ifdef CONFIG_ASH_MATH_SUPPORT_64
5905 len = fmtstr(expdest, 32, "%lld", (long long) num);
5906#else
Eric Andersenc470f442003-07-28 09:56:35 +00005907 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005908#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005909 STADJUST(len, expdest);
5910 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005911}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005912
Eric Andersenc470f442003-07-28 09:56:35 +00005913static void
5914varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005915{
Eric Andersenc470f442003-07-28 09:56:35 +00005916 const char *msg;
5917 const char *tail;
5918
5919 tail = nullstr;
5920 msg = "parameter not set";
5921 if (umsg) {
5922 if (*end == CTLENDVAR) {
5923 if (varflags & VSNUL)
5924 tail = " or null";
5925 } else
5926 msg = umsg;
5927 }
5928 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005929}
Eric Andersen90898442003-08-06 11:20:52 +00005930
5931
Eric Andersenc470f442003-07-28 09:56:35 +00005932/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005933
Eric Andersencb57d552001-06-28 07:25:16 +00005934/*
Eric Andersen90898442003-08-06 11:20:52 +00005935 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005936 */
5937
Eric Andersenc470f442003-07-28 09:56:35 +00005938#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5939#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005940
Eric Andersenc470f442003-07-28 09:56:35 +00005941static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005942
Eric Andersencb57d552001-06-28 07:25:16 +00005943/*
Eric Andersenc470f442003-07-28 09:56:35 +00005944 * Read a character from the script, returning PEOF on end of file.
5945 * Nul characters in the input are silently discarded.
5946 */
5947
5948#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5949
5950#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5951#define pgetc_macro() pgetc()
5952static int
5953pgetc(void)
5954{
5955 return pgetc_as_macro();
5956}
5957#else
5958#define pgetc_macro() pgetc_as_macro()
5959static int
5960pgetc(void)
5961{
5962 return pgetc_macro();
5963}
5964#endif
5965
5966
5967/*
5968 * Same as pgetc(), but ignores PEOA.
5969 */
5970#ifdef CONFIG_ASH_ALIAS
5971static int pgetc2(void)
5972{
5973 int c;
5974
5975 do {
5976 c = pgetc_macro();
5977 } while (c == PEOA);
5978 return c;
5979}
5980#else
5981static inline int pgetc2(void)
5982{
5983 return pgetc_macro();
5984}
5985#endif
5986
Glenn L McGrath28939ad2004-07-21 10:20:19 +00005987/*
5988 * Read a line from the script.
5989 */
5990
5991static inline char *
5992pfgets(char *line, int len)
5993{
5994 char *p = line;
5995 int nleft = len;
5996 int c;
5997
5998 while (--nleft > 0) {
5999 c = pgetc2();
6000 if (c == PEOF) {
6001 if (p == line)
6002 return NULL;
6003 break;
6004 }
6005 *p++ = c;
6006 if (c == '\n')
6007 break;
6008 }
6009 *p = '\0';
6010 return line;
6011}
6012
6013
Eric Andersenc470f442003-07-28 09:56:35 +00006014
6015#ifdef CONFIG_FEATURE_COMMAND_EDITING
6016static const char *cmdedit_prompt;
6017static inline void putprompt(const char *s)
6018{
6019 cmdedit_prompt = s;
6020}
6021#else
6022static inline void putprompt(const char *s)
6023{
6024 out2str(s);
6025}
6026#endif
6027
6028static inline int
6029preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006030{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006031 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006032 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006033 parsenextc = buf;
6034
Eric Andersenc470f442003-07-28 09:56:35 +00006035retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006036#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006037 if (!iflag || parsefile->fd)
6038 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6039 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006040#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006041 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006042#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006043 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6044 if(nr == 0) {
6045 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006046 if(trap[SIGINT]) {
6047 buf[0] = '\n';
6048 buf[1] = 0;
6049 raise(SIGINT);
6050 return 1;
6051 }
Eric Andersenc470f442003-07-28 09:56:35 +00006052 goto retry;
6053 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006054 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006055 /* Ctrl+D presend */
6056 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006057 }
Eric Andersencb57d552001-06-28 07:25:16 +00006058 }
6059#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006060 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006061#endif
6062
6063 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006064 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6065 int flags = fcntl(0, F_GETFL, 0);
6066 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006067 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006068 if (fcntl(0, F_SETFL, flags) >= 0) {
6069 out2str("sh: turning off NDELAY mode\n");
6070 goto retry;
6071 }
6072 }
6073 }
6074 }
6075 return nr;
6076}
6077
6078/*
6079 * Refill the input buffer and return the next input character:
6080 *
6081 * 1) If a string was pushed back on the input, pop it;
6082 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6083 * from a string so we can't refill the buffer, return EOF.
6084 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6085 * 4) Process input up to the next newline, deleting nul characters.
6086 */
6087
Eric Andersenc470f442003-07-28 09:56:35 +00006088int
6089preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006090{
6091 char *p, *q;
6092 int more;
6093 char savec;
6094
6095 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006096#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006097 if (parsenleft == -1 && parsefile->strpush->ap &&
6098 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006099 return PEOA;
6100 }
Eric Andersen2870d962001-07-02 17:27:21 +00006101#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006102 popstring();
6103 if (--parsenleft >= 0)
6104 return (*parsenextc++);
6105 }
6106 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6107 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006108 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006109
Eric Andersenc470f442003-07-28 09:56:35 +00006110again:
Eric Andersencb57d552001-06-28 07:25:16 +00006111 if (parselleft <= 0) {
6112 if ((parselleft = preadfd()) <= 0) {
6113 parselleft = parsenleft = EOF_NLEFT;
6114 return PEOF;
6115 }
6116 }
6117
6118 q = p = parsenextc;
6119
6120 /* delete nul characters */
6121 for (more = 1; more;) {
6122 switch (*p) {
6123 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006124 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006125 goto check;
6126
Eric Andersencb57d552001-06-28 07:25:16 +00006127 case '\n':
6128 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006129 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006130 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006131
Eric Andersencb57d552001-06-28 07:25:16 +00006132 }
6133
6134 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006135check:
Eric Andersencb57d552001-06-28 07:25:16 +00006136 if (--parselleft <= 0 && more) {
6137 parsenleft = q - parsenextc - 1;
6138 if (parsenleft < 0)
6139 goto again;
6140 more = 0;
6141 }
6142 }
6143
6144 savec = *q;
6145 *q = '\0';
6146
6147 if (vflag) {
6148 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006149 }
6150
6151 *q = savec;
6152
6153 return *parsenextc++;
6154}
6155
Eric Andersenc470f442003-07-28 09:56:35 +00006156/*
6157 * Undo the last call to pgetc. Only one character may be pushed back.
6158 * PEOF may be pushed back.
6159 */
6160
6161void
6162pungetc(void)
6163{
6164 parsenleft++;
6165 parsenextc--;
6166}
Eric Andersencb57d552001-06-28 07:25:16 +00006167
6168/*
6169 * Push a string back onto the input at this current parsefile level.
6170 * We handle aliases this way.
6171 */
Eric Andersenc470f442003-07-28 09:56:35 +00006172void
6173pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006174{
Eric Andersencb57d552001-06-28 07:25:16 +00006175 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006176 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006177
Eric Andersenc470f442003-07-28 09:56:35 +00006178 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006179 INTOFF;
6180/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6181 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006182 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006183 sp->prev = parsefile->strpush;
6184 parsefile->strpush = sp;
6185 } else
6186 sp = parsefile->strpush = &(parsefile->basestrpush);
6187 sp->prevstring = parsenextc;
6188 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006189#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006190 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006191 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006192 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006193 sp->string = s;
6194 }
Eric Andersen2870d962001-07-02 17:27:21 +00006195#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006196 parsenextc = s;
6197 parsenleft = len;
6198 INTON;
6199}
6200
Eric Andersenc470f442003-07-28 09:56:35 +00006201void
6202popstring(void)
6203{
6204 struct strpush *sp = parsefile->strpush;
6205
6206 INTOFF;
6207#ifdef CONFIG_ASH_ALIAS
6208 if (sp->ap) {
6209 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6210 checkkwd |= CHKALIAS;
6211 }
6212 if (sp->string != sp->ap->val) {
6213 ckfree(sp->string);
6214 }
6215 sp->ap->flag &= ~ALIASINUSE;
6216 if (sp->ap->flag & ALIASDEAD) {
6217 unalias(sp->ap->name);
6218 }
6219 }
6220#endif
6221 parsenextc = sp->prevstring;
6222 parsenleft = sp->prevnleft;
6223/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6224 parsefile->strpush = sp->prev;
6225 if (sp != &(parsefile->basestrpush))
6226 ckfree(sp);
6227 INTON;
6228}
6229
6230/*
6231 * Set the input to take input from a file. If push is set, push the
6232 * old input onto the stack first.
6233 */
6234
6235void
6236setinputfile(const char *fname, int push)
6237{
6238 int fd;
6239 int fd2;
6240
6241 INTOFF;
6242 if ((fd = open(fname, O_RDONLY)) < 0)
6243 error("Can't open %s", fname);
6244 if (fd < 10) {
6245 fd2 = copyfd(fd, 10);
6246 close(fd);
6247 if (fd2 < 0)
6248 error("Out of file descriptors");
6249 fd = fd2;
6250 }
6251 setinputfd(fd, push);
6252 INTON;
6253}
6254
6255
6256/*
6257 * Like setinputfile, but takes an open file descriptor. Call this with
6258 * interrupts off.
6259 */
6260
6261static void
6262setinputfd(int fd, int push)
6263{
6264 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6265 if (push) {
6266 pushfile();
6267 parsefile->buf = 0;
6268 }
6269 parsefile->fd = fd;
6270 if (parsefile->buf == NULL)
6271 parsefile->buf = ckmalloc(IBUFSIZ);
6272 parselleft = parsenleft = 0;
6273 plinno = 1;
6274}
6275
Eric Andersencb57d552001-06-28 07:25:16 +00006276
Eric Andersencb57d552001-06-28 07:25:16 +00006277/*
6278 * Like setinputfile, but takes input from a string.
6279 */
6280
Eric Andersenc470f442003-07-28 09:56:35 +00006281static void
6282setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006283{
Eric Andersencb57d552001-06-28 07:25:16 +00006284 INTOFF;
6285 pushfile();
6286 parsenextc = string;
6287 parsenleft = strlen(string);
6288 parsefile->buf = NULL;
6289 plinno = 1;
6290 INTON;
6291}
6292
6293
Eric Andersencb57d552001-06-28 07:25:16 +00006294/*
6295 * To handle the "." command, a stack of input files is used. Pushfile
6296 * adds a new entry to the stack and popfile restores the previous level.
6297 */
6298
Eric Andersenc470f442003-07-28 09:56:35 +00006299static void
6300pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006301{
Eric Andersencb57d552001-06-28 07:25:16 +00006302 struct parsefile *pf;
6303
6304 parsefile->nleft = parsenleft;
6305 parsefile->lleft = parselleft;
6306 parsefile->nextc = parsenextc;
6307 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006308 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006309 pf->prev = parsefile;
6310 pf->fd = -1;
6311 pf->strpush = NULL;
6312 pf->basestrpush.prev = NULL;
6313 parsefile = pf;
6314}
6315
Eric Andersenc470f442003-07-28 09:56:35 +00006316
6317static void
6318popfile(void)
6319{
6320 struct parsefile *pf = parsefile;
6321
6322 INTOFF;
6323 if (pf->fd >= 0)
6324 close(pf->fd);
6325 if (pf->buf)
6326 ckfree(pf->buf);
6327 while (pf->strpush)
6328 popstring();
6329 parsefile = pf->prev;
6330 ckfree(pf);
6331 parsenleft = parsefile->nleft;
6332 parselleft = parsefile->lleft;
6333 parsenextc = parsefile->nextc;
6334 plinno = parsefile->linno;
6335 INTON;
6336}
Eric Andersencb57d552001-06-28 07:25:16 +00006337
6338
Eric Andersen2870d962001-07-02 17:27:21 +00006339/*
Eric Andersenc470f442003-07-28 09:56:35 +00006340 * Return to top level.
6341 */
Eric Andersen2870d962001-07-02 17:27:21 +00006342
Eric Andersenc470f442003-07-28 09:56:35 +00006343static void
6344popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006345{
Eric Andersenc470f442003-07-28 09:56:35 +00006346 while (parsefile != &basepf)
6347 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006348}
6349
Eric Andersen2870d962001-07-02 17:27:21 +00006350
Eric Andersenc470f442003-07-28 09:56:35 +00006351/*
6352 * Close the file(s) that the shell is reading commands from. Called
6353 * after a fork is done.
6354 */
6355
6356static void
6357closescript(void)
6358{
6359 popallfiles();
6360 if (parsefile->fd > 0) {
6361 close(parsefile->fd);
6362 parsefile->fd = 0;
6363 }
6364}
Eric Andersenc470f442003-07-28 09:56:35 +00006365
Eric Andersen90898442003-08-06 11:20:52 +00006366/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006367
6368/* mode flags for set_curjob */
6369#define CUR_DELETE 2
6370#define CUR_RUNNING 1
6371#define CUR_STOPPED 0
6372
6373/* mode flags for dowait */
6374#define DOWAIT_NORMAL 0
6375#define DOWAIT_BLOCK 1
6376
6377/* array of jobs */
6378static struct job *jobtab;
6379/* size of array */
6380static unsigned njobs;
6381#if JOBS
6382/* pgrp of shell on invocation */
6383static int initialpgrp;
6384static int ttyfd = -1;
6385#endif
6386/* current job */
6387static struct job *curjob;
6388/* number of presumed living untracked jobs */
6389static int jobless;
6390
6391static void set_curjob(struct job *, unsigned);
6392#if JOBS
6393static int restartjob(struct job *, int);
6394static void xtcsetpgrp(int, pid_t);
6395static char *commandtext(union node *);
6396static void cmdlist(union node *, int);
6397static void cmdtxt(union node *);
6398static void cmdputs(const char *);
6399static void showpipe(struct job *, FILE *);
6400#endif
6401static int sprint_status(char *, int, int);
6402static void freejob(struct job *);
6403static struct job *getjob(const char *, int);
6404static struct job *growjobtab(void);
6405static void forkchild(struct job *, union node *, int);
6406static void forkparent(struct job *, union node *, int, pid_t);
6407static int dowait(int, struct job *);
6408static int getstatus(struct job *);
6409
6410static void
6411set_curjob(struct job *jp, unsigned mode)
6412{
6413 struct job *jp1;
6414 struct job **jpp, **curp;
6415
6416 /* first remove from list */
6417 jpp = curp = &curjob;
6418 do {
6419 jp1 = *jpp;
6420 if (jp1 == jp)
6421 break;
6422 jpp = &jp1->prev_job;
6423 } while (1);
6424 *jpp = jp1->prev_job;
6425
6426 /* Then re-insert in correct position */
6427 jpp = curp;
6428 switch (mode) {
6429 default:
6430#ifdef DEBUG
6431 abort();
6432#endif
6433 case CUR_DELETE:
6434 /* job being deleted */
6435 break;
6436 case CUR_RUNNING:
6437 /* newly created job or backgrounded job,
6438 put after all stopped jobs. */
6439 do {
6440 jp1 = *jpp;
6441#ifdef JOBS
6442 if (!jp1 || jp1->state != JOBSTOPPED)
6443#endif
6444 break;
6445 jpp = &jp1->prev_job;
6446 } while (1);
6447 /* FALLTHROUGH */
6448#ifdef JOBS
6449 case CUR_STOPPED:
6450#endif
6451 /* newly stopped job - becomes curjob */
6452 jp->prev_job = *jpp;
6453 *jpp = jp;
6454 break;
6455 }
6456}
6457
6458#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006459/*
6460 * Turn job control on and off.
6461 *
6462 * Note: This code assumes that the third arg to ioctl is a character
6463 * pointer, which is true on Berkeley systems but not System V. Since
6464 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006465 *
6466 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006467 */
6468
Eric Andersenc470f442003-07-28 09:56:35 +00006469void
6470setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006471{
Eric Andersenc470f442003-07-28 09:56:35 +00006472 int fd;
6473 int pgrp;
6474
6475 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006476 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006477 if (on) {
6478 int ofd;
6479 ofd = fd = open(_PATH_TTY, O_RDWR);
6480 if (fd < 0) {
6481 fd += 3;
6482 while (!isatty(fd) && --fd >= 0)
6483 ;
6484 }
6485 fd = fcntl(fd, F_DUPFD, 10);
6486 close(ofd);
6487 if (fd < 0)
6488 goto out;
6489 fcntl(fd, F_SETFD, FD_CLOEXEC);
6490 do { /* while we are in the background */
6491 if ((pgrp = tcgetpgrp(fd)) < 0) {
6492out:
6493 sh_warnx("can't access tty; job control turned off");
6494 mflag = on = 0;
6495 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006496 }
Eric Andersenc470f442003-07-28 09:56:35 +00006497 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006498 break;
6499 killpg(0, SIGTTIN);
6500 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006501 initialpgrp = pgrp;
6502
Eric Andersencb57d552001-06-28 07:25:16 +00006503 setsignal(SIGTSTP);
6504 setsignal(SIGTTOU);
6505 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006506 pgrp = rootpid;
6507 setpgid(0, pgrp);
6508 xtcsetpgrp(fd, pgrp);
6509 } else {
6510 /* turning job control off */
6511 fd = ttyfd;
6512 pgrp = initialpgrp;
6513 xtcsetpgrp(fd, pgrp);
6514 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006515 setsignal(SIGTSTP);
6516 setsignal(SIGTTOU);
6517 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006518close:
6519 close(fd);
6520 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006521 }
Eric Andersenc470f442003-07-28 09:56:35 +00006522 ttyfd = fd;
6523 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006524}
Eric Andersencb57d552001-06-28 07:25:16 +00006525
Eric Andersenc470f442003-07-28 09:56:35 +00006526static int
Eric Andersen90898442003-08-06 11:20:52 +00006527killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006528{
6529 int signo = -1;
6530 int list = 0;
6531 int i;
6532 pid_t pid;
6533 struct job *jp;
6534
6535 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006536usage:
6537 error(
6538"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6539"kill -l [exitstatus]"
6540 );
Eric Andersencb57d552001-06-28 07:25:16 +00006541 }
6542
Eric Andersenc470f442003-07-28 09:56:35 +00006543 if (**++argv == '-') {
6544 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006545 if (signo < 0) {
6546 int c;
6547
6548 while ((c = nextopt("ls:")) != '\0')
6549 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006550 default:
6551#ifdef DEBUG
6552 abort();
6553#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006554 case 'l':
6555 list = 1;
6556 break;
6557 case 's':
6558 signo = decode_signal(optionarg, 1);
6559 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006560 error(
6561 "invalid signal number or name: %s",
6562 optionarg
6563 );
Eric Andersencb57d552001-06-28 07:25:16 +00006564 }
Eric Andersen2870d962001-07-02 17:27:21 +00006565 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006566 }
Eric Andersenc470f442003-07-28 09:56:35 +00006567 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006568 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006569 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006570 }
6571
6572 if (!list && signo < 0)
6573 signo = SIGTERM;
6574
Eric Andersenc470f442003-07-28 09:56:35 +00006575 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006576 goto usage;
6577 }
6578
6579 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006580 const char *name;
6581
Eric Andersenc470f442003-07-28 09:56:35 +00006582 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006583 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006584 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006585 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006586 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006587 }
6588 return 0;
6589 }
Eric Andersen34506362001-08-02 05:02:46 +00006590 name = u_signal_names(*argptr, &signo, -1);
6591 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006592 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006593 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006594 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006595 return 0;
6596 }
6597
Eric Andersenc470f442003-07-28 09:56:35 +00006598 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006599 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006600 if (**argv == '%') {
6601 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006602 pid = -jp->ps[0].pid;
6603 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006604 pid = number(*argv);
6605 if (kill(pid, signo) != 0) {
6606 sh_warnx("%m\n");
6607 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006608 }
Eric Andersenc470f442003-07-28 09:56:35 +00006609 } while (*++argv);
6610
6611 return i;
6612}
6613#endif /* JOBS */
6614
6615#if defined(JOBS) || defined(DEBUG)
6616static int
6617jobno(const struct job *jp)
6618{
6619 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006620}
6621#endif
6622
Eric Andersenc470f442003-07-28 09:56:35 +00006623#ifdef JOBS
6624static int
6625fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006626{
Eric Andersenc470f442003-07-28 09:56:35 +00006627 struct job *jp;
6628 FILE *out;
6629 int mode;
6630 int retval;
6631
6632 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6633 nextopt(nullstr);
6634 argv = argptr;
6635 out = stdout;
6636 do {
6637 jp = getjob(*argv, 1);
6638 if (mode == FORK_BG) {
6639 set_curjob(jp, CUR_RUNNING);
6640 fprintf(out, "[%d] ", jobno(jp));
6641 }
6642 outstr(jp->ps->cmd, out);
6643 showpipe(jp, out);
6644 retval = restartjob(jp, mode);
6645 } while (*argv && *++argv);
6646 return retval;
6647}
6648
6649static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6650
6651
6652static int
6653restartjob(struct job *jp, int mode)
6654{
6655 struct procstat *ps;
6656 int i;
6657 int status;
6658 pid_t pgid;
6659
6660 INTOFF;
6661 if (jp->state == JOBDONE)
6662 goto out;
6663 jp->state = JOBRUNNING;
6664 pgid = jp->ps->pid;
6665 if (mode == FORK_FG)
6666 xtcsetpgrp(ttyfd, pgid);
6667 killpg(pgid, SIGCONT);
6668 ps = jp->ps;
6669 i = jp->nprocs;
6670 do {
6671 if (WIFSTOPPED(ps->status)) {
6672 ps->status = -1;
6673 }
6674 } while (ps++, --i);
6675out:
6676 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6677 INTON;
6678 return status;
6679}
6680#endif
6681
6682static int
6683sprint_status(char *s, int status, int sigonly)
6684{
6685 int col;
6686 int st;
6687
6688 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006689 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006690#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006691 if (WIFSTOPPED(status))
6692 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006693 else
Eric Andersenc470f442003-07-28 09:56:35 +00006694#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006695 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006696 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006697 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006698 goto out;
6699#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006700 if (WIFSTOPPED(status))
6701 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006702#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006703 }
6704 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006705 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006706 if (WCOREDUMP(status)) {
6707 col += fmtstr(s + col, 16, " (core dumped)");
6708 }
6709 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006710 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006711 if (st)
6712 col = fmtstr(s, 16, "Done(%d)", st);
6713 else
6714 col = fmtstr(s, 16, "Done");
6715 }
6716
6717out:
6718 return col;
6719}
6720
6721#if JOBS
6722static void
6723showjob(FILE *out, struct job *jp, int mode)
6724{
6725 struct procstat *ps;
6726 struct procstat *psend;
6727 int col;
6728 int indent;
6729 char s[80];
6730
6731 ps = jp->ps;
6732
6733 if (mode & SHOW_PGID) {
6734 /* just output process (group) id of pipeline */
6735 fprintf(out, "%d\n", ps->pid);
6736 return;
6737 }
6738
6739 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6740 indent = col;
6741
6742 if (jp == curjob)
6743 s[col - 2] = '+';
6744 else if (curjob && jp == curjob->prev_job)
6745 s[col - 2] = '-';
6746
6747 if (mode & SHOW_PID)
6748 col += fmtstr(s + col, 16, "%d ", ps->pid);
6749
6750 psend = ps + jp->nprocs;
6751
6752 if (jp->state == JOBRUNNING) {
6753 scopy("Running", s + col);
6754 col += strlen("Running");
6755 } else {
6756 int status = psend[-1].status;
6757#if JOBS
6758 if (jp->state == JOBSTOPPED)
6759 status = jp->stopstatus;
6760#endif
6761 col += sprint_status(s + col, status, 0);
6762 }
6763
6764 goto start;
6765
6766 do {
6767 /* for each process */
6768 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6769
6770start:
Eric Andersen90898442003-08-06 11:20:52 +00006771 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006772 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6773 );
6774 if (!(mode & SHOW_PID)) {
6775 showpipe(jp, out);
6776 break;
6777 }
6778 if (++ps == psend) {
6779 outcslow('\n', out);
6780 break;
6781 }
6782 } while (1);
6783
6784 jp->changed = 0;
6785
6786 if (jp->state == JOBDONE) {
6787 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6788 freejob(jp);
6789 }
6790}
6791
6792
6793static int
6794jobscmd(int argc, char **argv)
6795{
6796 int mode, m;
6797 FILE *out;
6798
6799 mode = 0;
6800 while ((m = nextopt("lp")))
6801 if (m == 'l')
6802 mode = SHOW_PID;
6803 else
6804 mode = SHOW_PGID;
6805
6806 out = stdout;
6807 argv = argptr;
6808 if (*argv)
6809 do
6810 showjob(out, getjob(*argv,0), mode);
6811 while (*++argv);
6812 else
6813 showjobs(out, mode);
6814
Eric Andersencb57d552001-06-28 07:25:16 +00006815 return 0;
6816}
6817
6818
6819/*
6820 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6821 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006822 */
6823
Eric Andersenc470f442003-07-28 09:56:35 +00006824static void
6825showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006826{
Eric Andersencb57d552001-06-28 07:25:16 +00006827 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006828
Eric Andersenc470f442003-07-28 09:56:35 +00006829 TRACE(("showjobs(%x) called\n", mode));
6830
6831 /* If not even one one job changed, there is nothing to do */
6832 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6833 continue;
6834
6835 for (jp = curjob; jp; jp = jp->prev_job) {
6836 if (!(mode & SHOW_CHANGED) || jp->changed)
6837 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006838 }
6839}
Eric Andersenc470f442003-07-28 09:56:35 +00006840#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006841
6842/*
6843 * Mark a job structure as unused.
6844 */
6845
Eric Andersenc470f442003-07-28 09:56:35 +00006846static void
6847freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006848{
Eric Andersenc470f442003-07-28 09:56:35 +00006849 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006850 int i;
6851
6852 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006853 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006854 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006855 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006856 }
6857 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006858 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006859 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006860 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006861 INTON;
6862}
6863
6864
Eric Andersenc470f442003-07-28 09:56:35 +00006865static int
6866waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006867{
6868 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006869 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006870 struct job *jp;
6871
Eric Andersenc470f442003-07-28 09:56:35 +00006872 EXSIGON();
6873
6874 nextopt(nullstr);
6875 retval = 0;
6876
6877 argv = argptr;
6878 if (!*argv) {
6879 /* wait for all jobs */
6880 for (;;) {
6881 jp = curjob;
6882 while (1) {
6883 if (!jp) {
6884 /* no running procs */
6885 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006886 }
Eric Andersenc470f442003-07-28 09:56:35 +00006887 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006888 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006889 jp->waited = 1;
6890 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006891 }
Eric Andersenc470f442003-07-28 09:56:35 +00006892 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006893 }
6894 }
Eric Andersenc470f442003-07-28 09:56:35 +00006895
6896 retval = 127;
6897 do {
6898 if (**argv != '%') {
6899 pid_t pid = number(*argv);
6900 job = curjob;
6901 goto start;
6902 do {
6903 if (job->ps[job->nprocs - 1].pid == pid)
6904 break;
6905 job = job->prev_job;
6906start:
6907 if (!job)
6908 goto repeat;
6909 } while (1);
6910 } else
6911 job = getjob(*argv, 0);
6912 /* loop until process terminated or stopped */
6913 while (job->state == JOBRUNNING)
6914 dowait(DOWAIT_BLOCK, 0);
6915 job->waited = 1;
6916 retval = getstatus(job);
6917repeat:
6918 ;
6919 } while (*++argv);
6920
6921out:
6922 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006923}
6924
6925
Eric Andersencb57d552001-06-28 07:25:16 +00006926/*
6927 * Convert a job name to a job structure.
6928 */
6929
Eric Andersenc470f442003-07-28 09:56:35 +00006930static struct job *
6931getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006932{
Eric Andersencb57d552001-06-28 07:25:16 +00006933 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006934 struct job *found;
6935 const char *err_msg = "No such job: %s";
6936 unsigned num;
6937 int c;
6938 const char *p;
6939 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006940
Eric Andersenc470f442003-07-28 09:56:35 +00006941 jp = curjob;
6942 p = name;
6943 if (!p)
6944 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006945
Eric Andersenc470f442003-07-28 09:56:35 +00006946 if (*p != '%')
6947 goto err;
6948
6949 c = *++p;
6950 if (!c)
6951 goto currentjob;
6952
6953 if (!p[1]) {
6954 if (c == '+' || c == '%') {
6955currentjob:
6956 err_msg = "No current job";
6957 goto check;
6958 } else if (c == '-') {
6959 if (jp)
6960 jp = jp->prev_job;
6961 err_msg = "No previous job";
6962check:
6963 if (!jp)
6964 goto err;
6965 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006966 }
6967 }
Eric Andersenc470f442003-07-28 09:56:35 +00006968
6969 if (is_number(p)) {
6970 num = atoi(p);
6971 if (num < njobs) {
6972 jp = jobtab + num - 1;
6973 if (jp->used)
6974 goto gotit;
6975 goto err;
6976 }
6977 }
6978
6979 match = prefix;
6980 if (*p == '?') {
6981 match = strstr;
6982 p++;
6983 }
6984
6985 found = 0;
6986 while (1) {
6987 if (!jp)
6988 goto err;
6989 if (match(jp->ps[0].cmd, p)) {
6990 if (found)
6991 goto err;
6992 found = jp;
6993 err_msg = "%s: ambiguous";
6994 }
6995 jp = jp->prev_job;
6996 }
6997
6998gotit:
6999#if JOBS
7000 err_msg = "job %s not created under job control";
7001 if (getctl && jp->jobctl == 0)
7002 goto err;
7003#endif
7004 return jp;
7005err:
7006 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007007}
7008
7009
Eric Andersencb57d552001-06-28 07:25:16 +00007010/*
Eric Andersenc470f442003-07-28 09:56:35 +00007011 * Return a new job structure.
7012 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007013 */
7014
Eric Andersenc470f442003-07-28 09:56:35 +00007015static struct job *
7016makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007017{
7018 int i;
7019 struct job *jp;
7020
Eric Andersenc470f442003-07-28 09:56:35 +00007021 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007022 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007023 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007024 break;
7025 }
7026 if (jp->used == 0)
7027 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007028 if (jp->state != JOBDONE || !jp->waited)
7029 continue;
7030#if JOBS
7031 if (jobctl)
7032 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007033#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007034 freejob(jp);
7035 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007036 }
Eric Andersenc470f442003-07-28 09:56:35 +00007037 memset(jp, 0, sizeof(*jp));
7038#if JOBS
7039 if (jobctl)
7040 jp->jobctl = 1;
7041#endif
7042 jp->prev_job = curjob;
7043 curjob = jp;
7044 jp->used = 1;
7045 jp->ps = &jp->ps0;
7046 if (nprocs > 1) {
7047 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7048 }
7049 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7050 jobno(jp)));
7051 return jp;
7052}
7053
7054static struct job *
7055growjobtab(void)
7056{
7057 size_t len;
7058 ptrdiff_t offset;
7059 struct job *jp, *jq;
7060
7061 len = njobs * sizeof(*jp);
7062 jq = jobtab;
7063 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7064
7065 offset = (char *)jp - (char *)jq;
7066 if (offset) {
7067 /* Relocate pointers */
7068 size_t l = len;
7069
7070 jq = (struct job *)((char *)jq + l);
7071 while (l) {
7072 l -= sizeof(*jp);
7073 jq--;
7074#define joff(p) ((struct job *)((char *)(p) + l))
7075#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007076 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007077 jmove(joff(jp)->ps);
7078 if (joff(jp)->prev_job)
7079 jmove(joff(jp)->prev_job);
7080 }
7081 if (curjob)
7082 jmove(curjob);
7083#undef joff
7084#undef jmove
7085 }
7086
7087 njobs += 4;
7088 jobtab = jp;
7089 jp = (struct job *)((char *)jp + len);
7090 jq = jp + 3;
7091 do {
7092 jq->used = 0;
7093 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007094 return jp;
7095}
7096
7097
7098/*
Eric Andersenc470f442003-07-28 09:56:35 +00007099 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007100 * own process group. Jp is a job structure that the job is to be added to.
7101 * N is the command that will be evaluated by the child. Both jp and n may
7102 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007103 * FORK_FG - Fork off a foreground process.
7104 * FORK_BG - Fork off a background process.
7105 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7106 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007107 *
7108 * When job control is turned off, background processes have their standard
7109 * input redirected to /dev/null (except for the second and later processes
7110 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007111 *
7112 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007113 */
7114
Eric Andersenc470f442003-07-28 09:56:35 +00007115static inline void
7116forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007117{
Eric Andersenc470f442003-07-28 09:56:35 +00007118 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007119
Eric Andersenc470f442003-07-28 09:56:35 +00007120 TRACE(("Child shell %d\n", getpid()));
7121 wasroot = rootshell;
7122 rootshell = 0;
7123
7124 closescript();
7125 clear_traps();
7126#if JOBS
7127 /* do job control only in root shell */
7128 jobctl = 0;
7129 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7130 pid_t pgrp;
7131
7132 if (jp->nprocs == 0)
7133 pgrp = getpid();
7134 else
7135 pgrp = jp->ps[0].pid;
7136 /* This can fail because we are doing it in the parent also */
7137 (void)setpgid(0, pgrp);
7138 if (mode == FORK_FG)
7139 xtcsetpgrp(ttyfd, pgrp);
7140 setsignal(SIGTSTP);
7141 setsignal(SIGTTOU);
7142 } else
Eric Andersen62483552001-07-10 06:09:16 +00007143#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007144 if (mode == FORK_BG) {
7145 ignoresig(SIGINT);
7146 ignoresig(SIGQUIT);
7147 if (jp->nprocs == 0) {
7148 close(0);
7149 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7150 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007151 }
Eric Andersencb57d552001-06-28 07:25:16 +00007152 }
Eric Andersenc470f442003-07-28 09:56:35 +00007153 if (wasroot && iflag) {
7154 setsignal(SIGINT);
7155 setsignal(SIGQUIT);
7156 setsignal(SIGTERM);
7157 }
7158 for (jp = curjob; jp; jp = jp->prev_job)
7159 freejob(jp);
7160 jobless = 0;
7161}
7162
7163static inline void
7164forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7165{
7166 TRACE(("In parent shell: child = %d\n", pid));
7167 if (!jp) {
7168 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7169 jobless++;
7170 return;
7171 }
7172#if JOBS
7173 if (mode != FORK_NOJOB && jp->jobctl) {
7174 int pgrp;
7175
7176 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007177 pgrp = pid;
7178 else
7179 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007180 /* This can fail because we are doing it in the child also */
7181 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007182 }
Eric Andersen62483552001-07-10 06:09:16 +00007183#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007184 if (mode == FORK_BG) {
7185 backgndpid = pid; /* set $! */
7186 set_curjob(jp, CUR_RUNNING);
7187 }
Eric Andersencb57d552001-06-28 07:25:16 +00007188 if (jp) {
7189 struct procstat *ps = &jp->ps[jp->nprocs++];
7190 ps->pid = pid;
7191 ps->status = -1;
7192 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007193#if JOBS
7194 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007195 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007196#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007197 }
Eric Andersencb57d552001-06-28 07:25:16 +00007198}
7199
Eric Andersenc470f442003-07-28 09:56:35 +00007200static int
7201forkshell(struct job *jp, union node *n, int mode)
7202{
7203 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007204
Eric Andersenc470f442003-07-28 09:56:35 +00007205 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7206 pid = fork();
7207 if (pid < 0) {
7208 TRACE(("Fork failed, errno=%d", errno));
7209 if (jp)
7210 freejob(jp);
7211 error("Cannot fork");
7212 }
7213 if (pid == 0)
7214 forkchild(jp, n, mode);
7215 else
7216 forkparent(jp, n, mode, pid);
7217 return pid;
7218}
Eric Andersencb57d552001-06-28 07:25:16 +00007219
7220/*
7221 * Wait for job to finish.
7222 *
7223 * Under job control we have the problem that while a child process is
7224 * running interrupts generated by the user are sent to the child but not
7225 * to the shell. This means that an infinite loop started by an inter-
7226 * active user may be hard to kill. With job control turned off, an
7227 * interactive user may place an interactive program inside a loop. If
7228 * the interactive program catches interrupts, the user doesn't want
7229 * these interrupts to also abort the loop. The approach we take here
7230 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007231 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007232 * signal if the child process was terminated by an interrupt signal.
7233 * Unfortunately, some programs want to do a bit of cleanup and then
7234 * exit on interrupt; unless these processes terminate themselves by
7235 * sending a signal to themselves (instead of calling exit) they will
7236 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007237 *
7238 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007239 */
7240
Eric Andersenc470f442003-07-28 09:56:35 +00007241int
7242waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007243{
Eric Andersencb57d552001-06-28 07:25:16 +00007244 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007245
Eric Andersenc470f442003-07-28 09:56:35 +00007246 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7247 while (jp->state == JOBRUNNING) {
7248 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007249 }
Eric Andersenc470f442003-07-28 09:56:35 +00007250 st = getstatus(jp);
7251#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007252 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007253 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007254 /*
7255 * This is truly gross.
7256 * If we're doing job control, then we did a TIOCSPGRP which
7257 * caused us (the shell) to no longer be in the controlling
7258 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7259 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007260 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007261 */
Eric Andersenc470f442003-07-28 09:56:35 +00007262 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007263 raise(SIGINT);
7264 }
Eric Andersen2870d962001-07-02 17:27:21 +00007265 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007266#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007267 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007268 return st;
7269}
7270
7271
Eric Andersen62483552001-07-10 06:09:16 +00007272/*
7273 * Do a wait system call. If job control is compiled in, we accept
7274 * stopped processes. If block is zero, we return a value of zero
7275 * rather than blocking.
7276 *
7277 * System V doesn't have a non-blocking wait system call. It does
7278 * have a SIGCLD signal that is sent to a process when one of it's
7279 * children dies. The obvious way to use SIGCLD would be to install
7280 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7281 * was received, and have waitproc bump another counter when it got
7282 * the status of a process. Waitproc would then know that a wait
7283 * system call would not block if the two counters were different.
7284 * This approach doesn't work because if a process has children that
7285 * have not been waited for, System V will send it a SIGCLD when it
7286 * installs a signal handler for SIGCLD. What this means is that when
7287 * a child exits, the shell will be sent SIGCLD signals continuously
7288 * until is runs out of stack space, unless it does a wait call before
7289 * restoring the signal handler. The code below takes advantage of
7290 * this (mis)feature by installing a signal handler for SIGCLD and
7291 * then checking to see whether it was called. If there are any
7292 * children to be waited for, it will be.
7293 *
Eric Andersenc470f442003-07-28 09:56:35 +00007294 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7295 * waits at all. In this case, the user will not be informed when
7296 * a background process until the next time she runs a real program
7297 * (as opposed to running a builtin command or just typing return),
7298 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007299 */
7300
Eric Andersenc470f442003-07-28 09:56:35 +00007301static inline int
7302waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007303{
Eric Andersenc470f442003-07-28 09:56:35 +00007304 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007305
Eric Andersenc470f442003-07-28 09:56:35 +00007306#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007307 if (jobctl)
7308 flags |= WUNTRACED;
7309#endif
7310 if (block == 0)
7311 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007312 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007313}
7314
Eric Andersenc470f442003-07-28 09:56:35 +00007315/*
7316 * Wait for a process to terminate.
7317 */
7318
7319static int
7320dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007321{
7322 int pid;
7323 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007324 struct job *jp;
7325 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007326 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007327
7328 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007329 pid = waitproc(block, &status);
7330 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007331 if (pid <= 0)
7332 return pid;
7333 INTOFF;
7334 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007335 for (jp = curjob; jp; jp = jp->prev_job) {
7336 struct procstat *sp;
7337 struct procstat *spend;
7338 if (jp->state == JOBDONE)
7339 continue;
7340 state = JOBDONE;
7341 spend = jp->ps + jp->nprocs;
7342 sp = jp->ps;
7343 do {
7344 if (sp->pid == pid) {
7345 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7346 sp->status = status;
7347 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007348 }
Eric Andersenc470f442003-07-28 09:56:35 +00007349 if (sp->status == -1)
7350 state = JOBRUNNING;
7351#ifdef JOBS
7352 if (state == JOBRUNNING)
7353 continue;
7354 if (WIFSTOPPED(sp->status)) {
7355 jp->stopstatus = sp->status;
7356 state = JOBSTOPPED;
7357 }
Eric Andersencb57d552001-06-28 07:25:16 +00007358#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007359 } while (++sp < spend);
7360 if (thisjob)
7361 goto gotjob;
7362 }
7363#ifdef JOBS
7364 if (!WIFSTOPPED(status))
7365#endif
7366
7367 jobless--;
7368 goto out;
7369
7370gotjob:
7371 if (state != JOBRUNNING) {
7372 thisjob->changed = 1;
7373
7374 if (thisjob->state != state) {
7375 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7376 thisjob->state = state;
7377#ifdef JOBS
7378 if (state == JOBSTOPPED) {
7379 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007380 }
Eric Andersenc470f442003-07-28 09:56:35 +00007381#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007382 }
7383 }
Eric Andersencb57d552001-06-28 07:25:16 +00007384
Eric Andersenc470f442003-07-28 09:56:35 +00007385out:
7386 INTON;
7387
7388 if (thisjob && thisjob == job) {
7389 char s[48 + 1];
7390 int len;
7391
7392 len = sprint_status(s, status, 1);
7393 if (len) {
7394 s[len] = '\n';
7395 s[len + 1] = 0;
7396 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007397 }
Eric Andersencb57d552001-06-28 07:25:16 +00007398 }
7399 return pid;
7400}
7401
7402
Eric Andersencb57d552001-06-28 07:25:16 +00007403/*
7404 * return 1 if there are stopped jobs, otherwise 0
7405 */
Eric Andersen90898442003-08-06 11:20:52 +00007406
Eric Andersenc470f442003-07-28 09:56:35 +00007407int
7408stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007409{
Eric Andersencb57d552001-06-28 07:25:16 +00007410 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007411 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007412
Eric Andersenc470f442003-07-28 09:56:35 +00007413 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007414 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007415 goto out;
7416 jp = curjob;
7417 if (jp && jp->state == JOBSTOPPED) {
7418 out2str("You have stopped jobs.\n");
7419 job_warning = 2;
7420 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007421 }
7422
Eric Andersenc470f442003-07-28 09:56:35 +00007423out:
7424 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007425}
7426
7427/*
7428 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007429 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007430 */
7431
Eric Andersenc470f442003-07-28 09:56:35 +00007432#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007433static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007434
Eric Andersenc470f442003-07-28 09:56:35 +00007435static char *
7436commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007437{
Eric Andersenc470f442003-07-28 09:56:35 +00007438 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007439
Eric Andersenc470f442003-07-28 09:56:35 +00007440 STARTSTACKSTR(cmdnextc);
7441 cmdtxt(n);
7442 name = stackblock();
7443 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7444 name, cmdnextc, cmdnextc));
7445 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007446}
7447
Eric Andersenc470f442003-07-28 09:56:35 +00007448static void
7449cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007450{
Eric Andersencb57d552001-06-28 07:25:16 +00007451 union node *np;
7452 struct nodelist *lp;
7453 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007454 char s[2];
7455
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007456 if (!n)
7457 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007458 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007459 default:
7460#if DEBUG
7461 abort();
7462#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007463 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007464 lp = n->npipe.cmdlist;
7465 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007466 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007467 lp = lp->next;
7468 if (!lp)
7469 break;
7470 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007471 }
7472 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007473 case NSEMI:
7474 p = "; ";
7475 goto binop;
7476 case NAND:
7477 p = " && ";
7478 goto binop;
7479 case NOR:
7480 p = " || ";
7481binop:
7482 cmdtxt(n->nbinary.ch1);
7483 cmdputs(p);
7484 n = n->nbinary.ch2;
7485 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007486 case NREDIR:
7487 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007488 n = n->nredir.n;
7489 goto donode;
7490 case NNOT:
7491 cmdputs("!");
7492 n = n->nnot.com;
7493donode:
7494 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007495 break;
7496 case NIF:
7497 cmdputs("if ");
7498 cmdtxt(n->nif.test);
7499 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007500 n = n->nif.ifpart;
7501 if (n->nif.elsepart) {
7502 cmdtxt(n);
7503 cmdputs("; else ");
7504 n = n->nif.elsepart;
7505 }
7506 p = "; fi";
7507 goto dotail;
7508 case NSUBSHELL:
7509 cmdputs("(");
7510 n = n->nredir.n;
7511 p = ")";
7512 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007513 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007514 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007515 goto until;
7516 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007517 p = "until ";
7518until:
7519 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007520 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007521 n = n->nbinary.ch2;
7522 p = "; done";
7523dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007524 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007525dotail:
7526 cmdtxt(n);
7527 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007528 case NFOR:
7529 cmdputs("for ");
7530 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007531 cmdputs(" in ");
7532 cmdlist(n->nfor.args, 1);
7533 n = n->nfor.body;
7534 p = "; done";
7535 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007536 case NDEFUN:
7537 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007538 p = "() { ... }";
7539 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007540 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007541 cmdlist(n->ncmd.args, 1);
7542 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007543 break;
7544 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007545 p = n->narg.text;
7546dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007547 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007548 break;
7549 case NHERE:
7550 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007551 p = "<<...";
7552 goto dotail2;
7553 case NCASE:
7554 cmdputs("case ");
7555 cmdputs(n->ncase.expr->narg.text);
7556 cmdputs(" in ");
7557 for (np = n->ncase.cases; np; np = np->nclist.next) {
7558 cmdtxt(np->nclist.pattern);
7559 cmdputs(") ");
7560 cmdtxt(np->nclist.body);
7561 cmdputs(";; ");
7562 }
7563 p = "esac";
7564 goto dotail2;
7565 case NTO:
7566 p = ">";
7567 goto redir;
7568 case NCLOBBER:
7569 p = ">|";
7570 goto redir;
7571 case NAPPEND:
7572 p = ">>";
7573 goto redir;
7574 case NTOFD:
7575 p = ">&";
7576 goto redir;
7577 case NFROM:
7578 p = "<";
7579 goto redir;
7580 case NFROMFD:
7581 p = "<&";
7582 goto redir;
7583 case NFROMTO:
7584 p = "<>";
7585redir:
7586 s[0] = n->nfile.fd + '0';
7587 s[1] = '\0';
7588 cmdputs(s);
7589 cmdputs(p);
7590 if (n->type == NTOFD || n->type == NFROMFD) {
7591 s[0] = n->ndup.dupfd + '0';
7592 p = s;
7593 goto dotail2;
7594 } else {
7595 n = n->nfile.fname;
7596 goto donode;
7597 }
Eric Andersencb57d552001-06-28 07:25:16 +00007598 }
7599}
Eric Andersencb57d552001-06-28 07:25:16 +00007600
Eric Andersenc470f442003-07-28 09:56:35 +00007601static void
7602cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007603{
Eric Andersenc470f442003-07-28 09:56:35 +00007604 for (; np; np = np->narg.next) {
7605 if (!sep)
7606 cmdputs(spcstr);
7607 cmdtxt(np);
7608 if (sep && np->narg.next)
7609 cmdputs(spcstr);
7610 }
Eric Andersencb57d552001-06-28 07:25:16 +00007611}
7612
Eric Andersenc470f442003-07-28 09:56:35 +00007613static void
7614cmdputs(const char *s)
7615{
7616 const char *p, *str;
7617 char c, cc[2] = " ";
7618 char *nextc;
7619 int subtype = 0;
7620 int quoted = 0;
7621 static const char *const vstype[16] = {
7622 nullstr, "}", "-", "+", "?", "=",
Eric Andersenc7bda1c2004-03-15 08:29:22 +00007623 "%", "%%", "#", "##", nullstr
Eric Andersenc470f442003-07-28 09:56:35 +00007624 };
7625
7626 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7627 p = s;
7628 while ((c = *p++) != 0) {
7629 str = 0;
7630 switch (c) {
7631 case CTLESC:
7632 c = *p++;
7633 break;
7634 case CTLVAR:
7635 subtype = *p++;
7636 if ((subtype & VSTYPE) == VSLENGTH)
7637 str = "${#";
7638 else
7639 str = "${";
7640 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7641 quoted ^= 1;
7642 c = '"';
7643 } else
7644 goto dostr;
7645 break;
7646 case CTLENDVAR:
7647 quoted >>= 1;
7648 subtype = 0;
7649 if (quoted & 1) {
7650 str = "\"}";
7651 goto dostr;
7652 }
7653 c = '}';
7654 break;
7655 case CTLBACKQ:
7656 str = "$(...)";
7657 goto dostr;
7658 case CTLBACKQ+CTLQUOTE:
7659 str = "\"$(...)\"";
7660 goto dostr;
7661#ifdef CONFIG_ASH_MATH_SUPPORT
7662 case CTLARI:
7663 str = "$((";
7664 goto dostr;
7665 case CTLENDARI:
7666 str = "))";
7667 goto dostr;
7668#endif
7669 case CTLQUOTEMARK:
7670 quoted ^= 1;
7671 c = '"';
7672 break;
7673 case '=':
7674 if (subtype == 0)
7675 break;
7676 str = vstype[subtype & VSTYPE];
7677 if (subtype & VSNUL)
7678 c = ':';
7679 else
7680 c = *str++;
7681 if (c != '}')
7682 quoted <<= 1;
7683 break;
7684 case '\'':
7685 case '\\':
7686 case '"':
7687 case '$':
7688 /* These can only happen inside quotes */
7689 cc[0] = c;
7690 str = cc;
7691 c = '\\';
7692 break;
7693 default:
7694 break;
7695 }
7696 USTPUTC(c, nextc);
7697 if (!str)
7698 continue;
7699dostr:
7700 while ((c = *str++)) {
7701 USTPUTC(c, nextc);
7702 }
7703 }
7704 if (quoted & 1) {
7705 USTPUTC('"', nextc);
7706 }
7707 *nextc = 0;
7708 cmdnextc = nextc;
7709}
7710
7711
7712static void
7713showpipe(struct job *jp, FILE *out)
7714{
7715 struct procstat *sp;
7716 struct procstat *spend;
7717
7718 spend = jp->ps + jp->nprocs;
7719 for (sp = jp->ps + 1; sp < spend; sp++)
7720 fprintf(out, " | %s", sp->cmd);
7721 outcslow('\n', out);
7722 flushall();
7723}
7724
7725static void
7726xtcsetpgrp(int fd, pid_t pgrp)
7727{
7728 if (tcsetpgrp(fd, pgrp))
7729 error("Cannot set tty process group (%m)");
7730}
7731#endif /* JOBS */
7732
7733static int
7734getstatus(struct job *job) {
7735 int status;
7736 int retval;
7737
7738 status = job->ps[job->nprocs - 1].status;
7739 retval = WEXITSTATUS(status);
7740 if (!WIFEXITED(status)) {
7741#if JOBS
7742 retval = WSTOPSIG(status);
7743 if (!WIFSTOPPED(status))
7744#endif
7745 {
7746 /* XXX: limits number of signals */
7747 retval = WTERMSIG(status);
7748#if JOBS
7749 if (retval == SIGINT)
7750 job->sigint = 1;
7751#endif
7752 }
7753 retval += 128;
7754 }
7755 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7756 jobno(job), job->nprocs, status, retval));
7757 return retval;
7758}
7759
Eric Andersend35c5df2002-01-09 15:37:36 +00007760#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007761/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007762
Eric Andersencb57d552001-06-28 07:25:16 +00007763/*
Eric Andersenc470f442003-07-28 09:56:35 +00007764 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007765 */
7766
Eric Andersencb57d552001-06-28 07:25:16 +00007767#define MAXMBOXES 10
7768
Eric Andersenc470f442003-07-28 09:56:35 +00007769/* times of mailboxes */
7770static time_t mailtime[MAXMBOXES];
7771/* Set if MAIL or MAILPATH is changed. */
7772static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007773
7774
7775
7776/*
Eric Andersenc470f442003-07-28 09:56:35 +00007777 * Print appropriate message(s) if mail has arrived.
7778 * If mail_var_path_changed is set,
7779 * then the value of MAIL has mail_var_path_changed,
7780 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007781 */
7782
Eric Andersenc470f442003-07-28 09:56:35 +00007783static void
7784chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007785{
Eric Andersencb57d552001-06-28 07:25:16 +00007786 const char *mpath;
7787 char *p;
7788 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007789 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007790 struct stackmark smark;
7791 struct stat statb;
7792
Eric Andersencb57d552001-06-28 07:25:16 +00007793 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007794 mpath = mpathset() ? mpathval() : mailval();
7795 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007796 p = padvance(&mpath, nullstr);
7797 if (p == NULL)
7798 break;
7799 if (*p == '\0')
7800 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007801 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007802#ifdef DEBUG
7803 if (q[-1] != '/')
7804 abort();
7805#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007806 q[-1] = '\0'; /* delete trailing '/' */
7807 if (stat(p, &statb) < 0) {
7808 *mtp = 0;
7809 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007810 }
Eric Andersenc470f442003-07-28 09:56:35 +00007811 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7812 fprintf(
7813 stderr, snlfmt,
7814 pathopt ? pathopt : "you have mail"
7815 );
7816 }
7817 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007818 }
Eric Andersenc470f442003-07-28 09:56:35 +00007819 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007820 popstackmark(&smark);
7821}
Eric Andersencb57d552001-06-28 07:25:16 +00007822
Eric Andersenec074692001-10-31 11:05:49 +00007823
Eric Andersenc470f442003-07-28 09:56:35 +00007824static void
7825changemail(const char *val)
7826{
7827 mail_var_path_changed++;
7828}
7829
7830#endif /* CONFIG_ASH_MAIL */
7831
7832/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7833
Eric Andersencb57d552001-06-28 07:25:16 +00007834
Eric Andersencb57d552001-06-28 07:25:16 +00007835#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007836static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007837extern int etext();
7838#endif
7839
Eric Andersenc470f442003-07-28 09:56:35 +00007840static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007841
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007842static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007843
Eric Andersencb57d552001-06-28 07:25:16 +00007844/*
7845 * Main routine. We initialize things, parse the arguments, execute
7846 * profiles if we're a login shell, and then call cmdloop to execute
7847 * commands. The setjmp call sets up the location to jump to when an
7848 * exception occurs. When an exception occurs the variable "state"
7849 * is used to figure out how far we had gotten.
7850 */
7851
Eric Andersenc470f442003-07-28 09:56:35 +00007852int
7853ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007854{
Eric Andersenc470f442003-07-28 09:56:35 +00007855 char *shinit;
7856 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007857 struct jmploc jmploc;
7858 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007859
Eric Andersenc470f442003-07-28 09:56:35 +00007860#ifdef __GLIBC__
7861 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007862#endif
7863
Eric Andersencb57d552001-06-28 07:25:16 +00007864#if PROFILE
7865 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7866#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007867 state = 0;
7868 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007869 int status;
7870 int e;
7871
Eric Andersencb57d552001-06-28 07:25:16 +00007872 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007873
7874 e = exception;
7875 switch (exception) {
7876 case EXEXEC:
7877 status = exerrno;
7878 break;
7879
7880 case EXERROR:
7881 status = 2;
7882 break;
7883
7884 default:
7885 status = exitstatus;
7886 break;
7887 }
7888 exitstatus = status;
7889
7890 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7891 exitshell();
7892
Eric Andersen90898442003-08-06 11:20:52 +00007893 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007894 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007895 }
7896 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007897 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007898 if (state == 1)
7899 goto state1;
7900 else if (state == 2)
7901 goto state2;
7902 else if (state == 3)
7903 goto state3;
7904 else
7905 goto state4;
7906 }
7907 handler = &jmploc;
7908#ifdef DEBUG
7909 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007910 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007911#endif
7912 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007913
7914#ifdef CONFIG_ASH_RANDOM_SUPPORT
7915 rseed = rootpid + ((time_t)time((time_t *)0));
7916#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007917 rootshell = 1;
7918 init();
7919 setstackmark(&smark);
7920 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007921#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7922 if ( iflag ) {
7923 const char *hp = lookupvar("HISTFILE");
7924
7925 if(hp == NULL ) {
7926 hp = lookupvar("HOME");
7927 if(hp != NULL) {
7928 char *defhp = concat_path_file(hp, ".ash_history");
7929 setvar("HISTFILE", defhp, 0);
7930 free(defhp);
7931 }
7932 }
7933 }
7934#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007935 if (argv[0] && argv[0][0] == '-')
7936 isloginsh = 1;
7937 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007938 state = 1;
7939 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007940state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007941 state = 2;
7942 read_profile(".profile");
7943 }
Eric Andersenc470f442003-07-28 09:56:35 +00007944state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007945 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007946 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007947#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007948 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007949#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007950 iflag
7951 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007952 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007953 read_profile(shinit);
7954 }
Eric Andersencb57d552001-06-28 07:25:16 +00007955 }
Eric Andersenc470f442003-07-28 09:56:35 +00007956state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007957 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007958 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007959 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007960
7961 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007962#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007963 if ( iflag ) {
7964 const char *hp = lookupvar("HISTFILE");
7965
7966 if(hp != NULL )
7967 load_history ( hp );
7968 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007969#endif
Eric Andersen90898442003-08-06 11:20:52 +00007970state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007971 cmdloop(1);
7972 }
7973#if PROFILE
7974 monitor(0);
7975#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007976#if GPROF
7977 {
7978 extern void _mcleanup(void);
7979 _mcleanup();
7980 }
7981#endif
7982 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007983 /* NOTREACHED */
7984}
7985
7986
7987/*
7988 * Read and execute commands. "Top" is nonzero for the top level command
7989 * loop; it turns on prompting if the shell is interactive.
7990 */
7991
Eric Andersenc470f442003-07-28 09:56:35 +00007992static void
7993cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007994{
7995 union node *n;
7996 struct stackmark smark;
7997 int inter;
7998 int numeof = 0;
7999
8000 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008001 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00008002 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00008003 if (pendingsigs)
8004 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00008005#if JOBS
8006 if (jobctl)
8007 showjobs(stderr, SHOW_CHANGED);
8008#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008009 inter = 0;
8010 if (iflag && top) {
8011 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008012#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008013 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008014#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008015 }
8016 n = parsecmd(inter);
8017 /* showtree(n); DEBUG */
8018 if (n == NEOF) {
8019 if (!top || numeof >= 50)
8020 break;
8021 if (!stoppedjobs()) {
8022 if (!Iflag)
8023 break;
8024 out2str("\nUse \"exit\" to leave shell.\n");
8025 }
8026 numeof++;
8027 } else if (n != NULL && nflag == 0) {
8028 job_warning = (job_warning == 2) ? 1 : 0;
8029 numeof = 0;
8030 evaltree(n, 0);
8031 }
8032 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008033 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008034 evalskip = 0;
8035 break;
8036 }
8037 }
Eric Andersencb57d552001-06-28 07:25:16 +00008038}
8039
8040
Eric Andersencb57d552001-06-28 07:25:16 +00008041/*
8042 * Read /etc/profile or .profile. Return on error.
8043 */
8044
Eric Andersenc470f442003-07-28 09:56:35 +00008045static void
8046read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008047{
8048 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008049 int xflag_set = 0;
8050 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008051
8052 INTOFF;
8053 if ((fd = open(name, O_RDONLY)) >= 0)
8054 setinputfd(fd, 1);
8055 INTON;
8056 if (fd < 0)
8057 return;
8058 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008059 if (qflag) {
8060 if (xflag)
8061 xflag = 0, xflag_set = 1;
8062 if (vflag)
8063 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008064 }
8065 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008066 if (qflag) {
8067 if (xflag_set)
8068 xflag = 1;
8069 if (vflag_set)
8070 vflag = 1;
8071 }
Eric Andersencb57d552001-06-28 07:25:16 +00008072 popfile();
8073}
8074
8075
Eric Andersencb57d552001-06-28 07:25:16 +00008076/*
8077 * Read a file containing shell functions.
8078 */
8079
Eric Andersenc470f442003-07-28 09:56:35 +00008080static void
8081readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008082{
8083 int fd;
8084
8085 INTOFF;
8086 if ((fd = open(name, O_RDONLY)) >= 0)
8087 setinputfd(fd, 1);
8088 else
8089 error("Can't open %s", name);
8090 INTON;
8091 cmdloop(0);
8092 popfile();
8093}
8094
8095
Eric Andersencb57d552001-06-28 07:25:16 +00008096/*
Eric Andersenc470f442003-07-28 09:56:35 +00008097 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008098 * search for the file, which is necessary to find sub-commands.
8099 */
8100
Eric Andersenc470f442003-07-28 09:56:35 +00008101static inline char *
8102find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008103{
8104 char *fullname;
8105 const char *path = pathval();
8106 struct stat statb;
8107
8108 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008109 if (strchr(name, '/'))
8110 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008111
Eric Andersenc470f442003-07-28 09:56:35 +00008112 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008113 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8114 /*
8115 * Don't bother freeing here, since it will
8116 * be freed by the caller.
8117 */
8118 return fullname;
8119 }
8120 stunalloc(fullname);
8121 }
8122
8123 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008124 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008125 /* NOTREACHED */
8126}
8127
Eric Andersen1e6aba92004-04-12 19:12:13 +00008128static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008129{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008130 struct strlist *sp;
8131 volatile struct shparam saveparam;
8132
Eric Andersencb57d552001-06-28 07:25:16 +00008133 exitstatus = 0;
8134
Eric Andersen1e6aba92004-04-12 19:12:13 +00008135 for (sp = cmdenviron; sp; sp = sp->next)
8136 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8137
8138 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008139 char *fullname;
8140 struct stackmark smark;
8141
8142 setstackmark(&smark);
8143 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008144
8145 if (argc > 2) {
8146 saveparam = shellparam;
8147 shellparam.malloc = 0;
8148 shellparam.nparam = argc - 2;
8149 shellparam.p = argv + 2;
8150 };
8151
Eric Andersencb57d552001-06-28 07:25:16 +00008152 setinputfile(fullname, 1);
8153 commandname = fullname;
8154 cmdloop(0);
8155 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008156
8157 if (argc > 2) {
8158 freeparam(&shellparam);
8159 shellparam = saveparam;
8160 };
8161
Eric Andersencb57d552001-06-28 07:25:16 +00008162 popstackmark(&smark);
8163 }
8164 return exitstatus;
8165}
8166
8167
Eric Andersenc470f442003-07-28 09:56:35 +00008168static int
8169exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008170{
8171 if (stoppedjobs())
8172 return 0;
8173 if (argc > 1)
8174 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008175 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008176 /* NOTREACHED */
8177}
Eric Andersen62483552001-07-10 06:09:16 +00008178
Eric Andersenc470f442003-07-28 09:56:35 +00008179/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8180
8181/*
Eric Andersen90898442003-08-06 11:20:52 +00008182 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008183 */
8184
8185static pointer
8186ckrealloc(pointer p, size_t nbytes)
8187{
8188 p = realloc(p, nbytes);
8189 if (p == NULL)
8190 error(bb_msg_memory_exhausted);
8191 return p;
8192}
8193
Eric Andersen90898442003-08-06 11:20:52 +00008194static pointer
8195ckmalloc(size_t nbytes)
8196{
8197 return ckrealloc(NULL, nbytes);
8198}
Eric Andersenc470f442003-07-28 09:56:35 +00008199
8200/*
8201 * Make a copy of a string in safe storage.
8202 */
8203
8204static char *
8205savestr(const char *s)
8206{
8207 char *p = strdup(s);
8208 if (!p)
8209 error(bb_msg_memory_exhausted);
8210 return p;
8211}
8212
8213
8214/*
8215 * Parse trees for commands are allocated in lifo order, so we use a stack
8216 * to make this more efficient, and also to avoid all sorts of exception
8217 * handling code to handle interrupts in the middle of a parse.
8218 *
8219 * The size 504 was chosen because the Ultrix malloc handles that size
8220 * well.
8221 */
8222
8223
8224static pointer
8225stalloc(size_t nbytes)
8226{
8227 char *p;
8228 size_t aligned;
8229
8230 aligned = SHELL_ALIGN(nbytes);
8231 if (aligned > stacknleft) {
8232 size_t len;
8233 size_t blocksize;
8234 struct stack_block *sp;
8235
8236 blocksize = aligned;
8237 if (blocksize < MINSIZE)
8238 blocksize = MINSIZE;
8239 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8240 if (len < blocksize)
8241 error(bb_msg_memory_exhausted);
8242 INTOFF;
8243 sp = ckmalloc(len);
8244 sp->prev = stackp;
8245 stacknxt = sp->space;
8246 stacknleft = blocksize;
8247 sstrend = stacknxt + blocksize;
8248 stackp = sp;
8249 INTON;
8250 }
8251 p = stacknxt;
8252 stacknxt += aligned;
8253 stacknleft -= aligned;
8254 return p;
8255}
8256
8257
8258void
8259stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008260{
Eric Andersencb57d552001-06-28 07:25:16 +00008261#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008262 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008263 write(2, "stunalloc\n", 10);
8264 abort();
8265 }
8266#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008267 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008268 stacknxt = p;
8269}
8270
8271
Eric Andersenc470f442003-07-28 09:56:35 +00008272void
8273setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008274{
Eric Andersencb57d552001-06-28 07:25:16 +00008275 mark->stackp = stackp;
8276 mark->stacknxt = stacknxt;
8277 mark->stacknleft = stacknleft;
8278 mark->marknext = markp;
8279 markp = mark;
8280}
8281
8282
Eric Andersenc470f442003-07-28 09:56:35 +00008283void
8284popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008285{
Eric Andersencb57d552001-06-28 07:25:16 +00008286 struct stack_block *sp;
8287
8288 INTOFF;
8289 markp = mark->marknext;
8290 while (stackp != mark->stackp) {
8291 sp = stackp;
8292 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008293 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008294 }
8295 stacknxt = mark->stacknxt;
8296 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008297 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008298 INTON;
8299}
8300
8301
8302/*
8303 * When the parser reads in a string, it wants to stick the string on the
8304 * stack and only adjust the stack pointer when it knows how big the
8305 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8306 * of space on top of the stack and stackblocklen returns the length of
8307 * this block. Growstackblock will grow this space by at least one byte,
8308 * possibly moving it (like realloc). Grabstackblock actually allocates the
8309 * part of the block that has been used.
8310 */
8311
Eric Andersenc470f442003-07-28 09:56:35 +00008312void
8313growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008314{
Eric Andersenc470f442003-07-28 09:56:35 +00008315 size_t newlen;
8316
8317 newlen = stacknleft * 2;
8318 if (newlen < stacknleft)
8319 error(bb_msg_memory_exhausted);
8320 if (newlen < 128)
8321 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008322
8323 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008324 struct stack_block *oldstackp;
8325 struct stackmark *xmark;
8326 struct stack_block *sp;
8327 struct stack_block *prevstackp;
8328 size_t grosslen;
8329
Eric Andersencb57d552001-06-28 07:25:16 +00008330 INTOFF;
8331 oldstackp = stackp;
8332 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008333 prevstackp = sp->prev;
8334 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8335 sp = ckrealloc((pointer)sp, grosslen);
8336 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008337 stackp = sp;
8338 stacknxt = sp->space;
8339 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008340 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008341
Eric Andersenc470f442003-07-28 09:56:35 +00008342 /*
8343 * Stack marks pointing to the start of the old block
8344 * must be relocated to point to the new block
8345 */
8346 xmark = markp;
8347 while (xmark != NULL && xmark->stackp == oldstackp) {
8348 xmark->stackp = stackp;
8349 xmark->stacknxt = stacknxt;
8350 xmark->stacknleft = stacknleft;
8351 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008352 }
8353 INTON;
8354 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008355 char *oldspace = stacknxt;
8356 int oldlen = stacknleft;
8357 char *p = stalloc(newlen);
8358
8359 /* free the space we just allocated */
8360 stacknxt = memcpy(p, oldspace, oldlen);
8361 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008362 }
8363}
8364
Eric Andersenc470f442003-07-28 09:56:35 +00008365static inline void
8366grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008367{
Eric Andersenc470f442003-07-28 09:56:35 +00008368 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008369 stacknxt += len;
8370 stacknleft -= len;
8371}
8372
Eric Andersencb57d552001-06-28 07:25:16 +00008373/*
Eric Andersenc470f442003-07-28 09:56:35 +00008374 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008375 * The user declares a variable of type STACKSTR, which may be declared
8376 * to be a register. The macro STARTSTACKSTR initializes things. Then
8377 * the user uses the macro STPUTC to add characters to the string. In
8378 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8379 * grown as necessary. When the user is done, she can just leave the
8380 * string there and refer to it using stackblock(). Or she can allocate
8381 * the space for it using grabstackstr(). If it is necessary to allow
8382 * someone else to use the stack temporarily and then continue to grow
8383 * the string, the user should use grabstack to allocate the space, and
8384 * then call ungrabstr(p) to return to the previous mode of operation.
8385 *
8386 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8387 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8388 * is space for at least one character.
8389 */
8390
Eric Andersenc470f442003-07-28 09:56:35 +00008391void *
8392growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008393{
Eric Andersenc470f442003-07-28 09:56:35 +00008394 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008395 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008396 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008397 return stackblock();
8398 }
8399 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008400 return stackblock() + len;
8401}
8402
Eric Andersencb57d552001-06-28 07:25:16 +00008403/*
8404 * Called from CHECKSTRSPACE.
8405 */
8406
Eric Andersenc470f442003-07-28 09:56:35 +00008407char *
8408makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008409{
Eric Andersenc470f442003-07-28 09:56:35 +00008410 size_t len = p - stacknxt;
8411 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008412
Eric Andersenc470f442003-07-28 09:56:35 +00008413 for (;;) {
8414 size_t nleft;
8415
8416 size = stackblocksize();
8417 nleft = size - len;
8418 if (nleft >= newlen)
8419 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008420 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008421 }
Eric Andersencb57d552001-06-28 07:25:16 +00008422 return stackblock() + len;
8423}
8424
Eric Andersenc470f442003-07-28 09:56:35 +00008425char *
8426stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008427{
Eric Andersenc470f442003-07-28 09:56:35 +00008428 p = makestrspace(n, p);
8429 p = mempcpy(p, s, n);
8430 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008431}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008432
Eric Andersenc470f442003-07-28 09:56:35 +00008433char *
8434stputs(const char *s, char *p)
8435{
8436 return stnputs(s, strlen(s), p);
8437}
8438
8439/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8440
Eric Andersencb57d552001-06-28 07:25:16 +00008441/*
Eric Andersenc470f442003-07-28 09:56:35 +00008442 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008443 *
Eric Andersenc470f442003-07-28 09:56:35 +00008444 * number(s) Convert a string of digits to an integer.
8445 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008446 */
8447
Eric Andersencb57d552001-06-28 07:25:16 +00008448/*
8449 * prefix -- see if pfx is a prefix of string.
8450 */
8451
Eric Andersenc470f442003-07-28 09:56:35 +00008452char *
8453prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008454{
Eric Andersencb57d552001-06-28 07:25:16 +00008455 while (*pfx) {
8456 if (*pfx++ != *string++)
8457 return 0;
8458 }
Eric Andersenc470f442003-07-28 09:56:35 +00008459 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008460}
8461
8462
8463/*
8464 * Convert a string of digits to an integer, printing an error message on
8465 * failure.
8466 */
8467
Eric Andersenc470f442003-07-28 09:56:35 +00008468int
8469number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008470{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008471
Eric Andersenc470f442003-07-28 09:56:35 +00008472 if (! is_number(s))
8473 error(illnum, s);
8474 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008475}
8476
Eric Andersenc470f442003-07-28 09:56:35 +00008477
Eric Andersenc470f442003-07-28 09:56:35 +00008478/*
8479 * Check for a valid number. This should be elsewhere.
8480 */
8481
8482int
8483is_number(const char *p)
8484{
8485 do {
8486 if (! is_digit(*p))
8487 return 0;
8488 } while (*++p != '\0');
8489 return 1;
8490}
8491
8492
Eric Andersencb57d552001-06-28 07:25:16 +00008493/*
8494 * Produce a possibly single quoted string suitable as input to the shell.
8495 * The return string is allocated on the stack.
8496 */
8497
Eric Andersenc470f442003-07-28 09:56:35 +00008498char *
8499single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008500 char *p;
8501
8502 STARTSTACKSTR(p);
8503
8504 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008505 char *q;
8506 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008507
Eric Andersenc470f442003-07-28 09:56:35 +00008508 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008509
Eric Andersenc470f442003-07-28 09:56:35 +00008510 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008511
Eric Andersenc470f442003-07-28 09:56:35 +00008512 *q++ = '\'';
8513 q = mempcpy(q, s, len);
8514 *q++ = '\'';
8515 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008516
Eric Andersenc470f442003-07-28 09:56:35 +00008517 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008518
Eric Andersenc470f442003-07-28 09:56:35 +00008519 len = strspn(s, "'");
8520 if (!len)
8521 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008522
Eric Andersenc470f442003-07-28 09:56:35 +00008523 q = p = makestrspace(len + 3, p);
8524
8525 *q++ = '"';
8526 q = mempcpy(q, s, len);
8527 *q++ = '"';
8528 s += len;
8529
8530 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008531 } while (*s);
8532
8533 USTPUTC(0, p);
8534
Eric Andersenc470f442003-07-28 09:56:35 +00008535 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008536}
8537
8538/*
Eric Andersenc470f442003-07-28 09:56:35 +00008539 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008540 */
8541
Eric Andersenc470f442003-07-28 09:56:35 +00008542char *
8543sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008544{
Eric Andersenc470f442003-07-28 09:56:35 +00008545 size_t len = strlen(p) + 1;
8546 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008547}
Eric Andersenc470f442003-07-28 09:56:35 +00008548
8549
8550static void
8551calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008552{
Eric Andersenc470f442003-07-28 09:56:35 +00008553 if (n == NULL)
8554 return;
8555 funcblocksize += nodesize[n->type];
8556 switch (n->type) {
8557 case NCMD:
8558 calcsize(n->ncmd.redirect);
8559 calcsize(n->ncmd.args);
8560 calcsize(n->ncmd.assign);
8561 break;
8562 case NPIPE:
8563 sizenodelist(n->npipe.cmdlist);
8564 break;
8565 case NREDIR:
8566 case NBACKGND:
8567 case NSUBSHELL:
8568 calcsize(n->nredir.redirect);
8569 calcsize(n->nredir.n);
8570 break;
8571 case NAND:
8572 case NOR:
8573 case NSEMI:
8574 case NWHILE:
8575 case NUNTIL:
8576 calcsize(n->nbinary.ch2);
8577 calcsize(n->nbinary.ch1);
8578 break;
8579 case NIF:
8580 calcsize(n->nif.elsepart);
8581 calcsize(n->nif.ifpart);
8582 calcsize(n->nif.test);
8583 break;
8584 case NFOR:
8585 funcstringsize += strlen(n->nfor.var) + 1;
8586 calcsize(n->nfor.body);
8587 calcsize(n->nfor.args);
8588 break;
8589 case NCASE:
8590 calcsize(n->ncase.cases);
8591 calcsize(n->ncase.expr);
8592 break;
8593 case NCLIST:
8594 calcsize(n->nclist.body);
8595 calcsize(n->nclist.pattern);
8596 calcsize(n->nclist.next);
8597 break;
8598 case NDEFUN:
8599 case NARG:
8600 sizenodelist(n->narg.backquote);
8601 funcstringsize += strlen(n->narg.text) + 1;
8602 calcsize(n->narg.next);
8603 break;
8604 case NTO:
8605 case NCLOBBER:
8606 case NFROM:
8607 case NFROMTO:
8608 case NAPPEND:
8609 calcsize(n->nfile.fname);
8610 calcsize(n->nfile.next);
8611 break;
8612 case NTOFD:
8613 case NFROMFD:
8614 calcsize(n->ndup.vname);
8615 calcsize(n->ndup.next);
8616 break;
8617 case NHERE:
8618 case NXHERE:
8619 calcsize(n->nhere.doc);
8620 calcsize(n->nhere.next);
8621 break;
8622 case NNOT:
8623 calcsize(n->nnot.com);
8624 break;
8625 };
Eric Andersencb57d552001-06-28 07:25:16 +00008626}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008627
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008628
Eric Andersenc470f442003-07-28 09:56:35 +00008629static void
8630sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008631{
8632 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008633 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008634 calcsize(lp->n);
8635 lp = lp->next;
8636 }
8637}
Eric Andersencb57d552001-06-28 07:25:16 +00008638
8639
Eric Andersenc470f442003-07-28 09:56:35 +00008640static union node *
8641copynode(union node *n)
8642{
8643 union node *new;
8644
8645 if (n == NULL)
8646 return NULL;
8647 new = funcblock;
8648 funcblock = (char *) funcblock + nodesize[n->type];
8649 switch (n->type) {
8650 case NCMD:
8651 new->ncmd.redirect = copynode(n->ncmd.redirect);
8652 new->ncmd.args = copynode(n->ncmd.args);
8653 new->ncmd.assign = copynode(n->ncmd.assign);
8654 break;
8655 case NPIPE:
8656 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8657 new->npipe.backgnd = n->npipe.backgnd;
8658 break;
8659 case NREDIR:
8660 case NBACKGND:
8661 case NSUBSHELL:
8662 new->nredir.redirect = copynode(n->nredir.redirect);
8663 new->nredir.n = copynode(n->nredir.n);
8664 break;
8665 case NAND:
8666 case NOR:
8667 case NSEMI:
8668 case NWHILE:
8669 case NUNTIL:
8670 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8671 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8672 break;
8673 case NIF:
8674 new->nif.elsepart = copynode(n->nif.elsepart);
8675 new->nif.ifpart = copynode(n->nif.ifpart);
8676 new->nif.test = copynode(n->nif.test);
8677 break;
8678 case NFOR:
8679 new->nfor.var = nodesavestr(n->nfor.var);
8680 new->nfor.body = copynode(n->nfor.body);
8681 new->nfor.args = copynode(n->nfor.args);
8682 break;
8683 case NCASE:
8684 new->ncase.cases = copynode(n->ncase.cases);
8685 new->ncase.expr = copynode(n->ncase.expr);
8686 break;
8687 case NCLIST:
8688 new->nclist.body = copynode(n->nclist.body);
8689 new->nclist.pattern = copynode(n->nclist.pattern);
8690 new->nclist.next = copynode(n->nclist.next);
8691 break;
8692 case NDEFUN:
8693 case NARG:
8694 new->narg.backquote = copynodelist(n->narg.backquote);
8695 new->narg.text = nodesavestr(n->narg.text);
8696 new->narg.next = copynode(n->narg.next);
8697 break;
8698 case NTO:
8699 case NCLOBBER:
8700 case NFROM:
8701 case NFROMTO:
8702 case NAPPEND:
8703 new->nfile.fname = copynode(n->nfile.fname);
8704 new->nfile.fd = n->nfile.fd;
8705 new->nfile.next = copynode(n->nfile.next);
8706 break;
8707 case NTOFD:
8708 case NFROMFD:
8709 new->ndup.vname = copynode(n->ndup.vname);
8710 new->ndup.dupfd = n->ndup.dupfd;
8711 new->ndup.fd = n->ndup.fd;
8712 new->ndup.next = copynode(n->ndup.next);
8713 break;
8714 case NHERE:
8715 case NXHERE:
8716 new->nhere.doc = copynode(n->nhere.doc);
8717 new->nhere.fd = n->nhere.fd;
8718 new->nhere.next = copynode(n->nhere.next);
8719 break;
8720 case NNOT:
8721 new->nnot.com = copynode(n->nnot.com);
8722 break;
8723 };
8724 new->type = n->type;
8725 return new;
8726}
8727
8728
8729static struct nodelist *
8730copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008731{
8732 struct nodelist *start;
8733 struct nodelist **lpp;
8734
8735 lpp = &start;
8736 while (lp) {
8737 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008738 funcblock = (char *) funcblock +
8739 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008740 (*lpp)->n = copynode(lp->n);
8741 lp = lp->next;
8742 lpp = &(*lpp)->next;
8743 }
8744 *lpp = NULL;
8745 return start;
8746}
8747
8748
Eric Andersenc470f442003-07-28 09:56:35 +00008749static char *
8750nodesavestr(char *s)
8751{
8752 char *rtn = funcstring;
8753
8754 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008755 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008756}
8757
Eric Andersenc470f442003-07-28 09:56:35 +00008758
Eric Andersenc470f442003-07-28 09:56:35 +00008759/*
8760 * Free a parse tree.
8761 */
8762
8763static void
8764freefunc(struct funcnode *f)
8765{
8766 if (f && --f->count < 0)
8767 ckfree(f);
8768}
8769
8770
8771static void options(int);
8772static void setoption(int, int);
8773
Eric Andersencb57d552001-06-28 07:25:16 +00008774
Eric Andersencb57d552001-06-28 07:25:16 +00008775/*
8776 * Process the shell command line arguments.
8777 */
8778
Eric Andersenc470f442003-07-28 09:56:35 +00008779void
8780procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008781{
8782 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008783 const char *xminusc;
8784 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008785
Eric Andersenc470f442003-07-28 09:56:35 +00008786 xargv = argv;
8787 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008788 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008789 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008790 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008791 optlist[i] = 2;
8792 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008793 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008794 xargv = argptr;
8795 xminusc = minusc;
8796 if (*xargv == NULL) {
8797 if (xminusc)
8798 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008799 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008800 }
Eric Andersencb57d552001-06-28 07:25:16 +00008801 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8802 iflag = 1;
8803 if (mflag == 2)
8804 mflag = iflag;
8805 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008806 if (optlist[i] == 2)
8807 optlist[i] = 0;
8808#if DEBUG == 2
8809 debug = 1;
8810#endif
8811 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8812 if (xminusc) {
8813 minusc = *xargv++;
8814 if (*xargv)
8815 goto setarg0;
8816 } else if (!sflag) {
8817 setinputfile(*xargv, 0);
8818setarg0:
8819 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008820 commandname = arg0;
8821 }
Eric Andersencb57d552001-06-28 07:25:16 +00008822
Eric Andersenc470f442003-07-28 09:56:35 +00008823 shellparam.p = xargv;
8824#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008825 shellparam.optind = 1;
8826 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008827#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008828 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008829 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008830 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008831 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008832 }
8833 optschanged();
8834}
8835
8836
Eric Andersenc470f442003-07-28 09:56:35 +00008837void
8838optschanged(void)
8839{
8840#ifdef DEBUG
8841 opentrace();
8842#endif
8843 setinteractive(iflag);
8844 setjobctl(mflag);
8845}
Eric Andersencb57d552001-06-28 07:25:16 +00008846
Eric Andersenc470f442003-07-28 09:56:35 +00008847static inline void
8848minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008849{
8850 int i;
8851
8852 if (name == NULL) {
8853 out1str("Current option settings\n");
8854 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008855 out1fmt("%-16s%s\n", optnames(i),
8856 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008857 } else {
8858 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008859 if (equal(name, optnames(i))) {
8860 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008861 return;
8862 }
8863 error("Illegal option -o %s", name);
8864 }
8865}
8866
Eric Andersenc470f442003-07-28 09:56:35 +00008867/*
8868 * Process shell options. The global variable argptr contains a pointer
8869 * to the argument list; we advance it past the options.
8870 */
Eric Andersen62483552001-07-10 06:09:16 +00008871
Eric Andersenc470f442003-07-28 09:56:35 +00008872static void
8873options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008874{
8875 char *p;
8876 int val;
8877 int c;
8878
8879 if (cmdline)
8880 minusc = NULL;
8881 while ((p = *argptr) != NULL) {
8882 argptr++;
8883 if ((c = *p++) == '-') {
8884 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008885 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8886 if (!cmdline) {
8887 /* "-" means turn off -x and -v */
8888 if (p[0] == '\0')
8889 xflag = vflag = 0;
8890 /* "--" means reset params */
8891 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008892 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008893 }
Eric Andersenc470f442003-07-28 09:56:35 +00008894 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008895 }
8896 } else if (c == '+') {
8897 val = 0;
8898 } else {
8899 argptr--;
8900 break;
8901 }
8902 while ((c = *p++) != '\0') {
8903 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008904 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008905 } else if (c == 'o') {
8906 minus_o(*argptr, val);
8907 if (*argptr)
8908 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008909 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008910 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008911 isloginsh = 1;
8912 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008913 } else {
8914 setoption(c, val);
8915 }
8916 }
8917 }
8918}
8919
Eric Andersencb57d552001-06-28 07:25:16 +00008920
Eric Andersenc470f442003-07-28 09:56:35 +00008921static void
8922setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008923{
Eric Andersencb57d552001-06-28 07:25:16 +00008924 int i;
8925
8926 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008927 if (optletters(i) == flag) {
8928 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008929 return;
8930 }
8931 error("Illegal option -%c", flag);
8932 /* NOTREACHED */
8933}
8934
8935
8936
Eric Andersencb57d552001-06-28 07:25:16 +00008937/*
8938 * Set the shell parameters.
8939 */
8940
Eric Andersenc470f442003-07-28 09:56:35 +00008941void
8942setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008943{
Eric Andersencb57d552001-06-28 07:25:16 +00008944 char **newparam;
8945 char **ap;
8946 int nparam;
8947
Eric Andersenc470f442003-07-28 09:56:35 +00008948 for (nparam = 0 ; argv[nparam] ; nparam++);
8949 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008950 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008951 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008952 }
8953 *ap = NULL;
8954 freeparam(&shellparam);
8955 shellparam.malloc = 1;
8956 shellparam.nparam = nparam;
8957 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008958#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008959 shellparam.optind = 1;
8960 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008961#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008962}
8963
8964
8965/*
8966 * Free the list of positional parameters.
8967 */
8968
Eric Andersenc470f442003-07-28 09:56:35 +00008969void
8970freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008971{
Eric Andersencb57d552001-06-28 07:25:16 +00008972 char **ap;
8973
8974 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008975 for (ap = param->p ; *ap ; ap++)
8976 ckfree(*ap);
8977 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008978 }
8979}
8980
8981
8982
8983/*
8984 * The shift builtin command.
8985 */
8986
Eric Andersenc470f442003-07-28 09:56:35 +00008987int
8988shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008989{
8990 int n;
8991 char **ap1, **ap2;
8992
8993 n = 1;
8994 if (argc > 1)
8995 n = number(argv[1]);
8996 if (n > shellparam.nparam)
8997 error("can't shift that many");
8998 INTOFF;
8999 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009000 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009001 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009002 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009003 }
9004 ap2 = shellparam.p;
9005 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009006#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009007 shellparam.optind = 1;
9008 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009009#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009010 INTON;
9011 return 0;
9012}
9013
9014
9015
9016/*
9017 * The set command builtin.
9018 */
9019
Eric Andersenc470f442003-07-28 09:56:35 +00009020int
9021setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009022{
9023 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009024 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009025 INTOFF;
9026 options(0);
9027 optschanged();
9028 if (*argptr != NULL) {
9029 setparam(argptr);
9030 }
9031 INTON;
9032 return 0;
9033}
9034
9035
Eric Andersenc470f442003-07-28 09:56:35 +00009036#ifdef CONFIG_ASH_GETOPTS
9037static void
9038getoptsreset(value)
9039 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009040{
9041 shellparam.optind = number(value);
9042 shellparam.optoff = -1;
9043}
Eric Andersenc470f442003-07-28 09:56:35 +00009044#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009045
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009046#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009047static void change_lc_all(const char *value)
9048{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009049 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009050 setlocale(LC_ALL, value);
9051}
9052
9053static void change_lc_ctype(const char *value)
9054{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009055 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009056 setlocale(LC_CTYPE, value);
9057}
9058
9059#endif
9060
Eric Andersen16767e22004-03-16 05:14:10 +00009061#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009062/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009063static void change_random(const char *value)
9064{
Eric Andersen16767e22004-03-16 05:14:10 +00009065 if(value == NULL) {
9066 /* "get", generate */
9067 char buf[16];
9068
9069 rseed = rseed * 1103515245 + 12345;
9070 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9071 /* set without recursion */
9072 setvar(vrandom.text, buf, VNOFUNC);
9073 vrandom.flags &= ~VNOFUNC;
9074 } else {
9075 /* set/reset */
9076 rseed = strtoul(value, (char **)NULL, 10);
9077 }
Eric Andersenef02f822004-03-11 13:34:24 +00009078}
Eric Andersen16767e22004-03-16 05:14:10 +00009079#endif
9080
Eric Andersenef02f822004-03-11 13:34:24 +00009081
Eric Andersend35c5df2002-01-09 15:37:36 +00009082#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009083static int
Eric Andersenc470f442003-07-28 09:56:35 +00009084getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009085{
9086 char *p, *q;
9087 char c = '?';
9088 int done = 0;
9089 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009090 char s[12];
9091 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009092
Eric Andersena48b0a32003-10-22 10:56:47 +00009093 if(*param_optind < 1)
9094 return 1;
9095 optnext = optfirst + *param_optind - 1;
9096
9097 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009098 p = NULL;
9099 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009100 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009101 if (p == NULL || *p == '\0') {
9102 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009103 p = *optnext;
9104 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009105atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009106 p = NULL;
9107 done = 1;
9108 goto out;
9109 }
9110 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009111 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009112 goto atend;
9113 }
9114
9115 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009116 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009117 if (*q == '\0') {
9118 if (optstr[0] == ':') {
9119 s[0] = c;
9120 s[1] = '\0';
9121 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009122 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009123 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009124 (void) unsetvar("OPTARG");
9125 }
9126 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009127 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009128 }
9129 if (*++q == ':')
9130 q++;
9131 }
9132
9133 if (*++q == ':') {
9134 if (*p == '\0' && (p = *optnext) == NULL) {
9135 if (optstr[0] == ':') {
9136 s[0] = c;
9137 s[1] = '\0';
9138 err |= setvarsafe("OPTARG", s, 0);
9139 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009140 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009141 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009142 (void) unsetvar("OPTARG");
9143 c = '?';
9144 }
Eric Andersenc470f442003-07-28 09:56:35 +00009145 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009146 }
9147
9148 if (p == *optnext)
9149 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009150 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009151 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009152 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009153 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009154
Eric Andersenc470f442003-07-28 09:56:35 +00009155out:
Eric Andersencb57d552001-06-28 07:25:16 +00009156 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009157 *param_optind = optnext - optfirst + 1;
9158 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009159 err |= setvarsafe("OPTIND", s, VNOFUNC);
9160 s[0] = c;
9161 s[1] = '\0';
9162 err |= setvarsafe(optvar, s, 0);
9163 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009164 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009165 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009166 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009167 exraise(EXERROR);
9168 }
9169 return done;
9170}
Eric Andersenc470f442003-07-28 09:56:35 +00009171
9172/*
9173 * The getopts builtin. Shellparam.optnext points to the next argument
9174 * to be processed. Shellparam.optptr points to the next character to
9175 * be processed in the current argument. If shellparam.optnext is NULL,
9176 * then it's the first time getopts has been called.
9177 */
9178
9179int
9180getoptscmd(int argc, char **argv)
9181{
9182 char **optbase;
9183
9184 if (argc < 3)
9185 error("Usage: getopts optstring var [arg]");
9186 else if (argc == 3) {
9187 optbase = shellparam.p;
9188 if (shellparam.optind > shellparam.nparam + 1) {
9189 shellparam.optind = 1;
9190 shellparam.optoff = -1;
9191 }
9192 }
9193 else {
9194 optbase = &argv[3];
9195 if (shellparam.optind > argc - 2) {
9196 shellparam.optind = 1;
9197 shellparam.optoff = -1;
9198 }
9199 }
9200
9201 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9202 &shellparam.optoff);
9203}
9204#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009205
9206/*
9207 * XXX - should get rid of. have all builtins use getopt(3). the
9208 * library getopt must have the BSD extension static variable "optreset"
9209 * otherwise it can't be used within the shell safely.
9210 *
9211 * Standard option processing (a la getopt) for builtin routines. The
9212 * only argument that is passed to nextopt is the option string; the
9213 * other arguments are unnecessary. It return the character, or '\0' on
9214 * end of input.
9215 */
9216
Eric Andersenc470f442003-07-28 09:56:35 +00009217static int
9218nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009219{
Eric Andersencb57d552001-06-28 07:25:16 +00009220 char *p;
9221 const char *q;
9222 char c;
9223
9224 if ((p = optptr) == NULL || *p == '\0') {
9225 p = *argptr;
9226 if (p == NULL || *p != '-' || *++p == '\0')
9227 return '\0';
9228 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009229 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009230 return '\0';
9231 }
9232 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009233 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009234 if (*q == '\0')
9235 error("Illegal option -%c", c);
9236 if (*++q == ':')
9237 q++;
9238 }
9239 if (*++q == ':') {
9240 if (*p == '\0' && (p = *argptr++) == NULL)
9241 error("No arg for -%c option", c);
9242 optionarg = p;
9243 p = NULL;
9244 }
9245 optptr = p;
9246 return c;
9247}
9248
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009249
Eric Andersenc470f442003-07-28 09:56:35 +00009250/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9251
Eric Andersenc470f442003-07-28 09:56:35 +00009252void
9253outstr(const char *p, FILE *file)
9254{
9255 INTOFF;
9256 fputs(p, file);
9257 INTON;
9258}
9259
9260void
9261flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009262{
Eric Andersencb57d552001-06-28 07:25:16 +00009263 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009264 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009265 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009266 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009267}
9268
Eric Andersenc470f442003-07-28 09:56:35 +00009269void
Eric Andersen16767e22004-03-16 05:14:10 +00009270flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009271{
9272 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009273 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009274 INTON;
9275}
9276
9277static void
9278outcslow(int c, FILE *dest)
9279{
9280 INTOFF;
9281 putc(c, dest);
9282 fflush(dest);
9283 INTON;
9284}
9285
9286
9287static int
9288out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009289{
9290 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009291 int r;
9292
9293 INTOFF;
9294 va_start(ap, fmt);
9295 r = vprintf(fmt, ap);
9296 va_end(ap);
9297 INTON;
9298 return r;
9299}
9300
9301
9302int
9303fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9304{
9305 va_list ap;
9306 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009307
Eric Andersencb57d552001-06-28 07:25:16 +00009308 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009309 INTOFF;
9310 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009311 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009312 INTON;
9313 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009314}
9315
Eric Andersenc470f442003-07-28 09:56:35 +00009316
Eric Andersencb57d552001-06-28 07:25:16 +00009317
Eric Andersenc470f442003-07-28 09:56:35 +00009318/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9319
9320
Eric Andersencb57d552001-06-28 07:25:16 +00009321/*
9322 * Shell command parser.
9323 */
9324
9325#define EOFMARKLEN 79
9326
9327
Eric Andersencb57d552001-06-28 07:25:16 +00009328struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009329 struct heredoc *next; /* next here document in list */
9330 union node *here; /* redirection node */
9331 char *eofmark; /* string indicating end of input */
9332 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009333};
9334
9335
9336
Eric Andersenc470f442003-07-28 09:56:35 +00009337static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009338
9339
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009340static union node *list(int);
9341static union node *andor(void);
9342static union node *pipeline(void);
9343static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009344static union node *simplecmd(void);
9345static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009346static void parsefname(void);
9347static void parseheredoc(void);
9348static char peektoken(void);
9349static int readtoken(void);
9350static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009351static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009352static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009353static void synexpect(int) __attribute__((__noreturn__));
9354static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009355static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009356
9357
Eric Andersenc470f442003-07-28 09:56:35 +00009358
9359static inline int
9360isassignment(const char *p)
9361{
9362 const char *q = endofname(p);
9363 if (p == q)
9364 return 0;
9365 return *q == '=';
9366}
9367
9368
Eric Andersencb57d552001-06-28 07:25:16 +00009369/*
9370 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9371 * valid parse tree indicating a blank line.)
9372 */
9373
Eric Andersenc470f442003-07-28 09:56:35 +00009374union node *
9375parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009376{
9377 int t;
9378
9379 tokpushback = 0;
9380 doprompt = interact;
9381 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009382 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009383 needprompt = 0;
9384 t = readtoken();
9385 if (t == TEOF)
9386 return NEOF;
9387 if (t == TNL)
9388 return NULL;
9389 tokpushback++;
9390 return list(1);
9391}
9392
9393
Eric Andersenc470f442003-07-28 09:56:35 +00009394static union node *
9395list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009396{
9397 union node *n1, *n2, *n3;
9398 int tok;
9399
Eric Andersenc470f442003-07-28 09:56:35 +00009400 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9401 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009402 return NULL;
9403 n1 = NULL;
9404 for (;;) {
9405 n2 = andor();
9406 tok = readtoken();
9407 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009408 if (n2->type == NPIPE) {
9409 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009410 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009411 if (n2->type != NREDIR) {
9412 n3 = stalloc(sizeof(struct nredir));
9413 n3->nredir.n = n2;
9414 n3->nredir.redirect = NULL;
9415 n2 = n3;
9416 }
9417 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009418 }
9419 }
9420 if (n1 == NULL) {
9421 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009422 }
9423 else {
9424 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009425 n3->type = NSEMI;
9426 n3->nbinary.ch1 = n1;
9427 n3->nbinary.ch2 = n2;
9428 n1 = n3;
9429 }
9430 switch (tok) {
9431 case TBACKGND:
9432 case TSEMI:
9433 tok = readtoken();
9434 /* fall through */
9435 case TNL:
9436 if (tok == TNL) {
9437 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009438 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009439 return n1;
9440 } else {
9441 tokpushback++;
9442 }
Eric Andersenc470f442003-07-28 09:56:35 +00009443 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009444 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009445 return n1;
9446 break;
9447 case TEOF:
9448 if (heredoclist)
9449 parseheredoc();
9450 else
Eric Andersenc470f442003-07-28 09:56:35 +00009451 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009452 return n1;
9453 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009454 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009455 synexpect(-1);
9456 tokpushback++;
9457 return n1;
9458 }
9459 }
9460}
9461
9462
9463
Eric Andersenc470f442003-07-28 09:56:35 +00009464static union node *
9465andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009466{
Eric Andersencb57d552001-06-28 07:25:16 +00009467 union node *n1, *n2, *n3;
9468 int t;
9469
Eric Andersencb57d552001-06-28 07:25:16 +00009470 n1 = pipeline();
9471 for (;;) {
9472 if ((t = readtoken()) == TAND) {
9473 t = NAND;
9474 } else if (t == TOR) {
9475 t = NOR;
9476 } else {
9477 tokpushback++;
9478 return n1;
9479 }
Eric Andersenc470f442003-07-28 09:56:35 +00009480 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009481 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009482 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009483 n3->type = t;
9484 n3->nbinary.ch1 = n1;
9485 n3->nbinary.ch2 = n2;
9486 n1 = n3;
9487 }
9488}
9489
9490
9491
Eric Andersenc470f442003-07-28 09:56:35 +00009492static union node *
9493pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009494{
Eric Andersencb57d552001-06-28 07:25:16 +00009495 union node *n1, *n2, *pipenode;
9496 struct nodelist *lp, *prev;
9497 int negate;
9498
9499 negate = 0;
9500 TRACE(("pipeline: entered\n"));
9501 if (readtoken() == TNOT) {
9502 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009503 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009504 } else
9505 tokpushback++;
9506 n1 = command();
9507 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009508 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009509 pipenode->type = NPIPE;
9510 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009511 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009512 pipenode->npipe.cmdlist = lp;
9513 lp->n = n1;
9514 do {
9515 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009516 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9517 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009518 lp->n = command();
9519 prev->next = lp;
9520 } while (readtoken() == TPIPE);
9521 lp->next = NULL;
9522 n1 = pipenode;
9523 }
9524 tokpushback++;
9525 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009526 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009527 n2->type = NNOT;
9528 n2->nnot.com = n1;
9529 return n2;
9530 } else
9531 return n1;
9532}
9533
9534
9535
Eric Andersenc470f442003-07-28 09:56:35 +00009536static union node *
9537command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009538{
Eric Andersencb57d552001-06-28 07:25:16 +00009539 union node *n1, *n2;
9540 union node *ap, **app;
9541 union node *cp, **cpp;
9542 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009543 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009544 int t;
9545
9546 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009547 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009548
Eric Andersencb57d552001-06-28 07:25:16 +00009549 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009550 default:
9551 synexpect(-1);
9552 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009553 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009554 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009555 n1->type = NIF;
9556 n1->nif.test = list(0);
9557 if (readtoken() != TTHEN)
9558 synexpect(TTHEN);
9559 n1->nif.ifpart = list(0);
9560 n2 = n1;
9561 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009562 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009563 n2 = n2->nif.elsepart;
9564 n2->type = NIF;
9565 n2->nif.test = list(0);
9566 if (readtoken() != TTHEN)
9567 synexpect(TTHEN);
9568 n2->nif.ifpart = list(0);
9569 }
9570 if (lasttoken == TELSE)
9571 n2->nif.elsepart = list(0);
9572 else {
9573 n2->nif.elsepart = NULL;
9574 tokpushback++;
9575 }
Eric Andersenc470f442003-07-28 09:56:35 +00009576 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009577 break;
9578 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009579 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009580 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009581 n1 = (union node *)stalloc(sizeof (struct nbinary));
9582 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009583 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009584 if ((got=readtoken()) != TDO) {
9585TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009586 synexpect(TDO);
9587 }
9588 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009589 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009590 break;
9591 }
9592 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009593 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009594 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009595 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009596 n1->type = NFOR;
9597 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009598 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009599 if (readtoken() == TIN) {
9600 app = &ap;
9601 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009602 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009603 n2->type = NARG;
9604 n2->narg.text = wordtext;
9605 n2->narg.backquote = backquotelist;
9606 *app = n2;
9607 app = &n2->narg.next;
9608 }
9609 *app = NULL;
9610 n1->nfor.args = ap;
9611 if (lasttoken != TNL && lasttoken != TSEMI)
9612 synexpect(-1);
9613 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009614 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009615 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009616 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009617 n2->narg.backquote = NULL;
9618 n2->narg.next = NULL;
9619 n1->nfor.args = n2;
9620 /*
9621 * Newline or semicolon here is optional (but note
9622 * that the original Bourne shell only allowed NL).
9623 */
9624 if (lasttoken != TNL && lasttoken != TSEMI)
9625 tokpushback++;
9626 }
Eric Andersenc470f442003-07-28 09:56:35 +00009627 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009628 if (readtoken() != TDO)
9629 synexpect(TDO);
9630 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009631 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009632 break;
9633 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009634 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009635 n1->type = NCASE;
9636 if (readtoken() != TWORD)
9637 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009638 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009639 n2->type = NARG;
9640 n2->narg.text = wordtext;
9641 n2->narg.backquote = backquotelist;
9642 n2->narg.next = NULL;
9643 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009644 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009645 } while (readtoken() == TNL);
9646 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009647 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009648 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009649next_case:
9650 checkkwd = CHKNL | CHKKWD;
9651 t = readtoken();
9652 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009653 if (lasttoken == TLP)
9654 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009655 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009656 cp->type = NCLIST;
9657 app = &cp->nclist.pattern;
9658 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009659 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009660 ap->type = NARG;
9661 ap->narg.text = wordtext;
9662 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009663 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009664 break;
9665 app = &ap->narg.next;
9666 readtoken();
9667 }
9668 ap->narg.next = NULL;
9669 if (lasttoken != TRP)
9670 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009671 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009672
Eric Andersenc470f442003-07-28 09:56:35 +00009673 cpp = &cp->nclist.next;
9674
9675 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009676 if ((t = readtoken()) != TESAC) {
9677 if (t != TENDCASE)
9678 synexpect(TENDCASE);
9679 else
Eric Andersenc470f442003-07-28 09:56:35 +00009680 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009681 }
Eric Andersenc470f442003-07-28 09:56:35 +00009682 }
Eric Andersencb57d552001-06-28 07:25:16 +00009683 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009684 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009685 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009686 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009687 n1->type = NSUBSHELL;
9688 n1->nredir.n = list(0);
9689 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009690 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009691 break;
9692 case TBEGIN:
9693 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009694 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009695 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009696 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009697 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009698 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009699 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009700 }
9701
Eric Andersenc470f442003-07-28 09:56:35 +00009702 if (readtoken() != t)
9703 synexpect(t);
9704
9705redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009706 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009707 checkkwd = CHKKWD | CHKALIAS;
9708 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009709 while (readtoken() == TREDIR) {
9710 *rpp = n2 = redirnode;
9711 rpp = &n2->nfile.next;
9712 parsefname();
9713 }
9714 tokpushback++;
9715 *rpp = NULL;
9716 if (redir) {
9717 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009718 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009719 n2->type = NREDIR;
9720 n2->nredir.n = n1;
9721 n1 = n2;
9722 }
9723 n1->nredir.redirect = redir;
9724 }
9725
9726 return n1;
9727}
9728
9729
Eric Andersenc470f442003-07-28 09:56:35 +00009730static union node *
9731simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009732 union node *args, **app;
9733 union node *n = NULL;
9734 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009735 union node **rpp, *redir;
9736 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009737
9738 args = NULL;
9739 app = &args;
9740 vars = NULL;
9741 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009742 redir = NULL;
9743 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009744
Eric Andersenc470f442003-07-28 09:56:35 +00009745 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009746 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009747 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009748 switch (readtoken()) {
9749 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009750 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009751 n->type = NARG;
9752 n->narg.text = wordtext;
9753 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009754 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009755 *vpp = n;
9756 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009757 } else {
9758 *app = n;
9759 app = &n->narg.next;
9760 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009761 }
9762 break;
9763 case TREDIR:
9764 *rpp = n = redirnode;
9765 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009766 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009767 break;
9768 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009769 if (
9770 args && app == &args->narg.next &&
9771 !vars && !redir
9772 ) {
9773 struct builtincmd *bcmd;
9774 const char *name;
9775
Eric Andersencb57d552001-06-28 07:25:16 +00009776 /* We have a function */
9777 if (readtoken() != TRP)
9778 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009779 name = n->narg.text;
9780 if (
9781 !goodname(name) || (
9782 (bcmd = find_builtin(name)) &&
9783 IS_BUILTIN_SPECIAL(bcmd)
9784 )
9785 )
9786 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009787 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009788 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009789 n->narg.next = command();
9790 return n;
9791 }
9792 /* fall through */
9793 default:
9794 tokpushback++;
9795 goto out;
9796 }
9797 }
Eric Andersenc470f442003-07-28 09:56:35 +00009798out:
Eric Andersencb57d552001-06-28 07:25:16 +00009799 *app = NULL;
9800 *vpp = NULL;
9801 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009802 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009803 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009804 n->ncmd.args = args;
9805 n->ncmd.assign = vars;
9806 n->ncmd.redirect = redir;
9807 return n;
9808}
9809
Eric Andersenc470f442003-07-28 09:56:35 +00009810static union node *
9811makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009812{
Eric Andersencb57d552001-06-28 07:25:16 +00009813 union node *n;
9814
Eric Andersenc470f442003-07-28 09:56:35 +00009815 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009816 n->type = NARG;
9817 n->narg.next = NULL;
9818 n->narg.text = wordtext;
9819 n->narg.backquote = backquotelist;
9820 return n;
9821}
9822
Eric Andersenc470f442003-07-28 09:56:35 +00009823void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009824{
Eric Andersencb57d552001-06-28 07:25:16 +00009825 TRACE(("Fix redir %s %d\n", text, err));
9826 if (!err)
9827 n->ndup.vname = NULL;
9828
9829 if (is_digit(text[0]) && text[1] == '\0')
9830 n->ndup.dupfd = digit_val(text[0]);
9831 else if (text[0] == '-' && text[1] == '\0')
9832 n->ndup.dupfd = -1;
9833 else {
9834
9835 if (err)
9836 synerror("Bad fd number");
9837 else
9838 n->ndup.vname = makename();
9839 }
9840}
9841
9842
Eric Andersenc470f442003-07-28 09:56:35 +00009843static void
9844parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009845{
Eric Andersencb57d552001-06-28 07:25:16 +00009846 union node *n = redirnode;
9847
9848 if (readtoken() != TWORD)
9849 synexpect(-1);
9850 if (n->type == NHERE) {
9851 struct heredoc *here = heredoc;
9852 struct heredoc *p;
9853 int i;
9854
9855 if (quoteflag == 0)
9856 n->type = NXHERE;
9857 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009858 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009859 synerror("Illegal eof marker for << redirection");
9860 rmescapes(wordtext);
9861 here->eofmark = wordtext;
9862 here->next = NULL;
9863 if (heredoclist == NULL)
9864 heredoclist = here;
9865 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009866 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009867 p->next = here;
9868 }
9869 } else if (n->type == NTOFD || n->type == NFROMFD) {
9870 fixredir(n, wordtext, 0);
9871 } else {
9872 n->nfile.fname = makename();
9873 }
9874}
9875
9876
9877/*
9878 * Input any here documents.
9879 */
9880
Eric Andersenc470f442003-07-28 09:56:35 +00009881static void
9882parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009883{
Eric Andersencb57d552001-06-28 07:25:16 +00009884 struct heredoc *here;
9885 union node *n;
9886
Eric Andersenc470f442003-07-28 09:56:35 +00009887 here = heredoclist;
9888 heredoclist = 0;
9889
9890 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009891 if (needprompt) {
9892 setprompt(2);
9893 needprompt = 0;
9894 }
Eric Andersenc470f442003-07-28 09:56:35 +00009895 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9896 here->eofmark, here->striptabs);
9897 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009898 n->narg.type = NARG;
9899 n->narg.next = NULL;
9900 n->narg.text = wordtext;
9901 n->narg.backquote = backquotelist;
9902 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009903 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009904 }
9905}
9906
Eric Andersenc470f442003-07-28 09:56:35 +00009907static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009908{
Eric Andersencb57d552001-06-28 07:25:16 +00009909 int t;
9910
9911 t = readtoken();
9912 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009913 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009914}
9915
Eric Andersenc470f442003-07-28 09:56:35 +00009916static int
9917readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009918{
Eric Andersencb57d552001-06-28 07:25:16 +00009919 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009920#ifdef DEBUG
9921 int alreadyseen = tokpushback;
9922#endif
9923
Eric Andersend35c5df2002-01-09 15:37:36 +00009924#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009925top:
Eric Andersen2870d962001-07-02 17:27:21 +00009926#endif
9927
Eric Andersencb57d552001-06-28 07:25:16 +00009928 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009929
Eric Andersenc470f442003-07-28 09:56:35 +00009930 /*
9931 * eat newlines
9932 */
9933 if (checkkwd & CHKNL) {
9934 while (t == TNL) {
9935 parseheredoc();
9936 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009937 }
9938 }
9939
Eric Andersenc470f442003-07-28 09:56:35 +00009940 if (t != TWORD || quoteflag) {
9941 goto out;
9942 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009943
Eric Andersenc470f442003-07-28 09:56:35 +00009944 /*
9945 * check for keywords
9946 */
9947 if (checkkwd & CHKKWD) {
9948 const char *const *pp;
9949
9950 if ((pp = findkwd(wordtext))) {
9951 lasttoken = t = pp - tokname_array;
9952 TRACE(("keyword %s recognized\n", tokname(t)));
9953 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009954 }
Eric Andersenc470f442003-07-28 09:56:35 +00009955 }
9956
9957 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009958#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009959 struct alias *ap;
9960 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009961 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009962 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009963 }
Eric Andersencb57d552001-06-28 07:25:16 +00009964 goto top;
9965 }
Eric Andersen2870d962001-07-02 17:27:21 +00009966#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009967 }
Eric Andersenc470f442003-07-28 09:56:35 +00009968out:
9969 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009970#ifdef DEBUG
9971 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009972 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009973 else
Eric Andersenc470f442003-07-28 09:56:35 +00009974 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009975#endif
9976 return (t);
9977}
9978
9979
9980/*
9981 * Read the next input token.
9982 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009983 * backquotes. We set quoteflag to true if any part of the word was
9984 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009985 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009986 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009987 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009988 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009989 *
9990 * [Change comment: here documents and internal procedures]
9991 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9992 * word parsing code into a separate routine. In this case, readtoken
9993 * doesn't need to have any internal procedures, but parseword does.
9994 * We could also make parseoperator in essence the main routine, and
9995 * have parseword (readtoken1?) handle both words and redirection.]
9996 */
9997
Eric Andersen81fe1232003-07-29 06:38:40 +00009998#define NEW_xxreadtoken
9999#ifdef NEW_xxreadtoken
10000
10001/* singles must be first! */
10002static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10003
10004static const char xxreadtoken_tokens[] = {
10005 TNL, TLP, TRP, /* only single occurrence allowed */
10006 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10007 TEOF, /* corresponds to trailing nul */
10008 TAND, TOR, TENDCASE, /* if double occurrence */
10009};
10010
10011#define xxreadtoken_doubles \
10012 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10013#define xxreadtoken_singles \
10014 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10015
10016static int xxreadtoken()
10017{
10018 int c;
10019
10020 if (tokpushback) {
10021 tokpushback = 0;
10022 return lasttoken;
10023 }
10024 if (needprompt) {
10025 setprompt(2);
10026 needprompt = 0;
10027 }
10028 startlinno = plinno;
10029 for (;;) { /* until token or start of word found */
10030 c = pgetc_macro();
10031
10032 if ((c != ' ') && (c != '\t')
10033#ifdef CONFIG_ASH_ALIAS
10034 && (c != PEOA)
10035#endif
10036 ) {
10037 if (c == '#') {
10038 while ((c = pgetc()) != '\n' && c != PEOF);
10039 pungetc();
10040 } else if (c == '\\') {
10041 if (pgetc() != '\n') {
10042 pungetc();
10043 goto READTOKEN1;
10044 }
10045 startlinno = ++plinno;
10046 if (doprompt)
10047 setprompt(2);
10048 } else {
10049 const char *p
10050 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10051
10052 if (c != PEOF) {
10053 if (c == '\n') {
10054 plinno++;
10055 needprompt = doprompt;
10056 }
10057
10058 p = strchr(xxreadtoken_chars, c);
10059 if (p == NULL) {
10060 READTOKEN1:
10061 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10062 }
10063
10064 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10065 if (pgetc() == *p) { /* double occurrence? */
10066 p += xxreadtoken_doubles + 1;
10067 } else {
10068 pungetc();
10069 }
10070 }
10071 }
10072
10073 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10074 }
10075 }
10076 }
10077}
10078
10079
10080#else
Eric Andersen2870d962001-07-02 17:27:21 +000010081#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010082
Eric Andersenc470f442003-07-28 09:56:35 +000010083static int
10084xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010085{
Eric Andersencb57d552001-06-28 07:25:16 +000010086 int c;
10087
10088 if (tokpushback) {
10089 tokpushback = 0;
10090 return lasttoken;
10091 }
10092 if (needprompt) {
10093 setprompt(2);
10094 needprompt = 0;
10095 }
10096 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010097 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010098 c = pgetc_macro();
10099 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010100 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010101#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010102 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010103#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010104 continue;
10105 case '#':
10106 while ((c = pgetc()) != '\n' && c != PEOF);
10107 pungetc();
10108 continue;
10109 case '\\':
10110 if (pgetc() == '\n') {
10111 startlinno = ++plinno;
10112 if (doprompt)
10113 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010114 continue;
10115 }
10116 pungetc();
10117 goto breakloop;
10118 case '\n':
10119 plinno++;
10120 needprompt = doprompt;
10121 RETURN(TNL);
10122 case PEOF:
10123 RETURN(TEOF);
10124 case '&':
10125 if (pgetc() == '&')
10126 RETURN(TAND);
10127 pungetc();
10128 RETURN(TBACKGND);
10129 case '|':
10130 if (pgetc() == '|')
10131 RETURN(TOR);
10132 pungetc();
10133 RETURN(TPIPE);
10134 case ';':
10135 if (pgetc() == ';')
10136 RETURN(TENDCASE);
10137 pungetc();
10138 RETURN(TSEMI);
10139 case '(':
10140 RETURN(TLP);
10141 case ')':
10142 RETURN(TRP);
10143 default:
10144 goto breakloop;
10145 }
10146 }
Eric Andersenc470f442003-07-28 09:56:35 +000010147breakloop:
10148 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010149#undef RETURN
10150}
Eric Andersen81fe1232003-07-29 06:38:40 +000010151#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010152
Eric Andersencb57d552001-06-28 07:25:16 +000010153
Eric Andersencb57d552001-06-28 07:25:16 +000010154/*
10155 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10156 * is not NULL, read a here document. In the latter case, eofmark is the
10157 * word which marks the end of the document and striptabs is true if
10158 * leading tabs should be stripped from the document. The argument firstc
10159 * is the first character of the input token or document.
10160 *
10161 * Because C does not have internal subroutines, I have simulated them
10162 * using goto's to implement the subroutine linkage. The following macros
10163 * will run code that appears at the end of readtoken1.
10164 */
10165
Eric Andersen2870d962001-07-02 17:27:21 +000010166#define CHECKEND() {goto checkend; checkend_return:;}
10167#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10168#define PARSESUB() {goto parsesub; parsesub_return:;}
10169#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10170#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10171#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010172
10173static int
Eric Andersenc470f442003-07-28 09:56:35 +000010174readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010175{
Eric Andersencb57d552001-06-28 07:25:16 +000010176 int c = firstc;
10177 char *out;
10178 int len;
10179 char line[EOFMARKLEN + 1];
10180 struct nodelist *bqlist;
10181 int quotef;
10182 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010183 int varnest; /* levels of variables expansion */
10184 int arinest; /* levels of arithmetic expansion */
10185 int parenlevel; /* levels of parens in arithmetic */
10186 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010187 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010188 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010189#if __GNUC__
10190 /* Avoid longjmp clobbering */
10191 (void) &out;
10192 (void) &quotef;
10193 (void) &dblquote;
10194 (void) &varnest;
10195 (void) &arinest;
10196 (void) &parenlevel;
10197 (void) &dqvarnest;
10198 (void) &oldstyle;
10199 (void) &prevsyntax;
10200 (void) &syntax;
10201#endif
10202
10203 startlinno = plinno;
10204 dblquote = 0;
10205 if (syntax == DQSYNTAX)
10206 dblquote = 1;
10207 quotef = 0;
10208 bqlist = NULL;
10209 varnest = 0;
10210 arinest = 0;
10211 parenlevel = 0;
10212 dqvarnest = 0;
10213
10214 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010215 loop: { /* for each line, until end of word */
10216 CHECKEND(); /* set c to PEOF if at end of here document */
10217 for (;;) { /* until end of line or end of word */
10218 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10219 switch(SIT(c, syntax)) {
10220 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010221 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010222 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010223 USTPUTC(c, out);
10224 plinno++;
10225 if (doprompt)
10226 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010227 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010228 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010229 case CWORD:
10230 USTPUTC(c, out);
10231 break;
10232 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010233 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010234 USTPUTC(CTLESC, out);
10235 USTPUTC(c, out);
10236 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010237 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010238 c = pgetc2();
10239 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010240 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010241 USTPUTC('\\', out);
10242 pungetc();
10243 } else if (c == '\n') {
10244 if (doprompt)
10245 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010246 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010247 if (
10248 dblquote &&
10249 c != '\\' && c != '`' &&
10250 c != '$' && (
10251 c != '"' ||
10252 eofmark != NULL
10253 )
10254 ) {
10255 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010256 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010257 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010258 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010259 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010260 USTPUTC(c, out);
10261 quotef++;
10262 }
10263 break;
10264 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010265 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010266quotemark:
10267 if (eofmark == NULL) {
10268 USTPUTC(CTLQUOTEMARK, out);
10269 }
Eric Andersencb57d552001-06-28 07:25:16 +000010270 break;
10271 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010272 syntax = DQSYNTAX;
10273 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010274 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010275 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010276 if (eofmark != NULL && arinest == 0 &&
10277 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010278 USTPUTC(c, out);
10279 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010280 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010281 syntax = BASESYNTAX;
10282 dblquote = 0;
10283 }
10284 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010285 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010286 }
10287 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010288 case CVAR: /* '$' */
10289 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010290 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010291 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010292 if (varnest > 0) {
10293 varnest--;
10294 if (dqvarnest > 0) {
10295 dqvarnest--;
10296 }
10297 USTPUTC(CTLENDVAR, out);
10298 } else {
10299 USTPUTC(c, out);
10300 }
10301 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010302#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010303 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010304 parenlevel++;
10305 USTPUTC(c, out);
10306 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010307 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010308 if (parenlevel > 0) {
10309 USTPUTC(c, out);
10310 --parenlevel;
10311 } else {
10312 if (pgetc() == ')') {
10313 if (--arinest == 0) {
10314 USTPUTC(CTLENDARI, out);
10315 syntax = prevsyntax;
10316 if (syntax == DQSYNTAX)
10317 dblquote = 1;
10318 else
10319 dblquote = 0;
10320 } else
10321 USTPUTC(')', out);
10322 } else {
10323 /*
10324 * unbalanced parens
10325 * (don't 2nd guess - no error)
10326 */
10327 pungetc();
10328 USTPUTC(')', out);
10329 }
10330 }
10331 break;
10332#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010333 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010334 PARSEBACKQOLD();
10335 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010336 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010337 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010338 case CIGN:
10339 break;
10340 default:
10341 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010342 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010343#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010344 if (c != PEOA)
10345#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010346 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010347
Eric Andersencb57d552001-06-28 07:25:16 +000010348 }
10349 c = pgetc_macro();
10350 }
10351 }
Eric Andersenc470f442003-07-28 09:56:35 +000010352endword:
10353#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010354 if (syntax == ARISYNTAX)
10355 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010356#endif
10357 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010358 synerror("Unterminated quoted string");
10359 if (varnest != 0) {
10360 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010361 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010362 synerror("Missing '}'");
10363 }
10364 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010365 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010366 out = stackblock();
10367 if (eofmark == NULL) {
10368 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010369 && quotef == 0
10370 && len <= 2
10371 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010372 PARSEREDIR();
10373 return lasttoken = TREDIR;
10374 } else {
10375 pungetc();
10376 }
10377 }
10378 quoteflag = quotef;
10379 backquotelist = bqlist;
10380 grabstackblock(len);
10381 wordtext = out;
10382 return lasttoken = TWORD;
10383/* end of readtoken routine */
10384
10385
10386
10387/*
10388 * Check to see whether we are at the end of the here document. When this
10389 * is called, c is set to the first character of the next input line. If
10390 * we are at the end of the here document, this routine sets the c to PEOF.
10391 */
10392
Eric Andersenc470f442003-07-28 09:56:35 +000010393checkend: {
10394 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010395#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010396 if (c == PEOA) {
10397 c = pgetc2();
10398 }
10399#endif
10400 if (striptabs) {
10401 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010402 c = pgetc2();
10403 }
Eric Andersenc470f442003-07-28 09:56:35 +000010404 }
10405 if (c == *eofmark) {
10406 if (pfgets(line, sizeof line) != NULL) {
10407 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010408
Eric Andersenc470f442003-07-28 09:56:35 +000010409 p = line;
10410 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10411 if (*p == '\n' && *q == '\0') {
10412 c = PEOF;
10413 plinno++;
10414 needprompt = doprompt;
10415 } else {
10416 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010417 }
10418 }
10419 }
10420 }
Eric Andersenc470f442003-07-28 09:56:35 +000010421 goto checkend_return;
10422}
Eric Andersencb57d552001-06-28 07:25:16 +000010423
10424
10425/*
10426 * Parse a redirection operator. The variable "out" points to a string
10427 * specifying the fd to be redirected. The variable "c" contains the
10428 * first character of the redirection operator.
10429 */
10430
Eric Andersenc470f442003-07-28 09:56:35 +000010431parseredir: {
10432 char fd = *out;
10433 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010434
Eric Andersenc470f442003-07-28 09:56:35 +000010435 np = (union node *)stalloc(sizeof (struct nfile));
10436 if (c == '>') {
10437 np->nfile.fd = 1;
10438 c = pgetc();
10439 if (c == '>')
10440 np->type = NAPPEND;
10441 else if (c == '|')
10442 np->type = NCLOBBER;
10443 else if (c == '&')
10444 np->type = NTOFD;
10445 else {
10446 np->type = NTO;
10447 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010448 }
Eric Andersenc470f442003-07-28 09:56:35 +000010449 } else { /* c == '<' */
10450 np->nfile.fd = 0;
10451 switch (c = pgetc()) {
10452 case '<':
10453 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10454 np = (union node *)stalloc(sizeof (struct nhere));
10455 np->nfile.fd = 0;
10456 }
10457 np->type = NHERE;
10458 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10459 heredoc->here = np;
10460 if ((c = pgetc()) == '-') {
10461 heredoc->striptabs = 1;
10462 } else {
10463 heredoc->striptabs = 0;
10464 pungetc();
10465 }
10466 break;
10467
10468 case '&':
10469 np->type = NFROMFD;
10470 break;
10471
10472 case '>':
10473 np->type = NFROMTO;
10474 break;
10475
10476 default:
10477 np->type = NFROM;
10478 pungetc();
10479 break;
10480 }
Eric Andersencb57d552001-06-28 07:25:16 +000010481 }
Eric Andersenc470f442003-07-28 09:56:35 +000010482 if (fd != '\0')
10483 np->nfile.fd = digit_val(fd);
10484 redirnode = np;
10485 goto parseredir_return;
10486}
Eric Andersencb57d552001-06-28 07:25:16 +000010487
10488
10489/*
10490 * Parse a substitution. At this point, we have read the dollar sign
10491 * and nothing else.
10492 */
10493
Eric Andersenc470f442003-07-28 09:56:35 +000010494parsesub: {
10495 int subtype;
10496 int typeloc;
10497 int flags;
10498 char *p;
10499 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010500
Eric Andersenc470f442003-07-28 09:56:35 +000010501 c = pgetc();
10502 if (
10503 c <= PEOA_OR_PEOF ||
10504 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10505 ) {
10506 USTPUTC('$', out);
10507 pungetc();
10508 } else if (c == '(') { /* $(command) or $((arith)) */
10509 if (pgetc() == '(') {
10510#ifdef CONFIG_ASH_MATH_SUPPORT
10511 PARSEARITH();
10512#else
10513 synerror("We unsupport $((arith))");
10514#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010515 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010516 pungetc();
10517 PARSEBACKQNEW();
10518 }
10519 } else {
10520 USTPUTC(CTLVAR, out);
10521 typeloc = out - (char *)stackblock();
10522 USTPUTC(VSNORMAL, out);
10523 subtype = VSNORMAL;
10524 if (c == '{') {
10525 c = pgetc();
10526 if (c == '#') {
10527 if ((c = pgetc()) == '}')
10528 c = '#';
10529 else
10530 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010531 }
Eric Andersenc470f442003-07-28 09:56:35 +000010532 else
10533 subtype = 0;
10534 }
10535 if (c > PEOA_OR_PEOF && is_name(c)) {
10536 do {
10537 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010538 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010539 } while (c > PEOA_OR_PEOF && is_in_name(c));
10540 } else if (is_digit(c)) {
10541 do {
10542 STPUTC(c, out);
10543 c = pgetc();
10544 } while (is_digit(c));
10545 }
10546 else if (is_special(c)) {
10547 USTPUTC(c, out);
10548 c = pgetc();
10549 }
10550 else
10551badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010552
Eric Andersenc470f442003-07-28 09:56:35 +000010553 STPUTC('=', out);
10554 flags = 0;
10555 if (subtype == 0) {
10556 switch (c) {
10557 case ':':
10558 flags = VSNUL;
10559 c = pgetc();
10560 /*FALLTHROUGH*/
10561 default:
10562 p = strchr(types, c);
10563 if (p == NULL)
10564 goto badsub;
10565 subtype = p - types + VSNORMAL;
10566 break;
10567 case '%':
10568 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010569 {
10570 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010571 subtype = c == '#' ? VSTRIMLEFT :
10572 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010573 c = pgetc();
10574 if (c == cc)
10575 subtype++;
10576 else
10577 pungetc();
10578 break;
10579 }
10580 }
Eric Andersenc470f442003-07-28 09:56:35 +000010581 } else {
10582 pungetc();
10583 }
10584 if (dblquote || arinest)
10585 flags |= VSQUOTE;
10586 *((char *)stackblock() + typeloc) = subtype | flags;
10587 if (subtype != VSNORMAL) {
10588 varnest++;
10589 if (dblquote || arinest) {
10590 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010591 }
10592 }
10593 }
Eric Andersenc470f442003-07-28 09:56:35 +000010594 goto parsesub_return;
10595}
Eric Andersencb57d552001-06-28 07:25:16 +000010596
10597
10598/*
10599 * Called to parse command substitutions. Newstyle is set if the command
10600 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10601 * list of commands (passed by reference), and savelen is the number of
10602 * characters on the top of the stack which must be preserved.
10603 */
10604
Eric Andersenc470f442003-07-28 09:56:35 +000010605parsebackq: {
10606 struct nodelist **nlpp;
10607 int savepbq;
10608 union node *n;
10609 char *volatile str;
10610 struct jmploc jmploc;
10611 struct jmploc *volatile savehandler;
10612 size_t savelen;
10613 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010614#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010615 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010616#endif
10617
Eric Andersenc470f442003-07-28 09:56:35 +000010618 savepbq = parsebackquote;
10619 if (setjmp(jmploc.loc)) {
10620 if (str)
10621 ckfree(str);
10622 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010623 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010624 longjmp(handler->loc, 1);
10625 }
10626 INTOFF;
10627 str = NULL;
10628 savelen = out - (char *)stackblock();
10629 if (savelen > 0) {
10630 str = ckmalloc(savelen);
10631 memcpy(str, stackblock(), savelen);
10632 }
10633 savehandler = handler;
10634 handler = &jmploc;
10635 INTON;
10636 if (oldstyle) {
10637 /* We must read until the closing backquote, giving special
10638 treatment to some slashes, and then push the string and
10639 reread it as input, interpreting it normally. */
10640 char *pout;
10641 int pc;
10642 size_t psavelen;
10643 char *pstr;
10644
10645
10646 STARTSTACKSTR(pout);
10647 for (;;) {
10648 if (needprompt) {
10649 setprompt(2);
10650 needprompt = 0;
10651 }
10652 switch (pc = pgetc()) {
10653 case '`':
10654 goto done;
10655
10656 case '\\':
10657 if ((pc = pgetc()) == '\n') {
10658 plinno++;
10659 if (doprompt)
10660 setprompt(2);
10661 /*
10662 * If eating a newline, avoid putting
10663 * the newline into the new character
10664 * stream (via the STPUTC after the
10665 * switch).
10666 */
10667 continue;
10668 }
10669 if (pc != '\\' && pc != '`' && pc != '$'
10670 && (!dblquote || pc != '"'))
10671 STPUTC('\\', pout);
10672 if (pc > PEOA_OR_PEOF) {
10673 break;
10674 }
10675 /* fall through */
10676
10677 case PEOF:
10678#ifdef CONFIG_ASH_ALIAS
10679 case PEOA:
10680#endif
10681 startlinno = plinno;
10682 synerror("EOF in backquote substitution");
10683
10684 case '\n':
10685 plinno++;
10686 needprompt = doprompt;
10687 break;
10688
10689 default:
10690 break;
10691 }
10692 STPUTC(pc, pout);
10693 }
10694done:
10695 STPUTC('\0', pout);
10696 psavelen = pout - (char *)stackblock();
10697 if (psavelen > 0) {
10698 pstr = grabstackstr(pout);
10699 setinputstring(pstr);
10700 }
10701 }
10702 nlpp = &bqlist;
10703 while (*nlpp)
10704 nlpp = &(*nlpp)->next;
10705 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10706 (*nlpp)->next = NULL;
10707 parsebackquote = oldstyle;
10708
10709 if (oldstyle) {
10710 saveprompt = doprompt;
10711 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010712 }
10713
Eric Andersenc470f442003-07-28 09:56:35 +000010714 n = list(2);
10715
10716 if (oldstyle)
10717 doprompt = saveprompt;
10718 else {
10719 if (readtoken() != TRP)
10720 synexpect(TRP);
10721 }
10722
10723 (*nlpp)->n = n;
10724 if (oldstyle) {
10725 /*
10726 * Start reading from old file again, ignoring any pushed back
10727 * tokens left from the backquote parsing
10728 */
10729 popfile();
10730 tokpushback = 0;
10731 }
10732 while (stackblocksize() <= savelen)
10733 growstackblock();
10734 STARTSTACKSTR(out);
10735 if (str) {
10736 memcpy(out, str, savelen);
10737 STADJUST(savelen, out);
10738 INTOFF;
10739 ckfree(str);
10740 str = NULL;
10741 INTON;
10742 }
10743 parsebackquote = savepbq;
10744 handler = savehandler;
10745 if (arinest || dblquote)
10746 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10747 else
10748 USTPUTC(CTLBACKQ, out);
10749 if (oldstyle)
10750 goto parsebackq_oldreturn;
10751 else
10752 goto parsebackq_newreturn;
10753}
10754
10755#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010756/*
10757 * Parse an arithmetic expansion (indicate start of one and set state)
10758 */
Eric Andersenc470f442003-07-28 09:56:35 +000010759parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010760
Eric Andersenc470f442003-07-28 09:56:35 +000010761 if (++arinest == 1) {
10762 prevsyntax = syntax;
10763 syntax = ARISYNTAX;
10764 USTPUTC(CTLARI, out);
10765 if (dblquote)
10766 USTPUTC('"',out);
10767 else
10768 USTPUTC(' ',out);
10769 } else {
10770 /*
10771 * we collapse embedded arithmetic expansion to
10772 * parenthesis, which should be equivalent
10773 */
10774 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010775 }
Eric Andersenc470f442003-07-28 09:56:35 +000010776 goto parsearith_return;
10777}
10778#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010779
Eric Andersenc470f442003-07-28 09:56:35 +000010780} /* end of readtoken */
10781
Eric Andersencb57d552001-06-28 07:25:16 +000010782
10783
Eric Andersencb57d552001-06-28 07:25:16 +000010784/*
10785 * Returns true if the text contains nothing to expand (no dollar signs
10786 * or backquotes).
10787 */
10788
Eric Andersenc470f442003-07-28 09:56:35 +000010789static int
10790noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010791{
Eric Andersencb57d552001-06-28 07:25:16 +000010792 char *p;
10793 char c;
10794
10795 p = text;
10796 while ((c = *p++) != '\0') {
10797 if (c == CTLQUOTEMARK)
10798 continue;
10799 if (c == CTLESC)
10800 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010801 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010802 return 0;
10803 }
10804 return 1;
10805}
10806
10807
10808/*
Eric Andersenc470f442003-07-28 09:56:35 +000010809 * Return of a legal variable name (a letter or underscore followed by zero or
10810 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010811 */
10812
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010813static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010814endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010815{
Eric Andersenc470f442003-07-28 09:56:35 +000010816 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010817
Eric Andersenc470f442003-07-28 09:56:35 +000010818 p = (char *) name;
10819 if (! is_name(*p))
10820 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010821 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010822 if (! is_in_name(*p))
10823 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010824 }
Eric Andersenc470f442003-07-28 09:56:35 +000010825 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010826}
10827
10828
10829/*
10830 * Called when an unexpected token is read during the parse. The argument
10831 * is the token that is expected, or -1 if more than one type of token can
10832 * occur at this point.
10833 */
10834
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010835static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010836{
10837 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010838 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010839
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010840 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10841 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010842 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010843 synerror(msg);
10844 /* NOTREACHED */
10845}
10846
Eric Andersenc470f442003-07-28 09:56:35 +000010847static void
10848synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010849{
Eric Andersenc470f442003-07-28 09:56:35 +000010850 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010851 /* NOTREACHED */
10852}
10853
Eric Andersencb57d552001-06-28 07:25:16 +000010854
10855/*
10856 * called by editline -- any expansions to the prompt
10857 * should be added here.
10858 */
Eric Andersenc470f442003-07-28 09:56:35 +000010859
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010860static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010861{
Eric Andersenc470f442003-07-28 09:56:35 +000010862 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010863
10864 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010865 case 1:
10866 prompt = ps1val();
10867 break;
10868 case 2:
10869 prompt = ps2val();
10870 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010871 default: /* 0 */
10872 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010873 }
10874 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010875}
10876
Eric Andersencb57d552001-06-28 07:25:16 +000010877
Eric Andersenc470f442003-07-28 09:56:35 +000010878static const char *const *findkwd(const char *s)
10879{
10880 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010881 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010882 sizeof(const char *), pstrcmp);
10883}
10884
10885/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10886
Eric Andersencb57d552001-06-28 07:25:16 +000010887/*
10888 * Code for dealing with input/output redirection.
10889 */
10890
Eric Andersenc470f442003-07-28 09:56:35 +000010891#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010892#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010893# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010894#else
10895# define PIPESIZE PIPE_BUF
10896#endif
10897
Eric Andersen62483552001-07-10 06:09:16 +000010898/*
10899 * Open a file in noclobber mode.
10900 * The code was copied from bash.
10901 */
Eric Andersenc470f442003-07-28 09:56:35 +000010902static inline int
10903noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010904{
10905 int r, fd;
10906 struct stat finfo, finfo2;
10907
10908 /*
10909 * If the file exists and is a regular file, return an error
10910 * immediately.
10911 */
10912 r = stat(fname, &finfo);
10913 if (r == 0 && S_ISREG(finfo.st_mode)) {
10914 errno = EEXIST;
10915 return -1;
10916 }
10917
10918 /*
10919 * If the file was not present (r != 0), make sure we open it
10920 * exclusively so that if it is created before we open it, our open
10921 * will fail. Make sure that we do not truncate an existing file.
10922 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10923 * file was not a regular file, we leave O_EXCL off.
10924 */
10925 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010926 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10927 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010928
10929 /* If the open failed, return the file descriptor right away. */
10930 if (fd < 0)
10931 return fd;
10932
10933 /*
10934 * OK, the open succeeded, but the file may have been changed from a
10935 * non-regular file to a regular file between the stat and the open.
10936 * We are assuming that the O_EXCL open handles the case where FILENAME
10937 * did not exist and is symlinked to an existing file between the stat
10938 * and open.
10939 */
10940
10941 /*
10942 * If we can open it and fstat the file descriptor, and neither check
10943 * revealed that it was a regular file, and the file has not been
10944 * replaced, return the file descriptor.
10945 */
Eric Andersenc470f442003-07-28 09:56:35 +000010946 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10947 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010948 return fd;
10949
10950 /* The file has been replaced. badness. */
10951 close(fd);
10952 errno = EEXIST;
10953 return -1;
10954}
Eric Andersencb57d552001-06-28 07:25:16 +000010955
10956/*
Eric Andersen62483552001-07-10 06:09:16 +000010957 * Handle here documents. Normally we fork off a process to write the
10958 * data to a pipe. If the document is short, we can stuff the data in
10959 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010960 */
10961
Eric Andersenc470f442003-07-28 09:56:35 +000010962static inline int
10963openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010964{
10965 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010966 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010967
Eric Andersen62483552001-07-10 06:09:16 +000010968 if (pipe(pip) < 0)
10969 error("Pipe call failed");
10970 if (redir->type == NHERE) {
10971 len = strlen(redir->nhere.doc->narg.text);
10972 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010973 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010974 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010975 }
Eric Andersencb57d552001-06-28 07:25:16 +000010976 }
Eric Andersenc470f442003-07-28 09:56:35 +000010977 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010978 close(pip[0]);
10979 signal(SIGINT, SIG_IGN);
10980 signal(SIGQUIT, SIG_IGN);
10981 signal(SIGHUP, SIG_IGN);
10982#ifdef SIGTSTP
10983 signal(SIGTSTP, SIG_IGN);
10984#endif
10985 signal(SIGPIPE, SIG_DFL);
10986 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000010987 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010988 else
10989 expandhere(redir->nhere.doc, pip[1]);
10990 _exit(0);
10991 }
Eric Andersenc470f442003-07-28 09:56:35 +000010992out:
Eric Andersen62483552001-07-10 06:09:16 +000010993 close(pip[1]);
10994 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010995}
10996
Eric Andersenc470f442003-07-28 09:56:35 +000010997static int
10998openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010999{
Eric Andersencb57d552001-06-28 07:25:16 +000011000 char *fname;
11001 int f;
11002
11003 switch (redir->nfile.type) {
11004 case NFROM:
11005 fname = redir->nfile.expfname;
11006 if ((f = open(fname, O_RDONLY)) < 0)
11007 goto eopen;
11008 break;
11009 case NFROMTO:
11010 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011011 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011012 goto ecreate;
11013 break;
11014 case NTO:
11015 /* Take care of noclobber mode. */
11016 if (Cflag) {
11017 fname = redir->nfile.expfname;
11018 if ((f = noclobberopen(fname)) < 0)
11019 goto ecreate;
11020 break;
11021 }
Eric Andersenc470f442003-07-28 09:56:35 +000011022 /* FALLTHROUGH */
11023 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011024 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011025 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011026 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011027 break;
11028 case NAPPEND:
11029 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011030 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011031 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011032 break;
11033 default:
11034#ifdef DEBUG
11035 abort();
11036#endif
11037 /* Fall through to eliminate warning. */
11038 case NTOFD:
11039 case NFROMFD:
11040 f = -1;
11041 break;
11042 case NHERE:
11043 case NXHERE:
11044 f = openhere(redir);
11045 break;
11046 }
11047
11048 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011049ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011050 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011051eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011052 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11053}
11054
Eric Andersenc470f442003-07-28 09:56:35 +000011055static inline void
11056dupredirect(union node *redir, int f)
11057{
11058 int fd = redir->nfile.fd;
11059
11060 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11061 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11062 copyfd(redir->ndup.dupfd, fd);
11063 }
11064 return;
11065 }
11066
11067 if (f != fd) {
11068 copyfd(f, fd);
11069 close(f);
11070 }
11071 return;
11072}
Eric Andersencb57d552001-06-28 07:25:16 +000011073
Eric Andersen62483552001-07-10 06:09:16 +000011074/*
11075 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11076 * old file descriptors are stashed away so that the redirection can be
11077 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11078 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011079 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011080 */
11081
Eric Andersenc470f442003-07-28 09:56:35 +000011082static void
11083redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011084{
11085 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011086 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011087 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011088 int fd;
11089 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011090 int *p;
11091 nullredirs++;
11092 if (!redir) {
11093 return;
Eric Andersen62483552001-07-10 06:09:16 +000011094 }
Eric Andersenc470f442003-07-28 09:56:35 +000011095 sv = NULL;
11096 INTOFF;
11097 if (flags & REDIR_PUSH) {
11098 struct redirtab *q;
11099 q = ckmalloc(sizeof (struct redirtab));
11100 q->next = redirlist;
11101 redirlist = q;
11102 q->nullredirs = nullredirs - 1;
11103 for (i = 0 ; i < 10 ; i++)
11104 q->renamed[i] = EMPTY;
11105 nullredirs = 0;
11106 sv = q;
11107 }
11108 n = redir;
11109 do {
Eric Andersen62483552001-07-10 06:09:16 +000011110 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011111 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011112 n->ndup.dupfd == fd)
11113 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011114
Eric Andersen62483552001-07-10 06:09:16 +000011115 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011116 if (fd == newfd)
11117 continue;
11118 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11119 i = fcntl(fd, F_DUPFD, 10);
11120
11121 if (i == -1) {
11122 i = errno;
11123 if (i != EBADF) {
11124 close(newfd);
11125 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011126 error("%d: %m", fd);
11127 /* NOTREACHED */
11128 }
Eric Andersenc470f442003-07-28 09:56:35 +000011129 } else {
11130 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011131 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011132 }
Eric Andersenc470f442003-07-28 09:56:35 +000011133 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011134 close(fd);
11135 }
Eric Andersenc470f442003-07-28 09:56:35 +000011136 dupredirect(n, newfd);
11137 } while ((n = n->nfile.next));
11138 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011139 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11140 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011141}
11142
11143
Eric Andersencb57d552001-06-28 07:25:16 +000011144/*
11145 * Undo the effects of the last redirection.
11146 */
11147
Eric Andersenc470f442003-07-28 09:56:35 +000011148void
11149popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011150{
Eric Andersenc470f442003-07-28 09:56:35 +000011151 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011152 int i;
11153
Eric Andersenc470f442003-07-28 09:56:35 +000011154 if (--nullredirs >= 0)
11155 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011156 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011157 rp = redirlist;
11158 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011159 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011160 if (!drop) {
11161 close(i);
11162 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011163 }
Eric Andersenc470f442003-07-28 09:56:35 +000011164 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011165 }
11166 }
11167 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011168 nullredirs = rp->nullredirs;
11169 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011170 INTON;
11171}
11172
11173/*
Eric Andersenc470f442003-07-28 09:56:35 +000011174 * Undo all redirections. Called on error or interrupt.
11175 */
11176
11177/*
Eric Andersencb57d552001-06-28 07:25:16 +000011178 * Discard all saved file descriptors.
11179 */
11180
Eric Andersenc470f442003-07-28 09:56:35 +000011181void
11182clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011183{
Eric Andersenc470f442003-07-28 09:56:35 +000011184 for (;;) {
11185 nullredirs = 0;
11186 if (!redirlist)
11187 break;
11188 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011189 }
Eric Andersencb57d552001-06-28 07:25:16 +000011190}
11191
11192
Eric Andersencb57d552001-06-28 07:25:16 +000011193/*
11194 * Copy a file descriptor to be >= to. Returns -1
11195 * if the source file descriptor is closed, EMPTY if there are no unused
11196 * file descriptors left.
11197 */
11198
Eric Andersenc470f442003-07-28 09:56:35 +000011199int
11200copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011201{
11202 int newfd;
11203
11204 newfd = fcntl(from, F_DUPFD, to);
11205 if (newfd < 0) {
11206 if (errno == EMFILE)
11207 return EMPTY;
11208 else
Eric Andersen2870d962001-07-02 17:27:21 +000011209 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011210 }
11211 return newfd;
11212}
11213
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011214
Eric Andersenc470f442003-07-28 09:56:35 +000011215int
11216redirectsafe(union node *redir, int flags)
11217{
11218 int err;
11219 volatile int saveint;
11220 struct jmploc *volatile savehandler = handler;
11221 struct jmploc jmploc;
11222
11223 SAVEINT(saveint);
11224 if (!(err = setjmp(jmploc.loc) * 2)) {
11225 handler = &jmploc;
11226 redirect(redir, flags);
11227 }
11228 handler = savehandler;
11229 if (err && exception != EXERROR)
11230 longjmp(handler->loc, 1);
11231 RESTOREINT(saveint);
11232 return err;
11233}
11234
11235/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11236
11237#ifdef DEBUG
11238static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011239static void shcmd(union node *, FILE *);
11240static void sharg(union node *, FILE *);
11241static void indent(int, char *, FILE *);
11242static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011243
11244
Eric Andersenc470f442003-07-28 09:56:35 +000011245void
11246showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011247{
11248 trputs("showtree called\n");
11249 shtree(n, 1, NULL, stdout);
11250}
Eric Andersencb57d552001-06-28 07:25:16 +000011251
Eric Andersenc470f442003-07-28 09:56:35 +000011252
11253static void
11254shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011255{
11256 struct nodelist *lp;
11257 const char *s;
11258
11259 if (n == NULL)
11260 return;
11261
11262 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011263 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011264 case NSEMI:
11265 s = "; ";
11266 goto binop;
11267 case NAND:
11268 s = " && ";
11269 goto binop;
11270 case NOR:
11271 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011272binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011273 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011274 /* if (ind < 0) */
11275 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011276 shtree(n->nbinary.ch2, ind, NULL, fp);
11277 break;
11278 case NCMD:
11279 shcmd(n, fp);
11280 if (ind >= 0)
11281 putc('\n', fp);
11282 break;
11283 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011284 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011285 shcmd(lp->n, fp);
11286 if (lp->next)
11287 fputs(" | ", fp);
11288 }
11289 if (n->npipe.backgnd)
11290 fputs(" &", fp);
11291 if (ind >= 0)
11292 putc('\n', fp);
11293 break;
11294 default:
11295 fprintf(fp, "<node type %d>", n->type);
11296 if (ind >= 0)
11297 putc('\n', fp);
11298 break;
11299 }
11300}
11301
11302
Eric Andersenc470f442003-07-28 09:56:35 +000011303static void
11304shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011305{
11306 union node *np;
11307 int first;
11308 const char *s;
11309 int dftfd;
11310
11311 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011312 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11313 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011314 putchar(' ');
11315 sharg(np, fp);
11316 first = 0;
11317 }
Eric Andersenc470f442003-07-28 09:56:35 +000011318 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11319 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011320 putchar(' ');
11321 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011322 case NTO: s = ">"; dftfd = 1; break;
11323 case NCLOBBER: s = ">|"; dftfd = 1; break;
11324 case NAPPEND: s = ">>"; dftfd = 1; break;
11325 case NTOFD: s = ">&"; dftfd = 1; break;
11326 case NFROM: s = "<"; dftfd = 0; break;
11327 case NFROMFD: s = "<&"; dftfd = 0; break;
11328 case NFROMTO: s = "<>"; dftfd = 0; break;
11329 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011330 }
11331 if (np->nfile.fd != dftfd)
11332 fprintf(fp, "%d", np->nfile.fd);
11333 fputs(s, fp);
11334 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11335 fprintf(fp, "%d", np->ndup.dupfd);
11336 } else {
11337 sharg(np->nfile.fname, fp);
11338 }
11339 first = 0;
11340 }
11341}
11342
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011343
Eric Andersenc470f442003-07-28 09:56:35 +000011344
11345static void
11346sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011347{
Eric Andersencb57d552001-06-28 07:25:16 +000011348 char *p;
11349 struct nodelist *bqlist;
11350 int subtype;
11351
11352 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011353 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011354 abort();
11355 }
11356 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011357 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011358 switch (*p) {
11359 case CTLESC:
11360 putc(*++p, fp);
11361 break;
11362 case CTLVAR:
11363 putc('$', fp);
11364 putc('{', fp);
11365 subtype = *++p;
11366 if (subtype == VSLENGTH)
11367 putc('#', fp);
11368
11369 while (*p != '=')
11370 putc(*p++, fp);
11371
11372 if (subtype & VSNUL)
11373 putc(':', fp);
11374
11375 switch (subtype & VSTYPE) {
11376 case VSNORMAL:
11377 putc('}', fp);
11378 break;
11379 case VSMINUS:
11380 putc('-', fp);
11381 break;
11382 case VSPLUS:
11383 putc('+', fp);
11384 break;
11385 case VSQUESTION:
11386 putc('?', fp);
11387 break;
11388 case VSASSIGN:
11389 putc('=', fp);
11390 break;
11391 case VSTRIMLEFT:
11392 putc('#', fp);
11393 break;
11394 case VSTRIMLEFTMAX:
11395 putc('#', fp);
11396 putc('#', fp);
11397 break;
11398 case VSTRIMRIGHT:
11399 putc('%', fp);
11400 break;
11401 case VSTRIMRIGHTMAX:
11402 putc('%', fp);
11403 putc('%', fp);
11404 break;
11405 case VSLENGTH:
11406 break;
11407 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011408 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011409 }
11410 break;
11411 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011412 putc('}', fp);
11413 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011414 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011415 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011416 putc('$', fp);
11417 putc('(', fp);
11418 shtree(bqlist->n, -1, NULL, fp);
11419 putc(')', fp);
11420 break;
11421 default:
11422 putc(*p, fp);
11423 break;
11424 }
11425 }
11426}
11427
11428
Eric Andersenc470f442003-07-28 09:56:35 +000011429static void
11430indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011431{
11432 int i;
11433
Eric Andersenc470f442003-07-28 09:56:35 +000011434 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011435 if (pfx && i == amount - 1)
11436 fputs(pfx, fp);
11437 putc('\t', fp);
11438 }
11439}
Eric Andersencb57d552001-06-28 07:25:16 +000011440
Eric Andersenc470f442003-07-28 09:56:35 +000011441
11442
11443/*
11444 * Debugging stuff.
11445 */
11446
11447
Eric Andersencb57d552001-06-28 07:25:16 +000011448FILE *tracefile;
11449
Eric Andersencb57d552001-06-28 07:25:16 +000011450
Eric Andersenc470f442003-07-28 09:56:35 +000011451void
11452trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011453{
Eric Andersenc470f442003-07-28 09:56:35 +000011454 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011455 return;
11456 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011457}
11458
Eric Andersenc470f442003-07-28 09:56:35 +000011459void
11460trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011461{
11462 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011463
Eric Andersenc470f442003-07-28 09:56:35 +000011464 if (debug != 1)
11465 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011466 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011467 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011468 va_end(va);
11469}
11470
Eric Andersenc470f442003-07-28 09:56:35 +000011471void
11472tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011473{
Eric Andersenc470f442003-07-28 09:56:35 +000011474 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011475 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011476 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011477}
11478
11479
Eric Andersenc470f442003-07-28 09:56:35 +000011480void
11481trputs(const char *s)
11482{
11483 if (debug != 1)
11484 return;
11485 fputs(s, tracefile);
11486}
11487
11488
11489static void
11490trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011491{
11492 char *p;
11493 char c;
11494
Eric Andersenc470f442003-07-28 09:56:35 +000011495 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011496 return;
11497 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011498 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011499 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011500 case '\n': c = 'n'; goto backslash;
11501 case '\t': c = 't'; goto backslash;
11502 case '\r': c = 'r'; goto backslash;
11503 case '"': c = '"'; goto backslash;
11504 case '\\': c = '\\'; goto backslash;
11505 case CTLESC: c = 'e'; goto backslash;
11506 case CTLVAR: c = 'v'; goto backslash;
11507 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11508 case CTLBACKQ: c = 'q'; goto backslash;
11509 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11510backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011511 putc(c, tracefile);
11512 break;
11513 default:
11514 if (*p >= ' ' && *p <= '~')
11515 putc(*p, tracefile);
11516 else {
11517 putc('\\', tracefile);
11518 putc(*p >> 6 & 03, tracefile);
11519 putc(*p >> 3 & 07, tracefile);
11520 putc(*p & 07, tracefile);
11521 }
11522 break;
11523 }
11524 }
11525 putc('"', tracefile);
11526}
11527
11528
Eric Andersenc470f442003-07-28 09:56:35 +000011529void
11530trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011531{
Eric Andersenc470f442003-07-28 09:56:35 +000011532 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011533 return;
11534 while (*ap) {
11535 trstring(*ap++);
11536 if (*ap)
11537 putc(' ', tracefile);
11538 else
11539 putc('\n', tracefile);
11540 }
Eric Andersencb57d552001-06-28 07:25:16 +000011541}
11542
11543
Eric Andersenc470f442003-07-28 09:56:35 +000011544void
11545opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011546{
Eric Andersencb57d552001-06-28 07:25:16 +000011547 char s[100];
11548#ifdef O_APPEND
11549 int flags;
11550#endif
11551
Eric Andersenc470f442003-07-28 09:56:35 +000011552 if (debug != 1) {
11553 if (tracefile)
11554 fflush(tracefile);
11555 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011556 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011557 }
Eric Andersenc470f442003-07-28 09:56:35 +000011558 scopy("./trace", s);
11559 if (tracefile) {
11560 if (!freopen(s, "a", tracefile)) {
11561 fprintf(stderr, "Can't re-open %s\n", s);
11562 debug = 0;
11563 return;
11564 }
11565 } else {
11566 if ((tracefile = fopen(s, "a")) == NULL) {
11567 fprintf(stderr, "Can't open %s\n", s);
11568 debug = 0;
11569 return;
11570 }
11571 }
Eric Andersencb57d552001-06-28 07:25:16 +000011572#ifdef O_APPEND
11573 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11574 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11575#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011576 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011577 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011578}
Eric Andersenc470f442003-07-28 09:56:35 +000011579#endif /* DEBUG */
11580
11581
11582/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11583
11584/*
11585 * Sigmode records the current value of the signal handlers for the various
11586 * modes. A value of zero means that the current handler is not known.
11587 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11588 */
11589
11590#define S_DFL 1 /* default signal handling (SIG_DFL) */
11591#define S_CATCH 2 /* signal is caught */
11592#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11593#define S_HARD_IGN 4 /* signal is ignored permenantly */
11594#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11595
Eric Andersencb57d552001-06-28 07:25:16 +000011596
11597
11598/*
Eric Andersencb57d552001-06-28 07:25:16 +000011599 * The trap builtin.
11600 */
11601
Eric Andersenc470f442003-07-28 09:56:35 +000011602int
11603trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011604{
11605 char *action;
11606 char **ap;
11607 int signo;
11608
Eric Andersenc470f442003-07-28 09:56:35 +000011609 nextopt(nullstr);
11610 ap = argptr;
11611 if (!*ap) {
11612 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011613 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011614 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011615
Eric Andersenc470f442003-07-28 09:56:35 +000011616 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011617 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011618 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011619 out1fmt("trap -- %s %s\n",
11620 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011621 }
11622 }
11623 return 0;
11624 }
Eric Andersenc470f442003-07-28 09:56:35 +000011625 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011626 action = NULL;
11627 else
11628 action = *ap++;
11629 while (*ap) {
11630 if ((signo = decode_signal(*ap, 0)) < 0)
11631 error("%s: bad trap", *ap);
11632 INTOFF;
11633 if (action) {
11634 if (action[0] == '-' && action[1] == '\0')
11635 action = NULL;
11636 else
Eric Andersenc470f442003-07-28 09:56:35 +000011637 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011638 }
Eric Andersenc470f442003-07-28 09:56:35 +000011639 if (trap[signo])
11640 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011641 trap[signo] = action;
11642 if (signo != 0)
11643 setsignal(signo);
11644 INTON;
11645 ap++;
11646 }
11647 return 0;
11648}
11649
11650
Eric Andersenc470f442003-07-28 09:56:35 +000011651/*
11652 * Clear traps on a fork.
11653 */
11654
11655void
11656clear_traps(void)
11657{
11658 char **tp;
11659
11660 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11661 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11662 INTOFF;
11663 ckfree(*tp);
11664 *tp = NULL;
11665 if (tp != &trap[0])
11666 setsignal(tp - trap);
11667 INTON;
11668 }
11669 }
11670}
11671
11672
Eric Andersencb57d552001-06-28 07:25:16 +000011673/*
11674 * Set the signal handler for the specified signal. The routine figures
11675 * out what it should be set to.
11676 */
11677
Eric Andersenc470f442003-07-28 09:56:35 +000011678void
11679setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011680{
11681 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011682 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011683 struct sigaction act;
11684
11685 if ((t = trap[signo]) == NULL)
11686 action = S_DFL;
11687 else if (*t != '\0')
11688 action = S_CATCH;
11689 else
11690 action = S_IGN;
11691 if (rootshell && action == S_DFL) {
11692 switch (signo) {
11693 case SIGINT:
11694 if (iflag || minusc || sflag == 0)
11695 action = S_CATCH;
11696 break;
11697 case SIGQUIT:
11698#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011699 if (debug)
11700 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011701#endif
11702 /* FALLTHROUGH */
11703 case SIGTERM:
11704 if (iflag)
11705 action = S_IGN;
11706 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011707#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011708 case SIGTSTP:
11709 case SIGTTOU:
11710 if (mflag)
11711 action = S_IGN;
11712 break;
11713#endif
11714 }
11715 }
11716
11717 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011718 tsig = *t;
11719 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011720 /*
11721 * current setting unknown
11722 */
11723 if (sigaction(signo, 0, &act) == -1) {
11724 /*
11725 * Pretend it worked; maybe we should give a warning
11726 * here, but other shells don't. We don't alter
11727 * sigmode, so that we retry every time.
11728 */
11729 return;
11730 }
11731 if (act.sa_handler == SIG_IGN) {
11732 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011733 signo == SIGTTIN || signo == SIGTTOU)) {
11734 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011735 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011736 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011737 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011738 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011739 }
11740 }
Eric Andersenc470f442003-07-28 09:56:35 +000011741 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011742 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011743 switch (action) {
11744 case S_CATCH:
11745 act.sa_handler = onsig;
11746 break;
11747 case S_IGN:
11748 act.sa_handler = SIG_IGN;
11749 break;
11750 default:
11751 act.sa_handler = SIG_DFL;
11752 }
Eric Andersencb57d552001-06-28 07:25:16 +000011753 *t = action;
11754 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011755 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011756 sigaction(signo, &act, 0);
11757}
11758
11759/*
11760 * Ignore a signal.
11761 */
11762
Eric Andersenc470f442003-07-28 09:56:35 +000011763void
11764ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011765{
11766 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11767 signal(signo, SIG_IGN);
11768 }
11769 sigmode[signo - 1] = S_HARD_IGN;
11770}
11771
11772
Eric Andersencb57d552001-06-28 07:25:16 +000011773/*
11774 * Signal handler.
11775 */
11776
Eric Andersenc470f442003-07-28 09:56:35 +000011777void
11778onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011779{
Eric Andersencb57d552001-06-28 07:25:16 +000011780 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011781 pendingsigs = signo;
11782
11783 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11784 if (!suppressint)
11785 onint();
11786 intpending = 1;
11787 }
Eric Andersencb57d552001-06-28 07:25:16 +000011788}
11789
11790
Eric Andersencb57d552001-06-28 07:25:16 +000011791/*
11792 * Called to execute a trap. Perhaps we should avoid entering new trap
11793 * handlers while we are executing a trap handler.
11794 */
11795
Eric Andersenc470f442003-07-28 09:56:35 +000011796void
11797dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011798{
Eric Andersenc470f442003-07-28 09:56:35 +000011799 char *p;
11800 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011801 int savestatus;
11802
Eric Andersenc470f442003-07-28 09:56:35 +000011803 savestatus = exitstatus;
11804 q = gotsig;
Glenn L McGrath2f325a02004-08-06 01:49:04 +000011805 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
Eric Andersenc470f442003-07-28 09:56:35 +000011806 *p = 0;
11807 p = trap[p - q + 1];
11808 if (!p)
11809 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011810 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011811 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011812 }
Eric Andersencb57d552001-06-28 07:25:16 +000011813}
11814
Eric Andersenc470f442003-07-28 09:56:35 +000011815
Eric Andersenc470f442003-07-28 09:56:35 +000011816/*
11817 * Controls whether the shell is interactive or not.
11818 */
11819
Eric Andersenc470f442003-07-28 09:56:35 +000011820void
11821setinteractive(int on)
11822{
11823 static int is_interactive;
11824
11825 if (++on == is_interactive)
11826 return;
11827 is_interactive = on;
11828 setsignal(SIGINT);
11829 setsignal(SIGQUIT);
11830 setsignal(SIGTERM);
11831#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11832 if(is_interactive > 1) {
11833 /* Looks like they want an interactive shell */
11834 static int do_banner;
11835
11836 if(!do_banner) {
11837 out1fmt(
11838 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11839 "Enter 'help' for a list of built-in commands.\n\n");
11840 do_banner++;
11841 }
11842 }
11843#endif
11844}
11845
11846
11847#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11848/*** List the available builtins ***/
11849
11850static int helpcmd(int argc, char **argv)
11851{
11852 int col, i;
11853
11854 out1fmt("\nBuilt-in commands:\n-------------------\n");
11855 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11856 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11857 builtincmd[i].name + 1);
11858 if (col > 60) {
11859 out1fmt("\n");
11860 col = 0;
11861 }
11862 }
11863#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11864 {
11865 extern const struct BB_applet applets[];
11866 extern const size_t NUM_APPLETS;
11867
11868 for (i = 0; i < NUM_APPLETS; i++) {
11869
11870 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11871 if (col > 60) {
11872 out1fmt("\n");
11873 col = 0;
11874 }
11875 }
11876 }
11877#endif
11878 out1fmt("\n\n");
11879 return EXIT_SUCCESS;
11880}
11881#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11882
Eric Andersencb57d552001-06-28 07:25:16 +000011883/*
11884 * Called to exit the shell.
11885 */
11886
Eric Andersenc470f442003-07-28 09:56:35 +000011887void
11888exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011889{
Eric Andersenc470f442003-07-28 09:56:35 +000011890 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011891 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011892 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011893 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011894
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011895 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011896 status = exitstatus;
11897 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011898 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011899 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011900 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011901 if ((p = trap[0]) != NULL && *p != '\0') {
11902 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011903 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011904 }
Eric Andersencb57d552001-06-28 07:25:16 +000011905 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011906 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011907#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11908 if (iflag && rootshell) {
11909 const char *hp = lookupvar("HISTFILE");
11910
11911 if(hp != NULL )
11912 save_history ( hp );
11913 }
11914#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011915out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011916 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011917 /* NOTREACHED */
11918}
11919
11920static int decode_signal(const char *string, int minsig)
11921{
11922 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011923 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011924
Eric Andersen34506362001-08-02 05:02:46 +000011925 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011926}
Eric Andersen34506362001-08-02 05:02:46 +000011927
Eric Andersenc470f442003-07-28 09:56:35 +000011928/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11929
11930static struct var *vartab[VTABSIZE];
11931
11932static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011933static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011934
11935/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011936 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011937 */
11938
Eric Andersenc470f442003-07-28 09:56:35 +000011939
11940#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011941/*
Eric Andersenc470f442003-07-28 09:56:35 +000011942 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011943 */
11944
Eric Andersenc470f442003-07-28 09:56:35 +000011945int
11946setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011947{
Eric Andersenc470f442003-07-28 09:56:35 +000011948 int err;
11949 volatile int saveint;
11950 struct jmploc *volatile savehandler = handler;
11951 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011952
Eric Andersenc470f442003-07-28 09:56:35 +000011953 SAVEINT(saveint);
11954 if (setjmp(jmploc.loc))
11955 err = 1;
11956 else {
11957 handler = &jmploc;
11958 setvar(name, val, flags);
11959 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011960 }
Eric Andersenc470f442003-07-28 09:56:35 +000011961 handler = savehandler;
11962 RESTOREINT(saveint);
11963 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011964}
Eric Andersenc470f442003-07-28 09:56:35 +000011965#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011966
11967/*
11968 * Set the value of a variable. The flags argument is ored with the
11969 * flags of the variable. If val is NULL, the variable is unset.
11970 */
11971
Eric Andersenc470f442003-07-28 09:56:35 +000011972static void
11973setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011974{
Eric Andersenc470f442003-07-28 09:56:35 +000011975 char *p, *q;
11976 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011977 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011978 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011979
Eric Andersenc470f442003-07-28 09:56:35 +000011980 q = endofname(name);
11981 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011982 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011983 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011984 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011985 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011986 if (val == NULL) {
11987 flags |= VUNSET;
11988 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011989 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011990 }
11991 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011992 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11993 *p++ = '\0';
11994 if (vallen) {
11995 p[-1] = '=';
11996 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011997 }
Eric Andersenc470f442003-07-28 09:56:35 +000011998 *p = '\0';
11999 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012000 INTON;
12001}
12002
12003
Eric Andersencb57d552001-06-28 07:25:16 +000012004/*
12005 * Same as setvar except that the variable and value are passed in
12006 * the first argument as name=value. Since the first argument will
12007 * be actually stored in the table, it should not be a string that
12008 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012009 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012010 */
12011
Eric Andersenc470f442003-07-28 09:56:35 +000012012void
12013setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012014{
12015 struct var *vp, **vpp;
12016
12017 vpp = hashvar(s);
12018 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012019 vp = *findvar(vpp, s);
12020 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012021 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12022 const char *n;
12023
Eric Andersenc470f442003-07-28 09:56:35 +000012024 if (flags & VNOSAVE)
12025 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012026 n = vp->text;
12027 error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012028 }
Eric Andersenc470f442003-07-28 09:56:35 +000012029
12030 if (flags & VNOSET)
12031 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012032
12033 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012034 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012035
Eric Andersenc470f442003-07-28 09:56:35 +000012036 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12037 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012038
Eric Andersenc470f442003-07-28 09:56:35 +000012039 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12040 } else {
12041 if (flags & VNOSET)
12042 return;
12043 /* not found */
12044 vp = ckmalloc(sizeof (*vp));
12045 vp->next = *vpp;
12046 vp->func = NULL;
12047 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012048 }
Eric Andersenc470f442003-07-28 09:56:35 +000012049 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12050 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012051 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012052 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012053}
12054
12055
Eric Andersencb57d552001-06-28 07:25:16 +000012056/*
12057 * Process a linked list of variable assignments.
12058 */
12059
Eric Andersenc470f442003-07-28 09:56:35 +000012060static void
12061listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012062{
Eric Andersenc470f442003-07-28 09:56:35 +000012063 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012064
Eric Andersenc470f442003-07-28 09:56:35 +000012065 if (!lp)
12066 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012067 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012068 do {
12069 setvareq(lp->text, flags);
12070 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012071 INTON;
12072}
12073
12074
Eric Andersencb57d552001-06-28 07:25:16 +000012075/*
12076 * Find the value of a variable. Returns NULL if not set.
12077 */
12078
Eric Andersenc470f442003-07-28 09:56:35 +000012079static char *
12080lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012081{
Eric Andersencb57d552001-06-28 07:25:16 +000012082 struct var *v;
12083
Eric Andersen16767e22004-03-16 05:14:10 +000012084 if ((v = *findvar(hashvar(name), name))) {
12085#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012086 /*
12087 * Dynamic variables are implemented roughly the same way they are
12088 * in bash. Namely, they're "special" so long as they aren't unset.
12089 * As soon as they're unset, they're no longer dynamic, and dynamic
12090 * lookup will no longer happen at that point. -- PFM.
12091 */
Eric Andersen16767e22004-03-16 05:14:10 +000012092 if((v->flags & VDYNAMIC))
12093 (*v->func)(NULL);
12094#endif
12095 if(!(v->flags & VUNSET))
12096 return strchrnul(v->text, '=') + 1;
12097 }
Eric Andersenef02f822004-03-11 13:34:24 +000012098
Eric Andersencb57d552001-06-28 07:25:16 +000012099 return NULL;
12100}
12101
12102
Eric Andersencb57d552001-06-28 07:25:16 +000012103/*
12104 * Search the environment of a builtin command.
12105 */
12106
Eric Andersenc470f442003-07-28 09:56:35 +000012107static char *
12108bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012109{
Eric Andersenc470f442003-07-28 09:56:35 +000012110 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012111
Eric Andersenc470f442003-07-28 09:56:35 +000012112 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012113 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012114 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012115 }
12116 return lookupvar(name);
12117}
12118
12119
Eric Andersencb57d552001-06-28 07:25:16 +000012120/*
Eric Andersenc470f442003-07-28 09:56:35 +000012121 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012122 */
12123
Eric Andersenc470f442003-07-28 09:56:35 +000012124static char **
12125listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012126{
Eric Andersencb57d552001-06-28 07:25:16 +000012127 struct var **vpp;
12128 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012129 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012130 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012131
Eric Andersenc470f442003-07-28 09:56:35 +000012132 STARTSTACKSTR(ep);
12133 vpp = vartab;
12134 mask = on | off;
12135 do {
12136 for (vp = *vpp ; vp ; vp = vp->next)
12137 if ((vp->flags & mask) == on) {
12138 if (ep == stackstrend())
12139 ep = growstackstr();
12140 *ep++ = (char *) vp->text;
12141 }
12142 } while (++vpp < vartab + VTABSIZE);
12143 if (ep == stackstrend())
12144 ep = growstackstr();
12145 if (end)
12146 *end = ep;
12147 *ep++ = NULL;
12148 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012149}
12150
12151
12152/*
Eric Andersenc470f442003-07-28 09:56:35 +000012153 * POSIX requires that 'set' (but not export or readonly) output the
12154 * variables in lexicographic order - by the locale's collating order (sigh).
12155 * Maybe we could keep them in an ordered balanced binary tree
12156 * instead of hashed lists.
12157 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012158 */
12159
Eric Andersenc470f442003-07-28 09:56:35 +000012160static int
12161showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012162{
Eric Andersenc470f442003-07-28 09:56:35 +000012163 const char *sep;
12164 char **ep, **epend;
12165
12166 ep = listvars(on, off, &epend);
12167 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12168
12169 sep = *sep_prefix ? spcstr : sep_prefix;
12170
12171 for (; ep < epend; ep++) {
12172 const char *p;
12173 const char *q;
12174
12175 p = strchrnul(*ep, '=');
12176 q = nullstr;
12177 if (*p)
12178 q = single_quote(++p);
12179
12180 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12181 }
12182
Eric Andersencb57d552001-06-28 07:25:16 +000012183 return 0;
12184}
12185
12186
12187
12188/*
12189 * The export and readonly commands.
12190 */
12191
Eric Andersenc470f442003-07-28 09:56:35 +000012192static int
12193exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012194{
12195 struct var *vp;
12196 char *name;
12197 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012198 char **aptr;
12199 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12200 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012201
Eric Andersenc470f442003-07-28 09:56:35 +000012202 notp = nextopt("p") - 'p';
12203 if (notp && ((name = *(aptr = argptr)))) {
12204 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012205 if ((p = strchr(name, '=')) != NULL) {
12206 p++;
12207 } else {
12208 if ((vp = *findvar(hashvar(name), name))) {
12209 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012210 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012211 }
12212 }
12213 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012214 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012215 } else {
12216 showvars(argv[0], flag, 0);
12217 }
12218 return 0;
12219}
12220
Eric Andersen34506362001-08-02 05:02:46 +000012221
Eric Andersencb57d552001-06-28 07:25:16 +000012222/*
Eric Andersencb57d552001-06-28 07:25:16 +000012223 * Make a variable a local variable. When a variable is made local, it's
12224 * value and flags are saved in a localvar structure. The saved values
12225 * will be restored when the shell function returns. We handle the name
12226 * "-" as a special case.
12227 */
12228
Eric Andersenc470f442003-07-28 09:56:35 +000012229static inline void
12230mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012231{
Eric Andersencb57d552001-06-28 07:25:16 +000012232 struct localvar *lvp;
12233 struct var **vpp;
12234 struct var *vp;
12235
12236 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012237 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012238 if (name[0] == '-' && name[1] == '\0') {
12239 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012240 p = ckmalloc(sizeof(optlist));
12241 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012242 vp = NULL;
12243 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012244 char *eq;
12245
Eric Andersencb57d552001-06-28 07:25:16 +000012246 vpp = hashvar(name);
12247 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012248 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012249 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012250 if (eq)
12251 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012252 else
12253 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012254 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012255 lvp->flags = VUNSET;
12256 } else {
12257 lvp->text = vp->text;
12258 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012259 vp->flags |= VSTRFIXED|VTEXTFIXED;
12260 if (eq)
12261 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012262 }
12263 }
12264 lvp->vp = vp;
12265 lvp->next = localvars;
12266 localvars = lvp;
12267 INTON;
12268}
12269
Eric Andersenc470f442003-07-28 09:56:35 +000012270/*
12271 * The "local" command.
12272 */
12273
12274static int
12275localcmd(int argc, char **argv)
12276{
12277 char *name;
12278
12279 argv = argptr;
12280 while ((name = *argv++) != NULL) {
12281 mklocal(name);
12282 }
12283 return 0;
12284}
12285
12286
Eric Andersencb57d552001-06-28 07:25:16 +000012287/*
12288 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012289 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012290 */
12291
Eric Andersenc470f442003-07-28 09:56:35 +000012292static void
12293poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012294{
Eric Andersencb57d552001-06-28 07:25:16 +000012295 struct localvar *lvp;
12296 struct var *vp;
12297
12298 while ((lvp = localvars) != NULL) {
12299 localvars = lvp->next;
12300 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012301 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12302 if (vp == NULL) { /* $- saved */
12303 memcpy(optlist, lvp->text, sizeof(optlist));
12304 ckfree(lvp->text);
12305 optschanged();
12306 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12307 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012308 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012309 if (vp->func)
12310 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12311 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12312 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012313 vp->flags = lvp->flags;
12314 vp->text = lvp->text;
12315 }
Eric Andersenc470f442003-07-28 09:56:35 +000012316 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012317 }
12318}
12319
12320
Eric Andersencb57d552001-06-28 07:25:16 +000012321/*
12322 * The unset builtin command. We unset the function before we unset the
12323 * variable to allow a function to be unset when there is a readonly variable
12324 * with the same name.
12325 */
12326
Eric Andersenc470f442003-07-28 09:56:35 +000012327int
12328unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012329{
12330 char **ap;
12331 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012332 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012333 int ret = 0;
12334
12335 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012336 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012337 }
Eric Andersencb57d552001-06-28 07:25:16 +000012338
Eric Andersenc470f442003-07-28 09:56:35 +000012339 for (ap = argptr; *ap ; ap++) {
12340 if (flag != 'f') {
12341 i = unsetvar(*ap);
12342 ret |= i;
12343 if (!(i & 2))
12344 continue;
12345 }
12346 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012347 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012348 }
Eric Andersenc470f442003-07-28 09:56:35 +000012349 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012350}
12351
12352
12353/*
12354 * Unset the specified variable.
12355 */
12356
Eric Andersenc470f442003-07-28 09:56:35 +000012357int
12358unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012359{
Eric Andersencb57d552001-06-28 07:25:16 +000012360 struct var **vpp;
12361 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012362 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012363
12364 vpp = findvar(hashvar(s), s);
12365 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012366 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012367 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012368 int flags = vp->flags;
12369
12370 retval = 1;
12371 if (flags & VREADONLY)
12372 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012373#ifdef DYNAMIC_VAR
12374 vp->flags &= ~VDYNAMIC;
12375#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012376 if (flags & VUNSET)
12377 goto ok;
12378 if ((flags & VSTRFIXED) == 0) {
12379 INTOFF;
12380 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12381 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012382 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012383 ckfree(vp);
12384 INTON;
12385 } else {
12386 setvar(s, 0, 0);
12387 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012388 }
Eric Andersenc470f442003-07-28 09:56:35 +000012389ok:
12390 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012391 }
12392
Eric Andersenc470f442003-07-28 09:56:35 +000012393out:
12394 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012395}
12396
12397
12398
12399/*
12400 * Find the appropriate entry in the hash table from the name.
12401 */
12402
Eric Andersenc470f442003-07-28 09:56:35 +000012403static struct var **
12404hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012405{
Eric Andersencb57d552001-06-28 07:25:16 +000012406 unsigned int hashval;
12407
12408 hashval = ((unsigned char) *p) << 4;
12409 while (*p && *p != '=')
12410 hashval += (unsigned char) *p++;
12411 return &vartab[hashval % VTABSIZE];
12412}
12413
12414
12415
12416/*
Eric Andersenc470f442003-07-28 09:56:35 +000012417 * Compares two strings up to the first = or '\0'. The first
12418 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012419 * either '=' or '\0'.
12420 */
12421
Eric Andersenc470f442003-07-28 09:56:35 +000012422int
12423varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012424{
Eric Andersenc470f442003-07-28 09:56:35 +000012425 int c, d;
12426
12427 while ((c = *p) == (d = *q)) {
12428 if (!c || c == '=')
12429 goto out;
12430 p++;
12431 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012432 }
Eric Andersenc470f442003-07-28 09:56:35 +000012433 if (c == '=')
12434 c = 0;
12435 if (d == '=')
12436 d = 0;
12437out:
12438 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012439}
12440
Eric Andersenc470f442003-07-28 09:56:35 +000012441static int
12442vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012443{
Eric Andersenc470f442003-07-28 09:56:35 +000012444 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012445}
12446
Eric Andersenc470f442003-07-28 09:56:35 +000012447static struct var **
12448findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012449{
12450 for (; *vpp; vpp = &(*vpp)->next) {
12451 if (varequal((*vpp)->text, name)) {
12452 break;
12453 }
12454 }
12455 return vpp;
12456}
Eric Andersenc470f442003-07-28 09:56:35 +000012457/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012458
Eric Andersenc470f442003-07-28 09:56:35 +000012459#include <sys/times.h>
12460
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012461static const unsigned char timescmd_str[] = {
12462 ' ', offsetof(struct tms, tms_utime),
12463 '\n', offsetof(struct tms, tms_stime),
12464 ' ', offsetof(struct tms, tms_cutime),
12465 '\n', offsetof(struct tms, tms_cstime),
12466 0
12467};
Eric Andersencb57d552001-06-28 07:25:16 +000012468
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012469static int timescmd(int ac, char **av)
12470{
12471 long int clk_tck, s, t;
12472 const unsigned char *p;
12473 struct tms buf;
12474
12475 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012476 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012477
12478 p = timescmd_str;
12479 do {
12480 t = *(clock_t *)(((char *) &buf) + p[1]);
12481 s = t / clk_tck;
12482 out1fmt("%ldm%ld.%.3lds%c",
12483 s/60, s%60,
12484 ((t - s * clk_tck) * 1000) / clk_tck,
12485 p[0]);
12486 } while (*(p += 2));
12487
Eric Andersencb57d552001-06-28 07:25:16 +000012488 return 0;
12489}
12490
Eric Andersend35c5df2002-01-09 15:37:36 +000012491#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012492static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012493dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012494{
Eric Andersened9ecf72004-06-22 08:29:45 +000012495 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012496 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012497
Eric Andersenc470f442003-07-28 09:56:35 +000012498 INTOFF;
12499 result = arith(s, &errcode);
12500 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012501 if (errcode == -3)
12502 error("exponent less than 0");
12503 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012504 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012505 else if (errcode == -5)
12506 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012507 else
12508 synerror(s);
12509 }
12510 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012511
Eric Andersenc470f442003-07-28 09:56:35 +000012512 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012513}
Eric Andersenc470f442003-07-28 09:56:35 +000012514
12515
12516/*
Eric Andersen90898442003-08-06 11:20:52 +000012517 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12518 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12519 *
12520 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012521 */
Eric Andersen90898442003-08-06 11:20:52 +000012522
Eric Andersenc470f442003-07-28 09:56:35 +000012523static int
Eric Andersen90898442003-08-06 11:20:52 +000012524letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012525{
Eric Andersenc470f442003-07-28 09:56:35 +000012526 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012527 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012528
Eric Andersen90898442003-08-06 11:20:52 +000012529 ap = argv + 1;
12530 if(!*ap)
12531 error("expression expected");
12532 for (ap = argv + 1; *ap; ap++) {
12533 i = dash_arith(*ap);
12534 }
Eric Andersenc470f442003-07-28 09:56:35 +000012535
Eric Andersen90898442003-08-06 11:20:52 +000012536 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012537}
12538#endif /* CONFIG_ASH_MATH_SUPPORT */
12539
12540/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12541
12542/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012543 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012544 */
12545
12546#undef rflag
12547
12548#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012549#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012550typedef enum __rlimit_resource rlim_t;
12551#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012552#endif
12553
12554
Eric Andersenc470f442003-07-28 09:56:35 +000012555/*
12556 * The read builtin. The -e option causes backslashes to escape the
12557 * following character.
12558 *
12559 * This uses unbuffered input, which may be avoidable in some cases.
12560 */
12561
12562static int
12563readcmd(int argc, char **argv)
12564{
12565 char **ap;
12566 int backslash;
12567 char c;
12568 int rflag;
12569 char *prompt;
12570 const char *ifs;
12571 char *p;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012572#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012573 fd_set set;
12574 int timeout;
12575 struct timeval timeout_struct;
12576 struct termios tty, old_tty;
12577#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012578 int startword;
12579 int status;
12580 int i;
12581
12582 rflag = 0;
12583 prompt = NULL;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012584#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012585 timeout = 0;
12586
12587 while ((i = nextopt("p:rt:")) != '\0')
12588#else
12589 while ((i = nextopt("p:r")) != '\0')
12590#endif
12591 {
Eric Andersenc470f442003-07-28 09:56:35 +000012592 if (i == 'p')
12593 prompt = optionarg;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012594 else if (i == 'r')
Eric Andersenc470f442003-07-28 09:56:35 +000012595 rflag = 1;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012596#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012597 else
12598 timeout = atoi(optionarg);
12599#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012600 }
12601 if (prompt && isatty(0)) {
12602 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012603 }
12604 if (*(ap = argptr) == NULL)
12605 error("arg count");
12606 if ((ifs = bltinlookup("IFS")) == NULL)
12607 ifs = defifs;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012608#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012609 c = 0;
12610#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012611 status = 0;
12612 startword = 1;
12613 backslash = 0;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012614
Eric Andersenc470f442003-07-28 09:56:35 +000012615 STARTSTACKSTR(p);
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012616#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012617 if (timeout > 0) {
12618 tcgetattr(0, &tty);
12619 old_tty = tty;
12620
12621 /* cfmakeraw(...) disables too much; we just do this instead. */
12622 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
12623 tcsetattr(0, TCSANOW, &tty);
12624
12625 FD_ZERO (&set);
12626 FD_SET (0, &set);
12627
12628 timeout_struct.tv_sec = timeout;
12629 timeout_struct.tv_usec = 0;
12630
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012631 if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012632 {
12633 read(0, &c, 1);
12634 if(c == '\n' || c == 4) /* Handle newlines and EOF */
12635 i = 0; /* Don't read further... */
12636 else
12637 STPUTC(c, p); /* Keep reading... */
12638 }
12639 tcsetattr(0, TCSANOW, &old_tty);
12640
12641 /* Echo the character so the user knows it was read...
12642 Yes, this can be done by setting the ECHO flag, but that
12643 echoes ^D and other control characters at this state */
12644 if(c != 0)
12645 write(1, &c, 1);
12646
12647 } else
12648 i = 1;
12649
12650 for (;i == 1;)
12651#else
12652 for (;;)
12653#endif
12654 {
Eric Andersenc470f442003-07-28 09:56:35 +000012655 if (read(0, &c, 1) != 1) {
12656 status = 1;
12657 break;
12658 }
12659 if (c == '\0')
12660 continue;
12661 if (backslash) {
12662 backslash = 0;
12663 if (c != '\n')
12664 goto put;
12665 continue;
12666 }
12667 if (!rflag && c == '\\') {
12668 backslash++;
12669 continue;
12670 }
12671 if (c == '\n')
12672 break;
12673 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12674 continue;
12675 }
12676 startword = 0;
12677 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12678 STACKSTRNUL(p);
12679 setvar(*ap, stackblock(), 0);
12680 ap++;
12681 startword = 1;
12682 STARTSTACKSTR(p);
12683 } else {
12684put:
12685 STPUTC(c, p);
12686 }
12687 }
12688 STACKSTRNUL(p);
12689 /* Remove trailing blanks */
12690 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12691 *p = '\0';
12692 setvar(*ap, stackblock(), 0);
12693 while (*++ap != NULL)
12694 setvar(*ap, nullstr, 0);
12695 return status;
12696}
12697
12698
12699static int umaskcmd(int argc, char **argv)
12700{
12701 static const char permuser[3] = "ugo";
12702 static const char permmode[3] = "rwx";
12703 static const short int permmask[] = {
12704 S_IRUSR, S_IWUSR, S_IXUSR,
12705 S_IRGRP, S_IWGRP, S_IXGRP,
12706 S_IROTH, S_IWOTH, S_IXOTH
12707 };
12708
12709 char *ap;
12710 mode_t mask;
12711 int i;
12712 int symbolic_mode = 0;
12713
12714 while (nextopt("S") != '\0') {
12715 symbolic_mode = 1;
12716 }
12717
12718 INTOFF;
12719 mask = umask(0);
12720 umask(mask);
12721 INTON;
12722
12723 if ((ap = *argptr) == NULL) {
12724 if (symbolic_mode) {
12725 char buf[18];
12726 char *p = buf;
12727
12728 for (i = 0; i < 3; i++) {
12729 int j;
12730
12731 *p++ = permuser[i];
12732 *p++ = '=';
12733 for (j = 0; j < 3; j++) {
12734 if ((mask & permmask[3 * i + j]) == 0) {
12735 *p++ = permmode[j];
12736 }
12737 }
12738 *p++ = ',';
12739 }
12740 *--p = 0;
12741 puts(buf);
12742 } else {
12743 out1fmt("%.4o\n", mask);
12744 }
12745 } else {
12746 if (is_digit((unsigned char) *ap)) {
12747 mask = 0;
12748 do {
12749 if (*ap >= '8' || *ap < '0')
12750 error(illnum, argv[1]);
12751 mask = (mask << 3) + (*ap - '0');
12752 } while (*++ap != '\0');
12753 umask(mask);
12754 } else {
12755 mask = ~mask & 0777;
12756 if (!bb_parse_mode(ap, &mask)) {
12757 error("Illegal mode: %s", ap);
12758 }
12759 umask(~mask & 0777);
12760 }
12761 }
12762 return 0;
12763}
12764
12765/*
12766 * ulimit builtin
12767 *
12768 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12769 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12770 * ash by J.T. Conklin.
12771 *
12772 * Public domain.
12773 */
12774
12775struct limits {
12776 const char *name;
12777 int cmd;
12778 int factor; /* multiply by to get rlim_{cur,max} values */
12779 char option;
12780};
12781
12782static const struct limits limits[] = {
12783#ifdef RLIMIT_CPU
12784 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12785#endif
12786#ifdef RLIMIT_FSIZE
12787 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12788#endif
12789#ifdef RLIMIT_DATA
12790 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12791#endif
12792#ifdef RLIMIT_STACK
12793 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12794#endif
12795#ifdef RLIMIT_CORE
12796 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12797#endif
12798#ifdef RLIMIT_RSS
12799 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12800#endif
12801#ifdef RLIMIT_MEMLOCK
12802 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12803#endif
12804#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012805 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012806#endif
12807#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012808 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012809#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012810#ifdef RLIMIT_AS
12811 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012812#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012813#ifdef RLIMIT_LOCKS
12814 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012815#endif
12816 { (char *) 0, 0, 0, '\0' }
12817};
12818
Glenn L McGrath76620622004-01-13 10:19:37 +000012819enum limtype { SOFT = 0x1, HARD = 0x2 };
12820
12821static void printlim(enum limtype how, const struct rlimit *limit,
12822 const struct limits *l)
12823{
12824 rlim_t val;
12825
12826 val = limit->rlim_max;
12827 if (how & SOFT)
12828 val = limit->rlim_cur;
12829
12830 if (val == RLIM_INFINITY)
12831 out1fmt("unlimited\n");
12832 else {
12833 val /= l->factor;
12834 out1fmt("%lld\n", (long long) val);
12835 }
12836}
12837
Eric Andersenc470f442003-07-28 09:56:35 +000012838int
12839ulimitcmd(int argc, char **argv)
12840{
12841 int c;
12842 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012843 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012844 const struct limits *l;
12845 int set, all = 0;
12846 int optc, what;
12847 struct rlimit limit;
12848
12849 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012850 while ((optc = nextopt("HSa"
12851#ifdef RLIMIT_CPU
12852 "t"
12853#endif
12854#ifdef RLIMIT_FSIZE
12855 "f"
12856#endif
12857#ifdef RLIMIT_DATA
12858 "d"
12859#endif
12860#ifdef RLIMIT_STACK
12861 "s"
12862#endif
12863#ifdef RLIMIT_CORE
12864 "c"
12865#endif
12866#ifdef RLIMIT_RSS
12867 "m"
12868#endif
12869#ifdef RLIMIT_MEMLOCK
12870 "l"
12871#endif
12872#ifdef RLIMIT_NPROC
12873 "p"
12874#endif
12875#ifdef RLIMIT_NOFILE
12876 "n"
12877#endif
12878#ifdef RLIMIT_AS
12879 "v"
12880#endif
12881#ifdef RLIMIT_LOCKS
12882 "w"
12883#endif
12884 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012885 switch (optc) {
12886 case 'H':
12887 how = HARD;
12888 break;
12889 case 'S':
12890 how = SOFT;
12891 break;
12892 case 'a':
12893 all = 1;
12894 break;
12895 default:
12896 what = optc;
12897 }
12898
Glenn L McGrath76620622004-01-13 10:19:37 +000012899 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012900 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012901
12902 set = *argptr ? 1 : 0;
12903 if (set) {
12904 char *p = *argptr;
12905
12906 if (all || argptr[1])
12907 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012908 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012909 val = RLIM_INFINITY;
12910 else {
12911 val = (rlim_t) 0;
12912
12913 while ((c = *p++) >= '0' && c <= '9')
12914 {
12915 val = (val * 10) + (long)(c - '0');
12916 if (val < (rlim_t) 0)
12917 break;
12918 }
12919 if (c)
12920 error("bad number");
12921 val *= l->factor;
12922 }
12923 }
12924 if (all) {
12925 for (l = limits; l->name; l++) {
12926 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012927 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012928 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012929 }
12930 return 0;
12931 }
12932
12933 getrlimit(l->cmd, &limit);
12934 if (set) {
12935 if (how & HARD)
12936 limit.rlim_max = val;
12937 if (how & SOFT)
12938 limit.rlim_cur = val;
12939 if (setrlimit(l->cmd, &limit) < 0)
12940 error("error setting limit (%m)");
12941 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012942 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012943 }
12944 return 0;
12945}
12946
Eric Andersen90898442003-08-06 11:20:52 +000012947
12948#ifdef CONFIG_ASH_MATH_SUPPORT
12949
12950/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12951
12952 Permission is hereby granted, free of charge, to any person obtaining
12953 a copy of this software and associated documentation files (the
12954 "Software"), to deal in the Software without restriction, including
12955 without limitation the rights to use, copy, modify, merge, publish,
12956 distribute, sublicense, and/or sell copies of the Software, and to
12957 permit persons to whom the Software is furnished to do so, subject to
12958 the following conditions:
12959
12960 The above copyright notice and this permission notice shall be
12961 included in all copies or substantial portions of the Software.
12962
12963 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12964 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12965 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12966 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12967 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12968 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12969 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12970*/
12971
12972/* This is my infix parser/evaluator. It is optimized for size, intended
12973 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000012974 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000012975 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000012976 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000012977 * be that which POSIX specifies for shells. */
12978
12979/* The code uses a simple two-stack algorithm. See
12980 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000012981 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000012982 * this is based (this code differs in that it applies operators immediately
12983 * to the stack instead of adding them to a queue to end up with an
12984 * expression). */
12985
12986/* To use the routine, call it with an expression string and error return
12987 * pointer */
12988
12989/*
12990 * Aug 24, 2001 Manuel Novoa III
12991 *
12992 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12993 *
12994 * 1) In arith_apply():
12995 * a) Cached values of *numptr and &(numptr[-1]).
12996 * b) Removed redundant test for zero denominator.
12997 *
12998 * 2) In arith():
12999 * a) Eliminated redundant code for processing operator tokens by moving
13000 * to a table-based implementation. Also folded handling of parens
13001 * into the table.
13002 * b) Combined all 3 loops which called arith_apply to reduce generated
13003 * code size at the cost of speed.
13004 *
13005 * 3) The following expressions were treated as valid by the original code:
13006 * 1() , 0! , 1 ( *3 ) .
13007 * These bugs have been fixed by internally enclosing the expression in
13008 * parens and then checking that all binary ops and right parens are
13009 * preceded by a valid expression (NUM_TOKEN).
13010 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013011 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013012 * ctype's isspace() if it is used by another busybox applet or if additional
13013 * whitespace chars should be considered. Look below the "#include"s for a
13014 * precompiler test.
13015 */
13016
13017/*
13018 * Aug 26, 2001 Manuel Novoa III
13019 *
13020 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13021 *
13022 * Merge in Aaron's comments previously posted to the busybox list,
13023 * modified slightly to take account of my changes to the code.
13024 *
13025 */
13026
13027/*
13028 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13029 *
13030 * - allow access to variable,
13031 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13032 * - realize assign syntax (VAR=expr, +=, *= etc)
13033 * - realize exponentiation (** operator)
13034 * - realize comma separated - expr, expr
13035 * - realise ++expr --expr expr++ expr--
13036 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013037 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013038 * - was restored loses XOR operator
13039 * - remove one goto label, added three ;-)
13040 * - protect $((num num)) as true zero expr (Manuel`s error)
13041 * - always use special isspace(), see comment from bash ;-)
13042 */
13043
13044
13045#define arith_isspace(arithval) \
13046 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13047
13048
13049typedef unsigned char operator;
13050
13051/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013052 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013053 * precedence. The ID portion is so that multiple operators can have the
13054 * same precedence, ensuring that the leftmost one is evaluated first.
13055 * Consider * and /. */
13056
13057#define tok_decl(prec,id) (((id)<<5)|(prec))
13058#define PREC(op) ((op) & 0x1F)
13059
13060#define TOK_LPAREN tok_decl(0,0)
13061
13062#define TOK_COMMA tok_decl(1,0)
13063
13064#define TOK_ASSIGN tok_decl(2,0)
13065#define TOK_AND_ASSIGN tok_decl(2,1)
13066#define TOK_OR_ASSIGN tok_decl(2,2)
13067#define TOK_XOR_ASSIGN tok_decl(2,3)
13068#define TOK_PLUS_ASSIGN tok_decl(2,4)
13069#define TOK_MINUS_ASSIGN tok_decl(2,5)
13070#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13071#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13072
13073#define TOK_MUL_ASSIGN tok_decl(3,0)
13074#define TOK_DIV_ASSIGN tok_decl(3,1)
13075#define TOK_REM_ASSIGN tok_decl(3,2)
13076
13077/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13078#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13079
13080/* conditional is right associativity too */
13081#define TOK_CONDITIONAL tok_decl(4,0)
13082#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13083
13084#define TOK_OR tok_decl(5,0)
13085
13086#define TOK_AND tok_decl(6,0)
13087
13088#define TOK_BOR tok_decl(7,0)
13089
13090#define TOK_BXOR tok_decl(8,0)
13091
13092#define TOK_BAND tok_decl(9,0)
13093
13094#define TOK_EQ tok_decl(10,0)
13095#define TOK_NE tok_decl(10,1)
13096
13097#define TOK_LT tok_decl(11,0)
13098#define TOK_GT tok_decl(11,1)
13099#define TOK_GE tok_decl(11,2)
13100#define TOK_LE tok_decl(11,3)
13101
13102#define TOK_LSHIFT tok_decl(12,0)
13103#define TOK_RSHIFT tok_decl(12,1)
13104
13105#define TOK_ADD tok_decl(13,0)
13106#define TOK_SUB tok_decl(13,1)
13107
13108#define TOK_MUL tok_decl(14,0)
13109#define TOK_DIV tok_decl(14,1)
13110#define TOK_REM tok_decl(14,2)
13111
13112/* exponent is right associativity */
13113#define TOK_EXPONENT tok_decl(15,1)
13114
13115/* For now unary operators. */
13116#define UNARYPREC 16
13117#define TOK_BNOT tok_decl(UNARYPREC,0)
13118#define TOK_NOT tok_decl(UNARYPREC,1)
13119
13120#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13121#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13122
13123#define PREC_PRE (UNARYPREC+2)
13124
13125#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13126#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13127
13128#define PREC_POST (UNARYPREC+3)
13129
13130#define TOK_POST_INC tok_decl(PREC_POST, 0)
13131#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13132
13133#define SPEC_PREC (UNARYPREC+4)
13134
13135#define TOK_NUM tok_decl(SPEC_PREC, 0)
13136#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13137
13138#define NUMPTR (*numstackptr)
13139
13140static inline int tok_have_assign(operator op)
13141{
13142 operator prec = PREC(op);
13143
13144 convert_prec_is_assing(prec);
13145 return (prec == PREC(TOK_ASSIGN) ||
13146 prec == PREC_PRE || prec == PREC_POST);
13147}
13148
13149static inline int is_right_associativity(operator prec)
13150{
13151 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13152 prec == PREC(TOK_CONDITIONAL));
13153}
13154
13155
13156typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013157 arith_t val;
13158 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013159 char contidional_second_val_initialized;
13160 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013161 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013162} v_n_t;
13163
13164
13165typedef struct CHK_VAR_RECURSIVE_LOOPED {
13166 const char *var;
13167 struct CHK_VAR_RECURSIVE_LOOPED *next;
13168} chk_var_recursive_looped_t;
13169
13170static chk_var_recursive_looped_t *prev_chk_var_recursive;
13171
13172
13173static int arith_lookup_val(v_n_t *t)
13174{
13175 if(t->var) {
13176 const char * p = lookupvar(t->var);
13177
13178 if(p) {
13179 int errcode;
13180
13181 /* recursive try as expression */
13182 chk_var_recursive_looped_t *cur;
13183 chk_var_recursive_looped_t cur_save;
13184
13185 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13186 if(strcmp(cur->var, t->var) == 0) {
13187 /* expression recursion loop detected */
13188 return -5;
13189 }
13190 }
13191 /* save current lookuped var name */
13192 cur = prev_chk_var_recursive;
13193 cur_save.var = t->var;
13194 cur_save.next = cur;
13195 prev_chk_var_recursive = &cur_save;
13196
13197 t->val = arith (p, &errcode);
13198 /* restore previous ptr after recursiving */
13199 prev_chk_var_recursive = cur;
13200 return errcode;
13201 } else {
13202 /* allow undefined var as 0 */
13203 t->val = 0;
13204 }
13205 }
13206 return 0;
13207}
13208
13209/* "applying" a token means performing it on the top elements on the integer
13210 * stack. For a unary operator it will only change the top element, but a
13211 * binary operator will pop two arguments and push a result */
13212static inline int
13213arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13214{
Eric Andersen90898442003-08-06 11:20:52 +000013215 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013216 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013217 int ret_arith_lookup_val;
13218
13219 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13220 without arguments */
13221 numptr_m1 = NUMPTR - 1;
13222
13223 /* check operand is var with noninteger value */
13224 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13225 if(ret_arith_lookup_val)
13226 return ret_arith_lookup_val;
13227
13228 rez = numptr_m1->val;
13229 if (op == TOK_UMINUS)
13230 rez *= -1;
13231 else if (op == TOK_NOT)
13232 rez = !rez;
13233 else if (op == TOK_BNOT)
13234 rez = ~rez;
13235 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13236 rez++;
13237 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13238 rez--;
13239 else if (op != TOK_UPLUS) {
13240 /* Binary operators */
13241
13242 /* check and binary operators need two arguments */
13243 if (numptr_m1 == numstack) goto err;
13244
13245 /* ... and they pop one */
13246 --NUMPTR;
13247 numptr_val = rez;
13248 if (op == TOK_CONDITIONAL) {
13249 if(! numptr_m1->contidional_second_val_initialized) {
13250 /* protect $((expr1 ? expr2)) without ": expr" */
13251 goto err;
13252 }
13253 rez = numptr_m1->contidional_second_val;
13254 } else if(numptr_m1->contidional_second_val_initialized) {
13255 /* protect $((expr1 : expr2)) without "expr ? " */
13256 goto err;
13257 }
13258 numptr_m1 = NUMPTR - 1;
13259 if(op != TOK_ASSIGN) {
13260 /* check operand is var with noninteger value for not '=' */
13261 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13262 if(ret_arith_lookup_val)
13263 return ret_arith_lookup_val;
13264 }
13265 if (op == TOK_CONDITIONAL) {
13266 numptr_m1->contidional_second_val = rez;
13267 }
13268 rez = numptr_m1->val;
13269 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13270 rez |= numptr_val;
13271 else if (op == TOK_OR)
13272 rez = numptr_val || rez;
13273 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13274 rez &= numptr_val;
13275 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13276 rez ^= numptr_val;
13277 else if (op == TOK_AND)
13278 rez = rez && numptr_val;
13279 else if (op == TOK_EQ)
13280 rez = (rez == numptr_val);
13281 else if (op == TOK_NE)
13282 rez = (rez != numptr_val);
13283 else if (op == TOK_GE)
13284 rez = (rez >= numptr_val);
13285 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13286 rez >>= numptr_val;
13287 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13288 rez <<= numptr_val;
13289 else if (op == TOK_GT)
13290 rez = (rez > numptr_val);
13291 else if (op == TOK_LT)
13292 rez = (rez < numptr_val);
13293 else if (op == TOK_LE)
13294 rez = (rez <= numptr_val);
13295 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13296 rez *= numptr_val;
13297 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13298 rez += numptr_val;
13299 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13300 rez -= numptr_val;
13301 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13302 rez = numptr_val;
13303 else if (op == TOK_CONDITIONAL_SEP) {
13304 if (numptr_m1 == numstack) {
13305 /* protect $((expr : expr)) without "expr ? " */
13306 goto err;
13307 }
13308 numptr_m1->contidional_second_val_initialized = op;
13309 numptr_m1->contidional_second_val = numptr_val;
13310 }
13311 else if (op == TOK_CONDITIONAL) {
13312 rez = rez ?
13313 numptr_val : numptr_m1->contidional_second_val;
13314 }
13315 else if(op == TOK_EXPONENT) {
13316 if(numptr_val < 0)
13317 return -3; /* exponent less than 0 */
13318 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013319 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013320
13321 if(numptr_val)
13322 while(numptr_val--)
13323 c *= rez;
13324 rez = c;
13325 }
13326 }
13327 else if(numptr_val==0) /* zero divisor check */
13328 return -2;
13329 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13330 rez /= numptr_val;
13331 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13332 rez %= numptr_val;
13333 }
13334 if(tok_have_assign(op)) {
13335 char buf[32];
13336
13337 if(numptr_m1->var == NULL) {
13338 /* Hmm, 1=2 ? */
13339 goto err;
13340 }
13341 /* save to shell variable */
Eric Andersenad63cb22004-10-08 09:43:34 +000013342 snprintf(buf, sizeof(buf), "%lld", (long long) rez);
Eric Andersen90898442003-08-06 11:20:52 +000013343 setvar(numptr_m1->var, buf, 0);
13344 /* after saving, make previous value for v++ or v-- */
13345 if(op == TOK_POST_INC)
13346 rez--;
13347 else if(op == TOK_POST_DEC)
13348 rez++;
13349 }
13350 numptr_m1->val = rez;
13351 /* protect geting var value, is number now */
13352 numptr_m1->var = NULL;
13353 return 0;
13354err: return(-1);
13355}
13356
13357/* longest must first */
13358static const char op_tokens[] = {
13359 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13360 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13361 '<','<', 0, TOK_LSHIFT,
13362 '>','>', 0, TOK_RSHIFT,
13363 '|','|', 0, TOK_OR,
13364 '&','&', 0, TOK_AND,
13365 '!','=', 0, TOK_NE,
13366 '<','=', 0, TOK_LE,
13367 '>','=', 0, TOK_GE,
13368 '=','=', 0, TOK_EQ,
13369 '|','=', 0, TOK_OR_ASSIGN,
13370 '&','=', 0, TOK_AND_ASSIGN,
13371 '*','=', 0, TOK_MUL_ASSIGN,
13372 '/','=', 0, TOK_DIV_ASSIGN,
13373 '%','=', 0, TOK_REM_ASSIGN,
13374 '+','=', 0, TOK_PLUS_ASSIGN,
13375 '-','=', 0, TOK_MINUS_ASSIGN,
13376 '-','-', 0, TOK_POST_DEC,
13377 '^','=', 0, TOK_XOR_ASSIGN,
13378 '+','+', 0, TOK_POST_INC,
13379 '*','*', 0, TOK_EXPONENT,
13380 '!', 0, TOK_NOT,
13381 '<', 0, TOK_LT,
13382 '>', 0, TOK_GT,
13383 '=', 0, TOK_ASSIGN,
13384 '|', 0, TOK_BOR,
13385 '&', 0, TOK_BAND,
13386 '*', 0, TOK_MUL,
13387 '/', 0, TOK_DIV,
13388 '%', 0, TOK_REM,
13389 '+', 0, TOK_ADD,
13390 '-', 0, TOK_SUB,
13391 '^', 0, TOK_BXOR,
13392 /* uniq */
13393 '~', 0, TOK_BNOT,
13394 ',', 0, TOK_COMMA,
13395 '?', 0, TOK_CONDITIONAL,
13396 ':', 0, TOK_CONDITIONAL_SEP,
13397 ')', 0, TOK_RPAREN,
13398 '(', 0, TOK_LPAREN,
13399 0
13400};
13401/* ptr to ")" */
13402#define endexpression &op_tokens[sizeof(op_tokens)-7]
13403
13404
Eric Andersened9ecf72004-06-22 08:29:45 +000013405static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013406{
13407 register char arithval; /* Current character under analysis */
13408 operator lasttok, op;
13409 operator prec;
13410
13411 const char *p = endexpression;
13412 int errcode;
13413
13414 size_t datasizes = strlen(expr) + 2;
13415
13416 /* Stack of integers */
13417 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013418 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013419 * the reader. */
13420 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13421 *numstackptr = numstack;
13422 /* Stack of operator tokens */
13423 operator *stack = alloca((datasizes) * sizeof(operator)),
13424 *stackptr = stack;
13425
13426 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13427 *perrcode = errcode = 0;
13428
13429 while(1) {
13430 if ((arithval = *expr) == 0) {
13431 if (p == endexpression) {
13432 /* Null expression. */
13433 return 0;
13434 }
13435
13436 /* This is only reached after all tokens have been extracted from the
13437 * input stream. If there are still tokens on the operator stack, they
13438 * are to be applied in order. At the end, there should be a final
13439 * result on the integer stack */
13440
13441 if (expr != endexpression + 1) {
13442 /* If we haven't done so already, */
13443 /* append a closing right paren */
13444 expr = endexpression;
13445 /* and let the loop process it. */
13446 continue;
13447 }
13448 /* At this point, we're done with the expression. */
13449 if (numstackptr != numstack+1) {
13450 /* ... but if there isn't, it's bad */
13451 err:
13452 return (*perrcode = -1);
13453 }
13454 if(numstack->var) {
13455 /* expression is $((var)) only, lookup now */
13456 errcode = arith_lookup_val(numstack);
13457 }
13458 ret:
13459 *perrcode = errcode;
13460 return numstack->val;
13461 } else {
13462 /* Continue processing the expression. */
13463 if (arith_isspace(arithval)) {
13464 /* Skip whitespace */
13465 goto prologue;
13466 }
13467 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013468 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013469
13470 numstackptr->var = alloca(var_name_size);
13471 safe_strncpy(numstackptr->var, expr, var_name_size);
13472 expr = p;
13473 num:
13474 numstackptr->contidional_second_val_initialized = 0;
13475 numstackptr++;
13476 lasttok = TOK_NUM;
13477 continue;
13478 } else if (is_digit(arithval)) {
13479 numstackptr->var = NULL;
Eric Andersenad63cb22004-10-08 09:43:34 +000013480 numstackptr->val = strtoll(expr, (char **) &expr, 0);
Eric Andersen90898442003-08-06 11:20:52 +000013481 goto num;
13482 }
13483 for(p = op_tokens; ; p++) {
13484 const char *o;
13485
13486 if(*p == 0) {
13487 /* strange operator not found */
13488 goto err;
13489 }
13490 for(o = expr; *p && *o == *p; p++)
13491 o++;
13492 if(! *p) {
13493 /* found */
13494 expr = o - 1;
13495 break;
13496 }
13497 /* skip tail uncompared token */
13498 while(*p)
13499 p++;
13500 /* skip zero delim */
13501 p++;
13502 }
13503 op = p[1];
13504
13505 /* post grammar: a++ reduce to num */
13506 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13507 lasttok = TOK_NUM;
13508
13509 /* Plus and minus are binary (not unary) _only_ if the last
13510 * token was as number, or a right paren (which pretends to be
13511 * a number, since it evaluates to one). Think about it.
13512 * It makes sense. */
13513 if (lasttok != TOK_NUM) {
13514 switch(op) {
13515 case TOK_ADD:
13516 op = TOK_UPLUS;
13517 break;
13518 case TOK_SUB:
13519 op = TOK_UMINUS;
13520 break;
13521 case TOK_POST_INC:
13522 op = TOK_PRE_INC;
13523 break;
13524 case TOK_POST_DEC:
13525 op = TOK_PRE_DEC;
13526 break;
13527 }
13528 }
13529 /* We don't want a unary operator to cause recursive descent on the
13530 * stack, because there can be many in a row and it could cause an
13531 * operator to be evaluated before its argument is pushed onto the
13532 * integer stack. */
13533 /* But for binary operators, "apply" everything on the operator
13534 * stack until we find an operator with a lesser priority than the
13535 * one we have just extracted. */
13536 /* Left paren is given the lowest priority so it will never be
13537 * "applied" in this way.
13538 * if associativity is right and priority eq, applied also skip
13539 */
13540 prec = PREC(op);
13541 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13542 /* not left paren or unary */
13543 if (lasttok != TOK_NUM) {
13544 /* binary op must be preceded by a num */
13545 goto err;
13546 }
13547 while (stackptr != stack) {
13548 if (op == TOK_RPAREN) {
13549 /* The algorithm employed here is simple: while we don't
13550 * hit an open paren nor the bottom of the stack, pop
13551 * tokens and apply them */
13552 if (stackptr[-1] == TOK_LPAREN) {
13553 --stackptr;
13554 /* Any operator directly after a */
13555 lasttok = TOK_NUM;
13556 /* close paren should consider itself binary */
13557 goto prologue;
13558 }
13559 } else {
13560 operator prev_prec = PREC(stackptr[-1]);
13561
13562 convert_prec_is_assing(prec);
13563 convert_prec_is_assing(prev_prec);
13564 if (prev_prec < prec)
13565 break;
13566 /* check right assoc */
13567 if(prev_prec == prec && is_right_associativity(prec))
13568 break;
13569 }
13570 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13571 if(errcode) goto ret;
13572 }
13573 if (op == TOK_RPAREN) {
13574 goto err;
13575 }
13576 }
13577
13578 /* Push this operator to the stack and remember it. */
13579 *stackptr++ = lasttok = op;
13580
13581 prologue:
13582 ++expr;
13583 }
13584 }
13585}
13586#endif /* CONFIG_ASH_MATH_SUPPORT */
13587
13588
Eric Andersenc470f442003-07-28 09:56:35 +000013589#ifdef DEBUG
13590const char *bb_applet_name = "debug stuff usage";
13591int main(int argc, char **argv)
13592{
13593 return ash_main(argc, argv);
13594}
13595#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013596
Eric Andersendf82f612001-06-28 07:46:40 +000013597/*-
13598 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013599 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013600 *
13601 * This code is derived from software contributed to Berkeley by
13602 * Kenneth Almquist.
13603 *
13604 * Redistribution and use in source and binary forms, with or without
13605 * modification, are permitted provided that the following conditions
13606 * are met:
13607 * 1. Redistributions of source code must retain the above copyright
13608 * notice, this list of conditions and the following disclaimer.
13609 * 2. Redistributions in binary form must reproduce the above copyright
13610 * notice, this list of conditions and the following disclaimer in the
13611 * documentation and/or other materials provided with the distribution.
13612 *
Eric Andersen2870d962001-07-02 17:27:21 +000013613 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13614 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013615 *
13616 * 4. Neither the name of the University nor the names of its contributors
13617 * may be used to endorse or promote products derived from this software
13618 * without specific prior written permission.
13619 *
13620 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13621 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13622 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13623 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13624 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13625 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13626 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13627 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13628 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13629 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13630 * SUCH DAMAGE.
13631 */