blob: 0e9d58ae66c0e207b2a8309d2a23cac16171769e [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
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003725 int flg_bb = 0;
Eric Andersen3102ac42001-07-06 04:26:23 +00003726 char *name = cmd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003727
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003728 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3729 flg_bb = 1;
3730 }
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003731 if(flg_bb) {
3732 char **ap;
3733 char **new;
3734
3735 *argv = name;
3736 if(strcmp(name, "busybox")) {
3737 for (ap = argv; *ap; ap++);
3738 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3739 *ap++ = cmd = "/bin/busybox";
3740 while ((*ap++ = *argv++));
3741 argv = new;
3742 repeated++;
3743 } else {
3744 cmd = "/bin/busybox";
3745 }
3746 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003747#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003748
3749repeat:
3750#ifdef SYSV
3751 do {
3752 execve(cmd, argv, envp);
3753 } while (errno == EINTR);
3754#else
Eric Andersencb57d552001-06-28 07:25:16 +00003755 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003756#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003757 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003758 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003759 } else if (errno == ENOEXEC) {
3760 char **ap;
3761 char **new;
3762
Eric Andersenc470f442003-07-28 09:56:35 +00003763 for (ap = argv; *ap; ap++)
3764 ;
3765 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003766 ap[1] = cmd;
3767 *ap = cmd = (char *)DEFAULT_SHELL;
3768 ap += 2;
3769 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003770 while ((*ap++ = *argv++))
3771 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003772 argv = new;
3773 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003774 }
Eric Andersencb57d552001-06-28 07:25:16 +00003775}
3776
Eric Andersenc470f442003-07-28 09:56:35 +00003777
Eric Andersencb57d552001-06-28 07:25:16 +00003778
3779/*
3780 * Do a path search. The variable path (passed by reference) should be
3781 * set to the start of the path before the first call; padvance will update
3782 * this value as it proceeds. Successive calls to padvance will return
3783 * the possible path expansions in sequence. If an option (indicated by
3784 * a percent sign) appears in the path entry then the global variable
3785 * pathopt will be set to point to it; otherwise pathopt will be set to
3786 * NULL.
3787 */
3788
Eric Andersenc470f442003-07-28 09:56:35 +00003789static char *
3790padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003791{
Eric Andersencb57d552001-06-28 07:25:16 +00003792 const char *p;
3793 char *q;
3794 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003795 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003796
3797 if (*path == NULL)
3798 return NULL;
3799 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003800 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3801 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003802 while (stackblocksize() < len)
3803 growstackblock();
3804 q = stackblock();
3805 if (p != start) {
3806 memcpy(q, start, p - start);
3807 q += p - start;
3808 *q++ = '/';
3809 }
3810 strcpy(q, name);
3811 pathopt = NULL;
3812 if (*p == '%') {
3813 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003814 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003815 }
3816 if (*p == ':')
3817 *path = p + 1;
3818 else
3819 *path = NULL;
3820 return stalloc(len);
3821}
3822
3823
Eric Andersencb57d552001-06-28 07:25:16 +00003824/*** Command hashing code ***/
3825
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003826static void
3827printentry(struct tblentry *cmdp)
3828{
3829 int idx;
3830 const char *path;
3831 char *name;
3832
3833 idx = cmdp->param.index;
3834 path = pathval();
3835 do {
3836 name = padvance(&path, cmdp->cmdname);
3837 stunalloc(name);
3838 } while (--idx >= 0);
3839 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3840}
3841
Eric Andersenc470f442003-07-28 09:56:35 +00003842
3843static int
3844hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003845{
3846 struct tblentry **pp;
3847 struct tblentry *cmdp;
3848 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003849 struct cmdentry entry;
3850 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003851
Eric Andersenc470f442003-07-28 09:56:35 +00003852 while ((c = nextopt("r")) != '\0') {
3853 clearcmdentry(0);
3854 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003855 }
3856 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003857 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3858 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3859 if (cmdp->cmdtype == CMDNORMAL)
3860 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003861 }
3862 }
3863 return 0;
3864 }
3865 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003866 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003867 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003868 && (cmdp->cmdtype == CMDNORMAL
3869 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003870 delete_cmd_entry();
3871 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003872 if (entry.cmdtype == CMDUNKNOWN)
3873 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003874 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003875 }
3876 return c;
3877}
3878
Eric Andersenc470f442003-07-28 09:56:35 +00003879
Eric Andersencb57d552001-06-28 07:25:16 +00003880/*
3881 * Resolve a command name. If you change this routine, you may have to
3882 * change the shellexec routine as well.
3883 */
3884
3885static void
Eric Andersenc470f442003-07-28 09:56:35 +00003886find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003887{
3888 struct tblentry *cmdp;
3889 int idx;
3890 int prev;
3891 char *fullname;
3892 struct stat statb;
3893 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003894 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003895 struct builtincmd *bcmd;
3896
Eric Andersenc470f442003-07-28 09:56:35 +00003897 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003898 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003899 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003900 if (act & DO_ABS) {
3901 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003902#ifdef SYSV
3903 if (errno == EINTR)
3904 continue;
3905#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003906 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003907 return;
3908 }
Eric Andersencb57d552001-06-28 07:25:16 +00003909 }
3910 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003911 return;
3912 }
3913
Eric Andersenbf8bf102002-09-17 08:41:08 +00003914#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3915 if (find_applet_by_name(name)) {
3916 entry->cmdtype = CMDNORMAL;
3917 entry->u.index = -1;
3918 return;
3919 }
3920#endif
3921
Eric Andersenc470f442003-07-28 09:56:35 +00003922 updatetbl = (path == pathval());
3923 if (!updatetbl) {
3924 act |= DO_ALTPATH;
3925 if (strstr(path, "%builtin") != NULL)
3926 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003927 }
3928
Eric Andersenc470f442003-07-28 09:56:35 +00003929 /* If name is in the table, check answer will be ok */
3930 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3931 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003932
Eric Andersenc470f442003-07-28 09:56:35 +00003933 switch (cmdp->cmdtype) {
3934 default:
3935#if DEBUG
3936 abort();
3937#endif
3938 case CMDNORMAL:
3939 bit = DO_ALTPATH;
3940 break;
3941 case CMDFUNCTION:
3942 bit = DO_NOFUNC;
3943 break;
3944 case CMDBUILTIN:
3945 bit = DO_ALTBLTIN;
3946 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003947 }
Eric Andersenc470f442003-07-28 09:56:35 +00003948 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003949 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003950 cmdp = NULL;
3951 } else if (cmdp->rehash == 0)
3952 /* if not invalidated by cd, we're done */
3953 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003954 }
3955
3956 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003957 bcmd = find_builtin(name);
3958 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3959 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3960 )))
3961 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003962
3963 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003964 prev = -1; /* where to start */
3965 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003966 if (cmdp->cmdtype == CMDBUILTIN)
3967 prev = builtinloc;
3968 else
3969 prev = cmdp->param.index;
3970 }
3971
3972 e = ENOENT;
3973 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003974loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003975 while ((fullname = padvance(&path, name)) != NULL) {
3976 stunalloc(fullname);
3977 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003978 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003979 if (prefix(pathopt, "builtin")) {
3980 if (bcmd)
3981 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003982 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003983 } else if (!(act & DO_NOFUNC) &&
3984 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003985 /* handled below */
3986 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003987 /* ignore unimplemented options */
3988 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003989 }
3990 }
3991 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003992 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003993 if (idx < prev)
3994 continue;
3995 TRACE(("searchexec \"%s\": no change\n", name));
3996 goto success;
3997 }
3998 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003999#ifdef SYSV
4000 if (errno == EINTR)
4001 continue;
4002#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004003 if (errno != ENOENT && errno != ENOTDIR)
4004 e = errno;
4005 goto loop;
4006 }
Eric Andersenc470f442003-07-28 09:56:35 +00004007 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004008 if (!S_ISREG(statb.st_mode))
4009 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004010 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004011 stalloc(strlen(fullname) + 1);
4012 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004013 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4014 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004015 error("%s not defined in %s", name, fullname);
4016 stunalloc(fullname);
4017 goto success;
4018 }
Eric Andersencb57d552001-06-28 07:25:16 +00004019 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004020 if (!updatetbl) {
4021 entry->cmdtype = CMDNORMAL;
4022 entry->u.index = idx;
4023 return;
4024 }
4025 INTOFF;
4026 cmdp = cmdlookup(name, 1);
4027 cmdp->cmdtype = CMDNORMAL;
4028 cmdp->param.index = idx;
4029 INTON;
4030 goto success;
4031 }
4032
4033 /* We failed. If there was an entry for this command, delete it */
4034 if (cmdp && updatetbl)
4035 delete_cmd_entry();
4036 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004037 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004038 entry->cmdtype = CMDUNKNOWN;
4039 return;
4040
Eric Andersenc470f442003-07-28 09:56:35 +00004041builtin_success:
4042 if (!updatetbl) {
4043 entry->cmdtype = CMDBUILTIN;
4044 entry->u.cmd = bcmd;
4045 return;
4046 }
4047 INTOFF;
4048 cmdp = cmdlookup(name, 1);
4049 cmdp->cmdtype = CMDBUILTIN;
4050 cmdp->param.cmd = bcmd;
4051 INTON;
4052success:
Eric Andersencb57d552001-06-28 07:25:16 +00004053 cmdp->rehash = 0;
4054 entry->cmdtype = cmdp->cmdtype;
4055 entry->u = cmdp->param;
4056}
4057
4058
Eric Andersenc470f442003-07-28 09:56:35 +00004059/*
4060 * Wrapper around strcmp for qsort/bsearch/...
4061 */
4062static int pstrcmp(const void *a, const void *b)
4063{
4064 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4065}
Eric Andersencb57d552001-06-28 07:25:16 +00004066
4067/*
4068 * Search the table of builtin commands.
4069 */
4070
Eric Andersenc470f442003-07-28 09:56:35 +00004071static struct builtincmd *
4072find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004073{
4074 struct builtincmd *bp;
4075
Eric Andersenc470f442003-07-28 09:56:35 +00004076 bp = bsearch(
4077 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4078 pstrcmp
4079 );
Eric Andersencb57d552001-06-28 07:25:16 +00004080 return bp;
4081}
4082
4083
Eric Andersenc470f442003-07-28 09:56:35 +00004084
Eric Andersencb57d552001-06-28 07:25:16 +00004085/*
4086 * Called when a cd is done. Marks all commands so the next time they
4087 * are executed they will be rehashed.
4088 */
4089
Eric Andersenc470f442003-07-28 09:56:35 +00004090static void
4091hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004092{
Eric Andersencb57d552001-06-28 07:25:16 +00004093 struct tblentry **pp;
4094 struct tblentry *cmdp;
4095
Eric Andersenc470f442003-07-28 09:56:35 +00004096 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4097 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4098 if (cmdp->cmdtype == CMDNORMAL || (
4099 cmdp->cmdtype == CMDBUILTIN &&
4100 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4101 builtinloc > 0
4102 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004103 cmdp->rehash = 1;
4104 }
4105 }
4106}
4107
4108
4109
4110/*
Eric Andersenc470f442003-07-28 09:56:35 +00004111 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004112 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004113 * pathval() still returns the old value at this point.
4114 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004115 */
4116
Eric Andersenc470f442003-07-28 09:56:35 +00004117static void
4118changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004119{
Eric Andersenc470f442003-07-28 09:56:35 +00004120 const char *old, *new;
4121 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004122 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004123 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004124
Eric Andersenc470f442003-07-28 09:56:35 +00004125 old = pathval();
4126 new = newval;
4127 firstchange = 9999; /* assume no change */
4128 idx = 0;
4129 idx_bltin = -1;
4130 for (;;) {
4131 if (*old != *new) {
4132 firstchange = idx;
4133 if ((*old == '\0' && *new == ':')
4134 || (*old == ':' && *new == '\0'))
4135 firstchange++;
4136 old = new; /* ignore subsequent differences */
4137 }
4138 if (*new == '\0')
4139 break;
4140 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4141 idx_bltin = idx;
4142 if (*new == ':') {
4143 idx++;
4144 }
4145 new++, old++;
4146 }
4147 if (builtinloc < 0 && idx_bltin >= 0)
4148 builtinloc = idx_bltin; /* zap builtins */
4149 if (builtinloc >= 0 && idx_bltin < 0)
4150 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004151 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004152 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004153}
4154
4155
4156/*
4157 * Clear out command entries. The argument specifies the first entry in
4158 * PATH which has changed.
4159 */
4160
Eric Andersenc470f442003-07-28 09:56:35 +00004161static void
4162clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004163{
4164 struct tblentry **tblp;
4165 struct tblentry **pp;
4166 struct tblentry *cmdp;
4167
4168 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004169 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004170 pp = tblp;
4171 while ((cmdp = *pp) != NULL) {
4172 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004173 cmdp->param.index >= firstchange)
4174 || (cmdp->cmdtype == CMDBUILTIN &&
4175 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004176 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004177 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004178 } else {
4179 pp = &cmdp->next;
4180 }
4181 }
4182 }
4183 INTON;
4184}
4185
4186
Eric Andersenc470f442003-07-28 09:56:35 +00004187
Eric Andersencb57d552001-06-28 07:25:16 +00004188/*
Eric Andersencb57d552001-06-28 07:25:16 +00004189 * Locate a command in the command hash table. If "add" is nonzero,
4190 * add the command to the table if it is not already present. The
4191 * variable "lastcmdentry" is set to point to the address of the link
4192 * pointing to the entry, so that delete_cmd_entry can delete the
4193 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004194 *
4195 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004196 */
4197
Eric Andersen2870d962001-07-02 17:27:21 +00004198static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004199
Eric Andersenc470f442003-07-28 09:56:35 +00004200
4201static struct tblentry *
4202cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004203{
Eric Andersenc470f442003-07-28 09:56:35 +00004204 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004205 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004206 struct tblentry *cmdp;
4207 struct tblentry **pp;
4208
4209 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004210 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004211 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004212 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004213 hashval &= 0x7FFF;
4214 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004215 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004216 if (equal(cmdp->cmdname, name))
4217 break;
4218 pp = &cmdp->next;
4219 }
4220 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004221 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4222 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004223 cmdp->next = NULL;
4224 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004225 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004226 }
4227 lastcmdentry = pp;
4228 return cmdp;
4229}
4230
4231/*
4232 * Delete the command entry returned on the last lookup.
4233 */
4234
Eric Andersenc470f442003-07-28 09:56:35 +00004235static void
4236delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004237{
Eric Andersencb57d552001-06-28 07:25:16 +00004238 struct tblentry *cmdp;
4239
4240 INTOFF;
4241 cmdp = *lastcmdentry;
4242 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004243 if (cmdp->cmdtype == CMDFUNCTION)
4244 freefunc(cmdp->param.func);
4245 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004246 INTON;
4247}
4248
4249
Eric Andersenc470f442003-07-28 09:56:35 +00004250/*
4251 * Add a new command entry, replacing any existing command entry for
4252 * the same name - except special builtins.
4253 */
Eric Andersencb57d552001-06-28 07:25:16 +00004254
Eric Andersenc470f442003-07-28 09:56:35 +00004255static inline void
4256addcmdentry(char *name, struct cmdentry *entry)
4257{
4258 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004259
Eric Andersenc470f442003-07-28 09:56:35 +00004260 cmdp = cmdlookup(name, 1);
4261 if (cmdp->cmdtype == CMDFUNCTION) {
4262 freefunc(cmdp->param.func);
4263 }
4264 cmdp->cmdtype = entry->cmdtype;
4265 cmdp->param = entry->u;
4266 cmdp->rehash = 0;
4267}
Eric Andersencb57d552001-06-28 07:25:16 +00004268
Eric Andersenc470f442003-07-28 09:56:35 +00004269/*
4270 * Make a copy of a parse tree.
4271 */
Eric Andersencb57d552001-06-28 07:25:16 +00004272
Eric Andersenc470f442003-07-28 09:56:35 +00004273static inline struct funcnode *
4274copyfunc(union node *n)
4275{
4276 struct funcnode *f;
4277 size_t blocksize;
4278
4279 funcblocksize = offsetof(struct funcnode, n);
4280 funcstringsize = 0;
4281 calcsize(n);
4282 blocksize = funcblocksize;
4283 f = ckmalloc(blocksize + funcstringsize);
4284 funcblock = (char *) f + offsetof(struct funcnode, n);
4285 funcstring = (char *) f + blocksize;
4286 copynode(n);
4287 f->count = 0;
4288 return f;
4289}
4290
4291/*
4292 * Define a shell function.
4293 */
4294
4295static void
4296defun(char *name, union node *func)
4297{
4298 struct cmdentry entry;
4299
4300 INTOFF;
4301 entry.cmdtype = CMDFUNCTION;
4302 entry.u.func = copyfunc(func);
4303 addcmdentry(name, &entry);
4304 INTON;
4305}
Eric Andersencb57d552001-06-28 07:25:16 +00004306
4307
4308/*
4309 * Delete a function if it exists.
4310 */
4311
Eric Andersenc470f442003-07-28 09:56:35 +00004312static void
4313unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004314{
Eric Andersencb57d552001-06-28 07:25:16 +00004315 struct tblentry *cmdp;
4316
Eric Andersenc470f442003-07-28 09:56:35 +00004317 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4318 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004319 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004320}
4321
Eric Andersen2870d962001-07-02 17:27:21 +00004322/*
Eric Andersencb57d552001-06-28 07:25:16 +00004323 * Locate and print what a word is...
4324 */
4325
Eric Andersenc470f442003-07-28 09:56:35 +00004326
4327#ifdef CONFIG_ASH_CMDCMD
4328static int
4329describe_command(char *command, int describe_command_verbose)
4330#else
4331#define describe_command_verbose 1
4332static int
4333describe_command(char *command)
4334#endif
4335{
4336 struct cmdentry entry;
4337 struct tblentry *cmdp;
4338#ifdef CONFIG_ASH_ALIAS
4339 const struct alias *ap;
4340#endif
4341 const char *path = pathval();
4342
4343 if (describe_command_verbose) {
4344 out1str(command);
4345 }
4346
4347 /* First look at the keywords */
4348 if (findkwd(command)) {
4349 out1str(describe_command_verbose ? " is a shell keyword" : command);
4350 goto out;
4351 }
4352
4353#ifdef CONFIG_ASH_ALIAS
4354 /* Then look at the aliases */
4355 if ((ap = lookupalias(command, 0)) != NULL) {
4356 if (describe_command_verbose) {
4357 out1fmt(" is an alias for %s", ap->val);
4358 } else {
4359 out1str("alias ");
4360 printalias(ap);
4361 return 0;
4362 }
4363 goto out;
4364 }
4365#endif
4366 /* Then check if it is a tracked alias */
4367 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4368 entry.cmdtype = cmdp->cmdtype;
4369 entry.u = cmdp->param;
4370 } else {
4371 /* Finally use brute force */
4372 find_command(command, &entry, DO_ABS, path);
4373 }
4374
4375 switch (entry.cmdtype) {
4376 case CMDNORMAL: {
4377 int j = entry.u.index;
4378 char *p;
4379 if (j == -1) {
4380 p = command;
4381 } else {
4382 do {
4383 p = padvance(&path, command);
4384 stunalloc(p);
4385 } while (--j >= 0);
4386 }
4387 if (describe_command_verbose) {
4388 out1fmt(" is%s %s",
4389 (cmdp ? " a tracked alias for" : nullstr), p
4390 );
4391 } else {
4392 out1str(p);
4393 }
4394 break;
4395 }
4396
4397 case CMDFUNCTION:
4398 if (describe_command_verbose) {
4399 out1str(" is a shell function");
4400 } else {
4401 out1str(command);
4402 }
4403 break;
4404
4405 case CMDBUILTIN:
4406 if (describe_command_verbose) {
4407 out1fmt(" is a %sshell builtin",
4408 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4409 "special " : nullstr
4410 );
4411 } else {
4412 out1str(command);
4413 }
4414 break;
4415
4416 default:
4417 if (describe_command_verbose) {
4418 out1str(": not found\n");
4419 }
4420 return 127;
4421 }
4422
4423out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004424 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004425 return 0;
4426}
4427
4428static int
4429typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004430{
4431 int i;
4432 int err = 0;
4433
4434 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004435#ifdef CONFIG_ASH_CMDCMD
4436 err |= describe_command(argv[i], 1);
4437#else
4438 err |= describe_command(argv[i]);
4439#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004440 }
4441 return err;
4442}
4443
Eric Andersend35c5df2002-01-09 15:37:36 +00004444#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004445static int
4446commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004447{
4448 int c;
4449 int default_path = 0;
4450 int verify_only = 0;
4451 int verbose_verify_only = 0;
4452
4453 while ((c = nextopt("pvV")) != '\0')
4454 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004455 default:
4456#ifdef DEBUG
4457 fprintf(stderr,
4458"command: nextopt returned character code 0%o\n", c);
4459 return EX_SOFTWARE;
4460#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004461 case 'p':
4462 default_path = 1;
4463 break;
4464 case 'v':
4465 verify_only = 1;
4466 break;
4467 case 'V':
4468 verbose_verify_only = 1;
4469 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004470 }
4471
Eric Andersenc470f442003-07-28 09:56:35 +00004472 if (default_path + verify_only + verbose_verify_only > 1 ||
4473 !*argptr) {
4474 fprintf(stderr,
4475 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004476 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004477 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004478 }
4479
Eric Andersencb57d552001-06-28 07:25:16 +00004480 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004481 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004482 }
Eric Andersencb57d552001-06-28 07:25:16 +00004483
4484 return 0;
4485}
Eric Andersen2870d962001-07-02 17:27:21 +00004486#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004487
Eric Andersenc470f442003-07-28 09:56:35 +00004488/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004489
Eric Andersencb57d552001-06-28 07:25:16 +00004490/*
4491 * Routines to expand arguments to commands. We have to deal with
4492 * backquotes, shell variables, and file metacharacters.
4493 */
Eric Andersenc470f442003-07-28 09:56:35 +00004494
Eric Andersencb57d552001-06-28 07:25:16 +00004495/*
4496 * _rmescape() flags
4497 */
Eric Andersenc470f442003-07-28 09:56:35 +00004498#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4499#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4500#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4501#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4502#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004503
4504/*
4505 * Structure specifying which parts of the string should be searched
4506 * for IFS characters.
4507 */
4508
4509struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004510 struct ifsregion *next; /* next region in list */
4511 int begoff; /* offset of start of region */
4512 int endoff; /* offset of end of region */
4513 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004514};
4515
Eric Andersenc470f442003-07-28 09:56:35 +00004516/* output of current string */
4517static char *expdest;
4518/* list of back quote expressions */
4519static struct nodelist *argbackq;
4520/* first struct in list of ifs regions */
4521static struct ifsregion ifsfirst;
4522/* last struct in list */
4523static struct ifsregion *ifslastp;
4524/* holds expanded arg list */
4525static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004526
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004527static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004528static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004529static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004530static const char *subevalvar(char *, char *, int, int, int, int, int);
4531static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004532static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004533static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004534static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004535static void recordregion(int, int, int);
4536static void removerecordregions(int);
4537static void ifsbreakup(char *, struct arglist *);
4538static void ifsfree(void);
4539static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004540static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004541
Eric Andersened9ecf72004-06-22 08:29:45 +00004542static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004543static size_t esclen(const char *, const char *);
4544static char *scanleft(char *, char *, char *, char *, int, int);
4545static char *scanright(char *, char *, char *, char *, int, int);
4546static void varunset(const char *, const char *, const char *, int)
4547 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004548
Eric Andersenc470f442003-07-28 09:56:35 +00004549
4550#define pmatch(a, b) !fnmatch((a), (b), 0)
4551/*
Eric Andersen90898442003-08-06 11:20:52 +00004552 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004553 *
4554 * Returns an stalloced string.
4555 */
4556
4557static inline char *
4558preglob(const char *pattern, int quoted, int flag) {
4559 flag |= RMESCAPE_GLOB;
4560 if (quoted) {
4561 flag |= RMESCAPE_QUOTED;
4562 }
4563 return _rmescapes((char *)pattern, flag);
4564}
4565
4566
4567static size_t
4568esclen(const char *start, const char *p) {
4569 size_t esc = 0;
4570
4571 while (p > start && *--p == CTLESC) {
4572 esc++;
4573 }
4574 return esc;
4575}
4576
Eric Andersencb57d552001-06-28 07:25:16 +00004577
4578/*
4579 * Expand shell variables and backquotes inside a here document.
4580 */
4581
Eric Andersenc470f442003-07-28 09:56:35 +00004582static inline void
4583expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004584{
Eric Andersencb57d552001-06-28 07:25:16 +00004585 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004586 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004587 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004588}
4589
4590
4591/*
4592 * Perform variable substitution and command substitution on an argument,
4593 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4594 * perform splitting and file name expansion. When arglist is NULL, perform
4595 * here document expansion.
4596 */
4597
Eric Andersenc470f442003-07-28 09:56:35 +00004598void
4599expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004600{
4601 struct strlist *sp;
4602 char *p;
4603
4604 argbackq = arg->narg.backquote;
4605 STARTSTACKSTR(expdest);
4606 ifsfirst.next = NULL;
4607 ifslastp = NULL;
4608 argstr(arg->narg.text, flag);
4609 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004610 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004611 }
4612 STPUTC('\0', expdest);
4613 p = grabstackstr(expdest);
4614 exparg.lastp = &exparg.list;
4615 /*
4616 * TODO - EXP_REDIR
4617 */
4618 if (flag & EXP_FULL) {
4619 ifsbreakup(p, &exparg);
4620 *exparg.lastp = NULL;
4621 exparg.lastp = &exparg.list;
4622 expandmeta(exparg.list, flag);
4623 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004624 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004625 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004626 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004627 sp->text = p;
4628 *exparg.lastp = sp;
4629 exparg.lastp = &sp->next;
4630 }
Eric Andersenc470f442003-07-28 09:56:35 +00004631 if (ifsfirst.next)
4632 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004633 *exparg.lastp = NULL;
4634 if (exparg.list) {
4635 *arglist->lastp = exparg.list;
4636 arglist->lastp = exparg.lastp;
4637 }
4638}
4639
4640
Eric Andersenc470f442003-07-28 09:56:35 +00004641/*
4642 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4643 * characters to allow for further processing. Otherwise treat
4644 * $@ like $* since no splitting will be performed.
4645 */
4646
4647static void
4648argstr(char *p, int flag)
4649{
4650 static const char spclchars[] = {
4651 '=',
4652 ':',
4653 CTLQUOTEMARK,
4654 CTLENDVAR,
4655 CTLESC,
4656 CTLVAR,
4657 CTLBACKQ,
4658 CTLBACKQ | CTLQUOTE,
4659#ifdef CONFIG_ASH_MATH_SUPPORT
4660 CTLENDARI,
4661#endif
4662 0
4663 };
4664 const char *reject = spclchars;
4665 int c;
4666 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4667 int breakall = flag & EXP_WORD;
4668 int inquotes;
4669 size_t length;
4670 int startloc;
4671
4672 if (!(flag & EXP_VARTILDE)) {
4673 reject += 2;
4674 } else if (flag & EXP_VARTILDE2) {
4675 reject++;
4676 }
4677 inquotes = 0;
4678 length = 0;
4679 if (flag & EXP_TILDE) {
4680 char *q;
4681
4682 flag &= ~EXP_TILDE;
4683tilde:
4684 q = p;
4685 if (*q == CTLESC && (flag & EXP_QWORD))
4686 q++;
4687 if (*q == '~')
4688 p = exptilde(p, q, flag);
4689 }
4690start:
4691 startloc = expdest - (char *)stackblock();
4692 for (;;) {
4693 length += strcspn(p + length, reject);
4694 c = p[length];
4695 if (c && (!(c & 0x80)
4696#ifdef CONFIG_ASH_MATH_SUPPORT
4697 || c == CTLENDARI
4698#endif
4699 )) {
4700 /* c == '=' || c == ':' || c == CTLENDARI */
4701 length++;
4702 }
4703 if (length > 0) {
4704 int newloc;
4705 expdest = stnputs(p, length, expdest);
4706 newloc = expdest - (char *)stackblock();
4707 if (breakall && !inquotes && newloc > startloc) {
4708 recordregion(startloc, newloc, 0);
4709 }
4710 startloc = newloc;
4711 }
4712 p += length + 1;
4713 length = 0;
4714
4715 switch (c) {
4716 case '\0':
4717 goto breakloop;
4718 case '=':
4719 if (flag & EXP_VARTILDE2) {
4720 p--;
4721 continue;
4722 }
4723 flag |= EXP_VARTILDE2;
4724 reject++;
4725 /* fall through */
4726 case ':':
4727 /*
4728 * sort of a hack - expand tildes in variable
4729 * assignments (after the first '=' and after ':'s).
4730 */
4731 if (*--p == '~') {
4732 goto tilde;
4733 }
4734 continue;
4735 }
4736
4737 switch (c) {
4738 case CTLENDVAR: /* ??? */
4739 goto breakloop;
4740 case CTLQUOTEMARK:
4741 /* "$@" syntax adherence hack */
4742 if (
4743 !inquotes &&
4744 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4745 (p[4] == CTLQUOTEMARK || (
4746 p[4] == CTLENDVAR &&
4747 p[5] == CTLQUOTEMARK
4748 ))
4749 ) {
4750 p = evalvar(p + 1, flag) + 1;
4751 goto start;
4752 }
4753 inquotes = !inquotes;
4754addquote:
4755 if (quotes) {
4756 p--;
4757 length++;
4758 startloc++;
4759 }
4760 break;
4761 case CTLESC:
4762 startloc++;
4763 length++;
4764 goto addquote;
4765 case CTLVAR:
4766 p = evalvar(p, flag);
4767 goto start;
4768 case CTLBACKQ:
4769 c = 0;
4770 case CTLBACKQ|CTLQUOTE:
4771 expbackq(argbackq->n, c, quotes);
4772 argbackq = argbackq->next;
4773 goto start;
4774#ifdef CONFIG_ASH_MATH_SUPPORT
4775 case CTLENDARI:
4776 p--;
4777 expari(quotes);
4778 goto start;
4779#endif
4780 }
4781 }
4782breakloop:
4783 ;
4784}
4785
4786static char *
4787exptilde(char *startp, char *p, int flag)
4788{
4789 char c;
4790 char *name;
4791 struct passwd *pw;
4792 const char *home;
4793 int quotes = flag & (EXP_FULL | EXP_CASE);
4794 int startloc;
4795
4796 name = p + 1;
4797
4798 while ((c = *++p) != '\0') {
4799 switch(c) {
4800 case CTLESC:
4801 return (startp);
4802 case CTLQUOTEMARK:
4803 return (startp);
4804 case ':':
4805 if (flag & EXP_VARTILDE)
4806 goto done;
4807 break;
4808 case '/':
4809 case CTLENDVAR:
4810 goto done;
4811 }
4812 }
4813done:
4814 *p = '\0';
4815 if (*name == '\0') {
4816 if ((home = lookupvar(homestr)) == NULL)
4817 goto lose;
4818 } else {
4819 if ((pw = getpwnam(name)) == NULL)
4820 goto lose;
4821 home = pw->pw_dir;
4822 }
4823 if (*home == '\0')
4824 goto lose;
4825 *p = c;
4826 startloc = expdest - (char *)stackblock();
4827 strtodest(home, SQSYNTAX, quotes);
4828 recordregion(startloc, expdest - (char *)stackblock(), 0);
4829 return (p);
4830lose:
4831 *p = c;
4832 return (startp);
4833}
4834
4835
4836static void
4837removerecordregions(int endoff)
4838{
4839 if (ifslastp == NULL)
4840 return;
4841
4842 if (ifsfirst.endoff > endoff) {
4843 while (ifsfirst.next != NULL) {
4844 struct ifsregion *ifsp;
4845 INTOFF;
4846 ifsp = ifsfirst.next->next;
4847 ckfree(ifsfirst.next);
4848 ifsfirst.next = ifsp;
4849 INTON;
4850 }
4851 if (ifsfirst.begoff > endoff)
4852 ifslastp = NULL;
4853 else {
4854 ifslastp = &ifsfirst;
4855 ifsfirst.endoff = endoff;
4856 }
4857 return;
4858 }
4859
4860 ifslastp = &ifsfirst;
4861 while (ifslastp->next && ifslastp->next->begoff < endoff)
4862 ifslastp=ifslastp->next;
4863 while (ifslastp->next != NULL) {
4864 struct ifsregion *ifsp;
4865 INTOFF;
4866 ifsp = ifslastp->next->next;
4867 ckfree(ifslastp->next);
4868 ifslastp->next = ifsp;
4869 INTON;
4870 }
4871 if (ifslastp->endoff > endoff)
4872 ifslastp->endoff = endoff;
4873}
4874
4875
4876#ifdef CONFIG_ASH_MATH_SUPPORT
4877/*
4878 * Expand arithmetic expression. Backup to start of expression,
4879 * evaluate, place result in (backed up) result, adjust string position.
4880 */
4881void
4882expari(int quotes)
4883{
4884 char *p, *start;
4885 int begoff;
4886 int flag;
4887 int len;
4888
4889 /* ifsfree(); */
4890
4891 /*
4892 * This routine is slightly over-complicated for
4893 * efficiency. Next we scan backwards looking for the
4894 * start of arithmetic.
4895 */
4896 start = stackblock();
4897 p = expdest - 1;
4898 *p = '\0';
4899 p--;
4900 do {
4901 int esc;
4902
4903 while (*p != CTLARI) {
4904 p--;
4905#ifdef DEBUG
4906 if (p < start) {
4907 error("missing CTLARI (shouldn't happen)");
4908 }
4909#endif
4910 }
4911
4912 esc = esclen(start, p);
4913 if (!(esc % 2)) {
4914 break;
4915 }
4916
4917 p -= esc + 1;
4918 } while (1);
4919
4920 begoff = p - start;
4921
4922 removerecordregions(begoff);
4923
4924 flag = p[1];
4925
4926 expdest = p;
4927
4928 if (quotes)
4929 rmescapes(p + 2);
4930
4931 len = cvtnum(dash_arith(p + 2));
4932
4933 if (flag != '"')
4934 recordregion(begoff, begoff + len, 0);
4935}
4936#endif
4937
4938/*
4939 * Expand stuff in backwards quotes.
4940 */
4941
4942static void
4943expbackq(union node *cmd, int quoted, int quotes)
4944{
4945 struct backcmd in;
4946 int i;
4947 char buf[128];
4948 char *p;
4949 char *dest;
4950 int startloc;
4951 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4952 struct stackmark smark;
4953
4954 INTOFF;
4955 setstackmark(&smark);
4956 dest = expdest;
4957 startloc = dest - (char *)stackblock();
4958 grabstackstr(dest);
4959 evalbackcmd(cmd, (struct backcmd *) &in);
4960 popstackmark(&smark);
4961
4962 p = in.buf;
4963 i = in.nleft;
4964 if (i == 0)
4965 goto read;
4966 for (;;) {
4967 memtodest(p, i, syntax, quotes);
4968read:
4969 if (in.fd < 0)
4970 break;
4971 i = safe_read(in.fd, buf, sizeof buf);
4972 TRACE(("expbackq: read returns %d\n", i));
4973 if (i <= 0)
4974 break;
4975 p = buf;
4976 }
4977
4978 if (in.buf)
4979 ckfree(in.buf);
4980 if (in.fd >= 0) {
4981 close(in.fd);
4982 back_exitstatus = waitforjob(in.jp);
4983 }
4984 INTON;
4985
4986 /* Eat all trailing newlines */
4987 dest = expdest;
4988 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4989 STUNPUTC(dest);
4990 expdest = dest;
4991
4992 if (quoted == 0)
4993 recordregion(startloc, dest - (char *)stackblock(), 0);
4994 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4995 (dest - (char *)stackblock()) - startloc,
4996 (dest - (char *)stackblock()) - startloc,
4997 stackblock() + startloc));
4998}
4999
5000
5001static char *
Eric Andersen90898442003-08-06 11:20:52 +00005002scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5003 int zero)
5004{
Eric Andersenc470f442003-07-28 09:56:35 +00005005 char *loc;
5006 char *loc2;
5007 char c;
5008
5009 loc = startp;
5010 loc2 = rmesc;
5011 do {
5012 int match;
5013 const char *s = loc2;
5014 c = *loc2;
5015 if (zero) {
5016 *loc2 = '\0';
5017 s = rmesc;
5018 }
5019 match = pmatch(str, s);
5020 *loc2 = c;
5021 if (match)
5022 return loc;
5023 if (quotes && *loc == CTLESC)
5024 loc++;
5025 loc++;
5026 loc2++;
5027 } while (c);
5028 return 0;
5029}
5030
5031
5032static char *
Eric Andersen90898442003-08-06 11:20:52 +00005033scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5034 int zero)
5035{
Eric Andersenc470f442003-07-28 09:56:35 +00005036 int esc = 0;
5037 char *loc;
5038 char *loc2;
5039
5040 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5041 int match;
5042 char c = *loc2;
5043 const char *s = loc2;
5044 if (zero) {
5045 *loc2 = '\0';
5046 s = rmesc;
5047 }
5048 match = pmatch(str, s);
5049 *loc2 = c;
5050 if (match)
5051 return loc;
5052 loc--;
5053 if (quotes) {
5054 if (--esc < 0) {
5055 esc = esclen(startp, loc);
5056 }
5057 if (esc % 2) {
5058 esc--;
5059 loc--;
5060 }
5061 }
5062 }
5063 return 0;
5064}
5065
5066static const char *
5067subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5068{
5069 char *startp;
5070 char *loc;
5071 int saveherefd = herefd;
5072 struct nodelist *saveargbackq = argbackq;
5073 int amount;
5074 char *rmesc, *rmescend;
5075 int zero;
5076 char *(*scan)(char *, char *, char *, char *, int , int);
5077
5078 herefd = -1;
5079 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5080 STPUTC('\0', expdest);
5081 herefd = saveherefd;
5082 argbackq = saveargbackq;
5083 startp = stackblock() + startloc;
5084
5085 switch (subtype) {
5086 case VSASSIGN:
5087 setvar(str, startp, 0);
5088 amount = startp - expdest;
5089 STADJUST(amount, expdest);
5090 return startp;
5091
5092 case VSQUESTION:
5093 varunset(p, str, startp, varflags);
5094 /* NOTREACHED */
5095 }
5096
5097 subtype -= VSTRIMRIGHT;
5098#ifdef DEBUG
5099 if (subtype < 0 || subtype > 3)
5100 abort();
5101#endif
5102
5103 rmesc = startp;
5104 rmescend = stackblock() + strloc;
5105 if (quotes) {
5106 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5107 if (rmesc != startp) {
5108 rmescend = expdest;
5109 startp = stackblock() + startloc;
5110 }
5111 }
5112 rmescend--;
5113 str = stackblock() + strloc;
5114 preglob(str, varflags & VSQUOTE, 0);
5115
5116 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5117 zero = subtype >> 1;
5118 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5119 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5120
5121 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5122 if (loc) {
5123 if (zero) {
5124 memmove(startp, loc, str - loc);
5125 loc = startp + (str - loc) - 1;
5126 }
5127 *loc = '\0';
5128 amount = loc - expdest;
5129 STADJUST(amount, expdest);
5130 }
5131 return loc;
5132}
5133
5134
Eric Andersen62483552001-07-10 06:09:16 +00005135/*
5136 * Expand a variable, and return a pointer to the next character in the
5137 * input string.
5138 */
Eric Andersenc470f442003-07-28 09:56:35 +00005139static char *
5140evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005141{
5142 int subtype;
5143 int varflags;
5144 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005145 int patloc;
5146 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005147 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005148 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005149 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005150 int quotes;
5151 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005152
Eric Andersenc470f442003-07-28 09:56:35 +00005153 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005154 varflags = *p++;
5155 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005156 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005157 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005158 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005159 startloc = expdest - (char *)stackblock();
5160 p = strchr(p, '=') + 1;
5161
Eric Andersenc470f442003-07-28 09:56:35 +00005162again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005163 varlen = varvalue(var, varflags, flag);
5164 if (varflags & VSNUL)
5165 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005166
Glenn L McGrath76620622004-01-13 10:19:37 +00005167 if (subtype == VSPLUS) {
5168 varlen = -1 - varlen;
5169 goto vsplus;
5170 }
Eric Andersen62483552001-07-10 06:09:16 +00005171
Eric Andersenc470f442003-07-28 09:56:35 +00005172 if (subtype == VSMINUS) {
5173vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005174 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005175 argstr(
5176 p, flag | EXP_TILDE |
5177 (quoted ? EXP_QWORD : EXP_WORD)
5178 );
5179 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005180 }
5181 if (easy)
5182 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005183 goto end;
5184 }
Eric Andersen62483552001-07-10 06:09:16 +00005185
Eric Andersenc470f442003-07-28 09:56:35 +00005186 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005187 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005188 if (subevalvar(p, var, 0, subtype, startloc,
5189 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005190 varflags &= ~VSNUL;
5191 /*
5192 * Remove any recorded regions beyond
5193 * start of variable
5194 */
5195 removerecordregions(startloc);
5196 goto again;
5197 }
Eric Andersenc470f442003-07-28 09:56:35 +00005198 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005199 }
5200 if (easy)
5201 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005202 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005203 }
5204
Glenn L McGrath76620622004-01-13 10:19:37 +00005205 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005206 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005207
Eric Andersenc470f442003-07-28 09:56:35 +00005208 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005209 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005210 goto record;
5211 }
5212
5213 if (subtype == VSNORMAL) {
5214 if (!easy)
5215 goto end;
5216record:
5217 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5218 goto end;
5219 }
5220
5221#ifdef DEBUG
5222 switch (subtype) {
5223 case VSTRIMLEFT:
5224 case VSTRIMLEFTMAX:
5225 case VSTRIMRIGHT:
5226 case VSTRIMRIGHTMAX:
5227 break;
5228 default:
5229 abort();
5230 }
5231#endif
5232
Glenn L McGrath76620622004-01-13 10:19:37 +00005233 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005234 /*
5235 * Terminate the string and start recording the pattern
5236 * right after it
5237 */
5238 STPUTC('\0', expdest);
5239 patloc = expdest - (char *)stackblock();
5240 if (subevalvar(p, NULL, patloc, subtype,
5241 startloc, varflags, quotes) == 0) {
5242 int amount = expdest - (
5243 (char *)stackblock() + patloc - 1
5244 );
5245 STADJUST(-amount, expdest);
5246 }
5247 /* Remove any recorded regions beyond start of variable */
5248 removerecordregions(startloc);
5249 goto record;
5250 }
5251
5252end:
5253 if (subtype != VSNORMAL) { /* skip to end of alternative */
5254 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005255 for (;;) {
5256 if ((c = *p++) == CTLESC)
5257 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005258 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005259 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005260 argbackq = argbackq->next;
5261 } else if (c == CTLVAR) {
5262 if ((*p++ & VSTYPE) != VSNORMAL)
5263 nesting++;
5264 } else if (c == CTLENDVAR) {
5265 if (--nesting == 0)
5266 break;
5267 }
5268 }
5269 }
5270 return p;
5271}
5272
Eric Andersencb57d552001-06-28 07:25:16 +00005273
Eric Andersencb57d552001-06-28 07:25:16 +00005274/*
5275 * Put a string on the stack.
5276 */
5277
Eric Andersenc470f442003-07-28 09:56:35 +00005278static void
5279memtodest(const char *p, size_t len, int syntax, int quotes) {
5280 char *q = expdest;
5281
5282 q = makestrspace(len * 2, q);
5283
5284 while (len--) {
5285 int c = *p++;
5286 if (!c)
5287 continue;
5288 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5289 USTPUTC(CTLESC, q);
5290 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005291 }
Eric Andersenc470f442003-07-28 09:56:35 +00005292
5293 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005294}
5295
Eric Andersenc470f442003-07-28 09:56:35 +00005296
5297static void
5298strtodest(const char *p, int syntax, int quotes)
5299{
5300 memtodest(p, strlen(p), syntax, quotes);
5301}
5302
5303
Eric Andersencb57d552001-06-28 07:25:16 +00005304/*
5305 * Add the value of a specialized variable to the stack string.
5306 */
5307
Glenn L McGrath76620622004-01-13 10:19:37 +00005308static ssize_t
5309varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005310{
5311 int num;
5312 char *p;
5313 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005314 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005315 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005316 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005317 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005318 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005319 int quoted = varflags & VSQUOTE;
5320 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005321 int quotes = flags & (EXP_FULL | EXP_CASE);
5322
Glenn L McGrath76620622004-01-13 10:19:37 +00005323 if (quoted && (flags & EXP_FULL))
5324 sep = 1 << CHAR_BIT;
5325
Eric Andersencb57d552001-06-28 07:25:16 +00005326 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5327 switch (*name) {
5328 case '$':
5329 num = rootpid;
5330 goto numvar;
5331 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005332 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005333 goto numvar;
5334 case '#':
5335 num = shellparam.nparam;
5336 goto numvar;
5337 case '!':
5338 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005339 if (num == 0)
5340 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005341numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005342 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005343 break;
5344 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005345 p = makestrspace(NOPTS, expdest);
5346 for (i = NOPTS - 1; i >= 0; i--) {
5347 if (optlist[i]) {
5348 USTPUTC(optletters(i), p);
5349 len++;
5350 }
Eric Andersencb57d552001-06-28 07:25:16 +00005351 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005352 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005353 break;
5354 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005355 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005356 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005357 /* fall through */
5358 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005359 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005360 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5361 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005362param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005363 if (!(ap = shellparam.p))
5364 return -1;
5365 while ((p = *ap++)) {
5366 size_t partlen;
5367
5368 partlen = strlen(p);
5369
5370 len += partlen;
5371 if (len > partlen && sep) {
5372 char *q;
5373
5374 len++;
5375 if (subtype == VSPLUS || subtype == VSLENGTH) {
5376 continue;
5377 }
5378 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005379 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005380 STPUTC(CTLESC, q);
5381 STPUTC(sep, q);
5382 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005383 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005384
5385 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5386 memtodest(p, partlen, syntax, quotes);
Eric Andersencb57d552001-06-28 07:25:16 +00005387 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005388 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005389 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005390 case '1':
5391 case '2':
5392 case '3':
5393 case '4':
5394 case '5':
5395 case '6':
5396 case '7':
5397 case '8':
5398 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005399 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005400 if (num < 0 || num > shellparam.nparam)
5401 return -1;
5402 p = num ? shellparam.p[num - 1] : arg0;
5403 goto value;
5404 default:
5405 p = lookupvar(name);
5406value:
5407 if (!p)
5408 return -1;
5409
5410 len = strlen(p);
5411 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5412 memtodest(p, len, syntax, quotes);
5413 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005414 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005415
5416 if (subtype == VSPLUS || subtype == VSLENGTH)
5417 STADJUST(-len, expdest);
5418 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005419}
5420
5421
Eric Andersencb57d552001-06-28 07:25:16 +00005422/*
5423 * Record the fact that we have to scan this region of the
5424 * string for IFS characters.
5425 */
5426
Eric Andersenc470f442003-07-28 09:56:35 +00005427static void
5428recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005429{
5430 struct ifsregion *ifsp;
5431
5432 if (ifslastp == NULL) {
5433 ifsp = &ifsfirst;
5434 } else {
5435 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005436 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005437 ifsp->next = NULL;
5438 ifslastp->next = ifsp;
5439 INTON;
5440 }
5441 ifslastp = ifsp;
5442 ifslastp->begoff = start;
5443 ifslastp->endoff = end;
5444 ifslastp->nulonly = nulonly;
5445}
5446
5447
Eric Andersencb57d552001-06-28 07:25:16 +00005448/*
5449 * Break the argument string into pieces based upon IFS and add the
5450 * strings to the argument list. The regions of the string to be
5451 * searched for IFS characters have been stored by recordregion.
5452 */
Eric Andersenc470f442003-07-28 09:56:35 +00005453static void
5454ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005455{
Eric Andersencb57d552001-06-28 07:25:16 +00005456 struct ifsregion *ifsp;
5457 struct strlist *sp;
5458 char *start;
5459 char *p;
5460 char *q;
5461 const char *ifs, *realifs;
5462 int ifsspc;
5463 int nulonly;
5464
5465
5466 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005467 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005468 ifsspc = 0;
5469 nulonly = 0;
5470 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005471 ifsp = &ifsfirst;
5472 do {
5473 p = string + ifsp->begoff;
5474 nulonly = ifsp->nulonly;
5475 ifs = nulonly ? nullstr : realifs;
5476 ifsspc = 0;
5477 while (p < string + ifsp->endoff) {
5478 q = p;
5479 if (*p == CTLESC)
5480 p++;
5481 if (strchr(ifs, *p)) {
5482 if (!nulonly)
5483 ifsspc = (strchr(defifs, *p) != NULL);
5484 /* Ignore IFS whitespace at start */
5485 if (q == start && ifsspc) {
5486 p++;
5487 start = p;
5488 continue;
5489 }
5490 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005491 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005492 sp->text = start;
5493 *arglist->lastp = sp;
5494 arglist->lastp = &sp->next;
5495 p++;
5496 if (!nulonly) {
5497 for (;;) {
5498 if (p >= string + ifsp->endoff) {
5499 break;
5500 }
5501 q = p;
5502 if (*p == CTLESC)
5503 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005504 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005505 p = q;
5506 break;
5507 } else if (strchr(defifs, *p) == NULL) {
5508 if (ifsspc) {
5509 p++;
5510 ifsspc = 0;
5511 } else {
5512 p = q;
5513 break;
5514 }
5515 } else
5516 p++;
5517 }
5518 }
5519 start = p;
5520 } else
5521 p++;
5522 }
5523 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005524 if (nulonly)
5525 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005526 }
5527
Eric Andersenc470f442003-07-28 09:56:35 +00005528 if (!*start)
5529 return;
5530
5531add:
5532 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005533 sp->text = start;
5534 *arglist->lastp = sp;
5535 arglist->lastp = &sp->next;
5536}
5537
Eric Andersenc470f442003-07-28 09:56:35 +00005538static void
5539ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005540{
Eric Andersenc470f442003-07-28 09:56:35 +00005541 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005542
Eric Andersenc470f442003-07-28 09:56:35 +00005543 INTOFF;
5544 p = ifsfirst.next;
5545 do {
5546 struct ifsregion *ifsp;
5547 ifsp = p->next;
5548 ckfree(p);
5549 p = ifsp;
5550 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005551 ifslastp = NULL;
5552 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005553 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005554}
5555
Eric Andersen90898442003-08-06 11:20:52 +00005556static void expmeta(char *, char *);
5557static struct strlist *expsort(struct strlist *);
5558static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005559
Eric Andersen90898442003-08-06 11:20:52 +00005560static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005561
Eric Andersencb57d552001-06-28 07:25:16 +00005562
Eric Andersenc470f442003-07-28 09:56:35 +00005563static void
Eric Andersen90898442003-08-06 11:20:52 +00005564expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005565{
Eric Andersen90898442003-08-06 11:20:52 +00005566 static const char metachars[] = {
5567 '*', '?', '[', 0
5568 };
Eric Andersencb57d552001-06-28 07:25:16 +00005569 /* TODO - EXP_REDIR */
5570
5571 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005572 struct strlist **savelastp;
5573 struct strlist *sp;
5574 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005575
Eric Andersencb57d552001-06-28 07:25:16 +00005576 if (fflag)
5577 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005578 if (!strpbrk(str->text, metachars))
5579 goto nometa;
5580 savelastp = exparg.lastp;
5581
Eric Andersencb57d552001-06-28 07:25:16 +00005582 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005583 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005584 {
5585 int i = strlen(str->text);
5586 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5587 }
5588
5589 expmeta(expdir, p);
5590 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005591 if (p != str->text)
5592 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005593 INTON;
5594 if (exparg.lastp == savelastp) {
5595 /*
5596 * no matches
5597 */
Eric Andersenc470f442003-07-28 09:56:35 +00005598nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005599 *exparg.lastp = str;
5600 rmescapes(str->text);
5601 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005602 } else {
5603 *exparg.lastp = NULL;
5604 *savelastp = sp = expsort(*savelastp);
5605 while (sp->next != NULL)
5606 sp = sp->next;
5607 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005608 }
5609 str = str->next;
5610 }
5611}
5612
Eric Andersencb57d552001-06-28 07:25:16 +00005613/*
Eric Andersenc470f442003-07-28 09:56:35 +00005614 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005615 */
5616
Eric Andersenc470f442003-07-28 09:56:35 +00005617static void
Eric Andersen90898442003-08-06 11:20:52 +00005618addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005619{
Eric Andersencb57d552001-06-28 07:25:16 +00005620 struct strlist *sp;
5621
Eric Andersenc470f442003-07-28 09:56:35 +00005622 sp = (struct strlist *)stalloc(sizeof *sp);
5623 sp->text = sstrdup(name);
5624 *exparg.lastp = sp;
5625 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005626}
5627
5628
Eric Andersencb57d552001-06-28 07:25:16 +00005629/*
Eric Andersen90898442003-08-06 11:20:52 +00005630 * Do metacharacter (i.e. *, ?, [...]) expansion.
5631 */
5632
5633static void
5634expmeta(char *enddir, char *name)
5635{
5636 char *p;
5637 const char *cp;
5638 char *start;
5639 char *endname;
5640 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005641 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005642 DIR *dirp;
5643 struct dirent *dp;
5644 int atend;
5645 int matchdot;
5646
5647 metaflag = 0;
5648 start = name;
5649 for (p = name; *p; p++) {
5650 if (*p == '*' || *p == '?')
5651 metaflag = 1;
5652 else if (*p == '[') {
5653 char *q = p + 1;
5654 if (*q == '!')
5655 q++;
5656 for (;;) {
5657 if (*q == '\\')
5658 q++;
5659 if (*q == '/' || *q == '\0')
5660 break;
5661 if (*++q == ']') {
5662 metaflag = 1;
5663 break;
5664 }
5665 }
5666 } else if (*p == '\\')
5667 p++;
5668 else if (*p == '/') {
5669 if (metaflag)
5670 goto out;
5671 start = p + 1;
5672 }
5673 }
5674out:
5675 if (metaflag == 0) { /* we've reached the end of the file name */
5676 if (enddir != expdir)
5677 metaflag++;
5678 p = name;
5679 do {
5680 if (*p == '\\')
5681 p++;
5682 *enddir++ = *p;
5683 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005684 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005685 addfname(expdir);
5686 return;
5687 }
5688 endname = p;
5689 if (name < start) {
5690 p = name;
5691 do {
5692 if (*p == '\\')
5693 p++;
5694 *enddir++ = *p++;
5695 } while (p < start);
5696 }
5697 if (enddir == expdir) {
5698 cp = ".";
5699 } else if (enddir == expdir + 1 && *expdir == '/') {
5700 cp = "/";
5701 } else {
5702 cp = expdir;
5703 enddir[-1] = '\0';
5704 }
5705 if ((dirp = opendir(cp)) == NULL)
5706 return;
5707 if (enddir != expdir)
5708 enddir[-1] = '/';
5709 if (*endname == 0) {
5710 atend = 1;
5711 } else {
5712 atend = 0;
5713 *endname++ = '\0';
5714 }
5715 matchdot = 0;
5716 p = start;
5717 if (*p == '\\')
5718 p++;
5719 if (*p == '.')
5720 matchdot++;
5721 while (! intpending && (dp = readdir(dirp)) != NULL) {
5722 if (dp->d_name[0] == '.' && ! matchdot)
5723 continue;
5724 if (pmatch(start, dp->d_name)) {
5725 if (atend) {
5726 scopy(dp->d_name, enddir);
5727 addfname(expdir);
5728 } else {
5729 for (p = enddir, cp = dp->d_name;
5730 (*p++ = *cp++) != '\0';)
5731 continue;
5732 p[-1] = '/';
5733 expmeta(p, endname);
5734 }
5735 }
5736 }
5737 closedir(dirp);
5738 if (! atend)
5739 endname[-1] = '/';
5740}
5741
5742/*
5743 * Sort the results of file name expansion. It calculates the number of
5744 * strings to sort and then calls msort (short for merge sort) to do the
5745 * work.
5746 */
5747
5748static struct strlist *
5749expsort(struct strlist *str)
5750{
5751 int len;
5752 struct strlist *sp;
5753
5754 len = 0;
5755 for (sp = str ; sp ; sp = sp->next)
5756 len++;
5757 return msort(str, len);
5758}
5759
5760
5761static struct strlist *
5762msort(struct strlist *list, int len)
5763{
5764 struct strlist *p, *q = NULL;
5765 struct strlist **lpp;
5766 int half;
5767 int n;
5768
5769 if (len <= 1)
5770 return list;
5771 half = len >> 1;
5772 p = list;
5773 for (n = half ; --n >= 0 ; ) {
5774 q = p;
5775 p = p->next;
5776 }
5777 q->next = NULL; /* terminate first half of list */
5778 q = msort(list, half); /* sort first half of list */
5779 p = msort(p, len - half); /* sort second half */
5780 lpp = &list;
5781 for (;;) {
5782#ifdef CONFIG_LOCALE_SUPPORT
5783 if (strcoll(p->text, q->text) < 0)
5784#else
5785 if (strcmp(p->text, q->text) < 0)
5786#endif
5787 {
5788 *lpp = p;
5789 lpp = &p->next;
5790 if ((p = *lpp) == NULL) {
5791 *lpp = q;
5792 break;
5793 }
5794 } else {
5795 *lpp = q;
5796 lpp = &q->next;
5797 if ((q = *lpp) == NULL) {
5798 *lpp = p;
5799 break;
5800 }
5801 }
5802 }
5803 return list;
5804}
5805
5806
5807/*
Eric Andersencb57d552001-06-28 07:25:16 +00005808 * Returns true if the pattern matches the string.
5809 */
5810
Eric Andersenc470f442003-07-28 09:56:35 +00005811static inline int
5812patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005813{
Eric Andersenc470f442003-07-28 09:56:35 +00005814 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005815}
5816
5817
Eric Andersencb57d552001-06-28 07:25:16 +00005818/*
5819 * Remove any CTLESC characters from a string.
5820 */
5821
Eric Andersenc470f442003-07-28 09:56:35 +00005822static char *
5823_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005824{
5825 char *p, *q, *r;
5826 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005827 unsigned inquotes;
5828 int notescaped;
5829 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005830
5831 p = strpbrk(str, qchars);
5832 if (!p) {
5833 return str;
5834 }
5835 q = p;
5836 r = str;
5837 if (flag & RMESCAPE_ALLOC) {
5838 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005839 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005840
Eric Andersenc470f442003-07-28 09:56:35 +00005841 if (flag & RMESCAPE_GROW) {
5842 r = makestrspace(fulllen, expdest);
5843 } else if (flag & RMESCAPE_HEAP) {
5844 r = ckmalloc(fulllen);
5845 } else {
5846 r = stalloc(fulllen);
5847 }
5848 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005849 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005850 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005851 }
5852 }
Eric Andersenc470f442003-07-28 09:56:35 +00005853 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5854 globbing = flag & RMESCAPE_GLOB;
5855 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005856 while (*p) {
5857 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005858 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005859 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005860 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005861 continue;
5862 }
Eric Andersenc470f442003-07-28 09:56:35 +00005863 if (*p == '\\') {
5864 /* naked back slash */
5865 notescaped = 0;
5866 goto copy;
5867 }
Eric Andersencb57d552001-06-28 07:25:16 +00005868 if (*p == CTLESC) {
5869 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005870 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005871 *q++ = '\\';
5872 }
5873 }
Eric Andersenc470f442003-07-28 09:56:35 +00005874 notescaped = globbing;
5875copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005876 *q++ = *p++;
5877 }
5878 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005879 if (flag & RMESCAPE_GROW) {
5880 expdest = r;
5881 STADJUST(q - r + 1, expdest);
5882 }
Eric Andersencb57d552001-06-28 07:25:16 +00005883 return r;
5884}
Eric Andersencb57d552001-06-28 07:25:16 +00005885
5886
Eric Andersencb57d552001-06-28 07:25:16 +00005887/*
5888 * See if a pattern matches in a case statement.
5889 */
5890
Eric Andersenc470f442003-07-28 09:56:35 +00005891int
5892casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005893{
Eric Andersencb57d552001-06-28 07:25:16 +00005894 struct stackmark smark;
5895 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005896
5897 setstackmark(&smark);
5898 argbackq = pattern->narg.backquote;
5899 STARTSTACKSTR(expdest);
5900 ifslastp = NULL;
5901 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005902 STACKSTRNUL(expdest);
5903 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005904 popstackmark(&smark);
5905 return result;
5906}
5907
5908/*
5909 * Our own itoa().
5910 */
5911
Eric Andersenc470f442003-07-28 09:56:35 +00005912static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005913cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005914{
Eric Andersencb57d552001-06-28 07:25:16 +00005915 int len;
5916
Eric Andersenc470f442003-07-28 09:56:35 +00005917 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005918#ifdef CONFIG_ASH_MATH_SUPPORT_64
5919 len = fmtstr(expdest, 32, "%lld", (long long) num);
5920#else
Eric Andersenc470f442003-07-28 09:56:35 +00005921 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005922#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005923 STADJUST(len, expdest);
5924 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005925}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005926
Eric Andersenc470f442003-07-28 09:56:35 +00005927static void
5928varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005929{
Eric Andersenc470f442003-07-28 09:56:35 +00005930 const char *msg;
5931 const char *tail;
5932
5933 tail = nullstr;
5934 msg = "parameter not set";
5935 if (umsg) {
5936 if (*end == CTLENDVAR) {
5937 if (varflags & VSNUL)
5938 tail = " or null";
5939 } else
5940 msg = umsg;
5941 }
5942 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005943}
Eric Andersen90898442003-08-06 11:20:52 +00005944
5945
Eric Andersenc470f442003-07-28 09:56:35 +00005946/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005947
Eric Andersencb57d552001-06-28 07:25:16 +00005948/*
Eric Andersen90898442003-08-06 11:20:52 +00005949 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005950 */
5951
Eric Andersenc470f442003-07-28 09:56:35 +00005952#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5953#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005954
Eric Andersenc470f442003-07-28 09:56:35 +00005955static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005956
Eric Andersencb57d552001-06-28 07:25:16 +00005957/*
Eric Andersenc470f442003-07-28 09:56:35 +00005958 * Read a character from the script, returning PEOF on end of file.
5959 * Nul characters in the input are silently discarded.
5960 */
5961
5962#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5963
5964#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5965#define pgetc_macro() pgetc()
5966static int
5967pgetc(void)
5968{
5969 return pgetc_as_macro();
5970}
5971#else
5972#define pgetc_macro() pgetc_as_macro()
5973static int
5974pgetc(void)
5975{
5976 return pgetc_macro();
5977}
5978#endif
5979
5980
5981/*
5982 * Same as pgetc(), but ignores PEOA.
5983 */
5984#ifdef CONFIG_ASH_ALIAS
5985static int pgetc2(void)
5986{
5987 int c;
5988
5989 do {
5990 c = pgetc_macro();
5991 } while (c == PEOA);
5992 return c;
5993}
5994#else
5995static inline int pgetc2(void)
5996{
5997 return pgetc_macro();
5998}
5999#endif
6000
Glenn L McGrath28939ad2004-07-21 10:20:19 +00006001/*
6002 * Read a line from the script.
6003 */
6004
6005static inline char *
6006pfgets(char *line, int len)
6007{
6008 char *p = line;
6009 int nleft = len;
6010 int c;
6011
6012 while (--nleft > 0) {
6013 c = pgetc2();
6014 if (c == PEOF) {
6015 if (p == line)
6016 return NULL;
6017 break;
6018 }
6019 *p++ = c;
6020 if (c == '\n')
6021 break;
6022 }
6023 *p = '\0';
6024 return line;
6025}
6026
6027
Eric Andersenc470f442003-07-28 09:56:35 +00006028
6029#ifdef CONFIG_FEATURE_COMMAND_EDITING
6030static const char *cmdedit_prompt;
6031static inline void putprompt(const char *s)
6032{
6033 cmdedit_prompt = s;
6034}
6035#else
6036static inline void putprompt(const char *s)
6037{
6038 out2str(s);
6039}
6040#endif
6041
6042static inline int
6043preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006044{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006045 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006046 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006047 parsenextc = buf;
6048
Eric Andersenc470f442003-07-28 09:56:35 +00006049retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006050#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006051 if (!iflag || parsefile->fd)
6052 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6053 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006054#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006055 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006056#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006057 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6058 if(nr == 0) {
6059 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006060 if(trap[SIGINT]) {
6061 buf[0] = '\n';
6062 buf[1] = 0;
6063 raise(SIGINT);
6064 return 1;
6065 }
Eric Andersenc470f442003-07-28 09:56:35 +00006066 goto retry;
6067 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006068 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006069 /* Ctrl+D presend */
6070 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006071 }
Eric Andersencb57d552001-06-28 07:25:16 +00006072 }
6073#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006074 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006075#endif
6076
6077 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006078 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6079 int flags = fcntl(0, F_GETFL, 0);
6080 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006081 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006082 if (fcntl(0, F_SETFL, flags) >= 0) {
6083 out2str("sh: turning off NDELAY mode\n");
6084 goto retry;
6085 }
6086 }
6087 }
6088 }
6089 return nr;
6090}
6091
6092/*
6093 * Refill the input buffer and return the next input character:
6094 *
6095 * 1) If a string was pushed back on the input, pop it;
6096 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6097 * from a string so we can't refill the buffer, return EOF.
6098 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6099 * 4) Process input up to the next newline, deleting nul characters.
6100 */
6101
Eric Andersenc470f442003-07-28 09:56:35 +00006102int
6103preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006104{
6105 char *p, *q;
6106 int more;
6107 char savec;
6108
6109 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006110#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006111 if (parsenleft == -1 && parsefile->strpush->ap &&
6112 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006113 return PEOA;
6114 }
Eric Andersen2870d962001-07-02 17:27:21 +00006115#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006116 popstring();
6117 if (--parsenleft >= 0)
6118 return (*parsenextc++);
6119 }
6120 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6121 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006122 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006123
Eric Andersenc470f442003-07-28 09:56:35 +00006124again:
Eric Andersencb57d552001-06-28 07:25:16 +00006125 if (parselleft <= 0) {
6126 if ((parselleft = preadfd()) <= 0) {
6127 parselleft = parsenleft = EOF_NLEFT;
6128 return PEOF;
6129 }
6130 }
6131
6132 q = p = parsenextc;
6133
6134 /* delete nul characters */
6135 for (more = 1; more;) {
6136 switch (*p) {
6137 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006138 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006139 goto check;
6140
Eric Andersencb57d552001-06-28 07:25:16 +00006141 case '\n':
6142 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006143 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006144 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006145
Eric Andersencb57d552001-06-28 07:25:16 +00006146 }
6147
6148 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006149check:
Eric Andersencb57d552001-06-28 07:25:16 +00006150 if (--parselleft <= 0 && more) {
6151 parsenleft = q - parsenextc - 1;
6152 if (parsenleft < 0)
6153 goto again;
6154 more = 0;
6155 }
6156 }
6157
6158 savec = *q;
6159 *q = '\0';
6160
6161 if (vflag) {
6162 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006163 }
6164
6165 *q = savec;
6166
6167 return *parsenextc++;
6168}
6169
Eric Andersenc470f442003-07-28 09:56:35 +00006170/*
6171 * Undo the last call to pgetc. Only one character may be pushed back.
6172 * PEOF may be pushed back.
6173 */
6174
6175void
6176pungetc(void)
6177{
6178 parsenleft++;
6179 parsenextc--;
6180}
Eric Andersencb57d552001-06-28 07:25:16 +00006181
6182/*
6183 * Push a string back onto the input at this current parsefile level.
6184 * We handle aliases this way.
6185 */
Eric Andersenc470f442003-07-28 09:56:35 +00006186void
6187pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006188{
Eric Andersencb57d552001-06-28 07:25:16 +00006189 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006190 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006191
Eric Andersenc470f442003-07-28 09:56:35 +00006192 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006193 INTOFF;
6194/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6195 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006196 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006197 sp->prev = parsefile->strpush;
6198 parsefile->strpush = sp;
6199 } else
6200 sp = parsefile->strpush = &(parsefile->basestrpush);
6201 sp->prevstring = parsenextc;
6202 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006203#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006204 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006205 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006206 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006207 sp->string = s;
6208 }
Eric Andersen2870d962001-07-02 17:27:21 +00006209#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006210 parsenextc = s;
6211 parsenleft = len;
6212 INTON;
6213}
6214
Eric Andersenc470f442003-07-28 09:56:35 +00006215void
6216popstring(void)
6217{
6218 struct strpush *sp = parsefile->strpush;
6219
6220 INTOFF;
6221#ifdef CONFIG_ASH_ALIAS
6222 if (sp->ap) {
6223 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6224 checkkwd |= CHKALIAS;
6225 }
6226 if (sp->string != sp->ap->val) {
6227 ckfree(sp->string);
6228 }
6229 sp->ap->flag &= ~ALIASINUSE;
6230 if (sp->ap->flag & ALIASDEAD) {
6231 unalias(sp->ap->name);
6232 }
6233 }
6234#endif
6235 parsenextc = sp->prevstring;
6236 parsenleft = sp->prevnleft;
6237/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6238 parsefile->strpush = sp->prev;
6239 if (sp != &(parsefile->basestrpush))
6240 ckfree(sp);
6241 INTON;
6242}
6243
6244/*
6245 * Set the input to take input from a file. If push is set, push the
6246 * old input onto the stack first.
6247 */
6248
6249void
6250setinputfile(const char *fname, int push)
6251{
6252 int fd;
6253 int fd2;
6254
6255 INTOFF;
6256 if ((fd = open(fname, O_RDONLY)) < 0)
6257 error("Can't open %s", fname);
6258 if (fd < 10) {
6259 fd2 = copyfd(fd, 10);
6260 close(fd);
6261 if (fd2 < 0)
6262 error("Out of file descriptors");
6263 fd = fd2;
6264 }
6265 setinputfd(fd, push);
6266 INTON;
6267}
6268
6269
6270/*
6271 * Like setinputfile, but takes an open file descriptor. Call this with
6272 * interrupts off.
6273 */
6274
6275static void
6276setinputfd(int fd, int push)
6277{
6278 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6279 if (push) {
6280 pushfile();
6281 parsefile->buf = 0;
6282 }
6283 parsefile->fd = fd;
6284 if (parsefile->buf == NULL)
6285 parsefile->buf = ckmalloc(IBUFSIZ);
6286 parselleft = parsenleft = 0;
6287 plinno = 1;
6288}
6289
Eric Andersencb57d552001-06-28 07:25:16 +00006290
Eric Andersencb57d552001-06-28 07:25:16 +00006291/*
6292 * Like setinputfile, but takes input from a string.
6293 */
6294
Eric Andersenc470f442003-07-28 09:56:35 +00006295static void
6296setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006297{
Eric Andersencb57d552001-06-28 07:25:16 +00006298 INTOFF;
6299 pushfile();
6300 parsenextc = string;
6301 parsenleft = strlen(string);
6302 parsefile->buf = NULL;
6303 plinno = 1;
6304 INTON;
6305}
6306
6307
Eric Andersencb57d552001-06-28 07:25:16 +00006308/*
6309 * To handle the "." command, a stack of input files is used. Pushfile
6310 * adds a new entry to the stack and popfile restores the previous level.
6311 */
6312
Eric Andersenc470f442003-07-28 09:56:35 +00006313static void
6314pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006315{
Eric Andersencb57d552001-06-28 07:25:16 +00006316 struct parsefile *pf;
6317
6318 parsefile->nleft = parsenleft;
6319 parsefile->lleft = parselleft;
6320 parsefile->nextc = parsenextc;
6321 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006322 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006323 pf->prev = parsefile;
6324 pf->fd = -1;
6325 pf->strpush = NULL;
6326 pf->basestrpush.prev = NULL;
6327 parsefile = pf;
6328}
6329
Eric Andersenc470f442003-07-28 09:56:35 +00006330
6331static void
6332popfile(void)
6333{
6334 struct parsefile *pf = parsefile;
6335
6336 INTOFF;
6337 if (pf->fd >= 0)
6338 close(pf->fd);
6339 if (pf->buf)
6340 ckfree(pf->buf);
6341 while (pf->strpush)
6342 popstring();
6343 parsefile = pf->prev;
6344 ckfree(pf);
6345 parsenleft = parsefile->nleft;
6346 parselleft = parsefile->lleft;
6347 parsenextc = parsefile->nextc;
6348 plinno = parsefile->linno;
6349 INTON;
6350}
Eric Andersencb57d552001-06-28 07:25:16 +00006351
6352
Eric Andersen2870d962001-07-02 17:27:21 +00006353/*
Eric Andersenc470f442003-07-28 09:56:35 +00006354 * Return to top level.
6355 */
Eric Andersen2870d962001-07-02 17:27:21 +00006356
Eric Andersenc470f442003-07-28 09:56:35 +00006357static void
6358popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006359{
Eric Andersenc470f442003-07-28 09:56:35 +00006360 while (parsefile != &basepf)
6361 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006362}
6363
Eric Andersen2870d962001-07-02 17:27:21 +00006364
Eric Andersenc470f442003-07-28 09:56:35 +00006365/*
6366 * Close the file(s) that the shell is reading commands from. Called
6367 * after a fork is done.
6368 */
6369
6370static void
6371closescript(void)
6372{
6373 popallfiles();
6374 if (parsefile->fd > 0) {
6375 close(parsefile->fd);
6376 parsefile->fd = 0;
6377 }
6378}
Eric Andersenc470f442003-07-28 09:56:35 +00006379
Eric Andersen90898442003-08-06 11:20:52 +00006380/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006381
6382/* mode flags for set_curjob */
6383#define CUR_DELETE 2
6384#define CUR_RUNNING 1
6385#define CUR_STOPPED 0
6386
6387/* mode flags for dowait */
6388#define DOWAIT_NORMAL 0
6389#define DOWAIT_BLOCK 1
6390
6391/* array of jobs */
6392static struct job *jobtab;
6393/* size of array */
6394static unsigned njobs;
6395#if JOBS
6396/* pgrp of shell on invocation */
6397static int initialpgrp;
6398static int ttyfd = -1;
6399#endif
6400/* current job */
6401static struct job *curjob;
6402/* number of presumed living untracked jobs */
6403static int jobless;
6404
6405static void set_curjob(struct job *, unsigned);
6406#if JOBS
6407static int restartjob(struct job *, int);
6408static void xtcsetpgrp(int, pid_t);
6409static char *commandtext(union node *);
6410static void cmdlist(union node *, int);
6411static void cmdtxt(union node *);
6412static void cmdputs(const char *);
6413static void showpipe(struct job *, FILE *);
6414#endif
6415static int sprint_status(char *, int, int);
6416static void freejob(struct job *);
6417static struct job *getjob(const char *, int);
6418static struct job *growjobtab(void);
6419static void forkchild(struct job *, union node *, int);
6420static void forkparent(struct job *, union node *, int, pid_t);
6421static int dowait(int, struct job *);
6422static int getstatus(struct job *);
6423
6424static void
6425set_curjob(struct job *jp, unsigned mode)
6426{
6427 struct job *jp1;
6428 struct job **jpp, **curp;
6429
6430 /* first remove from list */
6431 jpp = curp = &curjob;
6432 do {
6433 jp1 = *jpp;
6434 if (jp1 == jp)
6435 break;
6436 jpp = &jp1->prev_job;
6437 } while (1);
6438 *jpp = jp1->prev_job;
6439
6440 /* Then re-insert in correct position */
6441 jpp = curp;
6442 switch (mode) {
6443 default:
6444#ifdef DEBUG
6445 abort();
6446#endif
6447 case CUR_DELETE:
6448 /* job being deleted */
6449 break;
6450 case CUR_RUNNING:
6451 /* newly created job or backgrounded job,
6452 put after all stopped jobs. */
6453 do {
6454 jp1 = *jpp;
6455#ifdef JOBS
6456 if (!jp1 || jp1->state != JOBSTOPPED)
6457#endif
6458 break;
6459 jpp = &jp1->prev_job;
6460 } while (1);
6461 /* FALLTHROUGH */
6462#ifdef JOBS
6463 case CUR_STOPPED:
6464#endif
6465 /* newly stopped job - becomes curjob */
6466 jp->prev_job = *jpp;
6467 *jpp = jp;
6468 break;
6469 }
6470}
6471
6472#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006473/*
6474 * Turn job control on and off.
6475 *
6476 * Note: This code assumes that the third arg to ioctl is a character
6477 * pointer, which is true on Berkeley systems but not System V. Since
6478 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006479 *
6480 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006481 */
6482
Eric Andersenc470f442003-07-28 09:56:35 +00006483void
6484setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006485{
Eric Andersenc470f442003-07-28 09:56:35 +00006486 int fd;
6487 int pgrp;
6488
6489 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006490 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006491 if (on) {
6492 int ofd;
6493 ofd = fd = open(_PATH_TTY, O_RDWR);
6494 if (fd < 0) {
6495 fd += 3;
6496 while (!isatty(fd) && --fd >= 0)
6497 ;
6498 }
6499 fd = fcntl(fd, F_DUPFD, 10);
6500 close(ofd);
6501 if (fd < 0)
6502 goto out;
6503 fcntl(fd, F_SETFD, FD_CLOEXEC);
6504 do { /* while we are in the background */
6505 if ((pgrp = tcgetpgrp(fd)) < 0) {
6506out:
6507 sh_warnx("can't access tty; job control turned off");
6508 mflag = on = 0;
6509 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006510 }
Eric Andersenc470f442003-07-28 09:56:35 +00006511 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006512 break;
6513 killpg(0, SIGTTIN);
6514 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006515 initialpgrp = pgrp;
6516
Eric Andersencb57d552001-06-28 07:25:16 +00006517 setsignal(SIGTSTP);
6518 setsignal(SIGTTOU);
6519 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006520 pgrp = rootpid;
6521 setpgid(0, pgrp);
6522 xtcsetpgrp(fd, pgrp);
6523 } else {
6524 /* turning job control off */
6525 fd = ttyfd;
6526 pgrp = initialpgrp;
6527 xtcsetpgrp(fd, pgrp);
6528 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006529 setsignal(SIGTSTP);
6530 setsignal(SIGTTOU);
6531 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006532close:
6533 close(fd);
6534 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006535 }
Eric Andersenc470f442003-07-28 09:56:35 +00006536 ttyfd = fd;
6537 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006538}
Eric Andersencb57d552001-06-28 07:25:16 +00006539
Eric Andersenc470f442003-07-28 09:56:35 +00006540static int
Eric Andersen90898442003-08-06 11:20:52 +00006541killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006542{
6543 int signo = -1;
6544 int list = 0;
6545 int i;
6546 pid_t pid;
6547 struct job *jp;
6548
6549 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006550usage:
6551 error(
6552"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6553"kill -l [exitstatus]"
6554 );
Eric Andersencb57d552001-06-28 07:25:16 +00006555 }
6556
Eric Andersenc470f442003-07-28 09:56:35 +00006557 if (**++argv == '-') {
6558 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006559 if (signo < 0) {
6560 int c;
6561
6562 while ((c = nextopt("ls:")) != '\0')
6563 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006564 default:
6565#ifdef DEBUG
6566 abort();
6567#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006568 case 'l':
6569 list = 1;
6570 break;
6571 case 's':
6572 signo = decode_signal(optionarg, 1);
6573 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006574 error(
6575 "invalid signal number or name: %s",
6576 optionarg
6577 );
Eric Andersencb57d552001-06-28 07:25:16 +00006578 }
Eric Andersen2870d962001-07-02 17:27:21 +00006579 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006580 }
Eric Andersenc470f442003-07-28 09:56:35 +00006581 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006582 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006583 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006584 }
6585
6586 if (!list && signo < 0)
6587 signo = SIGTERM;
6588
Eric Andersenc470f442003-07-28 09:56:35 +00006589 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006590 goto usage;
6591 }
6592
6593 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006594 const char *name;
6595
Eric Andersenc470f442003-07-28 09:56:35 +00006596 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006597 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006598 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006599 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006600 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006601 }
6602 return 0;
6603 }
Eric Andersen34506362001-08-02 05:02:46 +00006604 name = u_signal_names(*argptr, &signo, -1);
6605 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006606 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006607 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006608 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006609 return 0;
6610 }
6611
Eric Andersenc470f442003-07-28 09:56:35 +00006612 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006613 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006614 if (**argv == '%') {
6615 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006616 pid = -jp->ps[0].pid;
6617 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006618 pid = number(*argv);
6619 if (kill(pid, signo) != 0) {
6620 sh_warnx("%m\n");
6621 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006622 }
Eric Andersenc470f442003-07-28 09:56:35 +00006623 } while (*++argv);
6624
6625 return i;
6626}
6627#endif /* JOBS */
6628
6629#if defined(JOBS) || defined(DEBUG)
6630static int
6631jobno(const struct job *jp)
6632{
6633 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006634}
6635#endif
6636
Eric Andersenc470f442003-07-28 09:56:35 +00006637#ifdef JOBS
6638static int
6639fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006640{
Eric Andersenc470f442003-07-28 09:56:35 +00006641 struct job *jp;
6642 FILE *out;
6643 int mode;
6644 int retval;
6645
6646 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6647 nextopt(nullstr);
6648 argv = argptr;
6649 out = stdout;
6650 do {
6651 jp = getjob(*argv, 1);
6652 if (mode == FORK_BG) {
6653 set_curjob(jp, CUR_RUNNING);
6654 fprintf(out, "[%d] ", jobno(jp));
6655 }
6656 outstr(jp->ps->cmd, out);
6657 showpipe(jp, out);
6658 retval = restartjob(jp, mode);
6659 } while (*argv && *++argv);
6660 return retval;
6661}
6662
6663static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6664
6665
6666static int
6667restartjob(struct job *jp, int mode)
6668{
6669 struct procstat *ps;
6670 int i;
6671 int status;
6672 pid_t pgid;
6673
6674 INTOFF;
6675 if (jp->state == JOBDONE)
6676 goto out;
6677 jp->state = JOBRUNNING;
6678 pgid = jp->ps->pid;
6679 if (mode == FORK_FG)
6680 xtcsetpgrp(ttyfd, pgid);
6681 killpg(pgid, SIGCONT);
6682 ps = jp->ps;
6683 i = jp->nprocs;
6684 do {
6685 if (WIFSTOPPED(ps->status)) {
6686 ps->status = -1;
6687 }
6688 } while (ps++, --i);
6689out:
6690 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6691 INTON;
6692 return status;
6693}
6694#endif
6695
6696static int
6697sprint_status(char *s, int status, int sigonly)
6698{
6699 int col;
6700 int st;
6701
6702 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006703 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006704#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006705 if (WIFSTOPPED(status))
6706 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006707 else
Eric Andersenc470f442003-07-28 09:56:35 +00006708#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006709 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006710 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006711 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006712 goto out;
6713#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006714 if (WIFSTOPPED(status))
6715 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006716#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006717 }
6718 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006719 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006720 if (WCOREDUMP(status)) {
6721 col += fmtstr(s + col, 16, " (core dumped)");
6722 }
6723 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006724 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006725 if (st)
6726 col = fmtstr(s, 16, "Done(%d)", st);
6727 else
6728 col = fmtstr(s, 16, "Done");
6729 }
6730
6731out:
6732 return col;
6733}
6734
6735#if JOBS
6736static void
6737showjob(FILE *out, struct job *jp, int mode)
6738{
6739 struct procstat *ps;
6740 struct procstat *psend;
6741 int col;
6742 int indent;
6743 char s[80];
6744
6745 ps = jp->ps;
6746
6747 if (mode & SHOW_PGID) {
6748 /* just output process (group) id of pipeline */
6749 fprintf(out, "%d\n", ps->pid);
6750 return;
6751 }
6752
6753 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6754 indent = col;
6755
6756 if (jp == curjob)
6757 s[col - 2] = '+';
6758 else if (curjob && jp == curjob->prev_job)
6759 s[col - 2] = '-';
6760
6761 if (mode & SHOW_PID)
6762 col += fmtstr(s + col, 16, "%d ", ps->pid);
6763
6764 psend = ps + jp->nprocs;
6765
6766 if (jp->state == JOBRUNNING) {
6767 scopy("Running", s + col);
6768 col += strlen("Running");
6769 } else {
6770 int status = psend[-1].status;
6771#if JOBS
6772 if (jp->state == JOBSTOPPED)
6773 status = jp->stopstatus;
6774#endif
6775 col += sprint_status(s + col, status, 0);
6776 }
6777
6778 goto start;
6779
6780 do {
6781 /* for each process */
6782 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6783
6784start:
Eric Andersen90898442003-08-06 11:20:52 +00006785 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006786 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6787 );
6788 if (!(mode & SHOW_PID)) {
6789 showpipe(jp, out);
6790 break;
6791 }
6792 if (++ps == psend) {
6793 outcslow('\n', out);
6794 break;
6795 }
6796 } while (1);
6797
6798 jp->changed = 0;
6799
6800 if (jp->state == JOBDONE) {
6801 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6802 freejob(jp);
6803 }
6804}
6805
6806
6807static int
6808jobscmd(int argc, char **argv)
6809{
6810 int mode, m;
6811 FILE *out;
6812
6813 mode = 0;
6814 while ((m = nextopt("lp")))
6815 if (m == 'l')
6816 mode = SHOW_PID;
6817 else
6818 mode = SHOW_PGID;
6819
6820 out = stdout;
6821 argv = argptr;
6822 if (*argv)
6823 do
6824 showjob(out, getjob(*argv,0), mode);
6825 while (*++argv);
6826 else
6827 showjobs(out, mode);
6828
Eric Andersencb57d552001-06-28 07:25:16 +00006829 return 0;
6830}
6831
6832
6833/*
6834 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6835 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006836 */
6837
Eric Andersenc470f442003-07-28 09:56:35 +00006838static void
6839showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006840{
Eric Andersencb57d552001-06-28 07:25:16 +00006841 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006842
Eric Andersenc470f442003-07-28 09:56:35 +00006843 TRACE(("showjobs(%x) called\n", mode));
6844
6845 /* If not even one one job changed, there is nothing to do */
6846 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6847 continue;
6848
6849 for (jp = curjob; jp; jp = jp->prev_job) {
6850 if (!(mode & SHOW_CHANGED) || jp->changed)
6851 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006852 }
6853}
Eric Andersenc470f442003-07-28 09:56:35 +00006854#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006855
6856/*
6857 * Mark a job structure as unused.
6858 */
6859
Eric Andersenc470f442003-07-28 09:56:35 +00006860static void
6861freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006862{
Eric Andersenc470f442003-07-28 09:56:35 +00006863 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006864 int i;
6865
6866 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006867 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006868 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006869 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006870 }
6871 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006872 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006873 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006874 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006875 INTON;
6876}
6877
6878
Eric Andersenc470f442003-07-28 09:56:35 +00006879static int
6880waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006881{
6882 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006883 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006884 struct job *jp;
6885
Eric Andersenc470f442003-07-28 09:56:35 +00006886 EXSIGON();
6887
6888 nextopt(nullstr);
6889 retval = 0;
6890
6891 argv = argptr;
6892 if (!*argv) {
6893 /* wait for all jobs */
6894 for (;;) {
6895 jp = curjob;
6896 while (1) {
6897 if (!jp) {
6898 /* no running procs */
6899 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006900 }
Eric Andersenc470f442003-07-28 09:56:35 +00006901 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006902 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006903 jp->waited = 1;
6904 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006905 }
Eric Andersenc470f442003-07-28 09:56:35 +00006906 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006907 }
6908 }
Eric Andersenc470f442003-07-28 09:56:35 +00006909
6910 retval = 127;
6911 do {
6912 if (**argv != '%') {
6913 pid_t pid = number(*argv);
6914 job = curjob;
6915 goto start;
6916 do {
6917 if (job->ps[job->nprocs - 1].pid == pid)
6918 break;
6919 job = job->prev_job;
6920start:
6921 if (!job)
6922 goto repeat;
6923 } while (1);
6924 } else
6925 job = getjob(*argv, 0);
6926 /* loop until process terminated or stopped */
6927 while (job->state == JOBRUNNING)
6928 dowait(DOWAIT_BLOCK, 0);
6929 job->waited = 1;
6930 retval = getstatus(job);
6931repeat:
6932 ;
6933 } while (*++argv);
6934
6935out:
6936 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006937}
6938
6939
Eric Andersencb57d552001-06-28 07:25:16 +00006940/*
6941 * Convert a job name to a job structure.
6942 */
6943
Eric Andersenc470f442003-07-28 09:56:35 +00006944static struct job *
6945getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006946{
Eric Andersencb57d552001-06-28 07:25:16 +00006947 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006948 struct job *found;
6949 const char *err_msg = "No such job: %s";
6950 unsigned num;
6951 int c;
6952 const char *p;
6953 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006954
Eric Andersenc470f442003-07-28 09:56:35 +00006955 jp = curjob;
6956 p = name;
6957 if (!p)
6958 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006959
Eric Andersenc470f442003-07-28 09:56:35 +00006960 if (*p != '%')
6961 goto err;
6962
6963 c = *++p;
6964 if (!c)
6965 goto currentjob;
6966
6967 if (!p[1]) {
6968 if (c == '+' || c == '%') {
6969currentjob:
6970 err_msg = "No current job";
6971 goto check;
6972 } else if (c == '-') {
6973 if (jp)
6974 jp = jp->prev_job;
6975 err_msg = "No previous job";
6976check:
6977 if (!jp)
6978 goto err;
6979 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006980 }
6981 }
Eric Andersenc470f442003-07-28 09:56:35 +00006982
6983 if (is_number(p)) {
6984 num = atoi(p);
6985 if (num < njobs) {
6986 jp = jobtab + num - 1;
6987 if (jp->used)
6988 goto gotit;
6989 goto err;
6990 }
6991 }
6992
6993 match = prefix;
6994 if (*p == '?') {
6995 match = strstr;
6996 p++;
6997 }
6998
6999 found = 0;
7000 while (1) {
7001 if (!jp)
7002 goto err;
7003 if (match(jp->ps[0].cmd, p)) {
7004 if (found)
7005 goto err;
7006 found = jp;
7007 err_msg = "%s: ambiguous";
7008 }
7009 jp = jp->prev_job;
7010 }
7011
7012gotit:
7013#if JOBS
7014 err_msg = "job %s not created under job control";
7015 if (getctl && jp->jobctl == 0)
7016 goto err;
7017#endif
7018 return jp;
7019err:
7020 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007021}
7022
7023
Eric Andersencb57d552001-06-28 07:25:16 +00007024/*
Eric Andersenc470f442003-07-28 09:56:35 +00007025 * Return a new job structure.
7026 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007027 */
7028
Eric Andersenc470f442003-07-28 09:56:35 +00007029static struct job *
7030makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007031{
7032 int i;
7033 struct job *jp;
7034
Eric Andersenc470f442003-07-28 09:56:35 +00007035 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007036 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007037 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007038 break;
7039 }
7040 if (jp->used == 0)
7041 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007042 if (jp->state != JOBDONE || !jp->waited)
7043 continue;
7044#if JOBS
7045 if (jobctl)
7046 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007047#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007048 freejob(jp);
7049 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007050 }
Eric Andersenc470f442003-07-28 09:56:35 +00007051 memset(jp, 0, sizeof(*jp));
7052#if JOBS
7053 if (jobctl)
7054 jp->jobctl = 1;
7055#endif
7056 jp->prev_job = curjob;
7057 curjob = jp;
7058 jp->used = 1;
7059 jp->ps = &jp->ps0;
7060 if (nprocs > 1) {
7061 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7062 }
7063 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7064 jobno(jp)));
7065 return jp;
7066}
7067
7068static struct job *
7069growjobtab(void)
7070{
7071 size_t len;
7072 ptrdiff_t offset;
7073 struct job *jp, *jq;
7074
7075 len = njobs * sizeof(*jp);
7076 jq = jobtab;
7077 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7078
7079 offset = (char *)jp - (char *)jq;
7080 if (offset) {
7081 /* Relocate pointers */
7082 size_t l = len;
7083
7084 jq = (struct job *)((char *)jq + l);
7085 while (l) {
7086 l -= sizeof(*jp);
7087 jq--;
7088#define joff(p) ((struct job *)((char *)(p) + l))
7089#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007090 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007091 jmove(joff(jp)->ps);
7092 if (joff(jp)->prev_job)
7093 jmove(joff(jp)->prev_job);
7094 }
7095 if (curjob)
7096 jmove(curjob);
7097#undef joff
7098#undef jmove
7099 }
7100
7101 njobs += 4;
7102 jobtab = jp;
7103 jp = (struct job *)((char *)jp + len);
7104 jq = jp + 3;
7105 do {
7106 jq->used = 0;
7107 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007108 return jp;
7109}
7110
7111
7112/*
Eric Andersenc470f442003-07-28 09:56:35 +00007113 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007114 * own process group. Jp is a job structure that the job is to be added to.
7115 * N is the command that will be evaluated by the child. Both jp and n may
7116 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007117 * FORK_FG - Fork off a foreground process.
7118 * FORK_BG - Fork off a background process.
7119 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7120 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007121 *
7122 * When job control is turned off, background processes have their standard
7123 * input redirected to /dev/null (except for the second and later processes
7124 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007125 *
7126 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007127 */
7128
Eric Andersenc470f442003-07-28 09:56:35 +00007129static inline void
7130forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007131{
Eric Andersenc470f442003-07-28 09:56:35 +00007132 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007133
Eric Andersenc470f442003-07-28 09:56:35 +00007134 TRACE(("Child shell %d\n", getpid()));
7135 wasroot = rootshell;
7136 rootshell = 0;
7137
7138 closescript();
7139 clear_traps();
7140#if JOBS
7141 /* do job control only in root shell */
7142 jobctl = 0;
7143 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7144 pid_t pgrp;
7145
7146 if (jp->nprocs == 0)
7147 pgrp = getpid();
7148 else
7149 pgrp = jp->ps[0].pid;
7150 /* This can fail because we are doing it in the parent also */
7151 (void)setpgid(0, pgrp);
7152 if (mode == FORK_FG)
7153 xtcsetpgrp(ttyfd, pgrp);
7154 setsignal(SIGTSTP);
7155 setsignal(SIGTTOU);
7156 } else
Eric Andersen62483552001-07-10 06:09:16 +00007157#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007158 if (mode == FORK_BG) {
7159 ignoresig(SIGINT);
7160 ignoresig(SIGQUIT);
7161 if (jp->nprocs == 0) {
7162 close(0);
7163 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7164 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007165 }
Eric Andersencb57d552001-06-28 07:25:16 +00007166 }
Eric Andersenc470f442003-07-28 09:56:35 +00007167 if (wasroot && iflag) {
7168 setsignal(SIGINT);
7169 setsignal(SIGQUIT);
7170 setsignal(SIGTERM);
7171 }
7172 for (jp = curjob; jp; jp = jp->prev_job)
7173 freejob(jp);
7174 jobless = 0;
7175}
7176
7177static inline void
7178forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7179{
7180 TRACE(("In parent shell: child = %d\n", pid));
7181 if (!jp) {
7182 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7183 jobless++;
7184 return;
7185 }
7186#if JOBS
7187 if (mode != FORK_NOJOB && jp->jobctl) {
7188 int pgrp;
7189
7190 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007191 pgrp = pid;
7192 else
7193 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007194 /* This can fail because we are doing it in the child also */
7195 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007196 }
Eric Andersen62483552001-07-10 06:09:16 +00007197#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007198 if (mode == FORK_BG) {
7199 backgndpid = pid; /* set $! */
7200 set_curjob(jp, CUR_RUNNING);
7201 }
Eric Andersencb57d552001-06-28 07:25:16 +00007202 if (jp) {
7203 struct procstat *ps = &jp->ps[jp->nprocs++];
7204 ps->pid = pid;
7205 ps->status = -1;
7206 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007207#if JOBS
7208 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007209 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007210#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007211 }
Eric Andersencb57d552001-06-28 07:25:16 +00007212}
7213
Eric Andersenc470f442003-07-28 09:56:35 +00007214static int
7215forkshell(struct job *jp, union node *n, int mode)
7216{
7217 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007218
Eric Andersenc470f442003-07-28 09:56:35 +00007219 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7220 pid = fork();
7221 if (pid < 0) {
7222 TRACE(("Fork failed, errno=%d", errno));
7223 if (jp)
7224 freejob(jp);
7225 error("Cannot fork");
7226 }
7227 if (pid == 0)
7228 forkchild(jp, n, mode);
7229 else
7230 forkparent(jp, n, mode, pid);
7231 return pid;
7232}
Eric Andersencb57d552001-06-28 07:25:16 +00007233
7234/*
7235 * Wait for job to finish.
7236 *
7237 * Under job control we have the problem that while a child process is
7238 * running interrupts generated by the user are sent to the child but not
7239 * to the shell. This means that an infinite loop started by an inter-
7240 * active user may be hard to kill. With job control turned off, an
7241 * interactive user may place an interactive program inside a loop. If
7242 * the interactive program catches interrupts, the user doesn't want
7243 * these interrupts to also abort the loop. The approach we take here
7244 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007245 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007246 * signal if the child process was terminated by an interrupt signal.
7247 * Unfortunately, some programs want to do a bit of cleanup and then
7248 * exit on interrupt; unless these processes terminate themselves by
7249 * sending a signal to themselves (instead of calling exit) they will
7250 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007251 *
7252 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007253 */
7254
Eric Andersenc470f442003-07-28 09:56:35 +00007255int
7256waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007257{
Eric Andersencb57d552001-06-28 07:25:16 +00007258 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007259
Eric Andersenc470f442003-07-28 09:56:35 +00007260 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7261 while (jp->state == JOBRUNNING) {
7262 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007263 }
Eric Andersenc470f442003-07-28 09:56:35 +00007264 st = getstatus(jp);
7265#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007266 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007267 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007268 /*
7269 * This is truly gross.
7270 * If we're doing job control, then we did a TIOCSPGRP which
7271 * caused us (the shell) to no longer be in the controlling
7272 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7273 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007274 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007275 */
Eric Andersenc470f442003-07-28 09:56:35 +00007276 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007277 raise(SIGINT);
7278 }
Eric Andersen2870d962001-07-02 17:27:21 +00007279 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007280#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007281 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007282 return st;
7283}
7284
7285
Eric Andersen62483552001-07-10 06:09:16 +00007286/*
7287 * Do a wait system call. If job control is compiled in, we accept
7288 * stopped processes. If block is zero, we return a value of zero
7289 * rather than blocking.
7290 *
7291 * System V doesn't have a non-blocking wait system call. It does
7292 * have a SIGCLD signal that is sent to a process when one of it's
7293 * children dies. The obvious way to use SIGCLD would be to install
7294 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7295 * was received, and have waitproc bump another counter when it got
7296 * the status of a process. Waitproc would then know that a wait
7297 * system call would not block if the two counters were different.
7298 * This approach doesn't work because if a process has children that
7299 * have not been waited for, System V will send it a SIGCLD when it
7300 * installs a signal handler for SIGCLD. What this means is that when
7301 * a child exits, the shell will be sent SIGCLD signals continuously
7302 * until is runs out of stack space, unless it does a wait call before
7303 * restoring the signal handler. The code below takes advantage of
7304 * this (mis)feature by installing a signal handler for SIGCLD and
7305 * then checking to see whether it was called. If there are any
7306 * children to be waited for, it will be.
7307 *
Eric Andersenc470f442003-07-28 09:56:35 +00007308 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7309 * waits at all. In this case, the user will not be informed when
7310 * a background process until the next time she runs a real program
7311 * (as opposed to running a builtin command or just typing return),
7312 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007313 */
7314
Eric Andersenc470f442003-07-28 09:56:35 +00007315static inline int
7316waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007317{
Eric Andersenc470f442003-07-28 09:56:35 +00007318 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007319
Eric Andersenc470f442003-07-28 09:56:35 +00007320#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007321 if (jobctl)
7322 flags |= WUNTRACED;
7323#endif
7324 if (block == 0)
7325 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007326 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007327}
7328
Eric Andersenc470f442003-07-28 09:56:35 +00007329/*
7330 * Wait for a process to terminate.
7331 */
7332
7333static int
7334dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007335{
7336 int pid;
7337 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007338 struct job *jp;
7339 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007340 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007341
7342 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007343 pid = waitproc(block, &status);
7344 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007345 if (pid <= 0)
7346 return pid;
7347 INTOFF;
7348 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007349 for (jp = curjob; jp; jp = jp->prev_job) {
7350 struct procstat *sp;
7351 struct procstat *spend;
7352 if (jp->state == JOBDONE)
7353 continue;
7354 state = JOBDONE;
7355 spend = jp->ps + jp->nprocs;
7356 sp = jp->ps;
7357 do {
7358 if (sp->pid == pid) {
7359 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7360 sp->status = status;
7361 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007362 }
Eric Andersenc470f442003-07-28 09:56:35 +00007363 if (sp->status == -1)
7364 state = JOBRUNNING;
7365#ifdef JOBS
7366 if (state == JOBRUNNING)
7367 continue;
7368 if (WIFSTOPPED(sp->status)) {
7369 jp->stopstatus = sp->status;
7370 state = JOBSTOPPED;
7371 }
Eric Andersencb57d552001-06-28 07:25:16 +00007372#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007373 } while (++sp < spend);
7374 if (thisjob)
7375 goto gotjob;
7376 }
7377#ifdef JOBS
7378 if (!WIFSTOPPED(status))
7379#endif
7380
7381 jobless--;
7382 goto out;
7383
7384gotjob:
7385 if (state != JOBRUNNING) {
7386 thisjob->changed = 1;
7387
7388 if (thisjob->state != state) {
7389 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7390 thisjob->state = state;
7391#ifdef JOBS
7392 if (state == JOBSTOPPED) {
7393 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007394 }
Eric Andersenc470f442003-07-28 09:56:35 +00007395#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007396 }
7397 }
Eric Andersencb57d552001-06-28 07:25:16 +00007398
Eric Andersenc470f442003-07-28 09:56:35 +00007399out:
7400 INTON;
7401
7402 if (thisjob && thisjob == job) {
7403 char s[48 + 1];
7404 int len;
7405
7406 len = sprint_status(s, status, 1);
7407 if (len) {
7408 s[len] = '\n';
7409 s[len + 1] = 0;
7410 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007411 }
Eric Andersencb57d552001-06-28 07:25:16 +00007412 }
7413 return pid;
7414}
7415
7416
Eric Andersencb57d552001-06-28 07:25:16 +00007417/*
7418 * return 1 if there are stopped jobs, otherwise 0
7419 */
Eric Andersen90898442003-08-06 11:20:52 +00007420
Eric Andersenc470f442003-07-28 09:56:35 +00007421int
7422stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007423{
Eric Andersencb57d552001-06-28 07:25:16 +00007424 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007425 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007426
Eric Andersenc470f442003-07-28 09:56:35 +00007427 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007428 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007429 goto out;
7430 jp = curjob;
7431 if (jp && jp->state == JOBSTOPPED) {
7432 out2str("You have stopped jobs.\n");
7433 job_warning = 2;
7434 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007435 }
7436
Eric Andersenc470f442003-07-28 09:56:35 +00007437out:
7438 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007439}
7440
7441/*
7442 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007443 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007444 */
7445
Eric Andersenc470f442003-07-28 09:56:35 +00007446#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007447static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007448
Eric Andersenc470f442003-07-28 09:56:35 +00007449static char *
7450commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007451{
Eric Andersenc470f442003-07-28 09:56:35 +00007452 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007453
Eric Andersenc470f442003-07-28 09:56:35 +00007454 STARTSTACKSTR(cmdnextc);
7455 cmdtxt(n);
7456 name = stackblock();
7457 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7458 name, cmdnextc, cmdnextc));
7459 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007460}
7461
Eric Andersenc470f442003-07-28 09:56:35 +00007462static void
7463cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007464{
Eric Andersencb57d552001-06-28 07:25:16 +00007465 union node *np;
7466 struct nodelist *lp;
7467 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007468 char s[2];
7469
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007470 if (!n)
7471 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007472 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007473 default:
7474#if DEBUG
7475 abort();
7476#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007477 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007478 lp = n->npipe.cmdlist;
7479 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007480 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007481 lp = lp->next;
7482 if (!lp)
7483 break;
7484 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007485 }
7486 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007487 case NSEMI:
7488 p = "; ";
7489 goto binop;
7490 case NAND:
7491 p = " && ";
7492 goto binop;
7493 case NOR:
7494 p = " || ";
7495binop:
7496 cmdtxt(n->nbinary.ch1);
7497 cmdputs(p);
7498 n = n->nbinary.ch2;
7499 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007500 case NREDIR:
7501 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007502 n = n->nredir.n;
7503 goto donode;
7504 case NNOT:
7505 cmdputs("!");
7506 n = n->nnot.com;
7507donode:
7508 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007509 break;
7510 case NIF:
7511 cmdputs("if ");
7512 cmdtxt(n->nif.test);
7513 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007514 n = n->nif.ifpart;
7515 if (n->nif.elsepart) {
7516 cmdtxt(n);
7517 cmdputs("; else ");
7518 n = n->nif.elsepart;
7519 }
7520 p = "; fi";
7521 goto dotail;
7522 case NSUBSHELL:
7523 cmdputs("(");
7524 n = n->nredir.n;
7525 p = ")";
7526 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007527 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007528 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007529 goto until;
7530 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007531 p = "until ";
7532until:
7533 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007534 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007535 n = n->nbinary.ch2;
7536 p = "; done";
7537dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007538 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007539dotail:
7540 cmdtxt(n);
7541 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007542 case NFOR:
7543 cmdputs("for ");
7544 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007545 cmdputs(" in ");
7546 cmdlist(n->nfor.args, 1);
7547 n = n->nfor.body;
7548 p = "; done";
7549 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007550 case NDEFUN:
7551 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007552 p = "() { ... }";
7553 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007554 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007555 cmdlist(n->ncmd.args, 1);
7556 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007557 break;
7558 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007559 p = n->narg.text;
7560dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007561 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007562 break;
7563 case NHERE:
7564 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007565 p = "<<...";
7566 goto dotail2;
7567 case NCASE:
7568 cmdputs("case ");
7569 cmdputs(n->ncase.expr->narg.text);
7570 cmdputs(" in ");
7571 for (np = n->ncase.cases; np; np = np->nclist.next) {
7572 cmdtxt(np->nclist.pattern);
7573 cmdputs(") ");
7574 cmdtxt(np->nclist.body);
7575 cmdputs(";; ");
7576 }
7577 p = "esac";
7578 goto dotail2;
7579 case NTO:
7580 p = ">";
7581 goto redir;
7582 case NCLOBBER:
7583 p = ">|";
7584 goto redir;
7585 case NAPPEND:
7586 p = ">>";
7587 goto redir;
7588 case NTOFD:
7589 p = ">&";
7590 goto redir;
7591 case NFROM:
7592 p = "<";
7593 goto redir;
7594 case NFROMFD:
7595 p = "<&";
7596 goto redir;
7597 case NFROMTO:
7598 p = "<>";
7599redir:
7600 s[0] = n->nfile.fd + '0';
7601 s[1] = '\0';
7602 cmdputs(s);
7603 cmdputs(p);
7604 if (n->type == NTOFD || n->type == NFROMFD) {
7605 s[0] = n->ndup.dupfd + '0';
7606 p = s;
7607 goto dotail2;
7608 } else {
7609 n = n->nfile.fname;
7610 goto donode;
7611 }
Eric Andersencb57d552001-06-28 07:25:16 +00007612 }
7613}
Eric Andersencb57d552001-06-28 07:25:16 +00007614
Eric Andersenc470f442003-07-28 09:56:35 +00007615static void
7616cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007617{
Eric Andersenc470f442003-07-28 09:56:35 +00007618 for (; np; np = np->narg.next) {
7619 if (!sep)
7620 cmdputs(spcstr);
7621 cmdtxt(np);
7622 if (sep && np->narg.next)
7623 cmdputs(spcstr);
7624 }
Eric Andersencb57d552001-06-28 07:25:16 +00007625}
7626
Eric Andersenc470f442003-07-28 09:56:35 +00007627static void
7628cmdputs(const char *s)
7629{
7630 const char *p, *str;
7631 char c, cc[2] = " ";
7632 char *nextc;
7633 int subtype = 0;
7634 int quoted = 0;
7635 static const char *const vstype[16] = {
7636 nullstr, "}", "-", "+", "?", "=",
Eric Andersenc7bda1c2004-03-15 08:29:22 +00007637 "%", "%%", "#", "##", nullstr
Eric Andersenc470f442003-07-28 09:56:35 +00007638 };
7639
7640 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7641 p = s;
7642 while ((c = *p++) != 0) {
7643 str = 0;
7644 switch (c) {
7645 case CTLESC:
7646 c = *p++;
7647 break;
7648 case CTLVAR:
7649 subtype = *p++;
7650 if ((subtype & VSTYPE) == VSLENGTH)
7651 str = "${#";
7652 else
7653 str = "${";
7654 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7655 quoted ^= 1;
7656 c = '"';
7657 } else
7658 goto dostr;
7659 break;
7660 case CTLENDVAR:
7661 quoted >>= 1;
7662 subtype = 0;
7663 if (quoted & 1) {
7664 str = "\"}";
7665 goto dostr;
7666 }
7667 c = '}';
7668 break;
7669 case CTLBACKQ:
7670 str = "$(...)";
7671 goto dostr;
7672 case CTLBACKQ+CTLQUOTE:
7673 str = "\"$(...)\"";
7674 goto dostr;
7675#ifdef CONFIG_ASH_MATH_SUPPORT
7676 case CTLARI:
7677 str = "$((";
7678 goto dostr;
7679 case CTLENDARI:
7680 str = "))";
7681 goto dostr;
7682#endif
7683 case CTLQUOTEMARK:
7684 quoted ^= 1;
7685 c = '"';
7686 break;
7687 case '=':
7688 if (subtype == 0)
7689 break;
7690 str = vstype[subtype & VSTYPE];
7691 if (subtype & VSNUL)
7692 c = ':';
7693 else
7694 c = *str++;
7695 if (c != '}')
7696 quoted <<= 1;
7697 break;
7698 case '\'':
7699 case '\\':
7700 case '"':
7701 case '$':
7702 /* These can only happen inside quotes */
7703 cc[0] = c;
7704 str = cc;
7705 c = '\\';
7706 break;
7707 default:
7708 break;
7709 }
7710 USTPUTC(c, nextc);
7711 if (!str)
7712 continue;
7713dostr:
7714 while ((c = *str++)) {
7715 USTPUTC(c, nextc);
7716 }
7717 }
7718 if (quoted & 1) {
7719 USTPUTC('"', nextc);
7720 }
7721 *nextc = 0;
7722 cmdnextc = nextc;
7723}
7724
7725
7726static void
7727showpipe(struct job *jp, FILE *out)
7728{
7729 struct procstat *sp;
7730 struct procstat *spend;
7731
7732 spend = jp->ps + jp->nprocs;
7733 for (sp = jp->ps + 1; sp < spend; sp++)
7734 fprintf(out, " | %s", sp->cmd);
7735 outcslow('\n', out);
7736 flushall();
7737}
7738
7739static void
7740xtcsetpgrp(int fd, pid_t pgrp)
7741{
7742 if (tcsetpgrp(fd, pgrp))
7743 error("Cannot set tty process group (%m)");
7744}
7745#endif /* JOBS */
7746
7747static int
7748getstatus(struct job *job) {
7749 int status;
7750 int retval;
7751
7752 status = job->ps[job->nprocs - 1].status;
7753 retval = WEXITSTATUS(status);
7754 if (!WIFEXITED(status)) {
7755#if JOBS
7756 retval = WSTOPSIG(status);
7757 if (!WIFSTOPPED(status))
7758#endif
7759 {
7760 /* XXX: limits number of signals */
7761 retval = WTERMSIG(status);
7762#if JOBS
7763 if (retval == SIGINT)
7764 job->sigint = 1;
7765#endif
7766 }
7767 retval += 128;
7768 }
7769 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7770 jobno(job), job->nprocs, status, retval));
7771 return retval;
7772}
7773
Eric Andersend35c5df2002-01-09 15:37:36 +00007774#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007775/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007776
Eric Andersencb57d552001-06-28 07:25:16 +00007777/*
Eric Andersenc470f442003-07-28 09:56:35 +00007778 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007779 */
7780
Eric Andersencb57d552001-06-28 07:25:16 +00007781#define MAXMBOXES 10
7782
Eric Andersenc470f442003-07-28 09:56:35 +00007783/* times of mailboxes */
7784static time_t mailtime[MAXMBOXES];
7785/* Set if MAIL or MAILPATH is changed. */
7786static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007787
7788
7789
7790/*
Eric Andersenc470f442003-07-28 09:56:35 +00007791 * Print appropriate message(s) if mail has arrived.
7792 * If mail_var_path_changed is set,
7793 * then the value of MAIL has mail_var_path_changed,
7794 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007795 */
7796
Eric Andersenc470f442003-07-28 09:56:35 +00007797static void
7798chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007799{
Eric Andersencb57d552001-06-28 07:25:16 +00007800 const char *mpath;
7801 char *p;
7802 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007803 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007804 struct stackmark smark;
7805 struct stat statb;
7806
Eric Andersencb57d552001-06-28 07:25:16 +00007807 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007808 mpath = mpathset() ? mpathval() : mailval();
7809 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007810 p = padvance(&mpath, nullstr);
7811 if (p == NULL)
7812 break;
7813 if (*p == '\0')
7814 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007815 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007816#ifdef DEBUG
7817 if (q[-1] != '/')
7818 abort();
7819#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007820 q[-1] = '\0'; /* delete trailing '/' */
7821 if (stat(p, &statb) < 0) {
7822 *mtp = 0;
7823 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007824 }
Eric Andersenc470f442003-07-28 09:56:35 +00007825 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7826 fprintf(
7827 stderr, snlfmt,
7828 pathopt ? pathopt : "you have mail"
7829 );
7830 }
7831 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007832 }
Eric Andersenc470f442003-07-28 09:56:35 +00007833 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007834 popstackmark(&smark);
7835}
Eric Andersencb57d552001-06-28 07:25:16 +00007836
Eric Andersenec074692001-10-31 11:05:49 +00007837
Eric Andersenc470f442003-07-28 09:56:35 +00007838static void
7839changemail(const char *val)
7840{
7841 mail_var_path_changed++;
7842}
7843
7844#endif /* CONFIG_ASH_MAIL */
7845
7846/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7847
Eric Andersencb57d552001-06-28 07:25:16 +00007848
Eric Andersencb57d552001-06-28 07:25:16 +00007849#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007850static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007851extern int etext();
7852#endif
7853
Eric Andersenc470f442003-07-28 09:56:35 +00007854static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007855
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007856static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007857
Eric Andersencb57d552001-06-28 07:25:16 +00007858/*
7859 * Main routine. We initialize things, parse the arguments, execute
7860 * profiles if we're a login shell, and then call cmdloop to execute
7861 * commands. The setjmp call sets up the location to jump to when an
7862 * exception occurs. When an exception occurs the variable "state"
7863 * is used to figure out how far we had gotten.
7864 */
7865
Eric Andersenc470f442003-07-28 09:56:35 +00007866int
7867ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007868{
Eric Andersenc470f442003-07-28 09:56:35 +00007869 char *shinit;
7870 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007871 struct jmploc jmploc;
7872 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007873
Eric Andersenc470f442003-07-28 09:56:35 +00007874#ifdef __GLIBC__
7875 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007876#endif
7877
Eric Andersencb57d552001-06-28 07:25:16 +00007878#if PROFILE
7879 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7880#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007881 state = 0;
7882 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007883 int status;
7884 int e;
7885
Eric Andersencb57d552001-06-28 07:25:16 +00007886 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007887
7888 e = exception;
7889 switch (exception) {
7890 case EXEXEC:
7891 status = exerrno;
7892 break;
7893
7894 case EXERROR:
7895 status = 2;
7896 break;
7897
7898 default:
7899 status = exitstatus;
7900 break;
7901 }
7902 exitstatus = status;
7903
7904 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7905 exitshell();
7906
Eric Andersen90898442003-08-06 11:20:52 +00007907 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007908 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007909 }
7910 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007911 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007912 if (state == 1)
7913 goto state1;
7914 else if (state == 2)
7915 goto state2;
7916 else if (state == 3)
7917 goto state3;
7918 else
7919 goto state4;
7920 }
7921 handler = &jmploc;
7922#ifdef DEBUG
7923 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007924 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007925#endif
7926 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007927
7928#ifdef CONFIG_ASH_RANDOM_SUPPORT
7929 rseed = rootpid + ((time_t)time((time_t *)0));
7930#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007931 rootshell = 1;
7932 init();
7933 setstackmark(&smark);
7934 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007935#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7936 if ( iflag ) {
7937 const char *hp = lookupvar("HISTFILE");
7938
7939 if(hp == NULL ) {
7940 hp = lookupvar("HOME");
7941 if(hp != NULL) {
7942 char *defhp = concat_path_file(hp, ".ash_history");
7943 setvar("HISTFILE", defhp, 0);
7944 free(defhp);
7945 }
7946 }
7947 }
7948#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007949 if (argv[0] && argv[0][0] == '-')
7950 isloginsh = 1;
7951 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007952 state = 1;
7953 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007954state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007955 state = 2;
7956 read_profile(".profile");
7957 }
Eric Andersenc470f442003-07-28 09:56:35 +00007958state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007959 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007960 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007961#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007962 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007963#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007964 iflag
7965 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007966 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007967 read_profile(shinit);
7968 }
Eric Andersencb57d552001-06-28 07:25:16 +00007969 }
Eric Andersenc470f442003-07-28 09:56:35 +00007970state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007971 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007972 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007973 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007974
7975 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007976#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007977 if ( iflag ) {
7978 const char *hp = lookupvar("HISTFILE");
7979
7980 if(hp != NULL )
7981 load_history ( hp );
7982 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007983#endif
Eric Andersen90898442003-08-06 11:20:52 +00007984state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007985 cmdloop(1);
7986 }
7987#if PROFILE
7988 monitor(0);
7989#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007990#if GPROF
7991 {
7992 extern void _mcleanup(void);
7993 _mcleanup();
7994 }
7995#endif
7996 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007997 /* NOTREACHED */
7998}
7999
8000
8001/*
8002 * Read and execute commands. "Top" is nonzero for the top level command
8003 * loop; it turns on prompting if the shell is interactive.
8004 */
8005
Eric Andersenc470f442003-07-28 09:56:35 +00008006static void
8007cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008008{
8009 union node *n;
8010 struct stackmark smark;
8011 int inter;
8012 int numeof = 0;
8013
8014 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008015 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00008016 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00008017 if (pendingsigs)
8018 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00008019#if JOBS
8020 if (jobctl)
8021 showjobs(stderr, SHOW_CHANGED);
8022#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008023 inter = 0;
8024 if (iflag && top) {
8025 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008026#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008027 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008028#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008029 }
8030 n = parsecmd(inter);
8031 /* showtree(n); DEBUG */
8032 if (n == NEOF) {
8033 if (!top || numeof >= 50)
8034 break;
8035 if (!stoppedjobs()) {
8036 if (!Iflag)
8037 break;
8038 out2str("\nUse \"exit\" to leave shell.\n");
8039 }
8040 numeof++;
8041 } else if (n != NULL && nflag == 0) {
8042 job_warning = (job_warning == 2) ? 1 : 0;
8043 numeof = 0;
8044 evaltree(n, 0);
8045 }
8046 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008047 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008048 evalskip = 0;
8049 break;
8050 }
8051 }
Eric Andersencb57d552001-06-28 07:25:16 +00008052}
8053
8054
Eric Andersencb57d552001-06-28 07:25:16 +00008055/*
8056 * Read /etc/profile or .profile. Return on error.
8057 */
8058
Eric Andersenc470f442003-07-28 09:56:35 +00008059static void
8060read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008061{
8062 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008063 int xflag_set = 0;
8064 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008065
8066 INTOFF;
8067 if ((fd = open(name, O_RDONLY)) >= 0)
8068 setinputfd(fd, 1);
8069 INTON;
8070 if (fd < 0)
8071 return;
8072 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008073 if (qflag) {
8074 if (xflag)
8075 xflag = 0, xflag_set = 1;
8076 if (vflag)
8077 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008078 }
8079 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008080 if (qflag) {
8081 if (xflag_set)
8082 xflag = 1;
8083 if (vflag_set)
8084 vflag = 1;
8085 }
Eric Andersencb57d552001-06-28 07:25:16 +00008086 popfile();
8087}
8088
8089
Eric Andersencb57d552001-06-28 07:25:16 +00008090/*
8091 * Read a file containing shell functions.
8092 */
8093
Eric Andersenc470f442003-07-28 09:56:35 +00008094static void
8095readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008096{
8097 int fd;
8098
8099 INTOFF;
8100 if ((fd = open(name, O_RDONLY)) >= 0)
8101 setinputfd(fd, 1);
8102 else
8103 error("Can't open %s", name);
8104 INTON;
8105 cmdloop(0);
8106 popfile();
8107}
8108
8109
Eric Andersencb57d552001-06-28 07:25:16 +00008110/*
Eric Andersenc470f442003-07-28 09:56:35 +00008111 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008112 * search for the file, which is necessary to find sub-commands.
8113 */
8114
Eric Andersenc470f442003-07-28 09:56:35 +00008115static inline char *
8116find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008117{
8118 char *fullname;
8119 const char *path = pathval();
8120 struct stat statb;
8121
8122 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008123 if (strchr(name, '/'))
8124 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008125
Eric Andersenc470f442003-07-28 09:56:35 +00008126 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008127 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8128 /*
8129 * Don't bother freeing here, since it will
8130 * be freed by the caller.
8131 */
8132 return fullname;
8133 }
8134 stunalloc(fullname);
8135 }
8136
8137 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008138 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008139 /* NOTREACHED */
8140}
8141
Eric Andersen1e6aba92004-04-12 19:12:13 +00008142static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008143{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008144 struct strlist *sp;
8145 volatile struct shparam saveparam;
8146
Eric Andersencb57d552001-06-28 07:25:16 +00008147 exitstatus = 0;
8148
Eric Andersen1e6aba92004-04-12 19:12:13 +00008149 for (sp = cmdenviron; sp; sp = sp->next)
8150 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8151
8152 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008153 char *fullname;
8154 struct stackmark smark;
8155
8156 setstackmark(&smark);
8157 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008158
8159 if (argc > 2) {
8160 saveparam = shellparam;
8161 shellparam.malloc = 0;
8162 shellparam.nparam = argc - 2;
8163 shellparam.p = argv + 2;
8164 };
8165
Eric Andersencb57d552001-06-28 07:25:16 +00008166 setinputfile(fullname, 1);
8167 commandname = fullname;
8168 cmdloop(0);
8169 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008170
8171 if (argc > 2) {
8172 freeparam(&shellparam);
8173 shellparam = saveparam;
8174 };
8175
Eric Andersencb57d552001-06-28 07:25:16 +00008176 popstackmark(&smark);
8177 }
8178 return exitstatus;
8179}
8180
8181
Eric Andersenc470f442003-07-28 09:56:35 +00008182static int
8183exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008184{
8185 if (stoppedjobs())
8186 return 0;
8187 if (argc > 1)
8188 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008189 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008190 /* NOTREACHED */
8191}
Eric Andersen62483552001-07-10 06:09:16 +00008192
Eric Andersenc470f442003-07-28 09:56:35 +00008193/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8194
8195/*
Eric Andersen90898442003-08-06 11:20:52 +00008196 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008197 */
8198
8199static pointer
8200ckrealloc(pointer p, size_t nbytes)
8201{
8202 p = realloc(p, nbytes);
8203 if (p == NULL)
8204 error(bb_msg_memory_exhausted);
8205 return p;
8206}
8207
Eric Andersen90898442003-08-06 11:20:52 +00008208static pointer
8209ckmalloc(size_t nbytes)
8210{
8211 return ckrealloc(NULL, nbytes);
8212}
Eric Andersenc470f442003-07-28 09:56:35 +00008213
8214/*
8215 * Make a copy of a string in safe storage.
8216 */
8217
8218static char *
8219savestr(const char *s)
8220{
8221 char *p = strdup(s);
8222 if (!p)
8223 error(bb_msg_memory_exhausted);
8224 return p;
8225}
8226
8227
8228/*
8229 * Parse trees for commands are allocated in lifo order, so we use a stack
8230 * to make this more efficient, and also to avoid all sorts of exception
8231 * handling code to handle interrupts in the middle of a parse.
8232 *
8233 * The size 504 was chosen because the Ultrix malloc handles that size
8234 * well.
8235 */
8236
8237
8238static pointer
8239stalloc(size_t nbytes)
8240{
8241 char *p;
8242 size_t aligned;
8243
8244 aligned = SHELL_ALIGN(nbytes);
8245 if (aligned > stacknleft) {
8246 size_t len;
8247 size_t blocksize;
8248 struct stack_block *sp;
8249
8250 blocksize = aligned;
8251 if (blocksize < MINSIZE)
8252 blocksize = MINSIZE;
8253 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8254 if (len < blocksize)
8255 error(bb_msg_memory_exhausted);
8256 INTOFF;
8257 sp = ckmalloc(len);
8258 sp->prev = stackp;
8259 stacknxt = sp->space;
8260 stacknleft = blocksize;
8261 sstrend = stacknxt + blocksize;
8262 stackp = sp;
8263 INTON;
8264 }
8265 p = stacknxt;
8266 stacknxt += aligned;
8267 stacknleft -= aligned;
8268 return p;
8269}
8270
8271
8272void
8273stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008274{
Eric Andersencb57d552001-06-28 07:25:16 +00008275#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008276 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008277 write(2, "stunalloc\n", 10);
8278 abort();
8279 }
8280#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008281 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008282 stacknxt = p;
8283}
8284
8285
Eric Andersenc470f442003-07-28 09:56:35 +00008286void
8287setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008288{
Eric Andersencb57d552001-06-28 07:25:16 +00008289 mark->stackp = stackp;
8290 mark->stacknxt = stacknxt;
8291 mark->stacknleft = stacknleft;
8292 mark->marknext = markp;
8293 markp = mark;
8294}
8295
8296
Eric Andersenc470f442003-07-28 09:56:35 +00008297void
8298popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008299{
Eric Andersencb57d552001-06-28 07:25:16 +00008300 struct stack_block *sp;
8301
8302 INTOFF;
8303 markp = mark->marknext;
8304 while (stackp != mark->stackp) {
8305 sp = stackp;
8306 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008307 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008308 }
8309 stacknxt = mark->stacknxt;
8310 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008311 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008312 INTON;
8313}
8314
8315
8316/*
8317 * When the parser reads in a string, it wants to stick the string on the
8318 * stack and only adjust the stack pointer when it knows how big the
8319 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8320 * of space on top of the stack and stackblocklen returns the length of
8321 * this block. Growstackblock will grow this space by at least one byte,
8322 * possibly moving it (like realloc). Grabstackblock actually allocates the
8323 * part of the block that has been used.
8324 */
8325
Eric Andersenc470f442003-07-28 09:56:35 +00008326void
8327growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008328{
Eric Andersenc470f442003-07-28 09:56:35 +00008329 size_t newlen;
8330
8331 newlen = stacknleft * 2;
8332 if (newlen < stacknleft)
8333 error(bb_msg_memory_exhausted);
8334 if (newlen < 128)
8335 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008336
8337 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008338 struct stack_block *oldstackp;
8339 struct stackmark *xmark;
8340 struct stack_block *sp;
8341 struct stack_block *prevstackp;
8342 size_t grosslen;
8343
Eric Andersencb57d552001-06-28 07:25:16 +00008344 INTOFF;
8345 oldstackp = stackp;
8346 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008347 prevstackp = sp->prev;
8348 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8349 sp = ckrealloc((pointer)sp, grosslen);
8350 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008351 stackp = sp;
8352 stacknxt = sp->space;
8353 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008354 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008355
Eric Andersenc470f442003-07-28 09:56:35 +00008356 /*
8357 * Stack marks pointing to the start of the old block
8358 * must be relocated to point to the new block
8359 */
8360 xmark = markp;
8361 while (xmark != NULL && xmark->stackp == oldstackp) {
8362 xmark->stackp = stackp;
8363 xmark->stacknxt = stacknxt;
8364 xmark->stacknleft = stacknleft;
8365 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008366 }
8367 INTON;
8368 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008369 char *oldspace = stacknxt;
8370 int oldlen = stacknleft;
8371 char *p = stalloc(newlen);
8372
8373 /* free the space we just allocated */
8374 stacknxt = memcpy(p, oldspace, oldlen);
8375 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008376 }
8377}
8378
Eric Andersenc470f442003-07-28 09:56:35 +00008379static inline void
8380grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008381{
Eric Andersenc470f442003-07-28 09:56:35 +00008382 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008383 stacknxt += len;
8384 stacknleft -= len;
8385}
8386
Eric Andersencb57d552001-06-28 07:25:16 +00008387/*
Eric Andersenc470f442003-07-28 09:56:35 +00008388 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008389 * The user declares a variable of type STACKSTR, which may be declared
8390 * to be a register. The macro STARTSTACKSTR initializes things. Then
8391 * the user uses the macro STPUTC to add characters to the string. In
8392 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8393 * grown as necessary. When the user is done, she can just leave the
8394 * string there and refer to it using stackblock(). Or she can allocate
8395 * the space for it using grabstackstr(). If it is necessary to allow
8396 * someone else to use the stack temporarily and then continue to grow
8397 * the string, the user should use grabstack to allocate the space, and
8398 * then call ungrabstr(p) to return to the previous mode of operation.
8399 *
8400 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8401 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8402 * is space for at least one character.
8403 */
8404
Eric Andersenc470f442003-07-28 09:56:35 +00008405void *
8406growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008407{
Eric Andersenc470f442003-07-28 09:56:35 +00008408 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008409 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008410 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008411 return stackblock();
8412 }
8413 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008414 return stackblock() + len;
8415}
8416
Eric Andersencb57d552001-06-28 07:25:16 +00008417/*
8418 * Called from CHECKSTRSPACE.
8419 */
8420
Eric Andersenc470f442003-07-28 09:56:35 +00008421char *
8422makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008423{
Eric Andersenc470f442003-07-28 09:56:35 +00008424 size_t len = p - stacknxt;
8425 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008426
Eric Andersenc470f442003-07-28 09:56:35 +00008427 for (;;) {
8428 size_t nleft;
8429
8430 size = stackblocksize();
8431 nleft = size - len;
8432 if (nleft >= newlen)
8433 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008434 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008435 }
Eric Andersencb57d552001-06-28 07:25:16 +00008436 return stackblock() + len;
8437}
8438
Eric Andersenc470f442003-07-28 09:56:35 +00008439char *
8440stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008441{
Eric Andersenc470f442003-07-28 09:56:35 +00008442 p = makestrspace(n, p);
8443 p = mempcpy(p, s, n);
8444 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008445}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008446
Eric Andersenc470f442003-07-28 09:56:35 +00008447char *
8448stputs(const char *s, char *p)
8449{
8450 return stnputs(s, strlen(s), p);
8451}
8452
8453/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8454
Eric Andersencb57d552001-06-28 07:25:16 +00008455/*
Eric Andersenc470f442003-07-28 09:56:35 +00008456 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008457 *
Eric Andersenc470f442003-07-28 09:56:35 +00008458 * number(s) Convert a string of digits to an integer.
8459 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008460 */
8461
Eric Andersencb57d552001-06-28 07:25:16 +00008462/*
8463 * prefix -- see if pfx is a prefix of string.
8464 */
8465
Eric Andersenc470f442003-07-28 09:56:35 +00008466char *
8467prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008468{
Eric Andersencb57d552001-06-28 07:25:16 +00008469 while (*pfx) {
8470 if (*pfx++ != *string++)
8471 return 0;
8472 }
Eric Andersenc470f442003-07-28 09:56:35 +00008473 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008474}
8475
8476
8477/*
8478 * Convert a string of digits to an integer, printing an error message on
8479 * failure.
8480 */
8481
Eric Andersenc470f442003-07-28 09:56:35 +00008482int
8483number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008484{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008485
Eric Andersenc470f442003-07-28 09:56:35 +00008486 if (! is_number(s))
8487 error(illnum, s);
8488 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008489}
8490
Eric Andersenc470f442003-07-28 09:56:35 +00008491
Eric Andersenc470f442003-07-28 09:56:35 +00008492/*
8493 * Check for a valid number. This should be elsewhere.
8494 */
8495
8496int
8497is_number(const char *p)
8498{
8499 do {
8500 if (! is_digit(*p))
8501 return 0;
8502 } while (*++p != '\0');
8503 return 1;
8504}
8505
8506
Eric Andersencb57d552001-06-28 07:25:16 +00008507/*
8508 * Produce a possibly single quoted string suitable as input to the shell.
8509 * The return string is allocated on the stack.
8510 */
8511
Eric Andersenc470f442003-07-28 09:56:35 +00008512char *
8513single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008514 char *p;
8515
8516 STARTSTACKSTR(p);
8517
8518 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008519 char *q;
8520 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008521
Eric Andersenc470f442003-07-28 09:56:35 +00008522 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008523
Eric Andersenc470f442003-07-28 09:56:35 +00008524 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008525
Eric Andersenc470f442003-07-28 09:56:35 +00008526 *q++ = '\'';
8527 q = mempcpy(q, s, len);
8528 *q++ = '\'';
8529 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008530
Eric Andersenc470f442003-07-28 09:56:35 +00008531 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008532
Eric Andersenc470f442003-07-28 09:56:35 +00008533 len = strspn(s, "'");
8534 if (!len)
8535 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008536
Eric Andersenc470f442003-07-28 09:56:35 +00008537 q = p = makestrspace(len + 3, p);
8538
8539 *q++ = '"';
8540 q = mempcpy(q, s, len);
8541 *q++ = '"';
8542 s += len;
8543
8544 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008545 } while (*s);
8546
8547 USTPUTC(0, p);
8548
Eric Andersenc470f442003-07-28 09:56:35 +00008549 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008550}
8551
8552/*
Eric Andersenc470f442003-07-28 09:56:35 +00008553 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008554 */
8555
Eric Andersenc470f442003-07-28 09:56:35 +00008556char *
8557sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008558{
Eric Andersenc470f442003-07-28 09:56:35 +00008559 size_t len = strlen(p) + 1;
8560 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008561}
Eric Andersenc470f442003-07-28 09:56:35 +00008562
8563
8564static void
8565calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008566{
Eric Andersenc470f442003-07-28 09:56:35 +00008567 if (n == NULL)
8568 return;
8569 funcblocksize += nodesize[n->type];
8570 switch (n->type) {
8571 case NCMD:
8572 calcsize(n->ncmd.redirect);
8573 calcsize(n->ncmd.args);
8574 calcsize(n->ncmd.assign);
8575 break;
8576 case NPIPE:
8577 sizenodelist(n->npipe.cmdlist);
8578 break;
8579 case NREDIR:
8580 case NBACKGND:
8581 case NSUBSHELL:
8582 calcsize(n->nredir.redirect);
8583 calcsize(n->nredir.n);
8584 break;
8585 case NAND:
8586 case NOR:
8587 case NSEMI:
8588 case NWHILE:
8589 case NUNTIL:
8590 calcsize(n->nbinary.ch2);
8591 calcsize(n->nbinary.ch1);
8592 break;
8593 case NIF:
8594 calcsize(n->nif.elsepart);
8595 calcsize(n->nif.ifpart);
8596 calcsize(n->nif.test);
8597 break;
8598 case NFOR:
8599 funcstringsize += strlen(n->nfor.var) + 1;
8600 calcsize(n->nfor.body);
8601 calcsize(n->nfor.args);
8602 break;
8603 case NCASE:
8604 calcsize(n->ncase.cases);
8605 calcsize(n->ncase.expr);
8606 break;
8607 case NCLIST:
8608 calcsize(n->nclist.body);
8609 calcsize(n->nclist.pattern);
8610 calcsize(n->nclist.next);
8611 break;
8612 case NDEFUN:
8613 case NARG:
8614 sizenodelist(n->narg.backquote);
8615 funcstringsize += strlen(n->narg.text) + 1;
8616 calcsize(n->narg.next);
8617 break;
8618 case NTO:
8619 case NCLOBBER:
8620 case NFROM:
8621 case NFROMTO:
8622 case NAPPEND:
8623 calcsize(n->nfile.fname);
8624 calcsize(n->nfile.next);
8625 break;
8626 case NTOFD:
8627 case NFROMFD:
8628 calcsize(n->ndup.vname);
8629 calcsize(n->ndup.next);
8630 break;
8631 case NHERE:
8632 case NXHERE:
8633 calcsize(n->nhere.doc);
8634 calcsize(n->nhere.next);
8635 break;
8636 case NNOT:
8637 calcsize(n->nnot.com);
8638 break;
8639 };
Eric Andersencb57d552001-06-28 07:25:16 +00008640}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008641
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008642
Eric Andersenc470f442003-07-28 09:56:35 +00008643static void
8644sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008645{
8646 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008647 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008648 calcsize(lp->n);
8649 lp = lp->next;
8650 }
8651}
Eric Andersencb57d552001-06-28 07:25:16 +00008652
8653
Eric Andersenc470f442003-07-28 09:56:35 +00008654static union node *
8655copynode(union node *n)
8656{
8657 union node *new;
8658
8659 if (n == NULL)
8660 return NULL;
8661 new = funcblock;
8662 funcblock = (char *) funcblock + nodesize[n->type];
8663 switch (n->type) {
8664 case NCMD:
8665 new->ncmd.redirect = copynode(n->ncmd.redirect);
8666 new->ncmd.args = copynode(n->ncmd.args);
8667 new->ncmd.assign = copynode(n->ncmd.assign);
8668 break;
8669 case NPIPE:
8670 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8671 new->npipe.backgnd = n->npipe.backgnd;
8672 break;
8673 case NREDIR:
8674 case NBACKGND:
8675 case NSUBSHELL:
8676 new->nredir.redirect = copynode(n->nredir.redirect);
8677 new->nredir.n = copynode(n->nredir.n);
8678 break;
8679 case NAND:
8680 case NOR:
8681 case NSEMI:
8682 case NWHILE:
8683 case NUNTIL:
8684 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8685 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8686 break;
8687 case NIF:
8688 new->nif.elsepart = copynode(n->nif.elsepart);
8689 new->nif.ifpart = copynode(n->nif.ifpart);
8690 new->nif.test = copynode(n->nif.test);
8691 break;
8692 case NFOR:
8693 new->nfor.var = nodesavestr(n->nfor.var);
8694 new->nfor.body = copynode(n->nfor.body);
8695 new->nfor.args = copynode(n->nfor.args);
8696 break;
8697 case NCASE:
8698 new->ncase.cases = copynode(n->ncase.cases);
8699 new->ncase.expr = copynode(n->ncase.expr);
8700 break;
8701 case NCLIST:
8702 new->nclist.body = copynode(n->nclist.body);
8703 new->nclist.pattern = copynode(n->nclist.pattern);
8704 new->nclist.next = copynode(n->nclist.next);
8705 break;
8706 case NDEFUN:
8707 case NARG:
8708 new->narg.backquote = copynodelist(n->narg.backquote);
8709 new->narg.text = nodesavestr(n->narg.text);
8710 new->narg.next = copynode(n->narg.next);
8711 break;
8712 case NTO:
8713 case NCLOBBER:
8714 case NFROM:
8715 case NFROMTO:
8716 case NAPPEND:
8717 new->nfile.fname = copynode(n->nfile.fname);
8718 new->nfile.fd = n->nfile.fd;
8719 new->nfile.next = copynode(n->nfile.next);
8720 break;
8721 case NTOFD:
8722 case NFROMFD:
8723 new->ndup.vname = copynode(n->ndup.vname);
8724 new->ndup.dupfd = n->ndup.dupfd;
8725 new->ndup.fd = n->ndup.fd;
8726 new->ndup.next = copynode(n->ndup.next);
8727 break;
8728 case NHERE:
8729 case NXHERE:
8730 new->nhere.doc = copynode(n->nhere.doc);
8731 new->nhere.fd = n->nhere.fd;
8732 new->nhere.next = copynode(n->nhere.next);
8733 break;
8734 case NNOT:
8735 new->nnot.com = copynode(n->nnot.com);
8736 break;
8737 };
8738 new->type = n->type;
8739 return new;
8740}
8741
8742
8743static struct nodelist *
8744copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008745{
8746 struct nodelist *start;
8747 struct nodelist **lpp;
8748
8749 lpp = &start;
8750 while (lp) {
8751 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008752 funcblock = (char *) funcblock +
8753 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008754 (*lpp)->n = copynode(lp->n);
8755 lp = lp->next;
8756 lpp = &(*lpp)->next;
8757 }
8758 *lpp = NULL;
8759 return start;
8760}
8761
8762
Eric Andersenc470f442003-07-28 09:56:35 +00008763static char *
8764nodesavestr(char *s)
8765{
8766 char *rtn = funcstring;
8767
8768 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008769 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008770}
8771
Eric Andersenc470f442003-07-28 09:56:35 +00008772
Eric Andersenc470f442003-07-28 09:56:35 +00008773/*
8774 * Free a parse tree.
8775 */
8776
8777static void
8778freefunc(struct funcnode *f)
8779{
8780 if (f && --f->count < 0)
8781 ckfree(f);
8782}
8783
8784
8785static void options(int);
8786static void setoption(int, int);
8787
Eric Andersencb57d552001-06-28 07:25:16 +00008788
Eric Andersencb57d552001-06-28 07:25:16 +00008789/*
8790 * Process the shell command line arguments.
8791 */
8792
Eric Andersenc470f442003-07-28 09:56:35 +00008793void
8794procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008795{
8796 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008797 const char *xminusc;
8798 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008799
Eric Andersenc470f442003-07-28 09:56:35 +00008800 xargv = argv;
8801 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008802 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008803 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008804 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008805 optlist[i] = 2;
8806 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008807 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008808 xargv = argptr;
8809 xminusc = minusc;
8810 if (*xargv == NULL) {
8811 if (xminusc)
8812 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008813 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008814 }
Eric Andersencb57d552001-06-28 07:25:16 +00008815 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8816 iflag = 1;
8817 if (mflag == 2)
8818 mflag = iflag;
8819 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008820 if (optlist[i] == 2)
8821 optlist[i] = 0;
8822#if DEBUG == 2
8823 debug = 1;
8824#endif
8825 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8826 if (xminusc) {
8827 minusc = *xargv++;
8828 if (*xargv)
8829 goto setarg0;
8830 } else if (!sflag) {
8831 setinputfile(*xargv, 0);
8832setarg0:
8833 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008834 commandname = arg0;
8835 }
Eric Andersencb57d552001-06-28 07:25:16 +00008836
Eric Andersenc470f442003-07-28 09:56:35 +00008837 shellparam.p = xargv;
8838#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008839 shellparam.optind = 1;
8840 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008841#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008842 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008843 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008844 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008845 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008846 }
8847 optschanged();
8848}
8849
8850
Eric Andersenc470f442003-07-28 09:56:35 +00008851void
8852optschanged(void)
8853{
8854#ifdef DEBUG
8855 opentrace();
8856#endif
8857 setinteractive(iflag);
8858 setjobctl(mflag);
8859}
Eric Andersencb57d552001-06-28 07:25:16 +00008860
Eric Andersenc470f442003-07-28 09:56:35 +00008861static inline void
8862minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008863{
8864 int i;
8865
8866 if (name == NULL) {
8867 out1str("Current option settings\n");
8868 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008869 out1fmt("%-16s%s\n", optnames(i),
8870 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008871 } else {
8872 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008873 if (equal(name, optnames(i))) {
8874 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008875 return;
8876 }
8877 error("Illegal option -o %s", name);
8878 }
8879}
8880
Eric Andersenc470f442003-07-28 09:56:35 +00008881/*
8882 * Process shell options. The global variable argptr contains a pointer
8883 * to the argument list; we advance it past the options.
8884 */
Eric Andersen62483552001-07-10 06:09:16 +00008885
Eric Andersenc470f442003-07-28 09:56:35 +00008886static void
8887options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008888{
8889 char *p;
8890 int val;
8891 int c;
8892
8893 if (cmdline)
8894 minusc = NULL;
8895 while ((p = *argptr) != NULL) {
8896 argptr++;
8897 if ((c = *p++) == '-') {
8898 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008899 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8900 if (!cmdline) {
8901 /* "-" means turn off -x and -v */
8902 if (p[0] == '\0')
8903 xflag = vflag = 0;
8904 /* "--" means reset params */
8905 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008906 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008907 }
Eric Andersenc470f442003-07-28 09:56:35 +00008908 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008909 }
8910 } else if (c == '+') {
8911 val = 0;
8912 } else {
8913 argptr--;
8914 break;
8915 }
8916 while ((c = *p++) != '\0') {
8917 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008918 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008919 } else if (c == 'o') {
8920 minus_o(*argptr, val);
8921 if (*argptr)
8922 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008923 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008924 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008925 isloginsh = 1;
8926 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008927 } else {
8928 setoption(c, val);
8929 }
8930 }
8931 }
8932}
8933
Eric Andersencb57d552001-06-28 07:25:16 +00008934
Eric Andersenc470f442003-07-28 09:56:35 +00008935static void
8936setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008937{
Eric Andersencb57d552001-06-28 07:25:16 +00008938 int i;
8939
8940 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008941 if (optletters(i) == flag) {
8942 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008943 return;
8944 }
8945 error("Illegal option -%c", flag);
8946 /* NOTREACHED */
8947}
8948
8949
8950
Eric Andersencb57d552001-06-28 07:25:16 +00008951/*
8952 * Set the shell parameters.
8953 */
8954
Eric Andersenc470f442003-07-28 09:56:35 +00008955void
8956setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008957{
Eric Andersencb57d552001-06-28 07:25:16 +00008958 char **newparam;
8959 char **ap;
8960 int nparam;
8961
Eric Andersenc470f442003-07-28 09:56:35 +00008962 for (nparam = 0 ; argv[nparam] ; nparam++);
8963 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008964 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008965 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008966 }
8967 *ap = NULL;
8968 freeparam(&shellparam);
8969 shellparam.malloc = 1;
8970 shellparam.nparam = nparam;
8971 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008972#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008973 shellparam.optind = 1;
8974 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008975#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008976}
8977
8978
8979/*
8980 * Free the list of positional parameters.
8981 */
8982
Eric Andersenc470f442003-07-28 09:56:35 +00008983void
8984freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008985{
Eric Andersencb57d552001-06-28 07:25:16 +00008986 char **ap;
8987
8988 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008989 for (ap = param->p ; *ap ; ap++)
8990 ckfree(*ap);
8991 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008992 }
8993}
8994
8995
8996
8997/*
8998 * The shift builtin command.
8999 */
9000
Eric Andersenc470f442003-07-28 09:56:35 +00009001int
9002shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009003{
9004 int n;
9005 char **ap1, **ap2;
9006
9007 n = 1;
9008 if (argc > 1)
9009 n = number(argv[1]);
9010 if (n > shellparam.nparam)
9011 error("can't shift that many");
9012 INTOFF;
9013 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009014 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009015 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009016 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009017 }
9018 ap2 = shellparam.p;
9019 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009020#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009021 shellparam.optind = 1;
9022 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009023#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009024 INTON;
9025 return 0;
9026}
9027
9028
9029
9030/*
9031 * The set command builtin.
9032 */
9033
Eric Andersenc470f442003-07-28 09:56:35 +00009034int
9035setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009036{
9037 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009038 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009039 INTOFF;
9040 options(0);
9041 optschanged();
9042 if (*argptr != NULL) {
9043 setparam(argptr);
9044 }
9045 INTON;
9046 return 0;
9047}
9048
9049
Eric Andersenc470f442003-07-28 09:56:35 +00009050#ifdef CONFIG_ASH_GETOPTS
9051static void
9052getoptsreset(value)
9053 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009054{
9055 shellparam.optind = number(value);
9056 shellparam.optoff = -1;
9057}
Eric Andersenc470f442003-07-28 09:56:35 +00009058#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009059
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009060#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009061static void change_lc_all(const char *value)
9062{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009063 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009064 setlocale(LC_ALL, value);
9065}
9066
9067static void change_lc_ctype(const char *value)
9068{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009069 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009070 setlocale(LC_CTYPE, value);
9071}
9072
9073#endif
9074
Eric Andersen16767e22004-03-16 05:14:10 +00009075#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009076/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009077static void change_random(const char *value)
9078{
Eric Andersen16767e22004-03-16 05:14:10 +00009079 if(value == NULL) {
9080 /* "get", generate */
9081 char buf[16];
9082
9083 rseed = rseed * 1103515245 + 12345;
9084 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9085 /* set without recursion */
9086 setvar(vrandom.text, buf, VNOFUNC);
9087 vrandom.flags &= ~VNOFUNC;
9088 } else {
9089 /* set/reset */
9090 rseed = strtoul(value, (char **)NULL, 10);
9091 }
Eric Andersenef02f822004-03-11 13:34:24 +00009092}
Eric Andersen16767e22004-03-16 05:14:10 +00009093#endif
9094
Eric Andersenef02f822004-03-11 13:34:24 +00009095
Eric Andersend35c5df2002-01-09 15:37:36 +00009096#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009097static int
Eric Andersenc470f442003-07-28 09:56:35 +00009098getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009099{
9100 char *p, *q;
9101 char c = '?';
9102 int done = 0;
9103 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009104 char s[12];
9105 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009106
Eric Andersena48b0a32003-10-22 10:56:47 +00009107 if(*param_optind < 1)
9108 return 1;
9109 optnext = optfirst + *param_optind - 1;
9110
9111 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009112 p = NULL;
9113 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009114 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009115 if (p == NULL || *p == '\0') {
9116 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009117 p = *optnext;
9118 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009119atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009120 p = NULL;
9121 done = 1;
9122 goto out;
9123 }
9124 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009125 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009126 goto atend;
9127 }
9128
9129 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009130 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009131 if (*q == '\0') {
9132 if (optstr[0] == ':') {
9133 s[0] = c;
9134 s[1] = '\0';
9135 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009136 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009137 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009138 (void) unsetvar("OPTARG");
9139 }
9140 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009141 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009142 }
9143 if (*++q == ':')
9144 q++;
9145 }
9146
9147 if (*++q == ':') {
9148 if (*p == '\0' && (p = *optnext) == NULL) {
9149 if (optstr[0] == ':') {
9150 s[0] = c;
9151 s[1] = '\0';
9152 err |= setvarsafe("OPTARG", s, 0);
9153 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009154 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009155 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009156 (void) unsetvar("OPTARG");
9157 c = '?';
9158 }
Eric Andersenc470f442003-07-28 09:56:35 +00009159 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009160 }
9161
9162 if (p == *optnext)
9163 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009164 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009165 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009166 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009167 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009168
Eric Andersenc470f442003-07-28 09:56:35 +00009169out:
Eric Andersencb57d552001-06-28 07:25:16 +00009170 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009171 *param_optind = optnext - optfirst + 1;
9172 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009173 err |= setvarsafe("OPTIND", s, VNOFUNC);
9174 s[0] = c;
9175 s[1] = '\0';
9176 err |= setvarsafe(optvar, s, 0);
9177 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009178 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009179 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009180 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009181 exraise(EXERROR);
9182 }
9183 return done;
9184}
Eric Andersenc470f442003-07-28 09:56:35 +00009185
9186/*
9187 * The getopts builtin. Shellparam.optnext points to the next argument
9188 * to be processed. Shellparam.optptr points to the next character to
9189 * be processed in the current argument. If shellparam.optnext is NULL,
9190 * then it's the first time getopts has been called.
9191 */
9192
9193int
9194getoptscmd(int argc, char **argv)
9195{
9196 char **optbase;
9197
9198 if (argc < 3)
9199 error("Usage: getopts optstring var [arg]");
9200 else if (argc == 3) {
9201 optbase = shellparam.p;
9202 if (shellparam.optind > shellparam.nparam + 1) {
9203 shellparam.optind = 1;
9204 shellparam.optoff = -1;
9205 }
9206 }
9207 else {
9208 optbase = &argv[3];
9209 if (shellparam.optind > argc - 2) {
9210 shellparam.optind = 1;
9211 shellparam.optoff = -1;
9212 }
9213 }
9214
9215 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9216 &shellparam.optoff);
9217}
9218#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009219
9220/*
9221 * XXX - should get rid of. have all builtins use getopt(3). the
9222 * library getopt must have the BSD extension static variable "optreset"
9223 * otherwise it can't be used within the shell safely.
9224 *
9225 * Standard option processing (a la getopt) for builtin routines. The
9226 * only argument that is passed to nextopt is the option string; the
9227 * other arguments are unnecessary. It return the character, or '\0' on
9228 * end of input.
9229 */
9230
Eric Andersenc470f442003-07-28 09:56:35 +00009231static int
9232nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009233{
Eric Andersencb57d552001-06-28 07:25:16 +00009234 char *p;
9235 const char *q;
9236 char c;
9237
9238 if ((p = optptr) == NULL || *p == '\0') {
9239 p = *argptr;
9240 if (p == NULL || *p != '-' || *++p == '\0')
9241 return '\0';
9242 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009243 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009244 return '\0';
9245 }
9246 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009247 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009248 if (*q == '\0')
9249 error("Illegal option -%c", c);
9250 if (*++q == ':')
9251 q++;
9252 }
9253 if (*++q == ':') {
9254 if (*p == '\0' && (p = *argptr++) == NULL)
9255 error("No arg for -%c option", c);
9256 optionarg = p;
9257 p = NULL;
9258 }
9259 optptr = p;
9260 return c;
9261}
9262
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009263
Eric Andersenc470f442003-07-28 09:56:35 +00009264/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9265
Eric Andersenc470f442003-07-28 09:56:35 +00009266void
9267outstr(const char *p, FILE *file)
9268{
9269 INTOFF;
9270 fputs(p, file);
9271 INTON;
9272}
9273
9274void
9275flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009276{
Eric Andersencb57d552001-06-28 07:25:16 +00009277 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009278 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009279 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009280 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009281}
9282
Eric Andersenc470f442003-07-28 09:56:35 +00009283void
Eric Andersen16767e22004-03-16 05:14:10 +00009284flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009285{
9286 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009287 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009288 INTON;
9289}
9290
9291static void
9292outcslow(int c, FILE *dest)
9293{
9294 INTOFF;
9295 putc(c, dest);
9296 fflush(dest);
9297 INTON;
9298}
9299
9300
9301static int
9302out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009303{
9304 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009305 int r;
9306
9307 INTOFF;
9308 va_start(ap, fmt);
9309 r = vprintf(fmt, ap);
9310 va_end(ap);
9311 INTON;
9312 return r;
9313}
9314
9315
9316int
9317fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9318{
9319 va_list ap;
9320 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009321
Eric Andersencb57d552001-06-28 07:25:16 +00009322 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009323 INTOFF;
9324 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009325 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009326 INTON;
9327 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009328}
9329
Eric Andersenc470f442003-07-28 09:56:35 +00009330
Eric Andersencb57d552001-06-28 07:25:16 +00009331
Eric Andersenc470f442003-07-28 09:56:35 +00009332/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9333
9334
Eric Andersencb57d552001-06-28 07:25:16 +00009335/*
9336 * Shell command parser.
9337 */
9338
9339#define EOFMARKLEN 79
9340
9341
Eric Andersencb57d552001-06-28 07:25:16 +00009342struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009343 struct heredoc *next; /* next here document in list */
9344 union node *here; /* redirection node */
9345 char *eofmark; /* string indicating end of input */
9346 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009347};
9348
9349
9350
Eric Andersenc470f442003-07-28 09:56:35 +00009351static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009352
9353
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009354static union node *list(int);
9355static union node *andor(void);
9356static union node *pipeline(void);
9357static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009358static union node *simplecmd(void);
9359static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009360static void parsefname(void);
9361static void parseheredoc(void);
9362static char peektoken(void);
9363static int readtoken(void);
9364static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009365static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009366static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009367static void synexpect(int) __attribute__((__noreturn__));
9368static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009369static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009370
9371
Eric Andersenc470f442003-07-28 09:56:35 +00009372
9373static inline int
9374isassignment(const char *p)
9375{
9376 const char *q = endofname(p);
9377 if (p == q)
9378 return 0;
9379 return *q == '=';
9380}
9381
9382
Eric Andersencb57d552001-06-28 07:25:16 +00009383/*
9384 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9385 * valid parse tree indicating a blank line.)
9386 */
9387
Eric Andersenc470f442003-07-28 09:56:35 +00009388union node *
9389parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009390{
9391 int t;
9392
9393 tokpushback = 0;
9394 doprompt = interact;
9395 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009396 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009397 needprompt = 0;
9398 t = readtoken();
9399 if (t == TEOF)
9400 return NEOF;
9401 if (t == TNL)
9402 return NULL;
9403 tokpushback++;
9404 return list(1);
9405}
9406
9407
Eric Andersenc470f442003-07-28 09:56:35 +00009408static union node *
9409list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009410{
9411 union node *n1, *n2, *n3;
9412 int tok;
9413
Eric Andersenc470f442003-07-28 09:56:35 +00009414 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9415 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009416 return NULL;
9417 n1 = NULL;
9418 for (;;) {
9419 n2 = andor();
9420 tok = readtoken();
9421 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009422 if (n2->type == NPIPE) {
9423 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009424 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009425 if (n2->type != NREDIR) {
9426 n3 = stalloc(sizeof(struct nredir));
9427 n3->nredir.n = n2;
9428 n3->nredir.redirect = NULL;
9429 n2 = n3;
9430 }
9431 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009432 }
9433 }
9434 if (n1 == NULL) {
9435 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009436 }
9437 else {
9438 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009439 n3->type = NSEMI;
9440 n3->nbinary.ch1 = n1;
9441 n3->nbinary.ch2 = n2;
9442 n1 = n3;
9443 }
9444 switch (tok) {
9445 case TBACKGND:
9446 case TSEMI:
9447 tok = readtoken();
9448 /* fall through */
9449 case TNL:
9450 if (tok == TNL) {
9451 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009452 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009453 return n1;
9454 } else {
9455 tokpushback++;
9456 }
Eric Andersenc470f442003-07-28 09:56:35 +00009457 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009458 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009459 return n1;
9460 break;
9461 case TEOF:
9462 if (heredoclist)
9463 parseheredoc();
9464 else
Eric Andersenc470f442003-07-28 09:56:35 +00009465 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009466 return n1;
9467 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009468 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009469 synexpect(-1);
9470 tokpushback++;
9471 return n1;
9472 }
9473 }
9474}
9475
9476
9477
Eric Andersenc470f442003-07-28 09:56:35 +00009478static union node *
9479andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009480{
Eric Andersencb57d552001-06-28 07:25:16 +00009481 union node *n1, *n2, *n3;
9482 int t;
9483
Eric Andersencb57d552001-06-28 07:25:16 +00009484 n1 = pipeline();
9485 for (;;) {
9486 if ((t = readtoken()) == TAND) {
9487 t = NAND;
9488 } else if (t == TOR) {
9489 t = NOR;
9490 } else {
9491 tokpushback++;
9492 return n1;
9493 }
Eric Andersenc470f442003-07-28 09:56:35 +00009494 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009495 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009496 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009497 n3->type = t;
9498 n3->nbinary.ch1 = n1;
9499 n3->nbinary.ch2 = n2;
9500 n1 = n3;
9501 }
9502}
9503
9504
9505
Eric Andersenc470f442003-07-28 09:56:35 +00009506static union node *
9507pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009508{
Eric Andersencb57d552001-06-28 07:25:16 +00009509 union node *n1, *n2, *pipenode;
9510 struct nodelist *lp, *prev;
9511 int negate;
9512
9513 negate = 0;
9514 TRACE(("pipeline: entered\n"));
9515 if (readtoken() == TNOT) {
9516 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009517 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009518 } else
9519 tokpushback++;
9520 n1 = command();
9521 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009522 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009523 pipenode->type = NPIPE;
9524 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009525 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009526 pipenode->npipe.cmdlist = lp;
9527 lp->n = n1;
9528 do {
9529 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009530 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9531 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009532 lp->n = command();
9533 prev->next = lp;
9534 } while (readtoken() == TPIPE);
9535 lp->next = NULL;
9536 n1 = pipenode;
9537 }
9538 tokpushback++;
9539 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009540 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009541 n2->type = NNOT;
9542 n2->nnot.com = n1;
9543 return n2;
9544 } else
9545 return n1;
9546}
9547
9548
9549
Eric Andersenc470f442003-07-28 09:56:35 +00009550static union node *
9551command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009552{
Eric Andersencb57d552001-06-28 07:25:16 +00009553 union node *n1, *n2;
9554 union node *ap, **app;
9555 union node *cp, **cpp;
9556 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009557 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009558 int t;
9559
9560 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009561 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009562
Eric Andersencb57d552001-06-28 07:25:16 +00009563 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009564 default:
9565 synexpect(-1);
9566 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009567 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009568 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009569 n1->type = NIF;
9570 n1->nif.test = list(0);
9571 if (readtoken() != TTHEN)
9572 synexpect(TTHEN);
9573 n1->nif.ifpart = list(0);
9574 n2 = n1;
9575 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009576 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009577 n2 = n2->nif.elsepart;
9578 n2->type = NIF;
9579 n2->nif.test = list(0);
9580 if (readtoken() != TTHEN)
9581 synexpect(TTHEN);
9582 n2->nif.ifpart = list(0);
9583 }
9584 if (lasttoken == TELSE)
9585 n2->nif.elsepart = list(0);
9586 else {
9587 n2->nif.elsepart = NULL;
9588 tokpushback++;
9589 }
Eric Andersenc470f442003-07-28 09:56:35 +00009590 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009591 break;
9592 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009593 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009594 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009595 n1 = (union node *)stalloc(sizeof (struct nbinary));
9596 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009597 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009598 if ((got=readtoken()) != TDO) {
9599TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009600 synexpect(TDO);
9601 }
9602 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009603 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009604 break;
9605 }
9606 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009607 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009608 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009609 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009610 n1->type = NFOR;
9611 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009612 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009613 if (readtoken() == TIN) {
9614 app = &ap;
9615 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009616 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009617 n2->type = NARG;
9618 n2->narg.text = wordtext;
9619 n2->narg.backquote = backquotelist;
9620 *app = n2;
9621 app = &n2->narg.next;
9622 }
9623 *app = NULL;
9624 n1->nfor.args = ap;
9625 if (lasttoken != TNL && lasttoken != TSEMI)
9626 synexpect(-1);
9627 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009628 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009629 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009630 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009631 n2->narg.backquote = NULL;
9632 n2->narg.next = NULL;
9633 n1->nfor.args = n2;
9634 /*
9635 * Newline or semicolon here is optional (but note
9636 * that the original Bourne shell only allowed NL).
9637 */
9638 if (lasttoken != TNL && lasttoken != TSEMI)
9639 tokpushback++;
9640 }
Eric Andersenc470f442003-07-28 09:56:35 +00009641 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009642 if (readtoken() != TDO)
9643 synexpect(TDO);
9644 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009645 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009646 break;
9647 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009648 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009649 n1->type = NCASE;
9650 if (readtoken() != TWORD)
9651 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009652 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009653 n2->type = NARG;
9654 n2->narg.text = wordtext;
9655 n2->narg.backquote = backquotelist;
9656 n2->narg.next = NULL;
9657 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009658 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009659 } while (readtoken() == TNL);
9660 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009661 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009662 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009663next_case:
9664 checkkwd = CHKNL | CHKKWD;
9665 t = readtoken();
9666 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009667 if (lasttoken == TLP)
9668 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009669 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009670 cp->type = NCLIST;
9671 app = &cp->nclist.pattern;
9672 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009673 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009674 ap->type = NARG;
9675 ap->narg.text = wordtext;
9676 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009677 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009678 break;
9679 app = &ap->narg.next;
9680 readtoken();
9681 }
9682 ap->narg.next = NULL;
9683 if (lasttoken != TRP)
9684 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009685 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009686
Eric Andersenc470f442003-07-28 09:56:35 +00009687 cpp = &cp->nclist.next;
9688
9689 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009690 if ((t = readtoken()) != TESAC) {
9691 if (t != TENDCASE)
9692 synexpect(TENDCASE);
9693 else
Eric Andersenc470f442003-07-28 09:56:35 +00009694 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009695 }
Eric Andersenc470f442003-07-28 09:56:35 +00009696 }
Eric Andersencb57d552001-06-28 07:25:16 +00009697 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009698 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009699 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009700 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009701 n1->type = NSUBSHELL;
9702 n1->nredir.n = list(0);
9703 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009704 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009705 break;
9706 case TBEGIN:
9707 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009708 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009709 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009710 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009711 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009712 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009713 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009714 }
9715
Eric Andersenc470f442003-07-28 09:56:35 +00009716 if (readtoken() != t)
9717 synexpect(t);
9718
9719redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009720 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009721 checkkwd = CHKKWD | CHKALIAS;
9722 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009723 while (readtoken() == TREDIR) {
9724 *rpp = n2 = redirnode;
9725 rpp = &n2->nfile.next;
9726 parsefname();
9727 }
9728 tokpushback++;
9729 *rpp = NULL;
9730 if (redir) {
9731 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009732 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009733 n2->type = NREDIR;
9734 n2->nredir.n = n1;
9735 n1 = n2;
9736 }
9737 n1->nredir.redirect = redir;
9738 }
9739
9740 return n1;
9741}
9742
9743
Eric Andersenc470f442003-07-28 09:56:35 +00009744static union node *
9745simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009746 union node *args, **app;
9747 union node *n = NULL;
9748 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009749 union node **rpp, *redir;
9750 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009751
9752 args = NULL;
9753 app = &args;
9754 vars = NULL;
9755 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009756 redir = NULL;
9757 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009758
Eric Andersenc470f442003-07-28 09:56:35 +00009759 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009760 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009761 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009762 switch (readtoken()) {
9763 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009764 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009765 n->type = NARG;
9766 n->narg.text = wordtext;
9767 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009768 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009769 *vpp = n;
9770 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009771 } else {
9772 *app = n;
9773 app = &n->narg.next;
9774 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009775 }
9776 break;
9777 case TREDIR:
9778 *rpp = n = redirnode;
9779 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009780 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009781 break;
9782 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009783 if (
9784 args && app == &args->narg.next &&
9785 !vars && !redir
9786 ) {
9787 struct builtincmd *bcmd;
9788 const char *name;
9789
Eric Andersencb57d552001-06-28 07:25:16 +00009790 /* We have a function */
9791 if (readtoken() != TRP)
9792 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009793 name = n->narg.text;
9794 if (
9795 !goodname(name) || (
9796 (bcmd = find_builtin(name)) &&
9797 IS_BUILTIN_SPECIAL(bcmd)
9798 )
9799 )
9800 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009801 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009802 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009803 n->narg.next = command();
9804 return n;
9805 }
9806 /* fall through */
9807 default:
9808 tokpushback++;
9809 goto out;
9810 }
9811 }
Eric Andersenc470f442003-07-28 09:56:35 +00009812out:
Eric Andersencb57d552001-06-28 07:25:16 +00009813 *app = NULL;
9814 *vpp = NULL;
9815 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009816 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009817 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009818 n->ncmd.args = args;
9819 n->ncmd.assign = vars;
9820 n->ncmd.redirect = redir;
9821 return n;
9822}
9823
Eric Andersenc470f442003-07-28 09:56:35 +00009824static union node *
9825makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009826{
Eric Andersencb57d552001-06-28 07:25:16 +00009827 union node *n;
9828
Eric Andersenc470f442003-07-28 09:56:35 +00009829 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009830 n->type = NARG;
9831 n->narg.next = NULL;
9832 n->narg.text = wordtext;
9833 n->narg.backquote = backquotelist;
9834 return n;
9835}
9836
Eric Andersenc470f442003-07-28 09:56:35 +00009837void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009838{
Eric Andersencb57d552001-06-28 07:25:16 +00009839 TRACE(("Fix redir %s %d\n", text, err));
9840 if (!err)
9841 n->ndup.vname = NULL;
9842
9843 if (is_digit(text[0]) && text[1] == '\0')
9844 n->ndup.dupfd = digit_val(text[0]);
9845 else if (text[0] == '-' && text[1] == '\0')
9846 n->ndup.dupfd = -1;
9847 else {
9848
9849 if (err)
9850 synerror("Bad fd number");
9851 else
9852 n->ndup.vname = makename();
9853 }
9854}
9855
9856
Eric Andersenc470f442003-07-28 09:56:35 +00009857static void
9858parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009859{
Eric Andersencb57d552001-06-28 07:25:16 +00009860 union node *n = redirnode;
9861
9862 if (readtoken() != TWORD)
9863 synexpect(-1);
9864 if (n->type == NHERE) {
9865 struct heredoc *here = heredoc;
9866 struct heredoc *p;
9867 int i;
9868
9869 if (quoteflag == 0)
9870 n->type = NXHERE;
9871 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009872 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009873 synerror("Illegal eof marker for << redirection");
9874 rmescapes(wordtext);
9875 here->eofmark = wordtext;
9876 here->next = NULL;
9877 if (heredoclist == NULL)
9878 heredoclist = here;
9879 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009880 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009881 p->next = here;
9882 }
9883 } else if (n->type == NTOFD || n->type == NFROMFD) {
9884 fixredir(n, wordtext, 0);
9885 } else {
9886 n->nfile.fname = makename();
9887 }
9888}
9889
9890
9891/*
9892 * Input any here documents.
9893 */
9894
Eric Andersenc470f442003-07-28 09:56:35 +00009895static void
9896parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009897{
Eric Andersencb57d552001-06-28 07:25:16 +00009898 struct heredoc *here;
9899 union node *n;
9900
Eric Andersenc470f442003-07-28 09:56:35 +00009901 here = heredoclist;
9902 heredoclist = 0;
9903
9904 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009905 if (needprompt) {
9906 setprompt(2);
9907 needprompt = 0;
9908 }
Eric Andersenc470f442003-07-28 09:56:35 +00009909 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9910 here->eofmark, here->striptabs);
9911 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009912 n->narg.type = NARG;
9913 n->narg.next = NULL;
9914 n->narg.text = wordtext;
9915 n->narg.backquote = backquotelist;
9916 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009917 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009918 }
9919}
9920
Eric Andersenc470f442003-07-28 09:56:35 +00009921static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009922{
Eric Andersencb57d552001-06-28 07:25:16 +00009923 int t;
9924
9925 t = readtoken();
9926 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009927 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009928}
9929
Eric Andersenc470f442003-07-28 09:56:35 +00009930static int
9931readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009932{
Eric Andersencb57d552001-06-28 07:25:16 +00009933 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009934#ifdef DEBUG
9935 int alreadyseen = tokpushback;
9936#endif
9937
Eric Andersend35c5df2002-01-09 15:37:36 +00009938#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009939top:
Eric Andersen2870d962001-07-02 17:27:21 +00009940#endif
9941
Eric Andersencb57d552001-06-28 07:25:16 +00009942 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009943
Eric Andersenc470f442003-07-28 09:56:35 +00009944 /*
9945 * eat newlines
9946 */
9947 if (checkkwd & CHKNL) {
9948 while (t == TNL) {
9949 parseheredoc();
9950 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009951 }
9952 }
9953
Eric Andersenc470f442003-07-28 09:56:35 +00009954 if (t != TWORD || quoteflag) {
9955 goto out;
9956 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009957
Eric Andersenc470f442003-07-28 09:56:35 +00009958 /*
9959 * check for keywords
9960 */
9961 if (checkkwd & CHKKWD) {
9962 const char *const *pp;
9963
9964 if ((pp = findkwd(wordtext))) {
9965 lasttoken = t = pp - tokname_array;
9966 TRACE(("keyword %s recognized\n", tokname(t)));
9967 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009968 }
Eric Andersenc470f442003-07-28 09:56:35 +00009969 }
9970
9971 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009972#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009973 struct alias *ap;
9974 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009975 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009976 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009977 }
Eric Andersencb57d552001-06-28 07:25:16 +00009978 goto top;
9979 }
Eric Andersen2870d962001-07-02 17:27:21 +00009980#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009981 }
Eric Andersenc470f442003-07-28 09:56:35 +00009982out:
9983 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009984#ifdef DEBUG
9985 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009986 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009987 else
Eric Andersenc470f442003-07-28 09:56:35 +00009988 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009989#endif
9990 return (t);
9991}
9992
9993
9994/*
9995 * Read the next input token.
9996 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009997 * backquotes. We set quoteflag to true if any part of the word was
9998 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009999 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010000 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010001 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010002 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010003 *
10004 * [Change comment: here documents and internal procedures]
10005 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10006 * word parsing code into a separate routine. In this case, readtoken
10007 * doesn't need to have any internal procedures, but parseword does.
10008 * We could also make parseoperator in essence the main routine, and
10009 * have parseword (readtoken1?) handle both words and redirection.]
10010 */
10011
Eric Andersen81fe1232003-07-29 06:38:40 +000010012#define NEW_xxreadtoken
10013#ifdef NEW_xxreadtoken
10014
10015/* singles must be first! */
10016static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10017
10018static const char xxreadtoken_tokens[] = {
10019 TNL, TLP, TRP, /* only single occurrence allowed */
10020 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10021 TEOF, /* corresponds to trailing nul */
10022 TAND, TOR, TENDCASE, /* if double occurrence */
10023};
10024
10025#define xxreadtoken_doubles \
10026 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10027#define xxreadtoken_singles \
10028 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10029
10030static int xxreadtoken()
10031{
10032 int c;
10033
10034 if (tokpushback) {
10035 tokpushback = 0;
10036 return lasttoken;
10037 }
10038 if (needprompt) {
10039 setprompt(2);
10040 needprompt = 0;
10041 }
10042 startlinno = plinno;
10043 for (;;) { /* until token or start of word found */
10044 c = pgetc_macro();
10045
10046 if ((c != ' ') && (c != '\t')
10047#ifdef CONFIG_ASH_ALIAS
10048 && (c != PEOA)
10049#endif
10050 ) {
10051 if (c == '#') {
10052 while ((c = pgetc()) != '\n' && c != PEOF);
10053 pungetc();
10054 } else if (c == '\\') {
10055 if (pgetc() != '\n') {
10056 pungetc();
10057 goto READTOKEN1;
10058 }
10059 startlinno = ++plinno;
10060 if (doprompt)
10061 setprompt(2);
10062 } else {
10063 const char *p
10064 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10065
10066 if (c != PEOF) {
10067 if (c == '\n') {
10068 plinno++;
10069 needprompt = doprompt;
10070 }
10071
10072 p = strchr(xxreadtoken_chars, c);
10073 if (p == NULL) {
10074 READTOKEN1:
10075 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10076 }
10077
10078 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10079 if (pgetc() == *p) { /* double occurrence? */
10080 p += xxreadtoken_doubles + 1;
10081 } else {
10082 pungetc();
10083 }
10084 }
10085 }
10086
10087 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10088 }
10089 }
10090 }
10091}
10092
10093
10094#else
Eric Andersen2870d962001-07-02 17:27:21 +000010095#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010096
Eric Andersenc470f442003-07-28 09:56:35 +000010097static int
10098xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010099{
Eric Andersencb57d552001-06-28 07:25:16 +000010100 int c;
10101
10102 if (tokpushback) {
10103 tokpushback = 0;
10104 return lasttoken;
10105 }
10106 if (needprompt) {
10107 setprompt(2);
10108 needprompt = 0;
10109 }
10110 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010111 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010112 c = pgetc_macro();
10113 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010114 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010115#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010116 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010117#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010118 continue;
10119 case '#':
10120 while ((c = pgetc()) != '\n' && c != PEOF);
10121 pungetc();
10122 continue;
10123 case '\\':
10124 if (pgetc() == '\n') {
10125 startlinno = ++plinno;
10126 if (doprompt)
10127 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010128 continue;
10129 }
10130 pungetc();
10131 goto breakloop;
10132 case '\n':
10133 plinno++;
10134 needprompt = doprompt;
10135 RETURN(TNL);
10136 case PEOF:
10137 RETURN(TEOF);
10138 case '&':
10139 if (pgetc() == '&')
10140 RETURN(TAND);
10141 pungetc();
10142 RETURN(TBACKGND);
10143 case '|':
10144 if (pgetc() == '|')
10145 RETURN(TOR);
10146 pungetc();
10147 RETURN(TPIPE);
10148 case ';':
10149 if (pgetc() == ';')
10150 RETURN(TENDCASE);
10151 pungetc();
10152 RETURN(TSEMI);
10153 case '(':
10154 RETURN(TLP);
10155 case ')':
10156 RETURN(TRP);
10157 default:
10158 goto breakloop;
10159 }
10160 }
Eric Andersenc470f442003-07-28 09:56:35 +000010161breakloop:
10162 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010163#undef RETURN
10164}
Eric Andersen81fe1232003-07-29 06:38:40 +000010165#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010166
Eric Andersencb57d552001-06-28 07:25:16 +000010167
Eric Andersencb57d552001-06-28 07:25:16 +000010168/*
10169 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10170 * is not NULL, read a here document. In the latter case, eofmark is the
10171 * word which marks the end of the document and striptabs is true if
10172 * leading tabs should be stripped from the document. The argument firstc
10173 * is the first character of the input token or document.
10174 *
10175 * Because C does not have internal subroutines, I have simulated them
10176 * using goto's to implement the subroutine linkage. The following macros
10177 * will run code that appears at the end of readtoken1.
10178 */
10179
Eric Andersen2870d962001-07-02 17:27:21 +000010180#define CHECKEND() {goto checkend; checkend_return:;}
10181#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10182#define PARSESUB() {goto parsesub; parsesub_return:;}
10183#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10184#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10185#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010186
10187static int
Eric Andersenc470f442003-07-28 09:56:35 +000010188readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010189{
Eric Andersencb57d552001-06-28 07:25:16 +000010190 int c = firstc;
10191 char *out;
10192 int len;
10193 char line[EOFMARKLEN + 1];
10194 struct nodelist *bqlist;
10195 int quotef;
10196 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010197 int varnest; /* levels of variables expansion */
10198 int arinest; /* levels of arithmetic expansion */
10199 int parenlevel; /* levels of parens in arithmetic */
10200 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010201 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010202 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010203#if __GNUC__
10204 /* Avoid longjmp clobbering */
10205 (void) &out;
10206 (void) &quotef;
10207 (void) &dblquote;
10208 (void) &varnest;
10209 (void) &arinest;
10210 (void) &parenlevel;
10211 (void) &dqvarnest;
10212 (void) &oldstyle;
10213 (void) &prevsyntax;
10214 (void) &syntax;
10215#endif
10216
10217 startlinno = plinno;
10218 dblquote = 0;
10219 if (syntax == DQSYNTAX)
10220 dblquote = 1;
10221 quotef = 0;
10222 bqlist = NULL;
10223 varnest = 0;
10224 arinest = 0;
10225 parenlevel = 0;
10226 dqvarnest = 0;
10227
10228 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010229 loop: { /* for each line, until end of word */
10230 CHECKEND(); /* set c to PEOF if at end of here document */
10231 for (;;) { /* until end of line or end of word */
10232 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10233 switch(SIT(c, syntax)) {
10234 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010235 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010236 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010237 USTPUTC(c, out);
10238 plinno++;
10239 if (doprompt)
10240 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010241 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010242 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010243 case CWORD:
10244 USTPUTC(c, out);
10245 break;
10246 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010247 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010248 USTPUTC(CTLESC, out);
10249 USTPUTC(c, out);
10250 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010251 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010252 c = pgetc2();
10253 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010254 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010255 USTPUTC('\\', out);
10256 pungetc();
10257 } else if (c == '\n') {
10258 if (doprompt)
10259 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010260 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010261 if (
10262 dblquote &&
10263 c != '\\' && c != '`' &&
10264 c != '$' && (
10265 c != '"' ||
10266 eofmark != NULL
10267 )
10268 ) {
10269 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010270 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010271 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010272 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010273 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010274 USTPUTC(c, out);
10275 quotef++;
10276 }
10277 break;
10278 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010279 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010280quotemark:
10281 if (eofmark == NULL) {
10282 USTPUTC(CTLQUOTEMARK, out);
10283 }
Eric Andersencb57d552001-06-28 07:25:16 +000010284 break;
10285 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010286 syntax = DQSYNTAX;
10287 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010288 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010289 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010290 if (eofmark != NULL && arinest == 0 &&
10291 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010292 USTPUTC(c, out);
10293 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010294 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010295 syntax = BASESYNTAX;
10296 dblquote = 0;
10297 }
10298 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010299 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010300 }
10301 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010302 case CVAR: /* '$' */
10303 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010304 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010305 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010306 if (varnest > 0) {
10307 varnest--;
10308 if (dqvarnest > 0) {
10309 dqvarnest--;
10310 }
10311 USTPUTC(CTLENDVAR, out);
10312 } else {
10313 USTPUTC(c, out);
10314 }
10315 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010316#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010317 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010318 parenlevel++;
10319 USTPUTC(c, out);
10320 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010321 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010322 if (parenlevel > 0) {
10323 USTPUTC(c, out);
10324 --parenlevel;
10325 } else {
10326 if (pgetc() == ')') {
10327 if (--arinest == 0) {
10328 USTPUTC(CTLENDARI, out);
10329 syntax = prevsyntax;
10330 if (syntax == DQSYNTAX)
10331 dblquote = 1;
10332 else
10333 dblquote = 0;
10334 } else
10335 USTPUTC(')', out);
10336 } else {
10337 /*
10338 * unbalanced parens
10339 * (don't 2nd guess - no error)
10340 */
10341 pungetc();
10342 USTPUTC(')', out);
10343 }
10344 }
10345 break;
10346#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010347 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010348 PARSEBACKQOLD();
10349 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010350 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010351 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010352 case CIGN:
10353 break;
10354 default:
10355 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010356 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010357#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010358 if (c != PEOA)
10359#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010360 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010361
Eric Andersencb57d552001-06-28 07:25:16 +000010362 }
10363 c = pgetc_macro();
10364 }
10365 }
Eric Andersenc470f442003-07-28 09:56:35 +000010366endword:
10367#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010368 if (syntax == ARISYNTAX)
10369 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010370#endif
10371 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010372 synerror("Unterminated quoted string");
10373 if (varnest != 0) {
10374 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010375 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010376 synerror("Missing '}'");
10377 }
10378 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010379 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010380 out = stackblock();
10381 if (eofmark == NULL) {
10382 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010383 && quotef == 0
10384 && len <= 2
10385 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010386 PARSEREDIR();
10387 return lasttoken = TREDIR;
10388 } else {
10389 pungetc();
10390 }
10391 }
10392 quoteflag = quotef;
10393 backquotelist = bqlist;
10394 grabstackblock(len);
10395 wordtext = out;
10396 return lasttoken = TWORD;
10397/* end of readtoken routine */
10398
10399
10400
10401/*
10402 * Check to see whether we are at the end of the here document. When this
10403 * is called, c is set to the first character of the next input line. If
10404 * we are at the end of the here document, this routine sets the c to PEOF.
10405 */
10406
Eric Andersenc470f442003-07-28 09:56:35 +000010407checkend: {
10408 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010409#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010410 if (c == PEOA) {
10411 c = pgetc2();
10412 }
10413#endif
10414 if (striptabs) {
10415 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010416 c = pgetc2();
10417 }
Eric Andersenc470f442003-07-28 09:56:35 +000010418 }
10419 if (c == *eofmark) {
10420 if (pfgets(line, sizeof line) != NULL) {
10421 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010422
Eric Andersenc470f442003-07-28 09:56:35 +000010423 p = line;
10424 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10425 if (*p == '\n' && *q == '\0') {
10426 c = PEOF;
10427 plinno++;
10428 needprompt = doprompt;
10429 } else {
10430 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010431 }
10432 }
10433 }
10434 }
Eric Andersenc470f442003-07-28 09:56:35 +000010435 goto checkend_return;
10436}
Eric Andersencb57d552001-06-28 07:25:16 +000010437
10438
10439/*
10440 * Parse a redirection operator. The variable "out" points to a string
10441 * specifying the fd to be redirected. The variable "c" contains the
10442 * first character of the redirection operator.
10443 */
10444
Eric Andersenc470f442003-07-28 09:56:35 +000010445parseredir: {
10446 char fd = *out;
10447 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010448
Eric Andersenc470f442003-07-28 09:56:35 +000010449 np = (union node *)stalloc(sizeof (struct nfile));
10450 if (c == '>') {
10451 np->nfile.fd = 1;
10452 c = pgetc();
10453 if (c == '>')
10454 np->type = NAPPEND;
10455 else if (c == '|')
10456 np->type = NCLOBBER;
10457 else if (c == '&')
10458 np->type = NTOFD;
10459 else {
10460 np->type = NTO;
10461 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010462 }
Eric Andersenc470f442003-07-28 09:56:35 +000010463 } else { /* c == '<' */
10464 np->nfile.fd = 0;
10465 switch (c = pgetc()) {
10466 case '<':
10467 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10468 np = (union node *)stalloc(sizeof (struct nhere));
10469 np->nfile.fd = 0;
10470 }
10471 np->type = NHERE;
10472 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10473 heredoc->here = np;
10474 if ((c = pgetc()) == '-') {
10475 heredoc->striptabs = 1;
10476 } else {
10477 heredoc->striptabs = 0;
10478 pungetc();
10479 }
10480 break;
10481
10482 case '&':
10483 np->type = NFROMFD;
10484 break;
10485
10486 case '>':
10487 np->type = NFROMTO;
10488 break;
10489
10490 default:
10491 np->type = NFROM;
10492 pungetc();
10493 break;
10494 }
Eric Andersencb57d552001-06-28 07:25:16 +000010495 }
Eric Andersenc470f442003-07-28 09:56:35 +000010496 if (fd != '\0')
10497 np->nfile.fd = digit_val(fd);
10498 redirnode = np;
10499 goto parseredir_return;
10500}
Eric Andersencb57d552001-06-28 07:25:16 +000010501
10502
10503/*
10504 * Parse a substitution. At this point, we have read the dollar sign
10505 * and nothing else.
10506 */
10507
Eric Andersenc470f442003-07-28 09:56:35 +000010508parsesub: {
10509 int subtype;
10510 int typeloc;
10511 int flags;
10512 char *p;
10513 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010514
Eric Andersenc470f442003-07-28 09:56:35 +000010515 c = pgetc();
10516 if (
10517 c <= PEOA_OR_PEOF ||
10518 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10519 ) {
10520 USTPUTC('$', out);
10521 pungetc();
10522 } else if (c == '(') { /* $(command) or $((arith)) */
10523 if (pgetc() == '(') {
10524#ifdef CONFIG_ASH_MATH_SUPPORT
10525 PARSEARITH();
10526#else
10527 synerror("We unsupport $((arith))");
10528#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010529 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010530 pungetc();
10531 PARSEBACKQNEW();
10532 }
10533 } else {
10534 USTPUTC(CTLVAR, out);
10535 typeloc = out - (char *)stackblock();
10536 USTPUTC(VSNORMAL, out);
10537 subtype = VSNORMAL;
10538 if (c == '{') {
10539 c = pgetc();
10540 if (c == '#') {
10541 if ((c = pgetc()) == '}')
10542 c = '#';
10543 else
10544 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010545 }
Eric Andersenc470f442003-07-28 09:56:35 +000010546 else
10547 subtype = 0;
10548 }
10549 if (c > PEOA_OR_PEOF && is_name(c)) {
10550 do {
10551 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010552 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010553 } while (c > PEOA_OR_PEOF && is_in_name(c));
10554 } else if (is_digit(c)) {
10555 do {
10556 STPUTC(c, out);
10557 c = pgetc();
10558 } while (is_digit(c));
10559 }
10560 else if (is_special(c)) {
10561 USTPUTC(c, out);
10562 c = pgetc();
10563 }
10564 else
10565badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010566
Eric Andersenc470f442003-07-28 09:56:35 +000010567 STPUTC('=', out);
10568 flags = 0;
10569 if (subtype == 0) {
10570 switch (c) {
10571 case ':':
10572 flags = VSNUL;
10573 c = pgetc();
10574 /*FALLTHROUGH*/
10575 default:
10576 p = strchr(types, c);
10577 if (p == NULL)
10578 goto badsub;
10579 subtype = p - types + VSNORMAL;
10580 break;
10581 case '%':
10582 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010583 {
10584 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010585 subtype = c == '#' ? VSTRIMLEFT :
10586 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010587 c = pgetc();
10588 if (c == cc)
10589 subtype++;
10590 else
10591 pungetc();
10592 break;
10593 }
10594 }
Eric Andersenc470f442003-07-28 09:56:35 +000010595 } else {
10596 pungetc();
10597 }
10598 if (dblquote || arinest)
10599 flags |= VSQUOTE;
10600 *((char *)stackblock() + typeloc) = subtype | flags;
10601 if (subtype != VSNORMAL) {
10602 varnest++;
10603 if (dblquote || arinest) {
10604 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010605 }
10606 }
10607 }
Eric Andersenc470f442003-07-28 09:56:35 +000010608 goto parsesub_return;
10609}
Eric Andersencb57d552001-06-28 07:25:16 +000010610
10611
10612/*
10613 * Called to parse command substitutions. Newstyle is set if the command
10614 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10615 * list of commands (passed by reference), and savelen is the number of
10616 * characters on the top of the stack which must be preserved.
10617 */
10618
Eric Andersenc470f442003-07-28 09:56:35 +000010619parsebackq: {
10620 struct nodelist **nlpp;
10621 int savepbq;
10622 union node *n;
10623 char *volatile str;
10624 struct jmploc jmploc;
10625 struct jmploc *volatile savehandler;
10626 size_t savelen;
10627 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010628#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010629 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010630#endif
10631
Eric Andersenc470f442003-07-28 09:56:35 +000010632 savepbq = parsebackquote;
10633 if (setjmp(jmploc.loc)) {
10634 if (str)
10635 ckfree(str);
10636 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010637 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010638 longjmp(handler->loc, 1);
10639 }
10640 INTOFF;
10641 str = NULL;
10642 savelen = out - (char *)stackblock();
10643 if (savelen > 0) {
10644 str = ckmalloc(savelen);
10645 memcpy(str, stackblock(), savelen);
10646 }
10647 savehandler = handler;
10648 handler = &jmploc;
10649 INTON;
10650 if (oldstyle) {
10651 /* We must read until the closing backquote, giving special
10652 treatment to some slashes, and then push the string and
10653 reread it as input, interpreting it normally. */
10654 char *pout;
10655 int pc;
10656 size_t psavelen;
10657 char *pstr;
10658
10659
10660 STARTSTACKSTR(pout);
10661 for (;;) {
10662 if (needprompt) {
10663 setprompt(2);
10664 needprompt = 0;
10665 }
10666 switch (pc = pgetc()) {
10667 case '`':
10668 goto done;
10669
10670 case '\\':
10671 if ((pc = pgetc()) == '\n') {
10672 plinno++;
10673 if (doprompt)
10674 setprompt(2);
10675 /*
10676 * If eating a newline, avoid putting
10677 * the newline into the new character
10678 * stream (via the STPUTC after the
10679 * switch).
10680 */
10681 continue;
10682 }
10683 if (pc != '\\' && pc != '`' && pc != '$'
10684 && (!dblquote || pc != '"'))
10685 STPUTC('\\', pout);
10686 if (pc > PEOA_OR_PEOF) {
10687 break;
10688 }
10689 /* fall through */
10690
10691 case PEOF:
10692#ifdef CONFIG_ASH_ALIAS
10693 case PEOA:
10694#endif
10695 startlinno = plinno;
10696 synerror("EOF in backquote substitution");
10697
10698 case '\n':
10699 plinno++;
10700 needprompt = doprompt;
10701 break;
10702
10703 default:
10704 break;
10705 }
10706 STPUTC(pc, pout);
10707 }
10708done:
10709 STPUTC('\0', pout);
10710 psavelen = pout - (char *)stackblock();
10711 if (psavelen > 0) {
10712 pstr = grabstackstr(pout);
10713 setinputstring(pstr);
10714 }
10715 }
10716 nlpp = &bqlist;
10717 while (*nlpp)
10718 nlpp = &(*nlpp)->next;
10719 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10720 (*nlpp)->next = NULL;
10721 parsebackquote = oldstyle;
10722
10723 if (oldstyle) {
10724 saveprompt = doprompt;
10725 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010726 }
10727
Eric Andersenc470f442003-07-28 09:56:35 +000010728 n = list(2);
10729
10730 if (oldstyle)
10731 doprompt = saveprompt;
10732 else {
10733 if (readtoken() != TRP)
10734 synexpect(TRP);
10735 }
10736
10737 (*nlpp)->n = n;
10738 if (oldstyle) {
10739 /*
10740 * Start reading from old file again, ignoring any pushed back
10741 * tokens left from the backquote parsing
10742 */
10743 popfile();
10744 tokpushback = 0;
10745 }
10746 while (stackblocksize() <= savelen)
10747 growstackblock();
10748 STARTSTACKSTR(out);
10749 if (str) {
10750 memcpy(out, str, savelen);
10751 STADJUST(savelen, out);
10752 INTOFF;
10753 ckfree(str);
10754 str = NULL;
10755 INTON;
10756 }
10757 parsebackquote = savepbq;
10758 handler = savehandler;
10759 if (arinest || dblquote)
10760 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10761 else
10762 USTPUTC(CTLBACKQ, out);
10763 if (oldstyle)
10764 goto parsebackq_oldreturn;
10765 else
10766 goto parsebackq_newreturn;
10767}
10768
10769#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010770/*
10771 * Parse an arithmetic expansion (indicate start of one and set state)
10772 */
Eric Andersenc470f442003-07-28 09:56:35 +000010773parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010774
Eric Andersenc470f442003-07-28 09:56:35 +000010775 if (++arinest == 1) {
10776 prevsyntax = syntax;
10777 syntax = ARISYNTAX;
10778 USTPUTC(CTLARI, out);
10779 if (dblquote)
10780 USTPUTC('"',out);
10781 else
10782 USTPUTC(' ',out);
10783 } else {
10784 /*
10785 * we collapse embedded arithmetic expansion to
10786 * parenthesis, which should be equivalent
10787 */
10788 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010789 }
Eric Andersenc470f442003-07-28 09:56:35 +000010790 goto parsearith_return;
10791}
10792#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010793
Eric Andersenc470f442003-07-28 09:56:35 +000010794} /* end of readtoken */
10795
Eric Andersencb57d552001-06-28 07:25:16 +000010796
10797
Eric Andersencb57d552001-06-28 07:25:16 +000010798/*
10799 * Returns true if the text contains nothing to expand (no dollar signs
10800 * or backquotes).
10801 */
10802
Eric Andersenc470f442003-07-28 09:56:35 +000010803static int
10804noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010805{
Eric Andersencb57d552001-06-28 07:25:16 +000010806 char *p;
10807 char c;
10808
10809 p = text;
10810 while ((c = *p++) != '\0') {
10811 if (c == CTLQUOTEMARK)
10812 continue;
10813 if (c == CTLESC)
10814 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010815 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010816 return 0;
10817 }
10818 return 1;
10819}
10820
10821
10822/*
Eric Andersenc470f442003-07-28 09:56:35 +000010823 * Return of a legal variable name (a letter or underscore followed by zero or
10824 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010825 */
10826
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010827static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010828endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010829{
Eric Andersenc470f442003-07-28 09:56:35 +000010830 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010831
Eric Andersenc470f442003-07-28 09:56:35 +000010832 p = (char *) name;
10833 if (! is_name(*p))
10834 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010835 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010836 if (! is_in_name(*p))
10837 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010838 }
Eric Andersenc470f442003-07-28 09:56:35 +000010839 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010840}
10841
10842
10843/*
10844 * Called when an unexpected token is read during the parse. The argument
10845 * is the token that is expected, or -1 if more than one type of token can
10846 * occur at this point.
10847 */
10848
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010849static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010850{
10851 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010852 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010853
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010854 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10855 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010856 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010857 synerror(msg);
10858 /* NOTREACHED */
10859}
10860
Eric Andersenc470f442003-07-28 09:56:35 +000010861static void
10862synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010863{
Eric Andersenc470f442003-07-28 09:56:35 +000010864 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010865 /* NOTREACHED */
10866}
10867
Eric Andersencb57d552001-06-28 07:25:16 +000010868
10869/*
10870 * called by editline -- any expansions to the prompt
10871 * should be added here.
10872 */
Eric Andersenc470f442003-07-28 09:56:35 +000010873
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010874static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010875{
Eric Andersenc470f442003-07-28 09:56:35 +000010876 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010877
10878 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010879 case 1:
10880 prompt = ps1val();
10881 break;
10882 case 2:
10883 prompt = ps2val();
10884 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010885 default: /* 0 */
10886 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010887 }
10888 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010889}
10890
Eric Andersencb57d552001-06-28 07:25:16 +000010891
Eric Andersenc470f442003-07-28 09:56:35 +000010892static const char *const *findkwd(const char *s)
10893{
10894 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010895 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010896 sizeof(const char *), pstrcmp);
10897}
10898
10899/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10900
Eric Andersencb57d552001-06-28 07:25:16 +000010901/*
10902 * Code for dealing with input/output redirection.
10903 */
10904
Eric Andersenc470f442003-07-28 09:56:35 +000010905#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010906#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010907# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010908#else
10909# define PIPESIZE PIPE_BUF
10910#endif
10911
Eric Andersen62483552001-07-10 06:09:16 +000010912/*
10913 * Open a file in noclobber mode.
10914 * The code was copied from bash.
10915 */
Eric Andersenc470f442003-07-28 09:56:35 +000010916static inline int
10917noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010918{
10919 int r, fd;
10920 struct stat finfo, finfo2;
10921
10922 /*
10923 * If the file exists and is a regular file, return an error
10924 * immediately.
10925 */
10926 r = stat(fname, &finfo);
10927 if (r == 0 && S_ISREG(finfo.st_mode)) {
10928 errno = EEXIST;
10929 return -1;
10930 }
10931
10932 /*
10933 * If the file was not present (r != 0), make sure we open it
10934 * exclusively so that if it is created before we open it, our open
10935 * will fail. Make sure that we do not truncate an existing file.
10936 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10937 * file was not a regular file, we leave O_EXCL off.
10938 */
10939 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010940 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10941 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010942
10943 /* If the open failed, return the file descriptor right away. */
10944 if (fd < 0)
10945 return fd;
10946
10947 /*
10948 * OK, the open succeeded, but the file may have been changed from a
10949 * non-regular file to a regular file between the stat and the open.
10950 * We are assuming that the O_EXCL open handles the case where FILENAME
10951 * did not exist and is symlinked to an existing file between the stat
10952 * and open.
10953 */
10954
10955 /*
10956 * If we can open it and fstat the file descriptor, and neither check
10957 * revealed that it was a regular file, and the file has not been
10958 * replaced, return the file descriptor.
10959 */
Eric Andersenc470f442003-07-28 09:56:35 +000010960 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10961 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010962 return fd;
10963
10964 /* The file has been replaced. badness. */
10965 close(fd);
10966 errno = EEXIST;
10967 return -1;
10968}
Eric Andersencb57d552001-06-28 07:25:16 +000010969
10970/*
Eric Andersen62483552001-07-10 06:09:16 +000010971 * Handle here documents. Normally we fork off a process to write the
10972 * data to a pipe. If the document is short, we can stuff the data in
10973 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010974 */
10975
Eric Andersenc470f442003-07-28 09:56:35 +000010976static inline int
10977openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010978{
10979 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010980 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010981
Eric Andersen62483552001-07-10 06:09:16 +000010982 if (pipe(pip) < 0)
10983 error("Pipe call failed");
10984 if (redir->type == NHERE) {
10985 len = strlen(redir->nhere.doc->narg.text);
10986 if (len <= PIPESIZE) {
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 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010989 }
Eric Andersencb57d552001-06-28 07:25:16 +000010990 }
Eric Andersenc470f442003-07-28 09:56:35 +000010991 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010992 close(pip[0]);
10993 signal(SIGINT, SIG_IGN);
10994 signal(SIGQUIT, SIG_IGN);
10995 signal(SIGHUP, SIG_IGN);
10996#ifdef SIGTSTP
10997 signal(SIGTSTP, SIG_IGN);
10998#endif
10999 signal(SIGPIPE, SIG_DFL);
11000 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000011001 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000011002 else
11003 expandhere(redir->nhere.doc, pip[1]);
11004 _exit(0);
11005 }
Eric Andersenc470f442003-07-28 09:56:35 +000011006out:
Eric Andersen62483552001-07-10 06:09:16 +000011007 close(pip[1]);
11008 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011009}
11010
Eric Andersenc470f442003-07-28 09:56:35 +000011011static int
11012openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011013{
Eric Andersencb57d552001-06-28 07:25:16 +000011014 char *fname;
11015 int f;
11016
11017 switch (redir->nfile.type) {
11018 case NFROM:
11019 fname = redir->nfile.expfname;
11020 if ((f = open(fname, O_RDONLY)) < 0)
11021 goto eopen;
11022 break;
11023 case NFROMTO:
11024 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011025 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011026 goto ecreate;
11027 break;
11028 case NTO:
11029 /* Take care of noclobber mode. */
11030 if (Cflag) {
11031 fname = redir->nfile.expfname;
11032 if ((f = noclobberopen(fname)) < 0)
11033 goto ecreate;
11034 break;
11035 }
Eric Andersenc470f442003-07-28 09:56:35 +000011036 /* FALLTHROUGH */
11037 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011038 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011039 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011040 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011041 break;
11042 case NAPPEND:
11043 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011044 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011045 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011046 break;
11047 default:
11048#ifdef DEBUG
11049 abort();
11050#endif
11051 /* Fall through to eliminate warning. */
11052 case NTOFD:
11053 case NFROMFD:
11054 f = -1;
11055 break;
11056 case NHERE:
11057 case NXHERE:
11058 f = openhere(redir);
11059 break;
11060 }
11061
11062 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011063ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011064 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011065eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011066 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11067}
11068
Eric Andersenc470f442003-07-28 09:56:35 +000011069static inline void
11070dupredirect(union node *redir, int f)
11071{
11072 int fd = redir->nfile.fd;
11073
11074 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11075 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11076 copyfd(redir->ndup.dupfd, fd);
11077 }
11078 return;
11079 }
11080
11081 if (f != fd) {
11082 copyfd(f, fd);
11083 close(f);
11084 }
11085 return;
11086}
Eric Andersencb57d552001-06-28 07:25:16 +000011087
Eric Andersen62483552001-07-10 06:09:16 +000011088/*
11089 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11090 * old file descriptors are stashed away so that the redirection can be
11091 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11092 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011093 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011094 */
11095
Eric Andersenc470f442003-07-28 09:56:35 +000011096static void
11097redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011098{
11099 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011100 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011101 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011102 int fd;
11103 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011104 int *p;
11105 nullredirs++;
11106 if (!redir) {
11107 return;
Eric Andersen62483552001-07-10 06:09:16 +000011108 }
Eric Andersenc470f442003-07-28 09:56:35 +000011109 sv = NULL;
11110 INTOFF;
11111 if (flags & REDIR_PUSH) {
11112 struct redirtab *q;
11113 q = ckmalloc(sizeof (struct redirtab));
11114 q->next = redirlist;
11115 redirlist = q;
11116 q->nullredirs = nullredirs - 1;
11117 for (i = 0 ; i < 10 ; i++)
11118 q->renamed[i] = EMPTY;
11119 nullredirs = 0;
11120 sv = q;
11121 }
11122 n = redir;
11123 do {
Eric Andersen62483552001-07-10 06:09:16 +000011124 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011125 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011126 n->ndup.dupfd == fd)
11127 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011128
Eric Andersen62483552001-07-10 06:09:16 +000011129 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011130 if (fd == newfd)
11131 continue;
11132 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11133 i = fcntl(fd, F_DUPFD, 10);
11134
11135 if (i == -1) {
11136 i = errno;
11137 if (i != EBADF) {
11138 close(newfd);
11139 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011140 error("%d: %m", fd);
11141 /* NOTREACHED */
11142 }
Eric Andersenc470f442003-07-28 09:56:35 +000011143 } else {
11144 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011145 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011146 }
Eric Andersenc470f442003-07-28 09:56:35 +000011147 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011148 close(fd);
11149 }
Eric Andersenc470f442003-07-28 09:56:35 +000011150 dupredirect(n, newfd);
11151 } while ((n = n->nfile.next));
11152 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011153 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11154 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011155}
11156
11157
Eric Andersencb57d552001-06-28 07:25:16 +000011158/*
11159 * Undo the effects of the last redirection.
11160 */
11161
Eric Andersenc470f442003-07-28 09:56:35 +000011162void
11163popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011164{
Eric Andersenc470f442003-07-28 09:56:35 +000011165 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011166 int i;
11167
Eric Andersenc470f442003-07-28 09:56:35 +000011168 if (--nullredirs >= 0)
11169 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011170 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011171 rp = redirlist;
11172 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011173 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011174 if (!drop) {
11175 close(i);
11176 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011177 }
Eric Andersenc470f442003-07-28 09:56:35 +000011178 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011179 }
11180 }
11181 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011182 nullredirs = rp->nullredirs;
11183 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011184 INTON;
11185}
11186
11187/*
Eric Andersenc470f442003-07-28 09:56:35 +000011188 * Undo all redirections. Called on error or interrupt.
11189 */
11190
11191/*
Eric Andersencb57d552001-06-28 07:25:16 +000011192 * Discard all saved file descriptors.
11193 */
11194
Eric Andersenc470f442003-07-28 09:56:35 +000011195void
11196clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011197{
Eric Andersenc470f442003-07-28 09:56:35 +000011198 for (;;) {
11199 nullredirs = 0;
11200 if (!redirlist)
11201 break;
11202 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011203 }
Eric Andersencb57d552001-06-28 07:25:16 +000011204}
11205
11206
Eric Andersencb57d552001-06-28 07:25:16 +000011207/*
11208 * Copy a file descriptor to be >= to. Returns -1
11209 * if the source file descriptor is closed, EMPTY if there are no unused
11210 * file descriptors left.
11211 */
11212
Eric Andersenc470f442003-07-28 09:56:35 +000011213int
11214copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011215{
11216 int newfd;
11217
11218 newfd = fcntl(from, F_DUPFD, to);
11219 if (newfd < 0) {
11220 if (errno == EMFILE)
11221 return EMPTY;
11222 else
Eric Andersen2870d962001-07-02 17:27:21 +000011223 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011224 }
11225 return newfd;
11226}
11227
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011228
Eric Andersenc470f442003-07-28 09:56:35 +000011229int
11230redirectsafe(union node *redir, int flags)
11231{
11232 int err;
11233 volatile int saveint;
11234 struct jmploc *volatile savehandler = handler;
11235 struct jmploc jmploc;
11236
11237 SAVEINT(saveint);
11238 if (!(err = setjmp(jmploc.loc) * 2)) {
11239 handler = &jmploc;
11240 redirect(redir, flags);
11241 }
11242 handler = savehandler;
11243 if (err && exception != EXERROR)
11244 longjmp(handler->loc, 1);
11245 RESTOREINT(saveint);
11246 return err;
11247}
11248
11249/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11250
11251#ifdef DEBUG
11252static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011253static void shcmd(union node *, FILE *);
11254static void sharg(union node *, FILE *);
11255static void indent(int, char *, FILE *);
11256static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011257
11258
Eric Andersenc470f442003-07-28 09:56:35 +000011259void
11260showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011261{
11262 trputs("showtree called\n");
11263 shtree(n, 1, NULL, stdout);
11264}
Eric Andersencb57d552001-06-28 07:25:16 +000011265
Eric Andersenc470f442003-07-28 09:56:35 +000011266
11267static void
11268shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011269{
11270 struct nodelist *lp;
11271 const char *s;
11272
11273 if (n == NULL)
11274 return;
11275
11276 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011277 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011278 case NSEMI:
11279 s = "; ";
11280 goto binop;
11281 case NAND:
11282 s = " && ";
11283 goto binop;
11284 case NOR:
11285 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011286binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011287 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011288 /* if (ind < 0) */
11289 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011290 shtree(n->nbinary.ch2, ind, NULL, fp);
11291 break;
11292 case NCMD:
11293 shcmd(n, fp);
11294 if (ind >= 0)
11295 putc('\n', fp);
11296 break;
11297 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011298 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011299 shcmd(lp->n, fp);
11300 if (lp->next)
11301 fputs(" | ", fp);
11302 }
11303 if (n->npipe.backgnd)
11304 fputs(" &", fp);
11305 if (ind >= 0)
11306 putc('\n', fp);
11307 break;
11308 default:
11309 fprintf(fp, "<node type %d>", n->type);
11310 if (ind >= 0)
11311 putc('\n', fp);
11312 break;
11313 }
11314}
11315
11316
Eric Andersenc470f442003-07-28 09:56:35 +000011317static void
11318shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011319{
11320 union node *np;
11321 int first;
11322 const char *s;
11323 int dftfd;
11324
11325 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011326 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11327 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011328 putchar(' ');
11329 sharg(np, fp);
11330 first = 0;
11331 }
Eric Andersenc470f442003-07-28 09:56:35 +000011332 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11333 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011334 putchar(' ');
11335 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011336 case NTO: s = ">"; dftfd = 1; break;
11337 case NCLOBBER: s = ">|"; dftfd = 1; break;
11338 case NAPPEND: s = ">>"; dftfd = 1; break;
11339 case NTOFD: s = ">&"; dftfd = 1; break;
11340 case NFROM: s = "<"; dftfd = 0; break;
11341 case NFROMFD: s = "<&"; dftfd = 0; break;
11342 case NFROMTO: s = "<>"; dftfd = 0; break;
11343 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011344 }
11345 if (np->nfile.fd != dftfd)
11346 fprintf(fp, "%d", np->nfile.fd);
11347 fputs(s, fp);
11348 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11349 fprintf(fp, "%d", np->ndup.dupfd);
11350 } else {
11351 sharg(np->nfile.fname, fp);
11352 }
11353 first = 0;
11354 }
11355}
11356
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011357
Eric Andersenc470f442003-07-28 09:56:35 +000011358
11359static void
11360sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011361{
Eric Andersencb57d552001-06-28 07:25:16 +000011362 char *p;
11363 struct nodelist *bqlist;
11364 int subtype;
11365
11366 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011367 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011368 abort();
11369 }
11370 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011371 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011372 switch (*p) {
11373 case CTLESC:
11374 putc(*++p, fp);
11375 break;
11376 case CTLVAR:
11377 putc('$', fp);
11378 putc('{', fp);
11379 subtype = *++p;
11380 if (subtype == VSLENGTH)
11381 putc('#', fp);
11382
11383 while (*p != '=')
11384 putc(*p++, fp);
11385
11386 if (subtype & VSNUL)
11387 putc(':', fp);
11388
11389 switch (subtype & VSTYPE) {
11390 case VSNORMAL:
11391 putc('}', fp);
11392 break;
11393 case VSMINUS:
11394 putc('-', fp);
11395 break;
11396 case VSPLUS:
11397 putc('+', fp);
11398 break;
11399 case VSQUESTION:
11400 putc('?', fp);
11401 break;
11402 case VSASSIGN:
11403 putc('=', fp);
11404 break;
11405 case VSTRIMLEFT:
11406 putc('#', fp);
11407 break;
11408 case VSTRIMLEFTMAX:
11409 putc('#', fp);
11410 putc('#', fp);
11411 break;
11412 case VSTRIMRIGHT:
11413 putc('%', fp);
11414 break;
11415 case VSTRIMRIGHTMAX:
11416 putc('%', fp);
11417 putc('%', fp);
11418 break;
11419 case VSLENGTH:
11420 break;
11421 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011422 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011423 }
11424 break;
11425 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011426 putc('}', fp);
11427 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011428 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011429 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011430 putc('$', fp);
11431 putc('(', fp);
11432 shtree(bqlist->n, -1, NULL, fp);
11433 putc(')', fp);
11434 break;
11435 default:
11436 putc(*p, fp);
11437 break;
11438 }
11439 }
11440}
11441
11442
Eric Andersenc470f442003-07-28 09:56:35 +000011443static void
11444indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011445{
11446 int i;
11447
Eric Andersenc470f442003-07-28 09:56:35 +000011448 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011449 if (pfx && i == amount - 1)
11450 fputs(pfx, fp);
11451 putc('\t', fp);
11452 }
11453}
Eric Andersencb57d552001-06-28 07:25:16 +000011454
Eric Andersenc470f442003-07-28 09:56:35 +000011455
11456
11457/*
11458 * Debugging stuff.
11459 */
11460
11461
Eric Andersencb57d552001-06-28 07:25:16 +000011462FILE *tracefile;
11463
Eric Andersencb57d552001-06-28 07:25:16 +000011464
Eric Andersenc470f442003-07-28 09:56:35 +000011465void
11466trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011467{
Eric Andersenc470f442003-07-28 09:56:35 +000011468 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011469 return;
11470 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011471}
11472
Eric Andersenc470f442003-07-28 09:56:35 +000011473void
11474trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011475{
11476 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011477
Eric Andersenc470f442003-07-28 09:56:35 +000011478 if (debug != 1)
11479 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011480 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011481 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011482 va_end(va);
11483}
11484
Eric Andersenc470f442003-07-28 09:56:35 +000011485void
11486tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011487{
Eric Andersenc470f442003-07-28 09:56:35 +000011488 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011489 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011490 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011491}
11492
11493
Eric Andersenc470f442003-07-28 09:56:35 +000011494void
11495trputs(const char *s)
11496{
11497 if (debug != 1)
11498 return;
11499 fputs(s, tracefile);
11500}
11501
11502
11503static void
11504trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011505{
11506 char *p;
11507 char c;
11508
Eric Andersenc470f442003-07-28 09:56:35 +000011509 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011510 return;
11511 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011512 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011513 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011514 case '\n': c = 'n'; goto backslash;
11515 case '\t': c = 't'; goto backslash;
11516 case '\r': c = 'r'; goto backslash;
11517 case '"': c = '"'; goto backslash;
11518 case '\\': c = '\\'; goto backslash;
11519 case CTLESC: c = 'e'; goto backslash;
11520 case CTLVAR: c = 'v'; goto backslash;
11521 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11522 case CTLBACKQ: c = 'q'; goto backslash;
11523 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11524backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011525 putc(c, tracefile);
11526 break;
11527 default:
11528 if (*p >= ' ' && *p <= '~')
11529 putc(*p, tracefile);
11530 else {
11531 putc('\\', tracefile);
11532 putc(*p >> 6 & 03, tracefile);
11533 putc(*p >> 3 & 07, tracefile);
11534 putc(*p & 07, tracefile);
11535 }
11536 break;
11537 }
11538 }
11539 putc('"', tracefile);
11540}
11541
11542
Eric Andersenc470f442003-07-28 09:56:35 +000011543void
11544trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011545{
Eric Andersenc470f442003-07-28 09:56:35 +000011546 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011547 return;
11548 while (*ap) {
11549 trstring(*ap++);
11550 if (*ap)
11551 putc(' ', tracefile);
11552 else
11553 putc('\n', tracefile);
11554 }
Eric Andersencb57d552001-06-28 07:25:16 +000011555}
11556
11557
Eric Andersenc470f442003-07-28 09:56:35 +000011558void
11559opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011560{
Eric Andersencb57d552001-06-28 07:25:16 +000011561 char s[100];
11562#ifdef O_APPEND
11563 int flags;
11564#endif
11565
Eric Andersenc470f442003-07-28 09:56:35 +000011566 if (debug != 1) {
11567 if (tracefile)
11568 fflush(tracefile);
11569 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011570 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011571 }
Eric Andersenc470f442003-07-28 09:56:35 +000011572 scopy("./trace", s);
11573 if (tracefile) {
11574 if (!freopen(s, "a", tracefile)) {
11575 fprintf(stderr, "Can't re-open %s\n", s);
11576 debug = 0;
11577 return;
11578 }
11579 } else {
11580 if ((tracefile = fopen(s, "a")) == NULL) {
11581 fprintf(stderr, "Can't open %s\n", s);
11582 debug = 0;
11583 return;
11584 }
11585 }
Eric Andersencb57d552001-06-28 07:25:16 +000011586#ifdef O_APPEND
11587 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11588 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11589#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011590 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011591 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011592}
Eric Andersenc470f442003-07-28 09:56:35 +000011593#endif /* DEBUG */
11594
11595
11596/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11597
11598/*
11599 * Sigmode records the current value of the signal handlers for the various
11600 * modes. A value of zero means that the current handler is not known.
11601 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11602 */
11603
11604#define S_DFL 1 /* default signal handling (SIG_DFL) */
11605#define S_CATCH 2 /* signal is caught */
11606#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11607#define S_HARD_IGN 4 /* signal is ignored permenantly */
11608#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11609
Eric Andersencb57d552001-06-28 07:25:16 +000011610
11611
11612/*
Eric Andersencb57d552001-06-28 07:25:16 +000011613 * The trap builtin.
11614 */
11615
Eric Andersenc470f442003-07-28 09:56:35 +000011616int
11617trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011618{
11619 char *action;
11620 char **ap;
11621 int signo;
11622
Eric Andersenc470f442003-07-28 09:56:35 +000011623 nextopt(nullstr);
11624 ap = argptr;
11625 if (!*ap) {
11626 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011627 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011628 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011629
Eric Andersenc470f442003-07-28 09:56:35 +000011630 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011631 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011632 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011633 out1fmt("trap -- %s %s\n",
11634 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011635 }
11636 }
11637 return 0;
11638 }
Eric Andersenc470f442003-07-28 09:56:35 +000011639 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011640 action = NULL;
11641 else
11642 action = *ap++;
11643 while (*ap) {
11644 if ((signo = decode_signal(*ap, 0)) < 0)
11645 error("%s: bad trap", *ap);
11646 INTOFF;
11647 if (action) {
11648 if (action[0] == '-' && action[1] == '\0')
11649 action = NULL;
11650 else
Eric Andersenc470f442003-07-28 09:56:35 +000011651 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011652 }
Eric Andersenc470f442003-07-28 09:56:35 +000011653 if (trap[signo])
11654 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011655 trap[signo] = action;
11656 if (signo != 0)
11657 setsignal(signo);
11658 INTON;
11659 ap++;
11660 }
11661 return 0;
11662}
11663
11664
Eric Andersenc470f442003-07-28 09:56:35 +000011665/*
11666 * Clear traps on a fork.
11667 */
11668
11669void
11670clear_traps(void)
11671{
11672 char **tp;
11673
11674 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11675 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11676 INTOFF;
11677 ckfree(*tp);
11678 *tp = NULL;
11679 if (tp != &trap[0])
11680 setsignal(tp - trap);
11681 INTON;
11682 }
11683 }
11684}
11685
11686
Eric Andersencb57d552001-06-28 07:25:16 +000011687/*
11688 * Set the signal handler for the specified signal. The routine figures
11689 * out what it should be set to.
11690 */
11691
Eric Andersenc470f442003-07-28 09:56:35 +000011692void
11693setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011694{
11695 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011696 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011697 struct sigaction act;
11698
11699 if ((t = trap[signo]) == NULL)
11700 action = S_DFL;
11701 else if (*t != '\0')
11702 action = S_CATCH;
11703 else
11704 action = S_IGN;
11705 if (rootshell && action == S_DFL) {
11706 switch (signo) {
11707 case SIGINT:
11708 if (iflag || minusc || sflag == 0)
11709 action = S_CATCH;
11710 break;
11711 case SIGQUIT:
11712#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011713 if (debug)
11714 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011715#endif
11716 /* FALLTHROUGH */
11717 case SIGTERM:
11718 if (iflag)
11719 action = S_IGN;
11720 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011721#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011722 case SIGTSTP:
11723 case SIGTTOU:
11724 if (mflag)
11725 action = S_IGN;
11726 break;
11727#endif
11728 }
11729 }
11730
11731 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011732 tsig = *t;
11733 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011734 /*
11735 * current setting unknown
11736 */
11737 if (sigaction(signo, 0, &act) == -1) {
11738 /*
11739 * Pretend it worked; maybe we should give a warning
11740 * here, but other shells don't. We don't alter
11741 * sigmode, so that we retry every time.
11742 */
11743 return;
11744 }
11745 if (act.sa_handler == SIG_IGN) {
11746 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011747 signo == SIGTTIN || signo == SIGTTOU)) {
11748 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011749 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011750 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011751 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011752 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011753 }
11754 }
Eric Andersenc470f442003-07-28 09:56:35 +000011755 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011756 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011757 switch (action) {
11758 case S_CATCH:
11759 act.sa_handler = onsig;
11760 break;
11761 case S_IGN:
11762 act.sa_handler = SIG_IGN;
11763 break;
11764 default:
11765 act.sa_handler = SIG_DFL;
11766 }
Eric Andersencb57d552001-06-28 07:25:16 +000011767 *t = action;
11768 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011769 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011770 sigaction(signo, &act, 0);
11771}
11772
11773/*
11774 * Ignore a signal.
11775 */
11776
Eric Andersenc470f442003-07-28 09:56:35 +000011777void
11778ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011779{
11780 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11781 signal(signo, SIG_IGN);
11782 }
11783 sigmode[signo - 1] = S_HARD_IGN;
11784}
11785
11786
Eric Andersencb57d552001-06-28 07:25:16 +000011787/*
11788 * Signal handler.
11789 */
11790
Eric Andersenc470f442003-07-28 09:56:35 +000011791void
11792onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011793{
Eric Andersencb57d552001-06-28 07:25:16 +000011794 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011795 pendingsigs = signo;
11796
11797 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11798 if (!suppressint)
11799 onint();
11800 intpending = 1;
11801 }
Eric Andersencb57d552001-06-28 07:25:16 +000011802}
11803
11804
Eric Andersencb57d552001-06-28 07:25:16 +000011805/*
11806 * Called to execute a trap. Perhaps we should avoid entering new trap
11807 * handlers while we are executing a trap handler.
11808 */
11809
Eric Andersenc470f442003-07-28 09:56:35 +000011810void
11811dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011812{
Eric Andersenc470f442003-07-28 09:56:35 +000011813 char *p;
11814 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011815 int savestatus;
11816
Eric Andersenc470f442003-07-28 09:56:35 +000011817 savestatus = exitstatus;
11818 q = gotsig;
Glenn L McGrath2f325a02004-08-06 01:49:04 +000011819 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
Eric Andersenc470f442003-07-28 09:56:35 +000011820 *p = 0;
11821 p = trap[p - q + 1];
11822 if (!p)
11823 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011824 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011825 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011826 }
Eric Andersencb57d552001-06-28 07:25:16 +000011827}
11828
Eric Andersenc470f442003-07-28 09:56:35 +000011829
Eric Andersenc470f442003-07-28 09:56:35 +000011830/*
11831 * Controls whether the shell is interactive or not.
11832 */
11833
Eric Andersenc470f442003-07-28 09:56:35 +000011834void
11835setinteractive(int on)
11836{
11837 static int is_interactive;
11838
11839 if (++on == is_interactive)
11840 return;
11841 is_interactive = on;
11842 setsignal(SIGINT);
11843 setsignal(SIGQUIT);
11844 setsignal(SIGTERM);
11845#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11846 if(is_interactive > 1) {
11847 /* Looks like they want an interactive shell */
11848 static int do_banner;
11849
11850 if(!do_banner) {
11851 out1fmt(
11852 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11853 "Enter 'help' for a list of built-in commands.\n\n");
11854 do_banner++;
11855 }
11856 }
11857#endif
11858}
11859
11860
11861#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11862/*** List the available builtins ***/
11863
11864static int helpcmd(int argc, char **argv)
11865{
11866 int col, i;
11867
11868 out1fmt("\nBuilt-in commands:\n-------------------\n");
11869 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11870 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11871 builtincmd[i].name + 1);
11872 if (col > 60) {
11873 out1fmt("\n");
11874 col = 0;
11875 }
11876 }
11877#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11878 {
11879 extern const struct BB_applet applets[];
11880 extern const size_t NUM_APPLETS;
11881
11882 for (i = 0; i < NUM_APPLETS; i++) {
11883
11884 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11885 if (col > 60) {
11886 out1fmt("\n");
11887 col = 0;
11888 }
11889 }
11890 }
11891#endif
11892 out1fmt("\n\n");
11893 return EXIT_SUCCESS;
11894}
11895#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11896
Eric Andersencb57d552001-06-28 07:25:16 +000011897/*
11898 * Called to exit the shell.
11899 */
11900
Eric Andersenc470f442003-07-28 09:56:35 +000011901void
11902exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011903{
Eric Andersenc470f442003-07-28 09:56:35 +000011904 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011905 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011906 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011907 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011908
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011909 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011910 status = exitstatus;
11911 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011912 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011913 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011914 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011915 if ((p = trap[0]) != NULL && *p != '\0') {
11916 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011917 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011918 }
Eric Andersencb57d552001-06-28 07:25:16 +000011919 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011920 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011921#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11922 if (iflag && rootshell) {
11923 const char *hp = lookupvar("HISTFILE");
11924
11925 if(hp != NULL )
11926 save_history ( hp );
11927 }
11928#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011929out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011930 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011931 /* NOTREACHED */
11932}
11933
11934static int decode_signal(const char *string, int minsig)
11935{
11936 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011937 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011938
Eric Andersen34506362001-08-02 05:02:46 +000011939 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011940}
Eric Andersen34506362001-08-02 05:02:46 +000011941
Eric Andersenc470f442003-07-28 09:56:35 +000011942/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11943
11944static struct var *vartab[VTABSIZE];
11945
11946static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011947static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011948
11949/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011950 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011951 */
11952
Eric Andersenc470f442003-07-28 09:56:35 +000011953
11954#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011955/*
Eric Andersenc470f442003-07-28 09:56:35 +000011956 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011957 */
11958
Eric Andersenc470f442003-07-28 09:56:35 +000011959int
11960setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011961{
Eric Andersenc470f442003-07-28 09:56:35 +000011962 int err;
11963 volatile int saveint;
11964 struct jmploc *volatile savehandler = handler;
11965 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011966
Eric Andersenc470f442003-07-28 09:56:35 +000011967 SAVEINT(saveint);
11968 if (setjmp(jmploc.loc))
11969 err = 1;
11970 else {
11971 handler = &jmploc;
11972 setvar(name, val, flags);
11973 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011974 }
Eric Andersenc470f442003-07-28 09:56:35 +000011975 handler = savehandler;
11976 RESTOREINT(saveint);
11977 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011978}
Eric Andersenc470f442003-07-28 09:56:35 +000011979#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011980
11981/*
11982 * Set the value of a variable. The flags argument is ored with the
11983 * flags of the variable. If val is NULL, the variable is unset.
11984 */
11985
Eric Andersenc470f442003-07-28 09:56:35 +000011986static void
11987setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011988{
Eric Andersenc470f442003-07-28 09:56:35 +000011989 char *p, *q;
11990 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011991 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011992 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011993
Eric Andersenc470f442003-07-28 09:56:35 +000011994 q = endofname(name);
11995 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011996 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011997 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011998 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011999 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012000 if (val == NULL) {
12001 flags |= VUNSET;
12002 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012003 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000012004 }
12005 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012006 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12007 *p++ = '\0';
12008 if (vallen) {
12009 p[-1] = '=';
12010 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000012011 }
Eric Andersenc470f442003-07-28 09:56:35 +000012012 *p = '\0';
12013 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012014 INTON;
12015}
12016
12017
Eric Andersencb57d552001-06-28 07:25:16 +000012018/*
12019 * Same as setvar except that the variable and value are passed in
12020 * the first argument as name=value. Since the first argument will
12021 * be actually stored in the table, it should not be a string that
12022 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012023 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012024 */
12025
Eric Andersenc470f442003-07-28 09:56:35 +000012026void
12027setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012028{
12029 struct var *vp, **vpp;
12030
12031 vpp = hashvar(s);
12032 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012033 vp = *findvar(vpp, s);
12034 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012035 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12036 const char *n;
12037
Eric Andersenc470f442003-07-28 09:56:35 +000012038 if (flags & VNOSAVE)
12039 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012040 n = vp->text;
12041 error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012042 }
Eric Andersenc470f442003-07-28 09:56:35 +000012043
12044 if (flags & VNOSET)
12045 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012046
12047 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012048 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012049
Eric Andersenc470f442003-07-28 09:56:35 +000012050 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12051 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012052
Eric Andersenc470f442003-07-28 09:56:35 +000012053 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12054 } else {
12055 if (flags & VNOSET)
12056 return;
12057 /* not found */
12058 vp = ckmalloc(sizeof (*vp));
12059 vp->next = *vpp;
12060 vp->func = NULL;
12061 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012062 }
Eric Andersenc470f442003-07-28 09:56:35 +000012063 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12064 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012065 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012066 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012067}
12068
12069
Eric Andersencb57d552001-06-28 07:25:16 +000012070/*
12071 * Process a linked list of variable assignments.
12072 */
12073
Eric Andersenc470f442003-07-28 09:56:35 +000012074static void
12075listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012076{
Eric Andersenc470f442003-07-28 09:56:35 +000012077 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012078
Eric Andersenc470f442003-07-28 09:56:35 +000012079 if (!lp)
12080 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012081 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012082 do {
12083 setvareq(lp->text, flags);
12084 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012085 INTON;
12086}
12087
12088
Eric Andersencb57d552001-06-28 07:25:16 +000012089/*
12090 * Find the value of a variable. Returns NULL if not set.
12091 */
12092
Eric Andersenc470f442003-07-28 09:56:35 +000012093static char *
12094lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012095{
Eric Andersencb57d552001-06-28 07:25:16 +000012096 struct var *v;
12097
Eric Andersen16767e22004-03-16 05:14:10 +000012098 if ((v = *findvar(hashvar(name), name))) {
12099#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012100 /*
12101 * Dynamic variables are implemented roughly the same way they are
12102 * in bash. Namely, they're "special" so long as they aren't unset.
12103 * As soon as they're unset, they're no longer dynamic, and dynamic
12104 * lookup will no longer happen at that point. -- PFM.
12105 */
Eric Andersen16767e22004-03-16 05:14:10 +000012106 if((v->flags & VDYNAMIC))
12107 (*v->func)(NULL);
12108#endif
12109 if(!(v->flags & VUNSET))
12110 return strchrnul(v->text, '=') + 1;
12111 }
Eric Andersenef02f822004-03-11 13:34:24 +000012112
Eric Andersencb57d552001-06-28 07:25:16 +000012113 return NULL;
12114}
12115
12116
Eric Andersencb57d552001-06-28 07:25:16 +000012117/*
12118 * Search the environment of a builtin command.
12119 */
12120
Eric Andersenc470f442003-07-28 09:56:35 +000012121static char *
12122bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012123{
Eric Andersenc470f442003-07-28 09:56:35 +000012124 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012125
Eric Andersenc470f442003-07-28 09:56:35 +000012126 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012127 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012128 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012129 }
12130 return lookupvar(name);
12131}
12132
12133
Eric Andersencb57d552001-06-28 07:25:16 +000012134/*
Eric Andersenc470f442003-07-28 09:56:35 +000012135 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012136 */
12137
Eric Andersenc470f442003-07-28 09:56:35 +000012138static char **
12139listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012140{
Eric Andersencb57d552001-06-28 07:25:16 +000012141 struct var **vpp;
12142 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012143 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012144 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012145
Eric Andersenc470f442003-07-28 09:56:35 +000012146 STARTSTACKSTR(ep);
12147 vpp = vartab;
12148 mask = on | off;
12149 do {
12150 for (vp = *vpp ; vp ; vp = vp->next)
12151 if ((vp->flags & mask) == on) {
12152 if (ep == stackstrend())
12153 ep = growstackstr();
12154 *ep++ = (char *) vp->text;
12155 }
12156 } while (++vpp < vartab + VTABSIZE);
12157 if (ep == stackstrend())
12158 ep = growstackstr();
12159 if (end)
12160 *end = ep;
12161 *ep++ = NULL;
12162 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012163}
12164
12165
12166/*
Eric Andersenc470f442003-07-28 09:56:35 +000012167 * POSIX requires that 'set' (but not export or readonly) output the
12168 * variables in lexicographic order - by the locale's collating order (sigh).
12169 * Maybe we could keep them in an ordered balanced binary tree
12170 * instead of hashed lists.
12171 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012172 */
12173
Eric Andersenc470f442003-07-28 09:56:35 +000012174static int
12175showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012176{
Eric Andersenc470f442003-07-28 09:56:35 +000012177 const char *sep;
12178 char **ep, **epend;
12179
12180 ep = listvars(on, off, &epend);
12181 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12182
12183 sep = *sep_prefix ? spcstr : sep_prefix;
12184
12185 for (; ep < epend; ep++) {
12186 const char *p;
12187 const char *q;
12188
12189 p = strchrnul(*ep, '=');
12190 q = nullstr;
12191 if (*p)
12192 q = single_quote(++p);
12193
12194 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12195 }
12196
Eric Andersencb57d552001-06-28 07:25:16 +000012197 return 0;
12198}
12199
12200
12201
12202/*
12203 * The export and readonly commands.
12204 */
12205
Eric Andersenc470f442003-07-28 09:56:35 +000012206static int
12207exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012208{
12209 struct var *vp;
12210 char *name;
12211 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012212 char **aptr;
12213 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12214 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012215
Eric Andersenc470f442003-07-28 09:56:35 +000012216 notp = nextopt("p") - 'p';
12217 if (notp && ((name = *(aptr = argptr)))) {
12218 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012219 if ((p = strchr(name, '=')) != NULL) {
12220 p++;
12221 } else {
12222 if ((vp = *findvar(hashvar(name), name))) {
12223 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012224 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012225 }
12226 }
12227 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012228 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012229 } else {
12230 showvars(argv[0], flag, 0);
12231 }
12232 return 0;
12233}
12234
Eric Andersen34506362001-08-02 05:02:46 +000012235
Eric Andersencb57d552001-06-28 07:25:16 +000012236/*
Eric Andersencb57d552001-06-28 07:25:16 +000012237 * Make a variable a local variable. When a variable is made local, it's
12238 * value and flags are saved in a localvar structure. The saved values
12239 * will be restored when the shell function returns. We handle the name
12240 * "-" as a special case.
12241 */
12242
Eric Andersenc470f442003-07-28 09:56:35 +000012243static inline void
12244mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012245{
Eric Andersencb57d552001-06-28 07:25:16 +000012246 struct localvar *lvp;
12247 struct var **vpp;
12248 struct var *vp;
12249
12250 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012251 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012252 if (name[0] == '-' && name[1] == '\0') {
12253 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012254 p = ckmalloc(sizeof(optlist));
12255 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012256 vp = NULL;
12257 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012258 char *eq;
12259
Eric Andersencb57d552001-06-28 07:25:16 +000012260 vpp = hashvar(name);
12261 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012262 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012263 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012264 if (eq)
12265 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012266 else
12267 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012268 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012269 lvp->flags = VUNSET;
12270 } else {
12271 lvp->text = vp->text;
12272 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012273 vp->flags |= VSTRFIXED|VTEXTFIXED;
12274 if (eq)
12275 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012276 }
12277 }
12278 lvp->vp = vp;
12279 lvp->next = localvars;
12280 localvars = lvp;
12281 INTON;
12282}
12283
Eric Andersenc470f442003-07-28 09:56:35 +000012284/*
12285 * The "local" command.
12286 */
12287
12288static int
12289localcmd(int argc, char **argv)
12290{
12291 char *name;
12292
12293 argv = argptr;
12294 while ((name = *argv++) != NULL) {
12295 mklocal(name);
12296 }
12297 return 0;
12298}
12299
12300
Eric Andersencb57d552001-06-28 07:25:16 +000012301/*
12302 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012303 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012304 */
12305
Eric Andersenc470f442003-07-28 09:56:35 +000012306static void
12307poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012308{
Eric Andersencb57d552001-06-28 07:25:16 +000012309 struct localvar *lvp;
12310 struct var *vp;
12311
12312 while ((lvp = localvars) != NULL) {
12313 localvars = lvp->next;
12314 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012315 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12316 if (vp == NULL) { /* $- saved */
12317 memcpy(optlist, lvp->text, sizeof(optlist));
12318 ckfree(lvp->text);
12319 optschanged();
12320 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12321 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012322 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012323 if (vp->func)
12324 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12325 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12326 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012327 vp->flags = lvp->flags;
12328 vp->text = lvp->text;
12329 }
Eric Andersenc470f442003-07-28 09:56:35 +000012330 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012331 }
12332}
12333
12334
Eric Andersencb57d552001-06-28 07:25:16 +000012335/*
12336 * The unset builtin command. We unset the function before we unset the
12337 * variable to allow a function to be unset when there is a readonly variable
12338 * with the same name.
12339 */
12340
Eric Andersenc470f442003-07-28 09:56:35 +000012341int
12342unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012343{
12344 char **ap;
12345 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012346 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012347 int ret = 0;
12348
12349 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012350 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012351 }
Eric Andersencb57d552001-06-28 07:25:16 +000012352
Eric Andersenc470f442003-07-28 09:56:35 +000012353 for (ap = argptr; *ap ; ap++) {
12354 if (flag != 'f') {
12355 i = unsetvar(*ap);
12356 ret |= i;
12357 if (!(i & 2))
12358 continue;
12359 }
12360 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012361 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012362 }
Eric Andersenc470f442003-07-28 09:56:35 +000012363 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012364}
12365
12366
12367/*
12368 * Unset the specified variable.
12369 */
12370
Eric Andersenc470f442003-07-28 09:56:35 +000012371int
12372unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012373{
Eric Andersencb57d552001-06-28 07:25:16 +000012374 struct var **vpp;
12375 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012376 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012377
12378 vpp = findvar(hashvar(s), s);
12379 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012380 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012381 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012382 int flags = vp->flags;
12383
12384 retval = 1;
12385 if (flags & VREADONLY)
12386 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012387#ifdef DYNAMIC_VAR
12388 vp->flags &= ~VDYNAMIC;
12389#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012390 if (flags & VUNSET)
12391 goto ok;
12392 if ((flags & VSTRFIXED) == 0) {
12393 INTOFF;
12394 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12395 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012396 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012397 ckfree(vp);
12398 INTON;
12399 } else {
12400 setvar(s, 0, 0);
12401 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012402 }
Eric Andersenc470f442003-07-28 09:56:35 +000012403ok:
12404 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012405 }
12406
Eric Andersenc470f442003-07-28 09:56:35 +000012407out:
12408 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012409}
12410
12411
12412
12413/*
12414 * Find the appropriate entry in the hash table from the name.
12415 */
12416
Eric Andersenc470f442003-07-28 09:56:35 +000012417static struct var **
12418hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012419{
Eric Andersencb57d552001-06-28 07:25:16 +000012420 unsigned int hashval;
12421
12422 hashval = ((unsigned char) *p) << 4;
12423 while (*p && *p != '=')
12424 hashval += (unsigned char) *p++;
12425 return &vartab[hashval % VTABSIZE];
12426}
12427
12428
12429
12430/*
Eric Andersenc470f442003-07-28 09:56:35 +000012431 * Compares two strings up to the first = or '\0'. The first
12432 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012433 * either '=' or '\0'.
12434 */
12435
Eric Andersenc470f442003-07-28 09:56:35 +000012436int
12437varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012438{
Eric Andersenc470f442003-07-28 09:56:35 +000012439 int c, d;
12440
12441 while ((c = *p) == (d = *q)) {
12442 if (!c || c == '=')
12443 goto out;
12444 p++;
12445 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012446 }
Eric Andersenc470f442003-07-28 09:56:35 +000012447 if (c == '=')
12448 c = 0;
12449 if (d == '=')
12450 d = 0;
12451out:
12452 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012453}
12454
Eric Andersenc470f442003-07-28 09:56:35 +000012455static int
12456vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012457{
Eric Andersenc470f442003-07-28 09:56:35 +000012458 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012459}
12460
Eric Andersenc470f442003-07-28 09:56:35 +000012461static struct var **
12462findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012463{
12464 for (; *vpp; vpp = &(*vpp)->next) {
12465 if (varequal((*vpp)->text, name)) {
12466 break;
12467 }
12468 }
12469 return vpp;
12470}
Eric Andersenc470f442003-07-28 09:56:35 +000012471/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012472
Eric Andersenc470f442003-07-28 09:56:35 +000012473#include <sys/times.h>
12474
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012475static const unsigned char timescmd_str[] = {
12476 ' ', offsetof(struct tms, tms_utime),
12477 '\n', offsetof(struct tms, tms_stime),
12478 ' ', offsetof(struct tms, tms_cutime),
12479 '\n', offsetof(struct tms, tms_cstime),
12480 0
12481};
Eric Andersencb57d552001-06-28 07:25:16 +000012482
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012483static int timescmd(int ac, char **av)
12484{
12485 long int clk_tck, s, t;
12486 const unsigned char *p;
12487 struct tms buf;
12488
12489 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012490 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012491
12492 p = timescmd_str;
12493 do {
12494 t = *(clock_t *)(((char *) &buf) + p[1]);
12495 s = t / clk_tck;
12496 out1fmt("%ldm%ld.%.3lds%c",
12497 s/60, s%60,
12498 ((t - s * clk_tck) * 1000) / clk_tck,
12499 p[0]);
12500 } while (*(p += 2));
12501
Eric Andersencb57d552001-06-28 07:25:16 +000012502 return 0;
12503}
12504
Eric Andersend35c5df2002-01-09 15:37:36 +000012505#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012506static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012507dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012508{
Eric Andersened9ecf72004-06-22 08:29:45 +000012509 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012510 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012511
Eric Andersenc470f442003-07-28 09:56:35 +000012512 INTOFF;
12513 result = arith(s, &errcode);
12514 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012515 if (errcode == -3)
12516 error("exponent less than 0");
12517 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012518 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012519 else if (errcode == -5)
12520 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012521 else
12522 synerror(s);
12523 }
12524 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012525
Eric Andersenc470f442003-07-28 09:56:35 +000012526 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012527}
Eric Andersenc470f442003-07-28 09:56:35 +000012528
12529
12530/*
Eric Andersen90898442003-08-06 11:20:52 +000012531 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12532 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12533 *
12534 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012535 */
Eric Andersen90898442003-08-06 11:20:52 +000012536
Eric Andersenc470f442003-07-28 09:56:35 +000012537static int
Eric Andersen90898442003-08-06 11:20:52 +000012538letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012539{
Eric Andersenc470f442003-07-28 09:56:35 +000012540 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012541 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012542
Eric Andersen90898442003-08-06 11:20:52 +000012543 ap = argv + 1;
12544 if(!*ap)
12545 error("expression expected");
12546 for (ap = argv + 1; *ap; ap++) {
12547 i = dash_arith(*ap);
12548 }
Eric Andersenc470f442003-07-28 09:56:35 +000012549
Eric Andersen90898442003-08-06 11:20:52 +000012550 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012551}
12552#endif /* CONFIG_ASH_MATH_SUPPORT */
12553
12554/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12555
12556/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012557 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012558 */
12559
12560#undef rflag
12561
12562#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012563#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012564typedef enum __rlimit_resource rlim_t;
12565#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012566#endif
12567
12568
Eric Andersenc470f442003-07-28 09:56:35 +000012569/*
12570 * The read builtin. The -e option causes backslashes to escape the
12571 * following character.
12572 *
12573 * This uses unbuffered input, which may be avoidable in some cases.
12574 */
12575
12576static int
12577readcmd(int argc, char **argv)
12578{
12579 char **ap;
12580 int backslash;
12581 char c;
12582 int rflag;
12583 char *prompt;
12584 const char *ifs;
12585 char *p;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012586#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012587 fd_set set;
12588 int timeout;
12589 struct timeval timeout_struct;
12590 struct termios tty, old_tty;
12591#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012592 int startword;
12593 int status;
12594 int i;
12595
12596 rflag = 0;
12597 prompt = NULL;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012598#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012599 timeout = 0;
12600
12601 while ((i = nextopt("p:rt:")) != '\0')
12602#else
12603 while ((i = nextopt("p:r")) != '\0')
12604#endif
12605 {
Eric Andersenc470f442003-07-28 09:56:35 +000012606 if (i == 'p')
12607 prompt = optionarg;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012608 else if (i == 'r')
Eric Andersenc470f442003-07-28 09:56:35 +000012609 rflag = 1;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012610#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012611 else
12612 timeout = atoi(optionarg);
12613#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012614 }
12615 if (prompt && isatty(0)) {
12616 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012617 }
12618 if (*(ap = argptr) == NULL)
12619 error("arg count");
12620 if ((ifs = bltinlookup("IFS")) == NULL)
12621 ifs = defifs;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012622#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012623 c = 0;
12624#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012625 status = 0;
12626 startword = 1;
12627 backslash = 0;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012628
Eric Andersenc470f442003-07-28 09:56:35 +000012629 STARTSTACKSTR(p);
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012630#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012631 if (timeout > 0) {
12632 tcgetattr(0, &tty);
12633 old_tty = tty;
12634
12635 /* cfmakeraw(...) disables too much; we just do this instead. */
12636 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
12637 tcsetattr(0, TCSANOW, &tty);
12638
12639 FD_ZERO (&set);
12640 FD_SET (0, &set);
12641
12642 timeout_struct.tv_sec = timeout;
12643 timeout_struct.tv_usec = 0;
12644
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012645 if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012646 {
12647 read(0, &c, 1);
12648 if(c == '\n' || c == 4) /* Handle newlines and EOF */
12649 i = 0; /* Don't read further... */
12650 else
12651 STPUTC(c, p); /* Keep reading... */
12652 }
12653 tcsetattr(0, TCSANOW, &old_tty);
12654
12655 /* Echo the character so the user knows it was read...
12656 Yes, this can be done by setting the ECHO flag, but that
12657 echoes ^D and other control characters at this state */
12658 if(c != 0)
12659 write(1, &c, 1);
12660
12661 } else
12662 i = 1;
12663
12664 for (;i == 1;)
12665#else
12666 for (;;)
12667#endif
12668 {
Eric Andersenc470f442003-07-28 09:56:35 +000012669 if (read(0, &c, 1) != 1) {
12670 status = 1;
12671 break;
12672 }
12673 if (c == '\0')
12674 continue;
12675 if (backslash) {
12676 backslash = 0;
12677 if (c != '\n')
12678 goto put;
12679 continue;
12680 }
12681 if (!rflag && c == '\\') {
12682 backslash++;
12683 continue;
12684 }
12685 if (c == '\n')
12686 break;
12687 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12688 continue;
12689 }
12690 startword = 0;
12691 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12692 STACKSTRNUL(p);
12693 setvar(*ap, stackblock(), 0);
12694 ap++;
12695 startword = 1;
12696 STARTSTACKSTR(p);
12697 } else {
12698put:
12699 STPUTC(c, p);
12700 }
12701 }
12702 STACKSTRNUL(p);
12703 /* Remove trailing blanks */
12704 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12705 *p = '\0';
12706 setvar(*ap, stackblock(), 0);
12707 while (*++ap != NULL)
12708 setvar(*ap, nullstr, 0);
12709 return status;
12710}
12711
12712
12713static int umaskcmd(int argc, char **argv)
12714{
12715 static const char permuser[3] = "ugo";
12716 static const char permmode[3] = "rwx";
12717 static const short int permmask[] = {
12718 S_IRUSR, S_IWUSR, S_IXUSR,
12719 S_IRGRP, S_IWGRP, S_IXGRP,
12720 S_IROTH, S_IWOTH, S_IXOTH
12721 };
12722
12723 char *ap;
12724 mode_t mask;
12725 int i;
12726 int symbolic_mode = 0;
12727
12728 while (nextopt("S") != '\0') {
12729 symbolic_mode = 1;
12730 }
12731
12732 INTOFF;
12733 mask = umask(0);
12734 umask(mask);
12735 INTON;
12736
12737 if ((ap = *argptr) == NULL) {
12738 if (symbolic_mode) {
12739 char buf[18];
12740 char *p = buf;
12741
12742 for (i = 0; i < 3; i++) {
12743 int j;
12744
12745 *p++ = permuser[i];
12746 *p++ = '=';
12747 for (j = 0; j < 3; j++) {
12748 if ((mask & permmask[3 * i + j]) == 0) {
12749 *p++ = permmode[j];
12750 }
12751 }
12752 *p++ = ',';
12753 }
12754 *--p = 0;
12755 puts(buf);
12756 } else {
12757 out1fmt("%.4o\n", mask);
12758 }
12759 } else {
12760 if (is_digit((unsigned char) *ap)) {
12761 mask = 0;
12762 do {
12763 if (*ap >= '8' || *ap < '0')
12764 error(illnum, argv[1]);
12765 mask = (mask << 3) + (*ap - '0');
12766 } while (*++ap != '\0');
12767 umask(mask);
12768 } else {
12769 mask = ~mask & 0777;
12770 if (!bb_parse_mode(ap, &mask)) {
12771 error("Illegal mode: %s", ap);
12772 }
12773 umask(~mask & 0777);
12774 }
12775 }
12776 return 0;
12777}
12778
12779/*
12780 * ulimit builtin
12781 *
12782 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12783 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12784 * ash by J.T. Conklin.
12785 *
12786 * Public domain.
12787 */
12788
12789struct limits {
12790 const char *name;
12791 int cmd;
12792 int factor; /* multiply by to get rlim_{cur,max} values */
12793 char option;
12794};
12795
12796static const struct limits limits[] = {
12797#ifdef RLIMIT_CPU
12798 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12799#endif
12800#ifdef RLIMIT_FSIZE
12801 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12802#endif
12803#ifdef RLIMIT_DATA
12804 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12805#endif
12806#ifdef RLIMIT_STACK
12807 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12808#endif
12809#ifdef RLIMIT_CORE
12810 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12811#endif
12812#ifdef RLIMIT_RSS
12813 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12814#endif
12815#ifdef RLIMIT_MEMLOCK
12816 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12817#endif
12818#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012819 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012820#endif
12821#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012822 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012823#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012824#ifdef RLIMIT_AS
12825 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012826#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012827#ifdef RLIMIT_LOCKS
12828 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012829#endif
12830 { (char *) 0, 0, 0, '\0' }
12831};
12832
Glenn L McGrath76620622004-01-13 10:19:37 +000012833enum limtype { SOFT = 0x1, HARD = 0x2 };
12834
12835static void printlim(enum limtype how, const struct rlimit *limit,
12836 const struct limits *l)
12837{
12838 rlim_t val;
12839
12840 val = limit->rlim_max;
12841 if (how & SOFT)
12842 val = limit->rlim_cur;
12843
12844 if (val == RLIM_INFINITY)
12845 out1fmt("unlimited\n");
12846 else {
12847 val /= l->factor;
12848 out1fmt("%lld\n", (long long) val);
12849 }
12850}
12851
Eric Andersenc470f442003-07-28 09:56:35 +000012852int
12853ulimitcmd(int argc, char **argv)
12854{
12855 int c;
12856 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012857 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012858 const struct limits *l;
12859 int set, all = 0;
12860 int optc, what;
12861 struct rlimit limit;
12862
12863 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012864 while ((optc = nextopt("HSa"
12865#ifdef RLIMIT_CPU
12866 "t"
12867#endif
12868#ifdef RLIMIT_FSIZE
12869 "f"
12870#endif
12871#ifdef RLIMIT_DATA
12872 "d"
12873#endif
12874#ifdef RLIMIT_STACK
12875 "s"
12876#endif
12877#ifdef RLIMIT_CORE
12878 "c"
12879#endif
12880#ifdef RLIMIT_RSS
12881 "m"
12882#endif
12883#ifdef RLIMIT_MEMLOCK
12884 "l"
12885#endif
12886#ifdef RLIMIT_NPROC
12887 "p"
12888#endif
12889#ifdef RLIMIT_NOFILE
12890 "n"
12891#endif
12892#ifdef RLIMIT_AS
12893 "v"
12894#endif
12895#ifdef RLIMIT_LOCKS
12896 "w"
12897#endif
12898 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012899 switch (optc) {
12900 case 'H':
12901 how = HARD;
12902 break;
12903 case 'S':
12904 how = SOFT;
12905 break;
12906 case 'a':
12907 all = 1;
12908 break;
12909 default:
12910 what = optc;
12911 }
12912
Glenn L McGrath76620622004-01-13 10:19:37 +000012913 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012914 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012915
12916 set = *argptr ? 1 : 0;
12917 if (set) {
12918 char *p = *argptr;
12919
12920 if (all || argptr[1])
12921 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012922 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012923 val = RLIM_INFINITY;
12924 else {
12925 val = (rlim_t) 0;
12926
12927 while ((c = *p++) >= '0' && c <= '9')
12928 {
12929 val = (val * 10) + (long)(c - '0');
12930 if (val < (rlim_t) 0)
12931 break;
12932 }
12933 if (c)
12934 error("bad number");
12935 val *= l->factor;
12936 }
12937 }
12938 if (all) {
12939 for (l = limits; l->name; l++) {
12940 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012941 out1fmt("%-20s ", l->name);
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
12947 getrlimit(l->cmd, &limit);
12948 if (set) {
12949 if (how & HARD)
12950 limit.rlim_max = val;
12951 if (how & SOFT)
12952 limit.rlim_cur = val;
12953 if (setrlimit(l->cmd, &limit) < 0)
12954 error("error setting limit (%m)");
12955 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012956 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012957 }
12958 return 0;
12959}
12960
Eric Andersen90898442003-08-06 11:20:52 +000012961
12962#ifdef CONFIG_ASH_MATH_SUPPORT
12963
12964/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12965
12966 Permission is hereby granted, free of charge, to any person obtaining
12967 a copy of this software and associated documentation files (the
12968 "Software"), to deal in the Software without restriction, including
12969 without limitation the rights to use, copy, modify, merge, publish,
12970 distribute, sublicense, and/or sell copies of the Software, and to
12971 permit persons to whom the Software is furnished to do so, subject to
12972 the following conditions:
12973
12974 The above copyright notice and this permission notice shall be
12975 included in all copies or substantial portions of the Software.
12976
12977 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12978 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12979 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12980 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12981 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12982 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12983 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12984*/
12985
12986/* This is my infix parser/evaluator. It is optimized for size, intended
12987 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000012988 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000012989 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000012990 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000012991 * be that which POSIX specifies for shells. */
12992
12993/* The code uses a simple two-stack algorithm. See
12994 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000012995 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000012996 * this is based (this code differs in that it applies operators immediately
12997 * to the stack instead of adding them to a queue to end up with an
12998 * expression). */
12999
13000/* To use the routine, call it with an expression string and error return
13001 * pointer */
13002
13003/*
13004 * Aug 24, 2001 Manuel Novoa III
13005 *
13006 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13007 *
13008 * 1) In arith_apply():
13009 * a) Cached values of *numptr and &(numptr[-1]).
13010 * b) Removed redundant test for zero denominator.
13011 *
13012 * 2) In arith():
13013 * a) Eliminated redundant code for processing operator tokens by moving
13014 * to a table-based implementation. Also folded handling of parens
13015 * into the table.
13016 * b) Combined all 3 loops which called arith_apply to reduce generated
13017 * code size at the cost of speed.
13018 *
13019 * 3) The following expressions were treated as valid by the original code:
13020 * 1() , 0! , 1 ( *3 ) .
13021 * These bugs have been fixed by internally enclosing the expression in
13022 * parens and then checking that all binary ops and right parens are
13023 * preceded by a valid expression (NUM_TOKEN).
13024 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013025 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013026 * ctype's isspace() if it is used by another busybox applet or if additional
13027 * whitespace chars should be considered. Look below the "#include"s for a
13028 * precompiler test.
13029 */
13030
13031/*
13032 * Aug 26, 2001 Manuel Novoa III
13033 *
13034 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13035 *
13036 * Merge in Aaron's comments previously posted to the busybox list,
13037 * modified slightly to take account of my changes to the code.
13038 *
13039 */
13040
13041/*
13042 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13043 *
13044 * - allow access to variable,
13045 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13046 * - realize assign syntax (VAR=expr, +=, *= etc)
13047 * - realize exponentiation (** operator)
13048 * - realize comma separated - expr, expr
13049 * - realise ++expr --expr expr++ expr--
13050 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013051 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013052 * - was restored loses XOR operator
13053 * - remove one goto label, added three ;-)
13054 * - protect $((num num)) as true zero expr (Manuel`s error)
13055 * - always use special isspace(), see comment from bash ;-)
13056 */
13057
13058
13059#define arith_isspace(arithval) \
13060 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13061
13062
13063typedef unsigned char operator;
13064
13065/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013066 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013067 * precedence. The ID portion is so that multiple operators can have the
13068 * same precedence, ensuring that the leftmost one is evaluated first.
13069 * Consider * and /. */
13070
13071#define tok_decl(prec,id) (((id)<<5)|(prec))
13072#define PREC(op) ((op) & 0x1F)
13073
13074#define TOK_LPAREN tok_decl(0,0)
13075
13076#define TOK_COMMA tok_decl(1,0)
13077
13078#define TOK_ASSIGN tok_decl(2,0)
13079#define TOK_AND_ASSIGN tok_decl(2,1)
13080#define TOK_OR_ASSIGN tok_decl(2,2)
13081#define TOK_XOR_ASSIGN tok_decl(2,3)
13082#define TOK_PLUS_ASSIGN tok_decl(2,4)
13083#define TOK_MINUS_ASSIGN tok_decl(2,5)
13084#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13085#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13086
13087#define TOK_MUL_ASSIGN tok_decl(3,0)
13088#define TOK_DIV_ASSIGN tok_decl(3,1)
13089#define TOK_REM_ASSIGN tok_decl(3,2)
13090
13091/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13092#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13093
13094/* conditional is right associativity too */
13095#define TOK_CONDITIONAL tok_decl(4,0)
13096#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13097
13098#define TOK_OR tok_decl(5,0)
13099
13100#define TOK_AND tok_decl(6,0)
13101
13102#define TOK_BOR tok_decl(7,0)
13103
13104#define TOK_BXOR tok_decl(8,0)
13105
13106#define TOK_BAND tok_decl(9,0)
13107
13108#define TOK_EQ tok_decl(10,0)
13109#define TOK_NE tok_decl(10,1)
13110
13111#define TOK_LT tok_decl(11,0)
13112#define TOK_GT tok_decl(11,1)
13113#define TOK_GE tok_decl(11,2)
13114#define TOK_LE tok_decl(11,3)
13115
13116#define TOK_LSHIFT tok_decl(12,0)
13117#define TOK_RSHIFT tok_decl(12,1)
13118
13119#define TOK_ADD tok_decl(13,0)
13120#define TOK_SUB tok_decl(13,1)
13121
13122#define TOK_MUL tok_decl(14,0)
13123#define TOK_DIV tok_decl(14,1)
13124#define TOK_REM tok_decl(14,2)
13125
13126/* exponent is right associativity */
13127#define TOK_EXPONENT tok_decl(15,1)
13128
13129/* For now unary operators. */
13130#define UNARYPREC 16
13131#define TOK_BNOT tok_decl(UNARYPREC,0)
13132#define TOK_NOT tok_decl(UNARYPREC,1)
13133
13134#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13135#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13136
13137#define PREC_PRE (UNARYPREC+2)
13138
13139#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13140#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13141
13142#define PREC_POST (UNARYPREC+3)
13143
13144#define TOK_POST_INC tok_decl(PREC_POST, 0)
13145#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13146
13147#define SPEC_PREC (UNARYPREC+4)
13148
13149#define TOK_NUM tok_decl(SPEC_PREC, 0)
13150#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13151
13152#define NUMPTR (*numstackptr)
13153
13154static inline int tok_have_assign(operator op)
13155{
13156 operator prec = PREC(op);
13157
13158 convert_prec_is_assing(prec);
13159 return (prec == PREC(TOK_ASSIGN) ||
13160 prec == PREC_PRE || prec == PREC_POST);
13161}
13162
13163static inline int is_right_associativity(operator prec)
13164{
13165 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13166 prec == PREC(TOK_CONDITIONAL));
13167}
13168
13169
13170typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013171 arith_t val;
13172 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013173 char contidional_second_val_initialized;
13174 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013175 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013176} v_n_t;
13177
13178
13179typedef struct CHK_VAR_RECURSIVE_LOOPED {
13180 const char *var;
13181 struct CHK_VAR_RECURSIVE_LOOPED *next;
13182} chk_var_recursive_looped_t;
13183
13184static chk_var_recursive_looped_t *prev_chk_var_recursive;
13185
13186
13187static int arith_lookup_val(v_n_t *t)
13188{
13189 if(t->var) {
13190 const char * p = lookupvar(t->var);
13191
13192 if(p) {
13193 int errcode;
13194
13195 /* recursive try as expression */
13196 chk_var_recursive_looped_t *cur;
13197 chk_var_recursive_looped_t cur_save;
13198
13199 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13200 if(strcmp(cur->var, t->var) == 0) {
13201 /* expression recursion loop detected */
13202 return -5;
13203 }
13204 }
13205 /* save current lookuped var name */
13206 cur = prev_chk_var_recursive;
13207 cur_save.var = t->var;
13208 cur_save.next = cur;
13209 prev_chk_var_recursive = &cur_save;
13210
13211 t->val = arith (p, &errcode);
13212 /* restore previous ptr after recursiving */
13213 prev_chk_var_recursive = cur;
13214 return errcode;
13215 } else {
13216 /* allow undefined var as 0 */
13217 t->val = 0;
13218 }
13219 }
13220 return 0;
13221}
13222
13223/* "applying" a token means performing it on the top elements on the integer
13224 * stack. For a unary operator it will only change the top element, but a
13225 * binary operator will pop two arguments and push a result */
13226static inline int
13227arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13228{
Eric Andersen90898442003-08-06 11:20:52 +000013229 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013230 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013231 int ret_arith_lookup_val;
13232
13233 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13234 without arguments */
13235 numptr_m1 = NUMPTR - 1;
13236
13237 /* check operand is var with noninteger value */
13238 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13239 if(ret_arith_lookup_val)
13240 return ret_arith_lookup_val;
13241
13242 rez = numptr_m1->val;
13243 if (op == TOK_UMINUS)
13244 rez *= -1;
13245 else if (op == TOK_NOT)
13246 rez = !rez;
13247 else if (op == TOK_BNOT)
13248 rez = ~rez;
13249 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13250 rez++;
13251 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13252 rez--;
13253 else if (op != TOK_UPLUS) {
13254 /* Binary operators */
13255
13256 /* check and binary operators need two arguments */
13257 if (numptr_m1 == numstack) goto err;
13258
13259 /* ... and they pop one */
13260 --NUMPTR;
13261 numptr_val = rez;
13262 if (op == TOK_CONDITIONAL) {
13263 if(! numptr_m1->contidional_second_val_initialized) {
13264 /* protect $((expr1 ? expr2)) without ": expr" */
13265 goto err;
13266 }
13267 rez = numptr_m1->contidional_second_val;
13268 } else if(numptr_m1->contidional_second_val_initialized) {
13269 /* protect $((expr1 : expr2)) without "expr ? " */
13270 goto err;
13271 }
13272 numptr_m1 = NUMPTR - 1;
13273 if(op != TOK_ASSIGN) {
13274 /* check operand is var with noninteger value for not '=' */
13275 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13276 if(ret_arith_lookup_val)
13277 return ret_arith_lookup_val;
13278 }
13279 if (op == TOK_CONDITIONAL) {
13280 numptr_m1->contidional_second_val = rez;
13281 }
13282 rez = numptr_m1->val;
13283 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13284 rez |= numptr_val;
13285 else if (op == TOK_OR)
13286 rez = numptr_val || rez;
13287 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13288 rez &= numptr_val;
13289 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13290 rez ^= numptr_val;
13291 else if (op == TOK_AND)
13292 rez = rez && numptr_val;
13293 else if (op == TOK_EQ)
13294 rez = (rez == numptr_val);
13295 else if (op == TOK_NE)
13296 rez = (rez != numptr_val);
13297 else if (op == TOK_GE)
13298 rez = (rez >= numptr_val);
13299 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13300 rez >>= numptr_val;
13301 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13302 rez <<= numptr_val;
13303 else if (op == TOK_GT)
13304 rez = (rez > numptr_val);
13305 else if (op == TOK_LT)
13306 rez = (rez < numptr_val);
13307 else if (op == TOK_LE)
13308 rez = (rez <= numptr_val);
13309 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13310 rez *= numptr_val;
13311 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13312 rez += numptr_val;
13313 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13314 rez -= numptr_val;
13315 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13316 rez = numptr_val;
13317 else if (op == TOK_CONDITIONAL_SEP) {
13318 if (numptr_m1 == numstack) {
13319 /* protect $((expr : expr)) without "expr ? " */
13320 goto err;
13321 }
13322 numptr_m1->contidional_second_val_initialized = op;
13323 numptr_m1->contidional_second_val = numptr_val;
13324 }
13325 else if (op == TOK_CONDITIONAL) {
13326 rez = rez ?
13327 numptr_val : numptr_m1->contidional_second_val;
13328 }
13329 else if(op == TOK_EXPONENT) {
13330 if(numptr_val < 0)
13331 return -3; /* exponent less than 0 */
13332 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013333 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013334
13335 if(numptr_val)
13336 while(numptr_val--)
13337 c *= rez;
13338 rez = c;
13339 }
13340 }
13341 else if(numptr_val==0) /* zero divisor check */
13342 return -2;
13343 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13344 rez /= numptr_val;
13345 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13346 rez %= numptr_val;
13347 }
13348 if(tok_have_assign(op)) {
13349 char buf[32];
13350
13351 if(numptr_m1->var == NULL) {
13352 /* Hmm, 1=2 ? */
13353 goto err;
13354 }
13355 /* save to shell variable */
Eric Andersenad63cb22004-10-08 09:43:34 +000013356 snprintf(buf, sizeof(buf), "%lld", (long long) rez);
Eric Andersen90898442003-08-06 11:20:52 +000013357 setvar(numptr_m1->var, buf, 0);
13358 /* after saving, make previous value for v++ or v-- */
13359 if(op == TOK_POST_INC)
13360 rez--;
13361 else if(op == TOK_POST_DEC)
13362 rez++;
13363 }
13364 numptr_m1->val = rez;
13365 /* protect geting var value, is number now */
13366 numptr_m1->var = NULL;
13367 return 0;
13368err: return(-1);
13369}
13370
13371/* longest must first */
13372static const char op_tokens[] = {
13373 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13374 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13375 '<','<', 0, TOK_LSHIFT,
13376 '>','>', 0, TOK_RSHIFT,
13377 '|','|', 0, TOK_OR,
13378 '&','&', 0, TOK_AND,
13379 '!','=', 0, TOK_NE,
13380 '<','=', 0, TOK_LE,
13381 '>','=', 0, TOK_GE,
13382 '=','=', 0, TOK_EQ,
13383 '|','=', 0, TOK_OR_ASSIGN,
13384 '&','=', 0, TOK_AND_ASSIGN,
13385 '*','=', 0, TOK_MUL_ASSIGN,
13386 '/','=', 0, TOK_DIV_ASSIGN,
13387 '%','=', 0, TOK_REM_ASSIGN,
13388 '+','=', 0, TOK_PLUS_ASSIGN,
13389 '-','=', 0, TOK_MINUS_ASSIGN,
13390 '-','-', 0, TOK_POST_DEC,
13391 '^','=', 0, TOK_XOR_ASSIGN,
13392 '+','+', 0, TOK_POST_INC,
13393 '*','*', 0, TOK_EXPONENT,
13394 '!', 0, TOK_NOT,
13395 '<', 0, TOK_LT,
13396 '>', 0, TOK_GT,
13397 '=', 0, TOK_ASSIGN,
13398 '|', 0, TOK_BOR,
13399 '&', 0, TOK_BAND,
13400 '*', 0, TOK_MUL,
13401 '/', 0, TOK_DIV,
13402 '%', 0, TOK_REM,
13403 '+', 0, TOK_ADD,
13404 '-', 0, TOK_SUB,
13405 '^', 0, TOK_BXOR,
13406 /* uniq */
13407 '~', 0, TOK_BNOT,
13408 ',', 0, TOK_COMMA,
13409 '?', 0, TOK_CONDITIONAL,
13410 ':', 0, TOK_CONDITIONAL_SEP,
13411 ')', 0, TOK_RPAREN,
13412 '(', 0, TOK_LPAREN,
13413 0
13414};
13415/* ptr to ")" */
13416#define endexpression &op_tokens[sizeof(op_tokens)-7]
13417
13418
Eric Andersened9ecf72004-06-22 08:29:45 +000013419static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013420{
13421 register char arithval; /* Current character under analysis */
13422 operator lasttok, op;
13423 operator prec;
13424
13425 const char *p = endexpression;
13426 int errcode;
13427
13428 size_t datasizes = strlen(expr) + 2;
13429
13430 /* Stack of integers */
13431 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013432 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013433 * the reader. */
13434 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13435 *numstackptr = numstack;
13436 /* Stack of operator tokens */
13437 operator *stack = alloca((datasizes) * sizeof(operator)),
13438 *stackptr = stack;
13439
13440 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13441 *perrcode = errcode = 0;
13442
13443 while(1) {
13444 if ((arithval = *expr) == 0) {
13445 if (p == endexpression) {
13446 /* Null expression. */
13447 return 0;
13448 }
13449
13450 /* This is only reached after all tokens have been extracted from the
13451 * input stream. If there are still tokens on the operator stack, they
13452 * are to be applied in order. At the end, there should be a final
13453 * result on the integer stack */
13454
13455 if (expr != endexpression + 1) {
13456 /* If we haven't done so already, */
13457 /* append a closing right paren */
13458 expr = endexpression;
13459 /* and let the loop process it. */
13460 continue;
13461 }
13462 /* At this point, we're done with the expression. */
13463 if (numstackptr != numstack+1) {
13464 /* ... but if there isn't, it's bad */
13465 err:
13466 return (*perrcode = -1);
13467 }
13468 if(numstack->var) {
13469 /* expression is $((var)) only, lookup now */
13470 errcode = arith_lookup_val(numstack);
13471 }
13472 ret:
13473 *perrcode = errcode;
13474 return numstack->val;
13475 } else {
13476 /* Continue processing the expression. */
13477 if (arith_isspace(arithval)) {
13478 /* Skip whitespace */
13479 goto prologue;
13480 }
13481 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013482 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013483
13484 numstackptr->var = alloca(var_name_size);
13485 safe_strncpy(numstackptr->var, expr, var_name_size);
13486 expr = p;
13487 num:
13488 numstackptr->contidional_second_val_initialized = 0;
13489 numstackptr++;
13490 lasttok = TOK_NUM;
13491 continue;
13492 } else if (is_digit(arithval)) {
13493 numstackptr->var = NULL;
Eric Andersenad63cb22004-10-08 09:43:34 +000013494 numstackptr->val = strtoll(expr, (char **) &expr, 0);
Eric Andersen90898442003-08-06 11:20:52 +000013495 goto num;
13496 }
13497 for(p = op_tokens; ; p++) {
13498 const char *o;
13499
13500 if(*p == 0) {
13501 /* strange operator not found */
13502 goto err;
13503 }
13504 for(o = expr; *p && *o == *p; p++)
13505 o++;
13506 if(! *p) {
13507 /* found */
13508 expr = o - 1;
13509 break;
13510 }
13511 /* skip tail uncompared token */
13512 while(*p)
13513 p++;
13514 /* skip zero delim */
13515 p++;
13516 }
13517 op = p[1];
13518
13519 /* post grammar: a++ reduce to num */
13520 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13521 lasttok = TOK_NUM;
13522
13523 /* Plus and minus are binary (not unary) _only_ if the last
13524 * token was as number, or a right paren (which pretends to be
13525 * a number, since it evaluates to one). Think about it.
13526 * It makes sense. */
13527 if (lasttok != TOK_NUM) {
13528 switch(op) {
13529 case TOK_ADD:
13530 op = TOK_UPLUS;
13531 break;
13532 case TOK_SUB:
13533 op = TOK_UMINUS;
13534 break;
13535 case TOK_POST_INC:
13536 op = TOK_PRE_INC;
13537 break;
13538 case TOK_POST_DEC:
13539 op = TOK_PRE_DEC;
13540 break;
13541 }
13542 }
13543 /* We don't want a unary operator to cause recursive descent on the
13544 * stack, because there can be many in a row and it could cause an
13545 * operator to be evaluated before its argument is pushed onto the
13546 * integer stack. */
13547 /* But for binary operators, "apply" everything on the operator
13548 * stack until we find an operator with a lesser priority than the
13549 * one we have just extracted. */
13550 /* Left paren is given the lowest priority so it will never be
13551 * "applied" in this way.
13552 * if associativity is right and priority eq, applied also skip
13553 */
13554 prec = PREC(op);
13555 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13556 /* not left paren or unary */
13557 if (lasttok != TOK_NUM) {
13558 /* binary op must be preceded by a num */
13559 goto err;
13560 }
13561 while (stackptr != stack) {
13562 if (op == TOK_RPAREN) {
13563 /* The algorithm employed here is simple: while we don't
13564 * hit an open paren nor the bottom of the stack, pop
13565 * tokens and apply them */
13566 if (stackptr[-1] == TOK_LPAREN) {
13567 --stackptr;
13568 /* Any operator directly after a */
13569 lasttok = TOK_NUM;
13570 /* close paren should consider itself binary */
13571 goto prologue;
13572 }
13573 } else {
13574 operator prev_prec = PREC(stackptr[-1]);
13575
13576 convert_prec_is_assing(prec);
13577 convert_prec_is_assing(prev_prec);
13578 if (prev_prec < prec)
13579 break;
13580 /* check right assoc */
13581 if(prev_prec == prec && is_right_associativity(prec))
13582 break;
13583 }
13584 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13585 if(errcode) goto ret;
13586 }
13587 if (op == TOK_RPAREN) {
13588 goto err;
13589 }
13590 }
13591
13592 /* Push this operator to the stack and remember it. */
13593 *stackptr++ = lasttok = op;
13594
13595 prologue:
13596 ++expr;
13597 }
13598 }
13599}
13600#endif /* CONFIG_ASH_MATH_SUPPORT */
13601
13602
Eric Andersenc470f442003-07-28 09:56:35 +000013603#ifdef DEBUG
13604const char *bb_applet_name = "debug stuff usage";
13605int main(int argc, char **argv)
13606{
13607 return ash_main(argc, argv);
13608}
13609#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013610
Eric Andersendf82f612001-06-28 07:46:40 +000013611/*-
13612 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013613 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013614 *
13615 * This code is derived from software contributed to Berkeley by
13616 * Kenneth Almquist.
13617 *
13618 * Redistribution and use in source and binary forms, with or without
13619 * modification, are permitted provided that the following conditions
13620 * are met:
13621 * 1. Redistributions of source code must retain the above copyright
13622 * notice, this list of conditions and the following disclaimer.
13623 * 2. Redistributions in binary form must reproduce the above copyright
13624 * notice, this list of conditions and the following disclaimer in the
13625 * documentation and/or other materials provided with the distribution.
13626 *
Eric Andersen2870d962001-07-02 17:27:21 +000013627 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13628 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013629 *
13630 * 4. Neither the name of the University nor the names of its contributors
13631 * may be used to endorse or promote products derived from this software
13632 * without specific prior written permission.
13633 *
13634 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13635 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13636 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13637 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13638 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13639 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13640 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13641 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13642 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13643 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13644 * SUCH DAMAGE.
13645 */