blob: 5ebc8acedd6b6f7599b353a602021429715a8e14 [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
177 * contains a code identifying the exeception. To implement nested
178 * 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
Eric Andersenc470f442003-07-28 09:56:35 +0000215#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
216#define INTOFF \
217 ({ \
218 suppressint++; \
219 barrier(); \
220 0; \
221 })
222#define SAVEINT(v) ((v) = suppressint)
223#define RESTOREINT(v) \
224 ({ \
225 barrier(); \
226 if ((suppressint = (v)) == 0 && intpending) onint(); \
227 0; \
228 })
229#define EXSIGON() \
230 ({ \
231 exsig++; \
232 barrier(); \
233 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 ({ \
266 barrier(); \
267 if (--suppressint == 0 && intpending) onint(); \
268 0; \
269 })
270#define FORCEINTON \
271 ({ \
272 barrier(); \
273 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
627#define likely(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
1448#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen009617f2004-04-05 13:24:07 +00001449static long dash_arith(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001450#endif
1451
Eric Andersen16767e22004-03-16 05:14:10 +00001452#ifdef CONFIG_ASH_RANDOM_SUPPORT
1453static unsigned long rseed;
1454static void change_random(const char *);
1455# ifndef DYNAMIC_VAR
1456# define DYNAMIC_VAR
1457# endif
1458#endif
1459
Eric Andersenc470f442003-07-28 09:56:35 +00001460/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1461
1462static void reset(void);
1463
1464/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001465
1466/*
1467 * Shell variables.
1468 */
1469
1470/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001471#define VEXPORT 0x01 /* variable is exported */
1472#define VREADONLY 0x02 /* variable cannot be modified */
1473#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1474#define VTEXTFIXED 0x08 /* text is statically allocated */
1475#define VSTACK 0x10 /* text is allocated on the stack */
1476#define VUNSET 0x20 /* the variable is not set */
1477#define VNOFUNC 0x40 /* don't call the callback function */
1478#define VNOSET 0x80 /* do not set variable - just readonly test */
1479#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001480#ifdef DYNAMIC_VAR
1481# define VDYNAMIC 0x200 /* dynamic variable */
1482# else
1483# define VDYNAMIC 0
1484#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001485
1486struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001487 struct var *next; /* next entry in hash list */
1488 int flags; /* flags are defined above */
1489 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001490 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001491 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001492};
1493
1494struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001495 struct localvar *next; /* next local variable in list */
1496 struct var *vp; /* the variable that was made local */
1497 int flags; /* saved flags */
1498 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001499};
1500
1501
Eric Andersen2870d962001-07-02 17:27:21 +00001502static struct localvar *localvars;
1503
Eric Andersenc470f442003-07-28 09:56:35 +00001504/*
1505 * Shell variables.
1506 */
1507
1508#ifdef CONFIG_ASH_GETOPTS
1509static void getoptsreset(const char *);
1510#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001511
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001512#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001513#include <locale.h>
1514static void change_lc_all(const char *value);
1515static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001516#endif
1517
Eric Andersenef02f822004-03-11 13:34:24 +00001518
Eric Andersen2870d962001-07-02 17:27:21 +00001519#define VTABSIZE 39
1520
Eric Andersen90898442003-08-06 11:20:52 +00001521static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001522#ifdef IFS_BROKEN
1523static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001524#define defifs (defifsvar + 4)
1525#else
Eric Andersenc470f442003-07-28 09:56:35 +00001526static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001527#endif
1528
Eric Andersenc470f442003-07-28 09:56:35 +00001529
1530static struct var varinit[] = {
1531#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001532 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001533#else
Eric Andersen16767e22004-03-16 05:14:10 +00001534 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001535#endif
1536
1537#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001538 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1539 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001540#endif
1541
Eric Andersen16767e22004-03-16 05:14:10 +00001542 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1543 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1544 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1545 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001546#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001547 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1548#endif
1549#ifdef CONFIG_ASH_RANDOM_SUPPORT
1550 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001551#endif
1552#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001553 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1554 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001555#endif
1556#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001557 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001558#endif
1559};
1560
1561#define vifs varinit[0]
1562#ifdef CONFIG_ASH_MAIL
1563#define vmail (&vifs)[1]
1564#define vmpath (&vmail)[1]
1565#else
1566#define vmpath vifs
1567#endif
1568#define vpath (&vmpath)[1]
1569#define vps1 (&vpath)[1]
1570#define vps2 (&vps1)[1]
1571#define vps4 (&vps2)[1]
1572#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001573#ifdef CONFIG_ASH_GETOPTS
1574#define vrandom (&voptind)[1]
1575#else
1576#define vrandom (&vps4)[1]
1577#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001578#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001579
1580/*
1581 * The following macros access the values of the above variables.
1582 * They have to skip over the name. They return the null string
1583 * for unset variables.
1584 */
1585
1586#define ifsval() (vifs.text + 4)
1587#define ifsset() ((vifs.flags & VUNSET) == 0)
1588#define mailval() (vmail.text + 5)
1589#define mpathval() (vmpath.text + 9)
1590#define pathval() (vpath.text + 5)
1591#define ps1val() (vps1.text + 4)
1592#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001593#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001594#define optindval() (voptind.text + 7)
1595
1596#define mpathset() ((vmpath.flags & VUNSET) == 0)
1597
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001598static void setvar(const char *, const char *, int);
1599static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001600static void listsetvar(struct strlist *, int);
1601static char *lookupvar(const char *);
1602static char *bltinlookup(const char *);
1603static char **listvars(int, int, char ***);
1604#define environment() listvars(VEXPORT, VUNSET, 0)
1605static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001606static void poplocalvars(void);
1607static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001608#ifdef CONFIG_ASH_GETOPTS
1609static int setvarsafe(const char *, const char *, int);
1610#endif
1611static int varcmp(const char *, const char *);
1612static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001613
1614
Eric Andersenc470f442003-07-28 09:56:35 +00001615static inline int varequal(const char *a, const char *b) {
1616 return !varcmp(a, b);
1617}
Eric Andersen2870d962001-07-02 17:27:21 +00001618
1619
Eric Andersenc470f442003-07-28 09:56:35 +00001620static int loopnest; /* current loop nesting level */
1621
Eric Andersenc470f442003-07-28 09:56:35 +00001622/*
1623 * The parsefile structure pointed to by the global variable parsefile
1624 * contains information about the current file being read.
1625 */
1626
1627
1628struct redirtab {
1629 struct redirtab *next;
1630 int renamed[10];
1631 int nullredirs;
1632};
1633
1634static struct redirtab *redirlist;
1635static int nullredirs;
1636
1637extern char **environ;
1638
1639/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1640
1641
1642static void outstr(const char *, FILE *);
1643static void outcslow(int, FILE *);
1644static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001645static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001646static int out1fmt(const char *, ...)
1647 __attribute__((__format__(__printf__,1,2)));
1648static int fmtstr(char *, size_t, const char *, ...)
1649 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001650
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001651static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001652
Eric Andersenc470f442003-07-28 09:56:35 +00001653
1654static void out1str(const char *p)
1655{
1656 outstr(p, stdout);
1657}
1658
1659static void out2str(const char *p)
1660{
1661 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001662 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001663}
1664
1665/*
1666 * Initialization code.
1667 */
1668
1669/*
1670 * This routine initializes the builtin variables.
1671 */
1672
1673static inline void
1674initvar(void)
1675{
1676 struct var *vp;
1677 struct var *end;
1678 struct var **vpp;
1679
1680 /*
1681 * PS1 depends on uid
1682 */
1683#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1684 vps1.text = "PS1=\\w \\$ ";
1685#else
1686 if (!geteuid())
1687 vps1.text = "PS1=# ";
1688#endif
1689 vp = varinit;
1690 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1691 do {
1692 vpp = hashvar(vp->text);
1693 vp->next = *vpp;
1694 *vpp = vp;
1695 } while (++vp < end);
1696}
1697
1698static inline void
1699init(void)
1700{
1701
1702 /* from input.c: */
1703 {
1704 basepf.nextc = basepf.buf = basebuf;
1705 }
1706
1707 /* from trap.c: */
1708 {
1709 signal(SIGCHLD, SIG_DFL);
1710 }
1711
1712 /* from var.c: */
1713 {
1714 char **envp;
1715 char ppid[32];
1716
1717 initvar();
1718 for (envp = environ ; *envp ; envp++) {
1719 if (strchr(*envp, '=')) {
1720 setvareq(*envp, VEXPORT|VTEXTFIXED);
1721 }
1722 }
1723
1724 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1725 setvar("PPID", ppid, 0);
1726 setpwd(0, 0);
1727 }
1728}
1729
1730/* PEOF (the end of file marker) */
1731
1732/*
1733 * The input line number. Input.c just defines this variable, and saves
1734 * and restores it when files are pushed and popped. The user of this
1735 * package must set its value.
1736 */
1737
1738static int pgetc(void);
1739static int pgetc2(void);
1740static int preadbuffer(void);
1741static void pungetc(void);
1742static void pushstring(char *, void *);
1743static void popstring(void);
1744static void setinputfile(const char *, int);
1745static void setinputfd(int, int);
1746static void setinputstring(char *);
1747static void popfile(void);
1748static void popallfiles(void);
1749static void closescript(void);
1750
1751
1752/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1753
1754
1755/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1756#define FORK_FG 0
1757#define FORK_BG 1
1758#define FORK_NOJOB 2
1759
1760/* mode flags for showjob(s) */
1761#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1762#define SHOW_PID 0x04 /* include process pid */
1763#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1764
1765
1766/*
1767 * A job structure contains information about a job. A job is either a
1768 * single process or a set of processes contained in a pipeline. In the
1769 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1770 * array of pids.
1771 */
1772
1773struct procstat {
1774 pid_t pid; /* process id */
1775 int status; /* last process status from wait() */
1776 char *cmd; /* text of command being run */
1777};
1778
1779struct job {
1780 struct procstat ps0; /* status of process */
1781 struct procstat *ps; /* status or processes when more than one */
1782#if JOBS
1783 int stopstatus; /* status of a stopped job */
1784#endif
1785 uint32_t
1786 nprocs: 16, /* number of processes */
1787 state: 8,
1788#define JOBRUNNING 0 /* at least one proc running */
1789#define JOBSTOPPED 1 /* all procs are stopped */
1790#define JOBDONE 2 /* all procs are completed */
1791#if JOBS
1792 sigint: 1, /* job was killed by SIGINT */
1793 jobctl: 1, /* job running under job control */
1794#endif
1795 waited: 1, /* true if this entry has been waited for */
1796 used: 1, /* true if this entry is in used */
1797 changed: 1; /* true if status has changed */
1798 struct job *prev_job; /* previous job */
1799};
1800
1801static pid_t backgndpid; /* pid of last background process */
1802static int job_warning; /* user was warned about stopped jobs */
1803#if JOBS
1804static int jobctl; /* true if doing job control */
1805#endif
1806
1807static struct job *makejob(union node *, int);
1808static int forkshell(struct job *, union node *, int);
1809static int waitforjob(struct job *);
1810static int stoppedjobs(void);
1811
1812#if ! JOBS
1813#define setjobctl(on) /* do nothing */
1814#else
1815static void setjobctl(int);
1816static void showjobs(FILE *, int);
1817#endif
1818
1819/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1820
1821
1822/* pid of main shell */
1823static int rootpid;
1824/* true if we aren't a child of the main shell */
1825static int rootshell;
1826
1827static void readcmdfile(char *);
1828static void cmdloop(int);
1829
1830/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1831
1832
1833struct stackmark {
1834 struct stack_block *stackp;
1835 char *stacknxt;
1836 size_t stacknleft;
1837 struct stackmark *marknext;
1838};
1839
1840/* minimum size of a block */
1841#define MINSIZE SHELL_ALIGN(504)
1842
1843struct stack_block {
1844 struct stack_block *prev;
1845 char space[MINSIZE];
1846};
1847
1848static struct stack_block stackbase;
1849static struct stack_block *stackp = &stackbase;
1850static struct stackmark *markp;
1851static char *stacknxt = stackbase.space;
1852static size_t stacknleft = MINSIZE;
1853static char *sstrend = stackbase.space + MINSIZE;
1854static int herefd = -1;
1855
1856
1857static pointer ckmalloc(size_t);
1858static pointer ckrealloc(pointer, size_t);
1859static char *savestr(const char *);
1860static pointer stalloc(size_t);
1861static void stunalloc(pointer);
1862static void setstackmark(struct stackmark *);
1863static void popstackmark(struct stackmark *);
1864static void growstackblock(void);
1865static void *growstackstr(void);
1866static char *makestrspace(size_t, char *);
1867static char *stnputs(const char *, size_t, char *);
1868static char *stputs(const char *, char *);
1869
1870
1871static inline char *_STPUTC(char c, char *p) {
1872 if (p == sstrend)
1873 p = growstackstr();
1874 *p++ = c;
1875 return p;
1876}
1877
1878#define stackblock() ((void *)stacknxt)
1879#define stackblocksize() stacknleft
1880#define STARTSTACKSTR(p) ((p) = stackblock())
1881#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1882#define CHECKSTRSPACE(n, p) \
1883 ({ \
1884 char *q = (p); \
1885 size_t l = (n); \
1886 size_t m = sstrend - q; \
1887 if (l > m) \
1888 (p) = makestrspace(l, q); \
1889 0; \
1890 })
1891#define USTPUTC(c, p) (*p++ = (c))
1892#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1893#define STUNPUTC(p) (--p)
1894#define STTOPC(p) p[-1]
1895#define STADJUST(amount, p) (p += (amount))
1896
1897#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1898#define ungrabstackstr(s, p) stunalloc((s))
1899#define stackstrend() ((void *)sstrend)
1900
1901#define ckfree(p) free((pointer)(p))
1902
1903/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1904
1905
1906#define DOLATSTRLEN 4
1907
1908static char *prefix(const char *, const char *);
1909static int number(const char *);
1910static int is_number(const char *);
1911static char *single_quote(const char *);
1912static char *sstrdup(const char *);
1913
1914#define equal(s1, s2) (strcmp(s1, s2) == 0)
1915#define scopy(s1, s2) ((void)strcpy(s2, s1))
1916
1917/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1918
1919struct shparam {
1920 int nparam; /* # of positional parameters (without $0) */
1921 unsigned char malloc; /* if parameter list dynamically allocated */
1922 char **p; /* parameter list */
1923#ifdef CONFIG_ASH_GETOPTS
1924 int optind; /* next parameter to be processed by getopts */
1925 int optoff; /* used by getopts */
1926#endif
1927};
1928
1929
1930#define eflag optlist[0]
1931#define fflag optlist[1]
1932#define Iflag optlist[2]
1933#define iflag optlist[3]
1934#define mflag optlist[4]
1935#define nflag optlist[5]
1936#define sflag optlist[6]
1937#define xflag optlist[7]
1938#define vflag optlist[8]
1939#define Cflag optlist[9]
1940#define aflag optlist[10]
1941#define bflag optlist[11]
1942#define uflag optlist[12]
1943#define qflag optlist[13]
1944
1945#ifdef DEBUG
1946#define nolog optlist[14]
1947#define debug optlist[15]
1948#define NOPTS 16
1949#else
1950#define NOPTS 14
1951#endif
1952
1953/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1954
1955
1956static const char *const optletters_optnames[NOPTS] = {
1957 "e" "errexit",
1958 "f" "noglob",
1959 "I" "ignoreeof",
1960 "i" "interactive",
1961 "m" "monitor",
1962 "n" "noexec",
1963 "s" "stdin",
1964 "x" "xtrace",
1965 "v" "verbose",
1966 "C" "noclobber",
1967 "a" "allexport",
1968 "b" "notify",
1969 "u" "nounset",
1970 "q" "quietprofile",
1971#ifdef DEBUG
1972 "\0" "nolog",
1973 "\0" "debug",
1974#endif
1975};
1976
1977#define optletters(n) optletters_optnames[(n)][0]
1978#define optnames(n) (&optletters_optnames[(n)][1])
1979
1980
1981static char optlist[NOPTS];
1982
1983
1984static char *arg0; /* value of $0 */
1985static struct shparam shellparam; /* $@ current positional parameters */
1986static char **argptr; /* argument list for builtin commands */
1987static char *optionarg; /* set by nextopt (like getopt) */
1988static char *optptr; /* used by nextopt */
1989
1990static char *minusc; /* argument to -c option */
1991
1992
1993static void procargs(int, char **);
1994static void optschanged(void);
1995static void setparam(char **);
1996static void freeparam(volatile struct shparam *);
1997static int shiftcmd(int, char **);
1998static int setcmd(int, char **);
1999static int nextopt(const char *);
2000
2001/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
2002
2003/* flags passed to redirect */
2004#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002005#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00002006
2007union node;
2008static void redirect(union node *, int);
2009static void popredir(int);
2010static void clearredir(int);
2011static int copyfd(int, int);
2012static int redirectsafe(union node *, int);
2013
2014/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2015
2016
2017#ifdef DEBUG
2018static void showtree(union node *);
2019static void trace(const char *, ...);
2020static void tracev(const char *, va_list);
2021static void trargs(char **);
2022static void trputc(int);
2023static void trputs(const char *);
2024static void opentrace(void);
2025#endif
2026
2027/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2028
2029
2030/* trap handler commands */
2031static char *trap[NSIG];
2032/* current value of signal */
2033static char sigmode[NSIG - 1];
2034/* indicates specified signal received */
2035static char gotsig[NSIG - 1];
2036
2037static void clear_traps(void);
2038static void setsignal(int);
2039static void ignoresig(int);
2040static void onsig(int);
2041static void dotrap(void);
2042static void setinteractive(int);
2043static void exitshell(void) __attribute__((__noreturn__));
2044static int decode_signal(const char *, int);
2045
2046/*
2047 * This routine is called when an error or an interrupt occurs in an
2048 * interactive shell and control is returned to the main command loop.
2049 */
2050
2051static void
2052reset(void)
2053{
2054 /* from eval.c: */
2055 {
2056 evalskip = 0;
2057 loopnest = 0;
2058 funcnest = 0;
2059 }
2060
2061 /* from input.c: */
2062 {
2063 parselleft = parsenleft = 0; /* clear input buffer */
2064 popallfiles();
2065 }
2066
2067 /* from parser.c: */
2068 {
2069 tokpushback = 0;
2070 checkkwd = 0;
2071 }
2072
2073 /* from redir.c: */
2074 {
2075 clearredir(0);
2076 }
2077
2078}
2079
2080#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002081static struct alias *atab[ATABSIZE];
2082
Eric Andersenc470f442003-07-28 09:56:35 +00002083static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002084static struct alias *freealias(struct alias *);
2085static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002086
Eric Andersenc470f442003-07-28 09:56:35 +00002087static void
2088setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002089{
2090 struct alias *ap, **app;
2091
2092 app = __lookupalias(name);
2093 ap = *app;
2094 INTOFF;
2095 if (ap) {
2096 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002097 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002098 }
Eric Andersenc470f442003-07-28 09:56:35 +00002099 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002100 ap->flag &= ~ALIASDEAD;
2101 } else {
2102 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002103 ap = ckmalloc(sizeof (struct alias));
2104 ap->name = savestr(name);
2105 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002106 ap->flag = 0;
2107 ap->next = 0;
2108 *app = ap;
2109 }
2110 INTON;
2111}
2112
Eric Andersenc470f442003-07-28 09:56:35 +00002113static int
2114unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002115{
Eric Andersencb57d552001-06-28 07:25:16 +00002116 struct alias **app;
2117
2118 app = __lookupalias(name);
2119
2120 if (*app) {
2121 INTOFF;
2122 *app = freealias(*app);
2123 INTON;
2124 return (0);
2125 }
2126
2127 return (1);
2128}
2129
Eric Andersenc470f442003-07-28 09:56:35 +00002130static void
2131rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002132{
Eric Andersencb57d552001-06-28 07:25:16 +00002133 struct alias *ap, **app;
2134 int i;
2135
2136 INTOFF;
2137 for (i = 0; i < ATABSIZE; i++) {
2138 app = &atab[i];
2139 for (ap = *app; ap; ap = *app) {
2140 *app = freealias(*app);
2141 if (ap == *app) {
2142 app = &ap->next;
2143 }
2144 }
2145 }
2146 INTON;
2147}
2148
Eric Andersenc470f442003-07-28 09:56:35 +00002149static struct alias *
2150lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002151{
Eric Andersenc470f442003-07-28 09:56:35 +00002152 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002153
Eric Andersenc470f442003-07-28 09:56:35 +00002154 if (check && ap && (ap->flag & ALIASINUSE))
2155 return (NULL);
2156 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002157}
2158
Eric Andersencb57d552001-06-28 07:25:16 +00002159/*
2160 * TODO - sort output
2161 */
Eric Andersenc470f442003-07-28 09:56:35 +00002162static int
2163aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002164{
2165 char *n, *v;
2166 int ret = 0;
2167 struct alias *ap;
2168
2169 if (argc == 1) {
2170 int i;
2171
2172 for (i = 0; i < ATABSIZE; i++)
2173 for (ap = atab[i]; ap; ap = ap->next) {
2174 printalias(ap);
2175 }
2176 return (0);
2177 }
2178 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002179 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002180 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002181 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002182 ret = 1;
2183 } else
2184 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002185 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002186 *v++ = '\0';
2187 setalias(n, v);
2188 }
2189 }
2190
2191 return (ret);
2192}
2193
Eric Andersenc470f442003-07-28 09:56:35 +00002194static int
2195unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002196{
2197 int i;
2198
2199 while ((i = nextopt("a")) != '\0') {
2200 if (i == 'a') {
2201 rmaliases();
2202 return (0);
2203 }
2204 }
2205 for (i = 0; *argptr; argptr++) {
2206 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002207 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002208 i = 1;
2209 }
2210 }
2211
2212 return (i);
2213}
2214
Eric Andersenc470f442003-07-28 09:56:35 +00002215static struct alias *
2216freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002217 struct alias *next;
2218
2219 if (ap->flag & ALIASINUSE) {
2220 ap->flag |= ALIASDEAD;
2221 return ap;
2222 }
2223
2224 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002225 ckfree(ap->name);
2226 ckfree(ap->val);
2227 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002228 return next;
2229}
2230
Eric Andersenc470f442003-07-28 09:56:35 +00002231static void
2232printalias(const struct alias *ap) {
2233 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2234}
Eric Andersencb57d552001-06-28 07:25:16 +00002235
Eric Andersenc470f442003-07-28 09:56:35 +00002236static struct alias **
2237__lookupalias(const char *name) {
2238 unsigned int hashval;
2239 struct alias **app;
2240 const char *p;
2241 unsigned int ch;
2242
2243 p = name;
2244
2245 ch = (unsigned char)*p;
2246 hashval = ch << 4;
2247 while (ch) {
2248 hashval += ch;
2249 ch = (unsigned char)*++p;
2250 }
2251 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002252
2253 for (; *app; app = &(*app)->next) {
2254 if (equal(name, (*app)->name)) {
2255 break;
2256 }
2257 }
2258
2259 return app;
2260}
Eric Andersenc470f442003-07-28 09:56:35 +00002261#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002262
Eric Andersencb57d552001-06-28 07:25:16 +00002263
Eric Andersenc470f442003-07-28 09:56:35 +00002264/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00002265
Eric Andersencb57d552001-06-28 07:25:16 +00002266/*
Eric Andersenc470f442003-07-28 09:56:35 +00002267 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002268 */
2269
Eric Andersenc470f442003-07-28 09:56:35 +00002270#define CD_PHYSICAL 1
2271#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002272
Eric Andersenc470f442003-07-28 09:56:35 +00002273static int docd(const char *, int);
2274static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002275
Eric Andersenc470f442003-07-28 09:56:35 +00002276static char *curdir = nullstr; /* current working directory */
2277static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002278
Eric Andersenc470f442003-07-28 09:56:35 +00002279static int
2280cdopt(void)
2281{
2282 int flags = 0;
2283 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002284
Eric Andersenc470f442003-07-28 09:56:35 +00002285 j = 'L';
2286 while ((i = nextopt("LP"))) {
2287 if (i != j) {
2288 flags ^= CD_PHYSICAL;
2289 j = i;
2290 }
2291 }
Eric Andersencb57d552001-06-28 07:25:16 +00002292
Eric Andersenc470f442003-07-28 09:56:35 +00002293 return flags;
2294}
Eric Andersen2870d962001-07-02 17:27:21 +00002295
Eric Andersenc470f442003-07-28 09:56:35 +00002296static int
2297cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002298{
2299 const char *dest;
2300 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002301 const char *p;
2302 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002303 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002304 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002305
Eric Andersenc470f442003-07-28 09:56:35 +00002306 flags = cdopt();
2307 dest = *argptr;
2308 if (!dest)
2309 dest = bltinlookup(homestr);
2310 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002311 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002312 flags |= CD_PRINT;
2313 goto step7;
Eric Andersencb57d552001-06-28 07:25:16 +00002314 }
Eric Andersenc470f442003-07-28 09:56:35 +00002315 if (!dest)
2316 dest = nullstr;
2317 if (*dest == '/')
2318 goto step7;
2319 if (*dest == '.') {
2320 c = dest[1];
2321dotdot:
2322 switch (c) {
2323 case '\0':
2324 case '/':
2325 goto step6;
2326 case '.':
2327 c = dest[2];
2328 if (c != '.')
2329 goto dotdot;
2330 }
2331 }
2332 if (!*dest)
2333 dest = ".";
2334 if (!(path = bltinlookup("CDPATH"))) {
2335step6:
2336step7:
2337 p = dest;
2338 goto docd;
2339 }
2340 do {
2341 c = *path;
2342 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002343 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002344 if (c && c != ':')
2345 flags |= CD_PRINT;
2346docd:
2347 if (!docd(p, flags))
2348 goto out;
2349 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002350 }
Eric Andersenc470f442003-07-28 09:56:35 +00002351 } while (path);
Eric Andersencb57d552001-06-28 07:25:16 +00002352 error("can't cd to %s", dest);
2353 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002354out:
2355 if (flags & CD_PRINT)
2356 out1fmt(snlfmt, curdir);
2357 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002358}
2359
2360
2361/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002362 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002363 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002364 */
2365
Eric Andersenc470f442003-07-28 09:56:35 +00002366static inline const char *
2367updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002368{
Eric Andersenc470f442003-07-28 09:56:35 +00002369 char *new;
2370 char *p;
2371 char *cdcomppath;
2372 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002373
Eric Andersenc470f442003-07-28 09:56:35 +00002374 cdcomppath = sstrdup(dir);
2375 STARTSTACKSTR(new);
2376 if (*dir != '/') {
2377 if (curdir == nullstr)
2378 return 0;
2379 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002380 }
Eric Andersenc470f442003-07-28 09:56:35 +00002381 new = makestrspace(strlen(dir) + 2, new);
2382 lim = stackblock() + 1;
2383 if (*dir != '/') {
2384 if (new[-1] != '/')
2385 USTPUTC('/', new);
2386 if (new > lim && *lim == '/')
2387 lim++;
2388 } else {
2389 USTPUTC('/', new);
2390 cdcomppath++;
2391 if (dir[1] == '/' && dir[2] != '/') {
2392 USTPUTC('/', new);
2393 cdcomppath++;
2394 lim++;
2395 }
2396 }
2397 p = strtok(cdcomppath, "/");
2398 while (p) {
2399 switch(*p) {
2400 case '.':
2401 if (p[1] == '.' && p[2] == '\0') {
2402 while (new > lim) {
2403 STUNPUTC(new);
2404 if (new[-1] == '/')
2405 break;
2406 }
2407 break;
2408 } else if (p[1] == '\0')
2409 break;
2410 /* fall through */
2411 default:
2412 new = stputs(p, new);
2413 USTPUTC('/', new);
2414 }
2415 p = strtok(0, "/");
2416 }
2417 if (new > lim)
2418 STUNPUTC(new);
2419 *new = 0;
2420 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002421}
2422
2423/*
Eric Andersenc470f442003-07-28 09:56:35 +00002424 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2425 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002426 */
2427
Eric Andersenc470f442003-07-28 09:56:35 +00002428static int
2429docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002430{
Eric Andersenc470f442003-07-28 09:56:35 +00002431 const char *dir = 0;
2432 int err;
2433
2434 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2435
Eric Andersencb57d552001-06-28 07:25:16 +00002436 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002437 if (!(flags & CD_PHYSICAL)) {
2438 dir = updatepwd(dest);
2439 if (dir)
2440 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002441 }
Eric Andersenc470f442003-07-28 09:56:35 +00002442 err = chdir(dest);
2443 if (err)
2444 goto out;
2445 setpwd(dir, 1);
2446 hashcd();
2447out:
Eric Andersencb57d552001-06-28 07:25:16 +00002448 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002449 return err;
2450}
2451
2452/*
2453 * Find out what the current directory is. If we already know the current
2454 * directory, this routine returns immediately.
2455 */
2456static inline char *
2457getpwd(void)
2458{
2459 char *dir = getcwd(0, 0);
2460 return dir ? dir : nullstr;
2461}
2462
2463static int
2464pwdcmd(int argc, char **argv)
2465{
2466 int flags;
2467 const char *dir = curdir;
2468
2469 flags = cdopt();
2470 if (flags) {
2471 if (physdir == nullstr)
2472 setpwd(dir, 0);
2473 dir = physdir;
2474 }
2475 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002476 return 0;
2477}
2478
Eric Andersenc470f442003-07-28 09:56:35 +00002479static void
2480setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002481{
Eric Andersenc470f442003-07-28 09:56:35 +00002482 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002483
Eric Andersenc470f442003-07-28 09:56:35 +00002484 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002485
Eric Andersencb57d552001-06-28 07:25:16 +00002486 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002487 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002488 }
2489 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002490 if (physdir != nullstr) {
2491 if (physdir != oldcur)
2492 free(physdir);
2493 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002494 }
Eric Andersenc470f442003-07-28 09:56:35 +00002495 if (oldcur == val || !val) {
2496 char *s = getpwd();
2497 physdir = s;
2498 if (!val)
2499 dir = s;
2500 } else
2501 dir = savestr(val);
2502 if (oldcur != dir && oldcur != nullstr) {
2503 free(oldcur);
2504 }
2505 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002506 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002507 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002508}
2509
Eric Andersenc470f442003-07-28 09:56:35 +00002510/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2511
Eric Andersencb57d552001-06-28 07:25:16 +00002512/*
2513 * Errors and exceptions.
2514 */
2515
2516/*
2517 * Code to handle exceptions in C.
2518 */
2519
Eric Andersen2870d962001-07-02 17:27:21 +00002520
Eric Andersencb57d552001-06-28 07:25:16 +00002521
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002522static void exverror(int, const char *, va_list)
Eric Andersenc470f442003-07-28 09:56:35 +00002523 __attribute__((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00002524
2525/*
2526 * Called to raise an exception. Since C doesn't include exceptions, we
2527 * just do a longjmp to the exception handler. The type of exception is
2528 * stored in the global variable "exception".
2529 */
2530
Eric Andersenc470f442003-07-28 09:56:35 +00002531static void
2532exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002533{
2534#ifdef DEBUG
2535 if (handler == NULL)
2536 abort();
2537#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002538 INTOFF;
2539
Eric Andersencb57d552001-06-28 07:25:16 +00002540 exception = e;
2541 longjmp(handler->loc, 1);
2542}
2543
2544
2545/*
2546 * Called from trap.c when a SIGINT is received. (If the user specifies
2547 * that SIGINT is to be trapped or ignored using the trap builtin, then
2548 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002549 * are held using the INTOFF macro. (The test for iflag is just
2550 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002551 */
2552
Eric Andersenc470f442003-07-28 09:56:35 +00002553static void
2554onint(void) {
2555 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002556
Eric Andersencb57d552001-06-28 07:25:16 +00002557 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002558 sigsetmask(0);
2559 i = EXSIG;
2560 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2561 if (!(rootshell && iflag)) {
2562 signal(SIGINT, SIG_DFL);
2563 raise(SIGINT);
2564 }
2565 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002566 }
Eric Andersenc470f442003-07-28 09:56:35 +00002567 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002568 /* NOTREACHED */
2569}
2570
Eric Andersenc470f442003-07-28 09:56:35 +00002571static void
2572exvwarning(const char *msg, va_list ap)
2573{
2574 FILE *errs;
2575 const char *name;
2576 const char *fmt;
Eric Andersencb57d552001-06-28 07:25:16 +00002577
Eric Andersenc470f442003-07-28 09:56:35 +00002578 errs = stderr;
2579 name = arg0;
2580 fmt = "%s: ";
2581 if (commandname) {
2582 name = commandname;
2583 fmt = "%s: %d: ";
2584 }
2585 fprintf(errs, fmt, name, startlinno);
2586 vfprintf(errs, msg, ap);
2587 outcslow('\n', errs);
2588}
Eric Andersen2870d962001-07-02 17:27:21 +00002589
Eric Andersencb57d552001-06-28 07:25:16 +00002590/*
Eric Andersenc470f442003-07-28 09:56:35 +00002591 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002592 * is not NULL then error prints an error message using printf style
2593 * formatting. It then raises the error exception.
2594 */
Eric Andersenc470f442003-07-28 09:56:35 +00002595static void
2596exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002597{
Eric Andersencb57d552001-06-28 07:25:16 +00002598#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002599 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002600 TRACE(("exverror(%d, \"", cond));
2601 TRACEV((msg, ap));
2602 TRACE(("\") pid=%d\n", getpid()));
2603 } else
2604 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2605 if (msg)
2606#endif
2607 exvwarning(msg, ap);
2608
2609 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002610 exraise(cond);
2611 /* NOTREACHED */
2612}
2613
2614
Eric Andersenc470f442003-07-28 09:56:35 +00002615static void
2616error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002617{
Eric Andersencb57d552001-06-28 07:25:16 +00002618 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002619
Eric Andersencb57d552001-06-28 07:25:16 +00002620 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002621 exverror(EXERROR, msg, ap);
2622 /* NOTREACHED */
2623 va_end(ap);
2624}
2625
2626
Eric Andersenc470f442003-07-28 09:56:35 +00002627static void
2628exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002629{
Eric Andersencb57d552001-06-28 07:25:16 +00002630 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002631
Eric Andersencb57d552001-06-28 07:25:16 +00002632 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002633 exverror(cond, msg, ap);
2634 /* NOTREACHED */
2635 va_end(ap);
2636}
2637
Eric Andersencb57d552001-06-28 07:25:16 +00002638/*
Eric Andersenc470f442003-07-28 09:56:35 +00002639 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002640 */
2641
Eric Andersenc470f442003-07-28 09:56:35 +00002642static void
2643sh_warnx(const char *fmt, ...)
2644{
2645 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002646
Eric Andersenc470f442003-07-28 09:56:35 +00002647 va_start(ap, fmt);
2648 exvwarning(fmt, ap);
2649 va_end(ap);
2650}
Eric Andersen2870d962001-07-02 17:27:21 +00002651
Eric Andersencb57d552001-06-28 07:25:16 +00002652
2653/*
2654 * Return a string describing an error. The returned string may be a
2655 * pointer to a static buffer that will be overwritten on the next call.
2656 * Action describes the operation that got the error.
2657 */
2658
Eric Andersenc470f442003-07-28 09:56:35 +00002659static const char *
2660errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002661{
Eric Andersenc470f442003-07-28 09:56:35 +00002662 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002663
Eric Andersenc470f442003-07-28 09:56:35 +00002664 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002665 }
Eric Andersenc470f442003-07-28 09:56:35 +00002666 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002667}
2668
2669
Eric Andersenc470f442003-07-28 09:56:35 +00002670/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2671
2672/*
2673 * Evaluate a command.
2674 */
Eric Andersencb57d552001-06-28 07:25:16 +00002675
2676/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002677#define EV_EXIT 01 /* exit after evaluating tree */
2678#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2679#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002680
2681
Eric Andersenc470f442003-07-28 09:56:35 +00002682static void evalloop(union node *, int);
2683static void evalfor(union node *, int);
2684static void evalcase(union node *, int);
2685static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002686static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002687static void evalpipe(union node *, int);
2688static void evalcommand(union node *, int);
2689static int evalbltin(const struct builtincmd *, int, char **);
2690static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002691static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002692static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002693
Eric Andersenc470f442003-07-28 09:56:35 +00002694
2695static const struct builtincmd bltin = {
2696 "\0\0", bltincmd
2697};
2698
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002699
Eric Andersencb57d552001-06-28 07:25:16 +00002700/*
2701 * Called to reset things after an exception.
2702 */
2703
Eric Andersencb57d552001-06-28 07:25:16 +00002704/*
2705 * The eval commmand.
2706 */
2707
Eric Andersenc470f442003-07-28 09:56:35 +00002708static int
2709evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002710{
Eric Andersen2870d962001-07-02 17:27:21 +00002711 char *p;
2712 char *concat;
2713 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002714
Eric Andersen2870d962001-07-02 17:27:21 +00002715 if (argc > 1) {
2716 p = argv[1];
2717 if (argc > 2) {
2718 STARTSTACKSTR(concat);
2719 ap = argv + 2;
2720 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002721 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002722 if ((p = *ap++) == NULL)
2723 break;
2724 STPUTC(' ', concat);
2725 }
2726 STPUTC('\0', concat);
2727 p = grabstackstr(concat);
2728 }
Glenn L McGrath76620622004-01-13 10:19:37 +00002729 evalstring(p);
Eric Andersen2870d962001-07-02 17:27:21 +00002730 }
2731 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002732}
2733
Eric Andersenc470f442003-07-28 09:56:35 +00002734
Eric Andersencb57d552001-06-28 07:25:16 +00002735/*
2736 * Execute a command or commands contained in a string.
2737 */
2738
Eric Andersenc470f442003-07-28 09:56:35 +00002739static void
Glenn L McGrath76620622004-01-13 10:19:37 +00002740evalstring(char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00002741{
Eric Andersencb57d552001-06-28 07:25:16 +00002742 union node *n;
2743 struct stackmark smark;
2744
2745 setstackmark(&smark);
2746 setinputstring(s);
Eric Andersenc470f442003-07-28 09:56:35 +00002747
Eric Andersencb57d552001-06-28 07:25:16 +00002748 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002749 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002750 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002751 if (evalskip)
2752 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002753 }
2754 popfile();
2755 popstackmark(&smark);
2756}
2757
Eric Andersenc470f442003-07-28 09:56:35 +00002758
Eric Andersen62483552001-07-10 06:09:16 +00002759
2760/*
Eric Andersenc470f442003-07-28 09:56:35 +00002761 * Evaluate a parse tree. The value is left in the global variable
2762 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002763 */
2764
Eric Andersenc470f442003-07-28 09:56:35 +00002765static void
2766evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002767{
Eric Andersenc470f442003-07-28 09:56:35 +00002768 int checkexit = 0;
2769 void (*evalfn)(union node *, int);
2770 unsigned isor;
2771 int status;
2772 if (n == NULL) {
2773 TRACE(("evaltree(NULL) called\n"));
2774 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002775 }
Eric Andersenc470f442003-07-28 09:56:35 +00002776 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2777 getpid(), n, n->type, flags));
2778 switch (n->type) {
2779 default:
2780#ifdef DEBUG
2781 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002782 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002783 break;
2784#endif
2785 case NNOT:
2786 evaltree(n->nnot.com, EV_TESTED);
2787 status = !exitstatus;
2788 goto setstatus;
2789 case NREDIR:
2790 expredir(n->nredir.redirect);
2791 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2792 if (!status) {
2793 evaltree(n->nredir.n, flags & EV_TESTED);
2794 status = exitstatus;
2795 }
2796 popredir(0);
2797 goto setstatus;
2798 case NCMD:
2799 evalfn = evalcommand;
2800checkexit:
2801 if (eflag && !(flags & EV_TESTED))
2802 checkexit = ~0;
2803 goto calleval;
2804 case NFOR:
2805 evalfn = evalfor;
2806 goto calleval;
2807 case NWHILE:
2808 case NUNTIL:
2809 evalfn = evalloop;
2810 goto calleval;
2811 case NSUBSHELL:
2812 case NBACKGND:
2813 evalfn = evalsubshell;
2814 goto calleval;
2815 case NPIPE:
2816 evalfn = evalpipe;
2817 goto checkexit;
2818 case NCASE:
2819 evalfn = evalcase;
2820 goto calleval;
2821 case NAND:
2822 case NOR:
2823 case NSEMI:
2824#if NAND + 1 != NOR
2825#error NAND + 1 != NOR
2826#endif
2827#if NOR + 1 != NSEMI
2828#error NOR + 1 != NSEMI
2829#endif
2830 isor = n->type - NAND;
2831 evaltree(
2832 n->nbinary.ch1,
2833 (flags | ((isor >> 1) - 1)) & EV_TESTED
2834 );
2835 if (!exitstatus == isor)
2836 break;
2837 if (!evalskip) {
2838 n = n->nbinary.ch2;
2839evaln:
2840 evalfn = evaltree;
2841calleval:
2842 evalfn(n, flags);
2843 break;
2844 }
2845 break;
2846 case NIF:
2847 evaltree(n->nif.test, EV_TESTED);
2848 if (evalskip)
2849 break;
2850 if (exitstatus == 0) {
2851 n = n->nif.ifpart;
2852 goto evaln;
2853 } else if (n->nif.elsepart) {
2854 n = n->nif.elsepart;
2855 goto evaln;
2856 }
2857 goto success;
2858 case NDEFUN:
2859 defun(n->narg.text, n->narg.next);
2860success:
2861 status = 0;
2862setstatus:
2863 exitstatus = status;
2864 break;
2865 }
2866out:
2867 if (pendingsigs)
2868 dotrap();
2869 if (flags & EV_EXIT || checkexit & exitstatus)
2870 exraise(EXEXIT);
Eric Andersen62483552001-07-10 06:09:16 +00002871}
2872
Eric Andersenc470f442003-07-28 09:56:35 +00002873
2874#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2875static
2876#endif
2877void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2878
2879
2880static void
2881evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002882{
2883 int status;
2884
2885 loopnest++;
2886 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002887 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002888 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002889 int i;
2890
Eric Andersencb57d552001-06-28 07:25:16 +00002891 evaltree(n->nbinary.ch1, EV_TESTED);
2892 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002893skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002894 evalskip = 0;
2895 continue;
2896 }
2897 if (evalskip == SKIPBREAK && --skipcount <= 0)
2898 evalskip = 0;
2899 break;
2900 }
Eric Andersenc470f442003-07-28 09:56:35 +00002901 i = exitstatus;
2902 if (n->type != NWHILE)
2903 i = !i;
2904 if (i != 0)
2905 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002906 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002907 status = exitstatus;
2908 if (evalskip)
2909 goto skipping;
2910 }
2911 loopnest--;
2912 exitstatus = status;
2913}
2914
Eric Andersenc470f442003-07-28 09:56:35 +00002915
2916
2917static void
2918evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002919{
2920 struct arglist arglist;
2921 union node *argp;
2922 struct strlist *sp;
2923 struct stackmark smark;
2924
2925 setstackmark(&smark);
2926 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002927 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002928 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002929 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002930 if (evalskip)
2931 goto out;
2932 }
2933 *arglist.lastp = NULL;
2934
2935 exitstatus = 0;
2936 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002937 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002938 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002939 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002940 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002941 if (evalskip) {
2942 if (evalskip == SKIPCONT && --skipcount <= 0) {
2943 evalskip = 0;
2944 continue;
2945 }
2946 if (evalskip == SKIPBREAK && --skipcount <= 0)
2947 evalskip = 0;
2948 break;
2949 }
2950 }
2951 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002952out:
Eric Andersencb57d552001-06-28 07:25:16 +00002953 popstackmark(&smark);
2954}
2955
Eric Andersenc470f442003-07-28 09:56:35 +00002956
2957
2958static void
2959evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002960{
2961 union node *cp;
2962 union node *patp;
2963 struct arglist arglist;
2964 struct stackmark smark;
2965
2966 setstackmark(&smark);
2967 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002968 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002969 exitstatus = 0;
2970 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2971 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002972 if (casematch(patp, arglist.list->text)) {
2973 if (evalskip == 0) {
2974 evaltree(cp->nclist.body, flags);
2975 }
2976 goto out;
2977 }
2978 }
2979 }
Eric Andersenc470f442003-07-28 09:56:35 +00002980out:
Eric Andersencb57d552001-06-28 07:25:16 +00002981 popstackmark(&smark);
2982}
2983
Eric Andersenc470f442003-07-28 09:56:35 +00002984
2985
2986/*
2987 * Kick off a subshell to evaluate a tree.
2988 */
2989
2990static void
2991evalsubshell(union node *n, int flags)
2992{
2993 struct job *jp;
2994 int backgnd = (n->type == NBACKGND);
2995 int status;
2996
2997 expredir(n->nredir.redirect);
2998 if (!backgnd && flags & EV_EXIT && !trap[0])
2999 goto nofork;
3000 INTOFF;
3001 jp = makejob(n, 1);
3002 if (forkshell(jp, n, backgnd) == 0) {
3003 INTON;
3004 flags |= EV_EXIT;
3005 if (backgnd)
3006 flags &=~ EV_TESTED;
3007nofork:
3008 redirect(n->nredir.redirect, 0);
3009 evaltreenr(n->nredir.n, flags);
3010 /* never returns */
3011 }
3012 status = 0;
3013 if (! backgnd)
3014 status = waitforjob(jp);
3015 exitstatus = status;
3016 INTON;
3017}
3018
3019
3020
3021/*
3022 * Compute the names of the files in a redirection list.
3023 */
3024
3025static void
3026expredir(union node *n)
3027{
3028 union node *redir;
3029
3030 for (redir = n ; redir ; redir = redir->nfile.next) {
3031 struct arglist fn;
3032 fn.lastp = &fn.list;
3033 switch (redir->type) {
3034 case NFROMTO:
3035 case NFROM:
3036 case NTO:
3037 case NCLOBBER:
3038 case NAPPEND:
3039 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3040 redir->nfile.expfname = fn.list->text;
3041 break;
3042 case NFROMFD:
3043 case NTOFD:
3044 if (redir->ndup.vname) {
3045 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3046 fixredir(redir, fn.list->text, 1);
3047 }
3048 break;
3049 }
3050 }
3051}
3052
3053
3054
Eric Andersencb57d552001-06-28 07:25:16 +00003055/*
Eric Andersencb57d552001-06-28 07:25:16 +00003056 * Evaluate a pipeline. All the processes in the pipeline are children
3057 * of the process creating the pipeline. (This differs from some versions
3058 * of the shell, which make the last process in a pipeline the parent
3059 * of all the rest.)
3060 */
3061
Eric Andersenc470f442003-07-28 09:56:35 +00003062static void
3063evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003064{
3065 struct job *jp;
3066 struct nodelist *lp;
3067 int pipelen;
3068 int prevfd;
3069 int pip[2];
3070
Eric Andersenc470f442003-07-28 09:56:35 +00003071 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003072 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003073 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003074 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003075 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003076 INTOFF;
3077 jp = makejob(n, pipelen);
3078 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003079 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003080 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003081 pip[1] = -1;
3082 if (lp->next) {
3083 if (pipe(pip) < 0) {
3084 close(prevfd);
3085 error("Pipe call failed");
3086 }
3087 }
3088 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3089 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003090 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003091 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003092 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003093 if (prevfd > 0) {
3094 dup2(prevfd, 0);
3095 close(prevfd);
3096 }
3097 if (pip[1] > 1) {
3098 dup2(pip[1], 1);
3099 close(pip[1]);
3100 }
Eric Andersenc470f442003-07-28 09:56:35 +00003101 evaltreenr(lp->n, flags);
3102 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003103 }
3104 if (prevfd >= 0)
3105 close(prevfd);
3106 prevfd = pip[0];
3107 close(pip[1]);
3108 }
Eric Andersencb57d552001-06-28 07:25:16 +00003109 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003110 exitstatus = waitforjob(jp);
3111 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003112 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003113 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003114}
3115
Eric Andersen62483552001-07-10 06:09:16 +00003116
3117
3118/*
3119 * Execute a command inside back quotes. If it's a builtin command, we
3120 * want to save its output in a block obtained from malloc. Otherwise
3121 * we fork off a subprocess and get the output of the command via a pipe.
3122 * Should be called with interrupts off.
3123 */
3124
Eric Andersenc470f442003-07-28 09:56:35 +00003125static void
3126evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003127{
Eric Andersenc470f442003-07-28 09:56:35 +00003128 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003129
Eric Andersen62483552001-07-10 06:09:16 +00003130 result->fd = -1;
3131 result->buf = NULL;
3132 result->nleft = 0;
3133 result->jp = NULL;
3134 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003135 goto out;
3136 }
Eric Andersenc470f442003-07-28 09:56:35 +00003137
3138 saveherefd = herefd;
3139 herefd = -1;
3140
3141 {
3142 int pip[2];
3143 struct job *jp;
3144
3145 if (pipe(pip) < 0)
3146 error("Pipe call failed");
3147 jp = makejob(n, 1);
3148 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3149 FORCEINTON;
3150 close(pip[0]);
3151 if (pip[1] != 1) {
3152 close(1);
3153 copyfd(pip[1], 1);
3154 close(pip[1]);
3155 }
3156 eflag = 0;
3157 evaltreenr(n, EV_EXIT);
3158 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003159 }
Eric Andersenc470f442003-07-28 09:56:35 +00003160 close(pip[1]);
3161 result->fd = pip[0];
3162 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003163 }
Eric Andersenc470f442003-07-28 09:56:35 +00003164 herefd = saveherefd;
3165out:
Eric Andersen62483552001-07-10 06:09:16 +00003166 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003167 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003168}
3169
Eric Andersenc470f442003-07-28 09:56:35 +00003170#ifdef CONFIG_ASH_CMDCMD
3171static inline char **
3172parse_command_args(char **argv, const char **path)
3173{
3174 char *cp, c;
3175
3176 for (;;) {
3177 cp = *++argv;
3178 if (!cp)
3179 return 0;
3180 if (*cp++ != '-')
3181 break;
3182 if (!(c = *cp++))
3183 break;
3184 if (c == '-' && !*cp) {
3185 argv++;
3186 break;
3187 }
3188 do {
3189 switch (c) {
3190 case 'p':
3191 *path = defpath;
3192 break;
3193 default:
3194 /* run 'typecmd' for other options */
3195 return 0;
3196 }
3197 } while ((c = *cp++));
3198 }
3199 return argv;
3200}
3201#endif
3202
3203
Eric Andersen62483552001-07-10 06:09:16 +00003204
3205/*
3206 * Execute a simple command.
3207 */
Eric Andersencb57d552001-06-28 07:25:16 +00003208
Eric Andersenc470f442003-07-28 09:56:35 +00003209static void
3210evalcommand(union node *cmd, int flags)
3211{
3212 struct stackmark smark;
3213 union node *argp;
3214 struct arglist arglist;
3215 struct arglist varlist;
3216 char **argv;
3217 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003218 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003219 struct cmdentry cmdentry;
3220 struct job *jp;
3221 char *lastarg;
3222 const char *path;
3223 int spclbltin;
3224 int cmd_is_exec;
3225 int status;
3226 char **nargv;
3227
3228 /* First expand the arguments. */
3229 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3230 setstackmark(&smark);
3231 back_exitstatus = 0;
3232
3233 cmdentry.cmdtype = CMDBUILTIN;
3234 cmdentry.u.cmd = &bltin;
3235 varlist.lastp = &varlist.list;
3236 *varlist.lastp = NULL;
3237 arglist.lastp = &arglist.list;
3238 *arglist.lastp = NULL;
3239
3240 argc = 0;
3241 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3242 struct strlist **spp;
3243
3244 spp = arglist.lastp;
3245 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3246 for (sp = *spp; sp; sp = sp->next)
3247 argc++;
3248 }
3249
3250 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3251 for (sp = arglist.list ; sp ; sp = sp->next) {
3252 TRACE(("evalcommand arg: %s\n", sp->text));
3253 *nargv++ = sp->text;
3254 }
3255 *nargv = NULL;
3256
3257 lastarg = NULL;
3258 if (iflag && funcnest == 0 && argc > 0)
3259 lastarg = nargv[-1];
3260
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003261 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003262 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003263 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003264
3265 path = vpath.text;
3266 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3267 struct strlist **spp;
3268 char *p;
3269
3270 spp = varlist.lastp;
3271 expandarg(argp, &varlist, EXP_VARTILDE);
3272
3273 /*
3274 * Modify the command lookup path, if a PATH= assignment
3275 * is present
3276 */
3277 p = (*spp)->text;
3278 if (varequal(p, path))
3279 path = p;
3280 }
3281
3282 /* Print the command if xflag is set. */
3283 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003284 int n;
3285 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003286
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003287 p++;
3288 dprintf(preverrout_fd, p, ps4val());
3289
3290 sp = varlist.list;
3291 for(n = 0; n < 2; n++) {
3292 while (sp) {
3293 dprintf(preverrout_fd, p, sp->text);
3294 sp = sp->next;
3295 if(*p == '%') {
3296 p--;
3297 }
3298 }
3299 sp = arglist.list;
3300 }
Eric Andersen16767e22004-03-16 05:14:10 +00003301 bb_full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003302 }
3303
3304 cmd_is_exec = 0;
3305 spclbltin = -1;
3306
3307 /* Now locate the command. */
3308 if (argc) {
3309 const char *oldpath;
3310 int cmd_flag = DO_ERR;
3311
3312 path += 5;
3313 oldpath = path;
3314 for (;;) {
3315 find_command(argv[0], &cmdentry, cmd_flag, path);
3316 if (cmdentry.cmdtype == CMDUNKNOWN) {
3317 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003318 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003319 goto bail;
3320 }
3321
3322 /* implement bltin and command here */
3323 if (cmdentry.cmdtype != CMDBUILTIN)
3324 break;
3325 if (spclbltin < 0)
3326 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3327 if (cmdentry.u.cmd == EXECCMD)
3328 cmd_is_exec++;
3329#ifdef CONFIG_ASH_CMDCMD
3330 if (cmdentry.u.cmd == COMMANDCMD) {
3331
3332 path = oldpath;
3333 nargv = parse_command_args(argv, &path);
3334 if (!nargv)
3335 break;
3336 argc -= nargv - argv;
3337 argv = nargv;
3338 cmd_flag |= DO_NOFUNC;
3339 } else
3340#endif
3341 break;
3342 }
3343 }
3344
3345 if (status) {
3346 /* We have a redirection error. */
3347 if (spclbltin > 0)
3348 exraise(EXERROR);
3349bail:
3350 exitstatus = status;
3351 goto out;
3352 }
3353
3354 /* Execute the command. */
3355 switch (cmdentry.cmdtype) {
3356 default:
3357 /* Fork off a child process if necessary. */
3358 if (!(flags & EV_EXIT) || trap[0]) {
3359 INTOFF;
3360 jp = makejob(cmd, 1);
3361 if (forkshell(jp, cmd, FORK_FG) != 0) {
3362 exitstatus = waitforjob(jp);
3363 INTON;
3364 break;
3365 }
3366 FORCEINTON;
3367 }
3368 listsetvar(varlist.list, VEXPORT|VSTACK);
3369 shellexec(argv, path, cmdentry.u.index);
3370 /* NOTREACHED */
3371
3372 case CMDBUILTIN:
3373 cmdenviron = varlist.list;
3374 if (cmdenviron) {
3375 struct strlist *list = cmdenviron;
3376 int i = VNOSET;
3377 if (spclbltin > 0 || argc == 0) {
3378 i = 0;
3379 if (cmd_is_exec && argc > 1)
3380 i = VEXPORT;
3381 }
3382 listsetvar(list, i);
3383 }
3384 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3385 int exit_status;
3386 int i, j;
3387
3388 i = exception;
3389 if (i == EXEXIT)
3390 goto raise;
3391
3392 exit_status = 2;
3393 j = 0;
3394 if (i == EXINT)
3395 j = SIGINT;
3396 if (i == EXSIG)
3397 j = pendingsigs;
3398 if (j)
3399 exit_status = j + 128;
3400 exitstatus = exit_status;
3401
3402 if (i == EXINT || spclbltin > 0) {
3403raise:
3404 longjmp(handler->loc, 1);
3405 }
3406 FORCEINTON;
3407 }
3408 break;
3409
3410 case CMDFUNCTION:
3411 listsetvar(varlist.list, 0);
3412 if (evalfun(cmdentry.u.func, argc, argv, flags))
3413 goto raise;
3414 break;
3415 }
3416
3417out:
3418 popredir(cmd_is_exec);
3419 if (lastarg)
3420 /* dsl: I think this is intended to be used to support
3421 * '_' in 'vi' command mode during line editing...
3422 * However I implemented that within libedit itself.
3423 */
3424 setvar("_", lastarg, 0);
3425 popstackmark(&smark);
3426}
3427
3428static int
3429evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3430 char *volatile savecmdname;
3431 struct jmploc *volatile savehandler;
3432 struct jmploc jmploc;
3433 int i;
3434
3435 savecmdname = commandname;
3436 if ((i = setjmp(jmploc.loc)))
3437 goto cmddone;
3438 savehandler = handler;
3439 handler = &jmploc;
3440 commandname = argv[0];
3441 argptr = argv + 1;
3442 optptr = NULL; /* initialize nextopt */
3443 exitstatus = (*cmd->builtin)(argc, argv);
3444 flushall();
3445cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003446 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003447 commandname = savecmdname;
3448 exsig = 0;
3449 handler = savehandler;
3450
3451 return i;
3452}
3453
3454static int
3455evalfun(struct funcnode *func, int argc, char **argv, int flags)
3456{
3457 volatile struct shparam saveparam;
3458 struct localvar *volatile savelocalvars;
3459 struct jmploc *volatile savehandler;
3460 struct jmploc jmploc;
3461 int e;
3462
3463 saveparam = shellparam;
3464 savelocalvars = localvars;
3465 if ((e = setjmp(jmploc.loc))) {
3466 goto funcdone;
3467 }
3468 INTOFF;
3469 savehandler = handler;
3470 handler = &jmploc;
3471 localvars = NULL;
3472 shellparam.malloc = 0;
3473 func->count++;
3474 INTON;
3475 shellparam.nparam = argc - 1;
3476 shellparam.p = argv + 1;
3477#ifdef CONFIG_ASH_GETOPTS
3478 shellparam.optind = 1;
3479 shellparam.optoff = -1;
3480#endif
3481 funcnest++;
3482 evaltree(&func->n, flags & EV_TESTED);
3483 funcnest--;
3484funcdone:
3485 INTOFF;
3486 freefunc(func);
3487 poplocalvars();
3488 localvars = savelocalvars;
3489 freeparam(&shellparam);
3490 shellparam = saveparam;
3491 handler = savehandler;
3492 INTON;
3493 if (evalskip == SKIPFUNC) {
3494 evalskip = 0;
3495 skipcount = 0;
3496 }
3497 return e;
3498}
3499
3500
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003501static inline int
3502goodname(const char *p)
3503{
3504 return !*endofname(p);
3505}
3506
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003507/*
3508 * Search for a command. This is called before we fork so that the
3509 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003510 * the child. The check for "goodname" is an overly conservative
3511 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003512 */
3513
Eric Andersenc470f442003-07-28 09:56:35 +00003514static void
3515prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003516{
3517 struct cmdentry entry;
3518
3519 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003520 if (goodname(n->ncmd.args->narg.text))
3521 find_command(n->ncmd.args->narg.text, &entry, 0,
3522 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003523}
3524
Eric Andersencb57d552001-06-28 07:25:16 +00003525
Eric Andersenc470f442003-07-28 09:56:35 +00003526
Eric Andersencb57d552001-06-28 07:25:16 +00003527/*
3528 * Builtin commands. Builtin commands whose functions are closely
3529 * tied to evaluation are implemented here.
3530 */
3531
3532/*
Eric Andersenc470f442003-07-28 09:56:35 +00003533 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003534 */
3535
Eric Andersenc470f442003-07-28 09:56:35 +00003536static int
3537bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003538{
3539 /*
3540 * Preserve exitstatus of a previous possible redirection
3541 * as POSIX mandates
3542 */
Eric Andersenc470f442003-07-28 09:56:35 +00003543 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003544}
3545
3546
3547/*
3548 * Handle break and continue commands. Break, continue, and return are
3549 * all handled by setting the evalskip flag. The evaluation routines
3550 * above all check this flag, and if it is set they start skipping
3551 * commands rather than executing them. The variable skipcount is
3552 * the number of loops to break/continue, or the number of function
3553 * levels to return. (The latter is always 1.) It should probably
3554 * be an error to break out of more loops than exist, but it isn't
3555 * in the standard shell so we don't make it one here.
3556 */
3557
Eric Andersenc470f442003-07-28 09:56:35 +00003558static int
3559breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003560{
3561 int n = argc > 1 ? number(argv[1]) : 1;
3562
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003563 if (n <= 0)
Eric Andersenc470f442003-07-28 09:56:35 +00003564 error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003565 if (n > loopnest)
3566 n = loopnest;
3567 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003568 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003569 skipcount = n;
3570 }
3571 return 0;
3572}
3573
3574
3575/*
3576 * The return command.
3577 */
3578
Eric Andersenc470f442003-07-28 09:56:35 +00003579static int
3580returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003581{
Eric Andersenc470f442003-07-28 09:56:35 +00003582 int ret = argc > 1 ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003583
3584 if (funcnest) {
3585 evalskip = SKIPFUNC;
3586 skipcount = 1;
3587 return ret;
Eric Andersenc470f442003-07-28 09:56:35 +00003588 }
3589 else {
Eric Andersencb57d552001-06-28 07:25:16 +00003590 /* Do what ksh does; skip the rest of the file */
3591 evalskip = SKIPFILE;
3592 skipcount = 1;
3593 return ret;
3594 }
3595}
3596
3597
Eric Andersenc470f442003-07-28 09:56:35 +00003598static int
3599falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003600{
3601 return 1;
3602}
3603
Eric Andersenc470f442003-07-28 09:56:35 +00003604
3605static int
3606truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003607{
3608 return 0;
3609}
Eric Andersen2870d962001-07-02 17:27:21 +00003610
Eric Andersencb57d552001-06-28 07:25:16 +00003611
Eric Andersenc470f442003-07-28 09:56:35 +00003612static int
3613execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003614{
3615 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003616 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003617 mflag = 0;
3618 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003619 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003620 }
3621 return 0;
3622}
3623
Eric Andersenc470f442003-07-28 09:56:35 +00003624
Eric Andersenc470f442003-07-28 09:56:35 +00003625/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3626
3627/*
3628 * When commands are first encountered, they are entered in a hash table.
3629 * This ensures that a full path search will not have to be done for them
3630 * on each invocation.
3631 *
3632 * We should investigate converting to a linear search, even though that
3633 * would make the command name "hash" a misnomer.
3634 */
3635
3636#define CMDTABLESIZE 31 /* should be prime */
3637#define ARB 1 /* actual size determined at run time */
3638
3639
3640
3641struct tblentry {
3642 struct tblentry *next; /* next entry in hash chain */
3643 union param param; /* definition of builtin function */
3644 short cmdtype; /* index identifying command */
3645 char rehash; /* if set, cd done since entry created */
3646 char cmdname[ARB]; /* name of command */
3647};
3648
3649
3650static struct tblentry *cmdtable[CMDTABLESIZE];
3651static int builtinloc = -1; /* index in path of %builtin, or -1 */
3652
3653
3654static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003655static void clearcmdentry(int);
3656static struct tblentry *cmdlookup(const char *, int);
3657static void delete_cmd_entry(void);
3658
Eric Andersencb57d552001-06-28 07:25:16 +00003659
3660/*
3661 * Exec a program. Never returns. If you change this routine, you may
3662 * have to change the find_command routine as well.
3663 */
3664
Eric Andersenc470f442003-07-28 09:56:35 +00003665static void
3666shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003667{
3668 char *cmdname;
3669 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003670 char **envp;
Eric Andersencb57d552001-06-28 07:25:16 +00003671
Eric Andersenc470f442003-07-28 09:56:35 +00003672 clearredir(1);
3673 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003674 if (strchr(argv[0], '/') != NULL
3675#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3676 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003677#endif
3678 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003679 tryexec(argv[0], argv, envp);
3680 e = errno;
3681 } else {
3682 e = ENOENT;
3683 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3684 if (--idx < 0 && pathopt == NULL) {
3685 tryexec(cmdname, argv, envp);
3686 if (errno != ENOENT && errno != ENOTDIR)
3687 e = errno;
3688 }
3689 stunalloc(cmdname);
3690 }
3691 }
3692
3693 /* Map to POSIX errors */
3694 switch (e) {
3695 case EACCES:
3696 exerrno = 126;
3697 break;
3698 case ENOENT:
3699 exerrno = 127;
3700 break;
3701 default:
3702 exerrno = 2;
3703 break;
3704 }
Eric Andersenc470f442003-07-28 09:56:35 +00003705 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3706 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003707 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3708 /* NOTREACHED */
3709}
3710
Eric Andersen2870d962001-07-02 17:27:21 +00003711
Eric Andersenc470f442003-07-28 09:56:35 +00003712static void
3713tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003714{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003715 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003716#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003717 int flg_bb = 0;
Eric Andersen3102ac42001-07-06 04:26:23 +00003718 char *name = cmd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003719
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003720#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Manuel Novoa III cad53642003-03-19 09:13:01 +00003721 name = bb_get_last_path_component(name);
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003722 if(find_applet_by_name(name) != NULL)
3723 flg_bb = 1;
3724#else
3725 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3726 flg_bb = 1;
3727 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003728#endif
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003729 if(flg_bb) {
3730 char **ap;
3731 char **new;
3732
3733 *argv = name;
3734 if(strcmp(name, "busybox")) {
3735 for (ap = argv; *ap; ap++);
3736 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3737 *ap++ = cmd = "/bin/busybox";
3738 while ((*ap++ = *argv++));
3739 argv = new;
3740 repeated++;
3741 } else {
3742 cmd = "/bin/busybox";
3743 }
3744 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003745#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003746
3747repeat:
3748#ifdef SYSV
3749 do {
3750 execve(cmd, argv, envp);
3751 } while (errno == EINTR);
3752#else
Eric Andersencb57d552001-06-28 07:25:16 +00003753 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003754#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003755 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003756 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003757 } else if (errno == ENOEXEC) {
3758 char **ap;
3759 char **new;
3760
Eric Andersenc470f442003-07-28 09:56:35 +00003761 for (ap = argv; *ap; ap++)
3762 ;
3763 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003764 ap[1] = cmd;
3765 *ap = cmd = (char *)DEFAULT_SHELL;
3766 ap += 2;
3767 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003768 while ((*ap++ = *argv++))
3769 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003770 argv = new;
3771 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003772 }
Eric Andersencb57d552001-06-28 07:25:16 +00003773}
3774
Eric Andersenc470f442003-07-28 09:56:35 +00003775
Eric Andersencb57d552001-06-28 07:25:16 +00003776
3777/*
3778 * Do a path search. The variable path (passed by reference) should be
3779 * set to the start of the path before the first call; padvance will update
3780 * this value as it proceeds. Successive calls to padvance will return
3781 * the possible path expansions in sequence. If an option (indicated by
3782 * a percent sign) appears in the path entry then the global variable
3783 * pathopt will be set to point to it; otherwise pathopt will be set to
3784 * NULL.
3785 */
3786
Eric Andersenc470f442003-07-28 09:56:35 +00003787static char *
3788padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003789{
Eric Andersencb57d552001-06-28 07:25:16 +00003790 const char *p;
3791 char *q;
3792 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003793 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003794
3795 if (*path == NULL)
3796 return NULL;
3797 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003798 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3799 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003800 while (stackblocksize() < len)
3801 growstackblock();
3802 q = stackblock();
3803 if (p != start) {
3804 memcpy(q, start, p - start);
3805 q += p - start;
3806 *q++ = '/';
3807 }
3808 strcpy(q, name);
3809 pathopt = NULL;
3810 if (*p == '%') {
3811 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003812 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003813 }
3814 if (*p == ':')
3815 *path = p + 1;
3816 else
3817 *path = NULL;
3818 return stalloc(len);
3819}
3820
3821
Eric Andersencb57d552001-06-28 07:25:16 +00003822/*** Command hashing code ***/
3823
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003824static void
3825printentry(struct tblentry *cmdp)
3826{
3827 int idx;
3828 const char *path;
3829 char *name;
3830
3831 idx = cmdp->param.index;
3832 path = pathval();
3833 do {
3834 name = padvance(&path, cmdp->cmdname);
3835 stunalloc(name);
3836 } while (--idx >= 0);
3837 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3838}
3839
Eric Andersenc470f442003-07-28 09:56:35 +00003840
3841static int
3842hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003843{
3844 struct tblentry **pp;
3845 struct tblentry *cmdp;
3846 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003847 struct cmdentry entry;
3848 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003849
Eric Andersenc470f442003-07-28 09:56:35 +00003850 while ((c = nextopt("r")) != '\0') {
3851 clearcmdentry(0);
3852 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003853 }
3854 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003855 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3856 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3857 if (cmdp->cmdtype == CMDNORMAL)
3858 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003859 }
3860 }
3861 return 0;
3862 }
3863 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003864 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003865 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003866 && (cmdp->cmdtype == CMDNORMAL
3867 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003868 delete_cmd_entry();
3869 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003870 if (entry.cmdtype == CMDUNKNOWN)
3871 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003872 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003873 }
3874 return c;
3875}
3876
Eric Andersenc470f442003-07-28 09:56:35 +00003877
Eric Andersencb57d552001-06-28 07:25:16 +00003878/*
3879 * Resolve a command name. If you change this routine, you may have to
3880 * change the shellexec routine as well.
3881 */
3882
3883static void
Eric Andersenc470f442003-07-28 09:56:35 +00003884find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003885{
3886 struct tblentry *cmdp;
3887 int idx;
3888 int prev;
3889 char *fullname;
3890 struct stat statb;
3891 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003892 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003893 struct builtincmd *bcmd;
3894
Eric Andersenc470f442003-07-28 09:56:35 +00003895 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003896 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003897 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003898 if (act & DO_ABS) {
3899 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003900#ifdef SYSV
3901 if (errno == EINTR)
3902 continue;
3903#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003904 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003905 return;
3906 }
Eric Andersencb57d552001-06-28 07:25:16 +00003907 }
3908 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003909 return;
3910 }
3911
Eric Andersenbf8bf102002-09-17 08:41:08 +00003912#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3913 if (find_applet_by_name(name)) {
3914 entry->cmdtype = CMDNORMAL;
3915 entry->u.index = -1;
3916 return;
3917 }
3918#endif
3919
Eric Andersenc470f442003-07-28 09:56:35 +00003920 updatetbl = (path == pathval());
3921 if (!updatetbl) {
3922 act |= DO_ALTPATH;
3923 if (strstr(path, "%builtin") != NULL)
3924 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003925 }
3926
Eric Andersenc470f442003-07-28 09:56:35 +00003927 /* If name is in the table, check answer will be ok */
3928 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3929 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003930
Eric Andersenc470f442003-07-28 09:56:35 +00003931 switch (cmdp->cmdtype) {
3932 default:
3933#if DEBUG
3934 abort();
3935#endif
3936 case CMDNORMAL:
3937 bit = DO_ALTPATH;
3938 break;
3939 case CMDFUNCTION:
3940 bit = DO_NOFUNC;
3941 break;
3942 case CMDBUILTIN:
3943 bit = DO_ALTBLTIN;
3944 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003945 }
Eric Andersenc470f442003-07-28 09:56:35 +00003946 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003947 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003948 cmdp = NULL;
3949 } else if (cmdp->rehash == 0)
3950 /* if not invalidated by cd, we're done */
3951 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003952 }
3953
3954 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003955 bcmd = find_builtin(name);
3956 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3957 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3958 )))
3959 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003960
3961 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003962 prev = -1; /* where to start */
3963 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003964 if (cmdp->cmdtype == CMDBUILTIN)
3965 prev = builtinloc;
3966 else
3967 prev = cmdp->param.index;
3968 }
3969
3970 e = ENOENT;
3971 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003972loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003973 while ((fullname = padvance(&path, name)) != NULL) {
3974 stunalloc(fullname);
3975 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003976 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003977 if (prefix(pathopt, "builtin")) {
3978 if (bcmd)
3979 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003980 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003981 } else if (!(act & DO_NOFUNC) &&
3982 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003983 /* handled below */
3984 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003985 /* ignore unimplemented options */
3986 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003987 }
3988 }
3989 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003990 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003991 if (idx < prev)
3992 continue;
3993 TRACE(("searchexec \"%s\": no change\n", name));
3994 goto success;
3995 }
3996 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003997#ifdef SYSV
3998 if (errno == EINTR)
3999 continue;
4000#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004001 if (errno != ENOENT && errno != ENOTDIR)
4002 e = errno;
4003 goto loop;
4004 }
Eric Andersenc470f442003-07-28 09:56:35 +00004005 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004006 if (!S_ISREG(statb.st_mode))
4007 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004008 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004009 stalloc(strlen(fullname) + 1);
4010 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004011 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4012 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004013 error("%s not defined in %s", name, fullname);
4014 stunalloc(fullname);
4015 goto success;
4016 }
Eric Andersencb57d552001-06-28 07:25:16 +00004017 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004018 if (!updatetbl) {
4019 entry->cmdtype = CMDNORMAL;
4020 entry->u.index = idx;
4021 return;
4022 }
4023 INTOFF;
4024 cmdp = cmdlookup(name, 1);
4025 cmdp->cmdtype = CMDNORMAL;
4026 cmdp->param.index = idx;
4027 INTON;
4028 goto success;
4029 }
4030
4031 /* We failed. If there was an entry for this command, delete it */
4032 if (cmdp && updatetbl)
4033 delete_cmd_entry();
4034 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004035 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004036 entry->cmdtype = CMDUNKNOWN;
4037 return;
4038
Eric Andersenc470f442003-07-28 09:56:35 +00004039builtin_success:
4040 if (!updatetbl) {
4041 entry->cmdtype = CMDBUILTIN;
4042 entry->u.cmd = bcmd;
4043 return;
4044 }
4045 INTOFF;
4046 cmdp = cmdlookup(name, 1);
4047 cmdp->cmdtype = CMDBUILTIN;
4048 cmdp->param.cmd = bcmd;
4049 INTON;
4050success:
Eric Andersencb57d552001-06-28 07:25:16 +00004051 cmdp->rehash = 0;
4052 entry->cmdtype = cmdp->cmdtype;
4053 entry->u = cmdp->param;
4054}
4055
4056
Eric Andersenc470f442003-07-28 09:56:35 +00004057/*
4058 * Wrapper around strcmp for qsort/bsearch/...
4059 */
4060static int pstrcmp(const void *a, const void *b)
4061{
4062 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4063}
Eric Andersencb57d552001-06-28 07:25:16 +00004064
4065/*
4066 * Search the table of builtin commands.
4067 */
4068
Eric Andersenc470f442003-07-28 09:56:35 +00004069static struct builtincmd *
4070find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004071{
4072 struct builtincmd *bp;
4073
Eric Andersenc470f442003-07-28 09:56:35 +00004074 bp = bsearch(
4075 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4076 pstrcmp
4077 );
Eric Andersencb57d552001-06-28 07:25:16 +00004078 return bp;
4079}
4080
4081
Eric Andersenc470f442003-07-28 09:56:35 +00004082
Eric Andersencb57d552001-06-28 07:25:16 +00004083/*
4084 * Called when a cd is done. Marks all commands so the next time they
4085 * are executed they will be rehashed.
4086 */
4087
Eric Andersenc470f442003-07-28 09:56:35 +00004088static void
4089hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004090{
Eric Andersencb57d552001-06-28 07:25:16 +00004091 struct tblentry **pp;
4092 struct tblentry *cmdp;
4093
Eric Andersenc470f442003-07-28 09:56:35 +00004094 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4095 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4096 if (cmdp->cmdtype == CMDNORMAL || (
4097 cmdp->cmdtype == CMDBUILTIN &&
4098 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4099 builtinloc > 0
4100 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004101 cmdp->rehash = 1;
4102 }
4103 }
4104}
4105
4106
4107
4108/*
Eric Andersenc470f442003-07-28 09:56:35 +00004109 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004110 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004111 * pathval() still returns the old value at this point.
4112 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004113 */
4114
Eric Andersenc470f442003-07-28 09:56:35 +00004115static void
4116changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004117{
Eric Andersenc470f442003-07-28 09:56:35 +00004118 const char *old, *new;
4119 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004120 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004121 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004122
Eric Andersenc470f442003-07-28 09:56:35 +00004123 old = pathval();
4124 new = newval;
4125 firstchange = 9999; /* assume no change */
4126 idx = 0;
4127 idx_bltin = -1;
4128 for (;;) {
4129 if (*old != *new) {
4130 firstchange = idx;
4131 if ((*old == '\0' && *new == ':')
4132 || (*old == ':' && *new == '\0'))
4133 firstchange++;
4134 old = new; /* ignore subsequent differences */
4135 }
4136 if (*new == '\0')
4137 break;
4138 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4139 idx_bltin = idx;
4140 if (*new == ':') {
4141 idx++;
4142 }
4143 new++, old++;
4144 }
4145 if (builtinloc < 0 && idx_bltin >= 0)
4146 builtinloc = idx_bltin; /* zap builtins */
4147 if (builtinloc >= 0 && idx_bltin < 0)
4148 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004149 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004150 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004151}
4152
4153
4154/*
4155 * Clear out command entries. The argument specifies the first entry in
4156 * PATH which has changed.
4157 */
4158
Eric Andersenc470f442003-07-28 09:56:35 +00004159static void
4160clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004161{
4162 struct tblentry **tblp;
4163 struct tblentry **pp;
4164 struct tblentry *cmdp;
4165
4166 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004167 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004168 pp = tblp;
4169 while ((cmdp = *pp) != NULL) {
4170 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004171 cmdp->param.index >= firstchange)
4172 || (cmdp->cmdtype == CMDBUILTIN &&
4173 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004174 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004175 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004176 } else {
4177 pp = &cmdp->next;
4178 }
4179 }
4180 }
4181 INTON;
4182}
4183
4184
Eric Andersenc470f442003-07-28 09:56:35 +00004185
Eric Andersencb57d552001-06-28 07:25:16 +00004186/*
Eric Andersencb57d552001-06-28 07:25:16 +00004187 * Locate a command in the command hash table. If "add" is nonzero,
4188 * add the command to the table if it is not already present. The
4189 * variable "lastcmdentry" is set to point to the address of the link
4190 * pointing to the entry, so that delete_cmd_entry can delete the
4191 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004192 *
4193 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004194 */
4195
Eric Andersen2870d962001-07-02 17:27:21 +00004196static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004197
Eric Andersenc470f442003-07-28 09:56:35 +00004198
4199static struct tblentry *
4200cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004201{
Eric Andersenc470f442003-07-28 09:56:35 +00004202 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004203 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004204 struct tblentry *cmdp;
4205 struct tblentry **pp;
4206
4207 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004208 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004209 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004210 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004211 hashval &= 0x7FFF;
4212 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004213 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004214 if (equal(cmdp->cmdname, name))
4215 break;
4216 pp = &cmdp->next;
4217 }
4218 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004219 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4220 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004221 cmdp->next = NULL;
4222 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004223 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004224 }
4225 lastcmdentry = pp;
4226 return cmdp;
4227}
4228
4229/*
4230 * Delete the command entry returned on the last lookup.
4231 */
4232
Eric Andersenc470f442003-07-28 09:56:35 +00004233static void
4234delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004235{
Eric Andersencb57d552001-06-28 07:25:16 +00004236 struct tblentry *cmdp;
4237
4238 INTOFF;
4239 cmdp = *lastcmdentry;
4240 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004241 if (cmdp->cmdtype == CMDFUNCTION)
4242 freefunc(cmdp->param.func);
4243 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004244 INTON;
4245}
4246
4247
Eric Andersenc470f442003-07-28 09:56:35 +00004248/*
4249 * Add a new command entry, replacing any existing command entry for
4250 * the same name - except special builtins.
4251 */
Eric Andersencb57d552001-06-28 07:25:16 +00004252
Eric Andersenc470f442003-07-28 09:56:35 +00004253static inline void
4254addcmdentry(char *name, struct cmdentry *entry)
4255{
4256 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004257
Eric Andersenc470f442003-07-28 09:56:35 +00004258 cmdp = cmdlookup(name, 1);
4259 if (cmdp->cmdtype == CMDFUNCTION) {
4260 freefunc(cmdp->param.func);
4261 }
4262 cmdp->cmdtype = entry->cmdtype;
4263 cmdp->param = entry->u;
4264 cmdp->rehash = 0;
4265}
Eric Andersencb57d552001-06-28 07:25:16 +00004266
Eric Andersenc470f442003-07-28 09:56:35 +00004267/*
4268 * Make a copy of a parse tree.
4269 */
Eric Andersencb57d552001-06-28 07:25:16 +00004270
Eric Andersenc470f442003-07-28 09:56:35 +00004271static inline struct funcnode *
4272copyfunc(union node *n)
4273{
4274 struct funcnode *f;
4275 size_t blocksize;
4276
4277 funcblocksize = offsetof(struct funcnode, n);
4278 funcstringsize = 0;
4279 calcsize(n);
4280 blocksize = funcblocksize;
4281 f = ckmalloc(blocksize + funcstringsize);
4282 funcblock = (char *) f + offsetof(struct funcnode, n);
4283 funcstring = (char *) f + blocksize;
4284 copynode(n);
4285 f->count = 0;
4286 return f;
4287}
4288
4289/*
4290 * Define a shell function.
4291 */
4292
4293static void
4294defun(char *name, union node *func)
4295{
4296 struct cmdentry entry;
4297
4298 INTOFF;
4299 entry.cmdtype = CMDFUNCTION;
4300 entry.u.func = copyfunc(func);
4301 addcmdentry(name, &entry);
4302 INTON;
4303}
Eric Andersencb57d552001-06-28 07:25:16 +00004304
4305
4306/*
4307 * Delete a function if it exists.
4308 */
4309
Eric Andersenc470f442003-07-28 09:56:35 +00004310static void
4311unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004312{
Eric Andersencb57d552001-06-28 07:25:16 +00004313 struct tblentry *cmdp;
4314
Eric Andersenc470f442003-07-28 09:56:35 +00004315 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4316 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004317 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004318}
4319
Eric Andersen2870d962001-07-02 17:27:21 +00004320/*
Eric Andersencb57d552001-06-28 07:25:16 +00004321 * Locate and print what a word is...
4322 */
4323
Eric Andersenc470f442003-07-28 09:56:35 +00004324
4325#ifdef CONFIG_ASH_CMDCMD
4326static int
4327describe_command(char *command, int describe_command_verbose)
4328#else
4329#define describe_command_verbose 1
4330static int
4331describe_command(char *command)
4332#endif
4333{
4334 struct cmdentry entry;
4335 struct tblentry *cmdp;
4336#ifdef CONFIG_ASH_ALIAS
4337 const struct alias *ap;
4338#endif
4339 const char *path = pathval();
4340
4341 if (describe_command_verbose) {
4342 out1str(command);
4343 }
4344
4345 /* First look at the keywords */
4346 if (findkwd(command)) {
4347 out1str(describe_command_verbose ? " is a shell keyword" : command);
4348 goto out;
4349 }
4350
4351#ifdef CONFIG_ASH_ALIAS
4352 /* Then look at the aliases */
4353 if ((ap = lookupalias(command, 0)) != NULL) {
4354 if (describe_command_verbose) {
4355 out1fmt(" is an alias for %s", ap->val);
4356 } else {
4357 out1str("alias ");
4358 printalias(ap);
4359 return 0;
4360 }
4361 goto out;
4362 }
4363#endif
4364 /* Then check if it is a tracked alias */
4365 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4366 entry.cmdtype = cmdp->cmdtype;
4367 entry.u = cmdp->param;
4368 } else {
4369 /* Finally use brute force */
4370 find_command(command, &entry, DO_ABS, path);
4371 }
4372
4373 switch (entry.cmdtype) {
4374 case CMDNORMAL: {
4375 int j = entry.u.index;
4376 char *p;
4377 if (j == -1) {
4378 p = command;
4379 } else {
4380 do {
4381 p = padvance(&path, command);
4382 stunalloc(p);
4383 } while (--j >= 0);
4384 }
4385 if (describe_command_verbose) {
4386 out1fmt(" is%s %s",
4387 (cmdp ? " a tracked alias for" : nullstr), p
4388 );
4389 } else {
4390 out1str(p);
4391 }
4392 break;
4393 }
4394
4395 case CMDFUNCTION:
4396 if (describe_command_verbose) {
4397 out1str(" is a shell function");
4398 } else {
4399 out1str(command);
4400 }
4401 break;
4402
4403 case CMDBUILTIN:
4404 if (describe_command_verbose) {
4405 out1fmt(" is a %sshell builtin",
4406 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4407 "special " : nullstr
4408 );
4409 } else {
4410 out1str(command);
4411 }
4412 break;
4413
4414 default:
4415 if (describe_command_verbose) {
4416 out1str(": not found\n");
4417 }
4418 return 127;
4419 }
4420
4421out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004422 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004423 return 0;
4424}
4425
4426static int
4427typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004428{
4429 int i;
4430 int err = 0;
4431
4432 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004433#ifdef CONFIG_ASH_CMDCMD
4434 err |= describe_command(argv[i], 1);
4435#else
4436 err |= describe_command(argv[i]);
4437#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004438 }
4439 return err;
4440}
4441
Eric Andersend35c5df2002-01-09 15:37:36 +00004442#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004443static int
4444commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004445{
4446 int c;
4447 int default_path = 0;
4448 int verify_only = 0;
4449 int verbose_verify_only = 0;
4450
4451 while ((c = nextopt("pvV")) != '\0')
4452 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004453 default:
4454#ifdef DEBUG
4455 fprintf(stderr,
4456"command: nextopt returned character code 0%o\n", c);
4457 return EX_SOFTWARE;
4458#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004459 case 'p':
4460 default_path = 1;
4461 break;
4462 case 'v':
4463 verify_only = 1;
4464 break;
4465 case 'V':
4466 verbose_verify_only = 1;
4467 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004468 }
4469
Eric Andersenc470f442003-07-28 09:56:35 +00004470 if (default_path + verify_only + verbose_verify_only > 1 ||
4471 !*argptr) {
4472 fprintf(stderr,
4473 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004474 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004475 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004476 }
4477
Eric Andersencb57d552001-06-28 07:25:16 +00004478 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004479 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004480 }
Eric Andersencb57d552001-06-28 07:25:16 +00004481
4482 return 0;
4483}
Eric Andersen2870d962001-07-02 17:27:21 +00004484#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004485
Eric Andersenc470f442003-07-28 09:56:35 +00004486/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004487
Eric Andersencb57d552001-06-28 07:25:16 +00004488/*
4489 * Routines to expand arguments to commands. We have to deal with
4490 * backquotes, shell variables, and file metacharacters.
4491 */
Eric Andersenc470f442003-07-28 09:56:35 +00004492
Eric Andersencb57d552001-06-28 07:25:16 +00004493/*
4494 * _rmescape() flags
4495 */
Eric Andersenc470f442003-07-28 09:56:35 +00004496#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4497#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4498#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4499#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4500#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004501
4502/*
4503 * Structure specifying which parts of the string should be searched
4504 * for IFS characters.
4505 */
4506
4507struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004508 struct ifsregion *next; /* next region in list */
4509 int begoff; /* offset of start of region */
4510 int endoff; /* offset of end of region */
4511 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004512};
4513
Eric Andersenc470f442003-07-28 09:56:35 +00004514/* output of current string */
4515static char *expdest;
4516/* list of back quote expressions */
4517static struct nodelist *argbackq;
4518/* first struct in list of ifs regions */
4519static struct ifsregion ifsfirst;
4520/* last struct in list */
4521static struct ifsregion *ifslastp;
4522/* holds expanded arg list */
4523static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004524
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004525static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004526static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004527static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004528static const char *subevalvar(char *, char *, int, int, int, int, int);
4529static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004530static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004531static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004532static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004533static void recordregion(int, int, int);
4534static void removerecordregions(int);
4535static void ifsbreakup(char *, struct arglist *);
4536static void ifsfree(void);
4537static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004538static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004539
Eric Andersenc470f442003-07-28 09:56:35 +00004540static int cvtnum(long);
4541static size_t esclen(const char *, const char *);
4542static char *scanleft(char *, char *, char *, char *, int, int);
4543static char *scanright(char *, char *, char *, char *, int, int);
4544static void varunset(const char *, const char *, const char *, int)
4545 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004546
Eric Andersenc470f442003-07-28 09:56:35 +00004547
4548#define pmatch(a, b) !fnmatch((a), (b), 0)
4549/*
Eric Andersen90898442003-08-06 11:20:52 +00004550 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004551 *
4552 * Returns an stalloced string.
4553 */
4554
4555static inline char *
4556preglob(const char *pattern, int quoted, int flag) {
4557 flag |= RMESCAPE_GLOB;
4558 if (quoted) {
4559 flag |= RMESCAPE_QUOTED;
4560 }
4561 return _rmescapes((char *)pattern, flag);
4562}
4563
4564
4565static size_t
4566esclen(const char *start, const char *p) {
4567 size_t esc = 0;
4568
4569 while (p > start && *--p == CTLESC) {
4570 esc++;
4571 }
4572 return esc;
4573}
4574
Eric Andersencb57d552001-06-28 07:25:16 +00004575
4576/*
4577 * Expand shell variables and backquotes inside a here document.
4578 */
4579
Eric Andersenc470f442003-07-28 09:56:35 +00004580static inline void
4581expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004582{
Eric Andersencb57d552001-06-28 07:25:16 +00004583 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004584 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004585 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004586}
4587
4588
4589/*
4590 * Perform variable substitution and command substitution on an argument,
4591 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4592 * perform splitting and file name expansion. When arglist is NULL, perform
4593 * here document expansion.
4594 */
4595
Eric Andersenc470f442003-07-28 09:56:35 +00004596void
4597expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004598{
4599 struct strlist *sp;
4600 char *p;
4601
4602 argbackq = arg->narg.backquote;
4603 STARTSTACKSTR(expdest);
4604 ifsfirst.next = NULL;
4605 ifslastp = NULL;
4606 argstr(arg->narg.text, flag);
4607 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004608 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004609 }
4610 STPUTC('\0', expdest);
4611 p = grabstackstr(expdest);
4612 exparg.lastp = &exparg.list;
4613 /*
4614 * TODO - EXP_REDIR
4615 */
4616 if (flag & EXP_FULL) {
4617 ifsbreakup(p, &exparg);
4618 *exparg.lastp = NULL;
4619 exparg.lastp = &exparg.list;
4620 expandmeta(exparg.list, flag);
4621 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004622 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004623 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004624 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004625 sp->text = p;
4626 *exparg.lastp = sp;
4627 exparg.lastp = &sp->next;
4628 }
Eric Andersenc470f442003-07-28 09:56:35 +00004629 if (ifsfirst.next)
4630 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004631 *exparg.lastp = NULL;
4632 if (exparg.list) {
4633 *arglist->lastp = exparg.list;
4634 arglist->lastp = exparg.lastp;
4635 }
4636}
4637
4638
Eric Andersenc470f442003-07-28 09:56:35 +00004639/*
4640 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4641 * characters to allow for further processing. Otherwise treat
4642 * $@ like $* since no splitting will be performed.
4643 */
4644
4645static void
4646argstr(char *p, int flag)
4647{
4648 static const char spclchars[] = {
4649 '=',
4650 ':',
4651 CTLQUOTEMARK,
4652 CTLENDVAR,
4653 CTLESC,
4654 CTLVAR,
4655 CTLBACKQ,
4656 CTLBACKQ | CTLQUOTE,
4657#ifdef CONFIG_ASH_MATH_SUPPORT
4658 CTLENDARI,
4659#endif
4660 0
4661 };
4662 const char *reject = spclchars;
4663 int c;
4664 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4665 int breakall = flag & EXP_WORD;
4666 int inquotes;
4667 size_t length;
4668 int startloc;
4669
4670 if (!(flag & EXP_VARTILDE)) {
4671 reject += 2;
4672 } else if (flag & EXP_VARTILDE2) {
4673 reject++;
4674 }
4675 inquotes = 0;
4676 length = 0;
4677 if (flag & EXP_TILDE) {
4678 char *q;
4679
4680 flag &= ~EXP_TILDE;
4681tilde:
4682 q = p;
4683 if (*q == CTLESC && (flag & EXP_QWORD))
4684 q++;
4685 if (*q == '~')
4686 p = exptilde(p, q, flag);
4687 }
4688start:
4689 startloc = expdest - (char *)stackblock();
4690 for (;;) {
4691 length += strcspn(p + length, reject);
4692 c = p[length];
4693 if (c && (!(c & 0x80)
4694#ifdef CONFIG_ASH_MATH_SUPPORT
4695 || c == CTLENDARI
4696#endif
4697 )) {
4698 /* c == '=' || c == ':' || c == CTLENDARI */
4699 length++;
4700 }
4701 if (length > 0) {
4702 int newloc;
4703 expdest = stnputs(p, length, expdest);
4704 newloc = expdest - (char *)stackblock();
4705 if (breakall && !inquotes && newloc > startloc) {
4706 recordregion(startloc, newloc, 0);
4707 }
4708 startloc = newloc;
4709 }
4710 p += length + 1;
4711 length = 0;
4712
4713 switch (c) {
4714 case '\0':
4715 goto breakloop;
4716 case '=':
4717 if (flag & EXP_VARTILDE2) {
4718 p--;
4719 continue;
4720 }
4721 flag |= EXP_VARTILDE2;
4722 reject++;
4723 /* fall through */
4724 case ':':
4725 /*
4726 * sort of a hack - expand tildes in variable
4727 * assignments (after the first '=' and after ':'s).
4728 */
4729 if (*--p == '~') {
4730 goto tilde;
4731 }
4732 continue;
4733 }
4734
4735 switch (c) {
4736 case CTLENDVAR: /* ??? */
4737 goto breakloop;
4738 case CTLQUOTEMARK:
4739 /* "$@" syntax adherence hack */
4740 if (
4741 !inquotes &&
4742 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4743 (p[4] == CTLQUOTEMARK || (
4744 p[4] == CTLENDVAR &&
4745 p[5] == CTLQUOTEMARK
4746 ))
4747 ) {
4748 p = evalvar(p + 1, flag) + 1;
4749 goto start;
4750 }
4751 inquotes = !inquotes;
4752addquote:
4753 if (quotes) {
4754 p--;
4755 length++;
4756 startloc++;
4757 }
4758 break;
4759 case CTLESC:
4760 startloc++;
4761 length++;
4762 goto addquote;
4763 case CTLVAR:
4764 p = evalvar(p, flag);
4765 goto start;
4766 case CTLBACKQ:
4767 c = 0;
4768 case CTLBACKQ|CTLQUOTE:
4769 expbackq(argbackq->n, c, quotes);
4770 argbackq = argbackq->next;
4771 goto start;
4772#ifdef CONFIG_ASH_MATH_SUPPORT
4773 case CTLENDARI:
4774 p--;
4775 expari(quotes);
4776 goto start;
4777#endif
4778 }
4779 }
4780breakloop:
4781 ;
4782}
4783
4784static char *
4785exptilde(char *startp, char *p, int flag)
4786{
4787 char c;
4788 char *name;
4789 struct passwd *pw;
4790 const char *home;
4791 int quotes = flag & (EXP_FULL | EXP_CASE);
4792 int startloc;
4793
4794 name = p + 1;
4795
4796 while ((c = *++p) != '\0') {
4797 switch(c) {
4798 case CTLESC:
4799 return (startp);
4800 case CTLQUOTEMARK:
4801 return (startp);
4802 case ':':
4803 if (flag & EXP_VARTILDE)
4804 goto done;
4805 break;
4806 case '/':
4807 case CTLENDVAR:
4808 goto done;
4809 }
4810 }
4811done:
4812 *p = '\0';
4813 if (*name == '\0') {
4814 if ((home = lookupvar(homestr)) == NULL)
4815 goto lose;
4816 } else {
4817 if ((pw = getpwnam(name)) == NULL)
4818 goto lose;
4819 home = pw->pw_dir;
4820 }
4821 if (*home == '\0')
4822 goto lose;
4823 *p = c;
4824 startloc = expdest - (char *)stackblock();
4825 strtodest(home, SQSYNTAX, quotes);
4826 recordregion(startloc, expdest - (char *)stackblock(), 0);
4827 return (p);
4828lose:
4829 *p = c;
4830 return (startp);
4831}
4832
4833
4834static void
4835removerecordregions(int endoff)
4836{
4837 if (ifslastp == NULL)
4838 return;
4839
4840 if (ifsfirst.endoff > endoff) {
4841 while (ifsfirst.next != NULL) {
4842 struct ifsregion *ifsp;
4843 INTOFF;
4844 ifsp = ifsfirst.next->next;
4845 ckfree(ifsfirst.next);
4846 ifsfirst.next = ifsp;
4847 INTON;
4848 }
4849 if (ifsfirst.begoff > endoff)
4850 ifslastp = NULL;
4851 else {
4852 ifslastp = &ifsfirst;
4853 ifsfirst.endoff = endoff;
4854 }
4855 return;
4856 }
4857
4858 ifslastp = &ifsfirst;
4859 while (ifslastp->next && ifslastp->next->begoff < endoff)
4860 ifslastp=ifslastp->next;
4861 while (ifslastp->next != NULL) {
4862 struct ifsregion *ifsp;
4863 INTOFF;
4864 ifsp = ifslastp->next->next;
4865 ckfree(ifslastp->next);
4866 ifslastp->next = ifsp;
4867 INTON;
4868 }
4869 if (ifslastp->endoff > endoff)
4870 ifslastp->endoff = endoff;
4871}
4872
4873
4874#ifdef CONFIG_ASH_MATH_SUPPORT
4875/*
4876 * Expand arithmetic expression. Backup to start of expression,
4877 * evaluate, place result in (backed up) result, adjust string position.
4878 */
4879void
4880expari(int quotes)
4881{
4882 char *p, *start;
4883 int begoff;
4884 int flag;
4885 int len;
4886
4887 /* ifsfree(); */
4888
4889 /*
4890 * This routine is slightly over-complicated for
4891 * efficiency. Next we scan backwards looking for the
4892 * start of arithmetic.
4893 */
4894 start = stackblock();
4895 p = expdest - 1;
4896 *p = '\0';
4897 p--;
4898 do {
4899 int esc;
4900
4901 while (*p != CTLARI) {
4902 p--;
4903#ifdef DEBUG
4904 if (p < start) {
4905 error("missing CTLARI (shouldn't happen)");
4906 }
4907#endif
4908 }
4909
4910 esc = esclen(start, p);
4911 if (!(esc % 2)) {
4912 break;
4913 }
4914
4915 p -= esc + 1;
4916 } while (1);
4917
4918 begoff = p - start;
4919
4920 removerecordregions(begoff);
4921
4922 flag = p[1];
4923
4924 expdest = p;
4925
4926 if (quotes)
4927 rmescapes(p + 2);
4928
4929 len = cvtnum(dash_arith(p + 2));
4930
4931 if (flag != '"')
4932 recordregion(begoff, begoff + len, 0);
4933}
4934#endif
4935
4936/*
4937 * Expand stuff in backwards quotes.
4938 */
4939
4940static void
4941expbackq(union node *cmd, int quoted, int quotes)
4942{
4943 struct backcmd in;
4944 int i;
4945 char buf[128];
4946 char *p;
4947 char *dest;
4948 int startloc;
4949 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4950 struct stackmark smark;
4951
4952 INTOFF;
4953 setstackmark(&smark);
4954 dest = expdest;
4955 startloc = dest - (char *)stackblock();
4956 grabstackstr(dest);
4957 evalbackcmd(cmd, (struct backcmd *) &in);
4958 popstackmark(&smark);
4959
4960 p = in.buf;
4961 i = in.nleft;
4962 if (i == 0)
4963 goto read;
4964 for (;;) {
4965 memtodest(p, i, syntax, quotes);
4966read:
4967 if (in.fd < 0)
4968 break;
4969 i = safe_read(in.fd, buf, sizeof buf);
4970 TRACE(("expbackq: read returns %d\n", i));
4971 if (i <= 0)
4972 break;
4973 p = buf;
4974 }
4975
4976 if (in.buf)
4977 ckfree(in.buf);
4978 if (in.fd >= 0) {
4979 close(in.fd);
4980 back_exitstatus = waitforjob(in.jp);
4981 }
4982 INTON;
4983
4984 /* Eat all trailing newlines */
4985 dest = expdest;
4986 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4987 STUNPUTC(dest);
4988 expdest = dest;
4989
4990 if (quoted == 0)
4991 recordregion(startloc, dest - (char *)stackblock(), 0);
4992 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4993 (dest - (char *)stackblock()) - startloc,
4994 (dest - (char *)stackblock()) - startloc,
4995 stackblock() + startloc));
4996}
4997
4998
4999static char *
Eric Andersen90898442003-08-06 11:20:52 +00005000scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5001 int zero)
5002{
Eric Andersenc470f442003-07-28 09:56:35 +00005003 char *loc;
5004 char *loc2;
5005 char c;
5006
5007 loc = startp;
5008 loc2 = rmesc;
5009 do {
5010 int match;
5011 const char *s = loc2;
5012 c = *loc2;
5013 if (zero) {
5014 *loc2 = '\0';
5015 s = rmesc;
5016 }
5017 match = pmatch(str, s);
5018 *loc2 = c;
5019 if (match)
5020 return loc;
5021 if (quotes && *loc == CTLESC)
5022 loc++;
5023 loc++;
5024 loc2++;
5025 } while (c);
5026 return 0;
5027}
5028
5029
5030static char *
Eric Andersen90898442003-08-06 11:20:52 +00005031scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5032 int zero)
5033{
Eric Andersenc470f442003-07-28 09:56:35 +00005034 int esc = 0;
5035 char *loc;
5036 char *loc2;
5037
5038 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5039 int match;
5040 char c = *loc2;
5041 const char *s = loc2;
5042 if (zero) {
5043 *loc2 = '\0';
5044 s = rmesc;
5045 }
5046 match = pmatch(str, s);
5047 *loc2 = c;
5048 if (match)
5049 return loc;
5050 loc--;
5051 if (quotes) {
5052 if (--esc < 0) {
5053 esc = esclen(startp, loc);
5054 }
5055 if (esc % 2) {
5056 esc--;
5057 loc--;
5058 }
5059 }
5060 }
5061 return 0;
5062}
5063
5064static const char *
5065subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5066{
5067 char *startp;
5068 char *loc;
5069 int saveherefd = herefd;
5070 struct nodelist *saveargbackq = argbackq;
5071 int amount;
5072 char *rmesc, *rmescend;
5073 int zero;
5074 char *(*scan)(char *, char *, char *, char *, int , int);
5075
5076 herefd = -1;
5077 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5078 STPUTC('\0', expdest);
5079 herefd = saveherefd;
5080 argbackq = saveargbackq;
5081 startp = stackblock() + startloc;
5082
5083 switch (subtype) {
5084 case VSASSIGN:
5085 setvar(str, startp, 0);
5086 amount = startp - expdest;
5087 STADJUST(amount, expdest);
5088 return startp;
5089
5090 case VSQUESTION:
5091 varunset(p, str, startp, varflags);
5092 /* NOTREACHED */
5093 }
5094
5095 subtype -= VSTRIMRIGHT;
5096#ifdef DEBUG
5097 if (subtype < 0 || subtype > 3)
5098 abort();
5099#endif
5100
5101 rmesc = startp;
5102 rmescend = stackblock() + strloc;
5103 if (quotes) {
5104 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5105 if (rmesc != startp) {
5106 rmescend = expdest;
5107 startp = stackblock() + startloc;
5108 }
5109 }
5110 rmescend--;
5111 str = stackblock() + strloc;
5112 preglob(str, varflags & VSQUOTE, 0);
5113
5114 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5115 zero = subtype >> 1;
5116 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5117 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5118
5119 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5120 if (loc) {
5121 if (zero) {
5122 memmove(startp, loc, str - loc);
5123 loc = startp + (str - loc) - 1;
5124 }
5125 *loc = '\0';
5126 amount = loc - expdest;
5127 STADJUST(amount, expdest);
5128 }
5129 return loc;
5130}
5131
5132
Eric Andersen62483552001-07-10 06:09:16 +00005133/*
5134 * Expand a variable, and return a pointer to the next character in the
5135 * input string.
5136 */
Eric Andersenc470f442003-07-28 09:56:35 +00005137static char *
5138evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005139{
5140 int subtype;
5141 int varflags;
5142 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005143 int patloc;
5144 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005145 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005146 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005147 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005148 int quotes;
5149 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005150
Eric Andersenc470f442003-07-28 09:56:35 +00005151 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005152 varflags = *p++;
5153 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005154 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005155 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005156 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005157 startloc = expdest - (char *)stackblock();
5158 p = strchr(p, '=') + 1;
5159
Eric Andersenc470f442003-07-28 09:56:35 +00005160again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005161 varlen = varvalue(var, varflags, flag);
5162 if (varflags & VSNUL)
5163 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005164
Glenn L McGrath76620622004-01-13 10:19:37 +00005165 if (subtype == VSPLUS) {
5166 varlen = -1 - varlen;
5167 goto vsplus;
5168 }
Eric Andersen62483552001-07-10 06:09:16 +00005169
Eric Andersenc470f442003-07-28 09:56:35 +00005170 if (subtype == VSMINUS) {
5171vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005172 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005173 argstr(
5174 p, flag | EXP_TILDE |
5175 (quoted ? EXP_QWORD : EXP_WORD)
5176 );
5177 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005178 }
5179 if (easy)
5180 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005181 goto end;
5182 }
Eric Andersen62483552001-07-10 06:09:16 +00005183
Eric Andersenc470f442003-07-28 09:56:35 +00005184 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005185 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005186 if (subevalvar(p, var, 0, subtype, startloc,
5187 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005188 varflags &= ~VSNUL;
5189 /*
5190 * Remove any recorded regions beyond
5191 * start of variable
5192 */
5193 removerecordregions(startloc);
5194 goto again;
5195 }
Eric Andersenc470f442003-07-28 09:56:35 +00005196 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005197 }
5198 if (easy)
5199 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005200 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005201 }
5202
Glenn L McGrath76620622004-01-13 10:19:37 +00005203 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005204 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005205
Eric Andersenc470f442003-07-28 09:56:35 +00005206 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005207 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005208 goto record;
5209 }
5210
5211 if (subtype == VSNORMAL) {
5212 if (!easy)
5213 goto end;
5214record:
5215 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5216 goto end;
5217 }
5218
5219#ifdef DEBUG
5220 switch (subtype) {
5221 case VSTRIMLEFT:
5222 case VSTRIMLEFTMAX:
5223 case VSTRIMRIGHT:
5224 case VSTRIMRIGHTMAX:
5225 break;
5226 default:
5227 abort();
5228 }
5229#endif
5230
Glenn L McGrath76620622004-01-13 10:19:37 +00005231 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005232 /*
5233 * Terminate the string and start recording the pattern
5234 * right after it
5235 */
5236 STPUTC('\0', expdest);
5237 patloc = expdest - (char *)stackblock();
5238 if (subevalvar(p, NULL, patloc, subtype,
5239 startloc, varflags, quotes) == 0) {
5240 int amount = expdest - (
5241 (char *)stackblock() + patloc - 1
5242 );
5243 STADJUST(-amount, expdest);
5244 }
5245 /* Remove any recorded regions beyond start of variable */
5246 removerecordregions(startloc);
5247 goto record;
5248 }
5249
5250end:
5251 if (subtype != VSNORMAL) { /* skip to end of alternative */
5252 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005253 for (;;) {
5254 if ((c = *p++) == CTLESC)
5255 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005256 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005257 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005258 argbackq = argbackq->next;
5259 } else if (c == CTLVAR) {
5260 if ((*p++ & VSTYPE) != VSNORMAL)
5261 nesting++;
5262 } else if (c == CTLENDVAR) {
5263 if (--nesting == 0)
5264 break;
5265 }
5266 }
5267 }
5268 return p;
5269}
5270
Eric Andersencb57d552001-06-28 07:25:16 +00005271
Eric Andersencb57d552001-06-28 07:25:16 +00005272/*
5273 * Put a string on the stack.
5274 */
5275
Eric Andersenc470f442003-07-28 09:56:35 +00005276static void
5277memtodest(const char *p, size_t len, int syntax, int quotes) {
5278 char *q = expdest;
5279
5280 q = makestrspace(len * 2, q);
5281
5282 while (len--) {
5283 int c = *p++;
5284 if (!c)
5285 continue;
5286 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5287 USTPUTC(CTLESC, q);
5288 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005289 }
Eric Andersenc470f442003-07-28 09:56:35 +00005290
5291 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005292}
5293
Eric Andersenc470f442003-07-28 09:56:35 +00005294
5295static void
5296strtodest(const char *p, int syntax, int quotes)
5297{
5298 memtodest(p, strlen(p), syntax, quotes);
5299}
5300
5301
Eric Andersencb57d552001-06-28 07:25:16 +00005302/*
5303 * Add the value of a specialized variable to the stack string.
5304 */
5305
Glenn L McGrath76620622004-01-13 10:19:37 +00005306static ssize_t
5307varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005308{
5309 int num;
5310 char *p;
5311 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005312 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005313 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005314 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005315 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005316 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005317 int quoted = varflags & VSQUOTE;
5318 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005319 int quotes = flags & (EXP_FULL | EXP_CASE);
5320
Glenn L McGrath76620622004-01-13 10:19:37 +00005321 if (quoted && (flags & EXP_FULL))
5322 sep = 1 << CHAR_BIT;
5323
Eric Andersencb57d552001-06-28 07:25:16 +00005324 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5325 switch (*name) {
5326 case '$':
5327 num = rootpid;
5328 goto numvar;
5329 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005330 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005331 goto numvar;
5332 case '#':
5333 num = shellparam.nparam;
5334 goto numvar;
5335 case '!':
5336 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005337 if (num == 0)
5338 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005339numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005340 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005341 break;
5342 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005343 p = makestrspace(NOPTS, expdest);
5344 for (i = NOPTS - 1; i >= 0; i--) {
5345 if (optlist[i]) {
5346 USTPUTC(optletters(i), p);
5347 len++;
5348 }
Eric Andersencb57d552001-06-28 07:25:16 +00005349 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005350 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005351 break;
5352 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005353 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005354 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005355 /* fall through */
5356 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005357 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005358 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5359 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005360param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005361 if (!(ap = shellparam.p))
5362 return -1;
5363 while ((p = *ap++)) {
5364 size_t partlen;
5365
5366 partlen = strlen(p);
5367
5368 len += partlen;
5369 if (len > partlen && sep) {
5370 char *q;
5371
5372 len++;
5373 if (subtype == VSPLUS || subtype == VSLENGTH) {
5374 continue;
5375 }
5376 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005377 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005378 STPUTC(CTLESC, q);
5379 STPUTC(sep, q);
5380 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005381 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005382
5383 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5384 memtodest(p, partlen, syntax, quotes);
Eric Andersencb57d552001-06-28 07:25:16 +00005385 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005386 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005387 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005388 case '1':
5389 case '2':
5390 case '3':
5391 case '4':
5392 case '5':
5393 case '6':
5394 case '7':
5395 case '8':
5396 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005397 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005398 if (num < 0 || num > shellparam.nparam)
5399 return -1;
5400 p = num ? shellparam.p[num - 1] : arg0;
5401 goto value;
5402 default:
5403 p = lookupvar(name);
5404value:
5405 if (!p)
5406 return -1;
5407
5408 len = strlen(p);
5409 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5410 memtodest(p, len, syntax, quotes);
5411 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005412 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005413
5414 if (subtype == VSPLUS || subtype == VSLENGTH)
5415 STADJUST(-len, expdest);
5416 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005417}
5418
5419
Eric Andersencb57d552001-06-28 07:25:16 +00005420/*
5421 * Record the fact that we have to scan this region of the
5422 * string for IFS characters.
5423 */
5424
Eric Andersenc470f442003-07-28 09:56:35 +00005425static void
5426recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005427{
5428 struct ifsregion *ifsp;
5429
5430 if (ifslastp == NULL) {
5431 ifsp = &ifsfirst;
5432 } else {
5433 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005434 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005435 ifsp->next = NULL;
5436 ifslastp->next = ifsp;
5437 INTON;
5438 }
5439 ifslastp = ifsp;
5440 ifslastp->begoff = start;
5441 ifslastp->endoff = end;
5442 ifslastp->nulonly = nulonly;
5443}
5444
5445
Eric Andersencb57d552001-06-28 07:25:16 +00005446/*
5447 * Break the argument string into pieces based upon IFS and add the
5448 * strings to the argument list. The regions of the string to be
5449 * searched for IFS characters have been stored by recordregion.
5450 */
Eric Andersenc470f442003-07-28 09:56:35 +00005451static void
5452ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005453{
Eric Andersencb57d552001-06-28 07:25:16 +00005454 struct ifsregion *ifsp;
5455 struct strlist *sp;
5456 char *start;
5457 char *p;
5458 char *q;
5459 const char *ifs, *realifs;
5460 int ifsspc;
5461 int nulonly;
5462
5463
5464 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005465 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005466 ifsspc = 0;
5467 nulonly = 0;
5468 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005469 ifsp = &ifsfirst;
5470 do {
5471 p = string + ifsp->begoff;
5472 nulonly = ifsp->nulonly;
5473 ifs = nulonly ? nullstr : realifs;
5474 ifsspc = 0;
5475 while (p < string + ifsp->endoff) {
5476 q = p;
5477 if (*p == CTLESC)
5478 p++;
5479 if (strchr(ifs, *p)) {
5480 if (!nulonly)
5481 ifsspc = (strchr(defifs, *p) != NULL);
5482 /* Ignore IFS whitespace at start */
5483 if (q == start && ifsspc) {
5484 p++;
5485 start = p;
5486 continue;
5487 }
5488 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005489 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005490 sp->text = start;
5491 *arglist->lastp = sp;
5492 arglist->lastp = &sp->next;
5493 p++;
5494 if (!nulonly) {
5495 for (;;) {
5496 if (p >= string + ifsp->endoff) {
5497 break;
5498 }
5499 q = p;
5500 if (*p == CTLESC)
5501 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005502 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005503 p = q;
5504 break;
5505 } else if (strchr(defifs, *p) == NULL) {
5506 if (ifsspc) {
5507 p++;
5508 ifsspc = 0;
5509 } else {
5510 p = q;
5511 break;
5512 }
5513 } else
5514 p++;
5515 }
5516 }
5517 start = p;
5518 } else
5519 p++;
5520 }
5521 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005522 if (nulonly)
5523 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005524 }
5525
Eric Andersenc470f442003-07-28 09:56:35 +00005526 if (!*start)
5527 return;
5528
5529add:
5530 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005531 sp->text = start;
5532 *arglist->lastp = sp;
5533 arglist->lastp = &sp->next;
5534}
5535
Eric Andersenc470f442003-07-28 09:56:35 +00005536static void
5537ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005538{
Eric Andersenc470f442003-07-28 09:56:35 +00005539 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005540
Eric Andersenc470f442003-07-28 09:56:35 +00005541 INTOFF;
5542 p = ifsfirst.next;
5543 do {
5544 struct ifsregion *ifsp;
5545 ifsp = p->next;
5546 ckfree(p);
5547 p = ifsp;
5548 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005549 ifslastp = NULL;
5550 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005551 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005552}
5553
Eric Andersen90898442003-08-06 11:20:52 +00005554static void expmeta(char *, char *);
5555static struct strlist *expsort(struct strlist *);
5556static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005557
Eric Andersen90898442003-08-06 11:20:52 +00005558static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005559
Eric Andersencb57d552001-06-28 07:25:16 +00005560
Eric Andersenc470f442003-07-28 09:56:35 +00005561static void
Eric Andersen90898442003-08-06 11:20:52 +00005562expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005563{
Eric Andersen90898442003-08-06 11:20:52 +00005564 static const char metachars[] = {
5565 '*', '?', '[', 0
5566 };
Eric Andersencb57d552001-06-28 07:25:16 +00005567 /* TODO - EXP_REDIR */
5568
5569 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005570 struct strlist **savelastp;
5571 struct strlist *sp;
5572 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005573
Eric Andersencb57d552001-06-28 07:25:16 +00005574 if (fflag)
5575 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005576 if (!strpbrk(str->text, metachars))
5577 goto nometa;
5578 savelastp = exparg.lastp;
5579
Eric Andersencb57d552001-06-28 07:25:16 +00005580 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005581 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005582 {
5583 int i = strlen(str->text);
5584 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5585 }
5586
5587 expmeta(expdir, p);
5588 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005589 if (p != str->text)
5590 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005591 INTON;
5592 if (exparg.lastp == savelastp) {
5593 /*
5594 * no matches
5595 */
Eric Andersenc470f442003-07-28 09:56:35 +00005596nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005597 *exparg.lastp = str;
5598 rmescapes(str->text);
5599 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005600 } else {
5601 *exparg.lastp = NULL;
5602 *savelastp = sp = expsort(*savelastp);
5603 while (sp->next != NULL)
5604 sp = sp->next;
5605 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005606 }
5607 str = str->next;
5608 }
5609}
5610
Eric Andersencb57d552001-06-28 07:25:16 +00005611/*
Eric Andersenc470f442003-07-28 09:56:35 +00005612 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005613 */
5614
Eric Andersenc470f442003-07-28 09:56:35 +00005615static void
Eric Andersen90898442003-08-06 11:20:52 +00005616addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005617{
Eric Andersencb57d552001-06-28 07:25:16 +00005618 struct strlist *sp;
5619
Eric Andersenc470f442003-07-28 09:56:35 +00005620 sp = (struct strlist *)stalloc(sizeof *sp);
5621 sp->text = sstrdup(name);
5622 *exparg.lastp = sp;
5623 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005624}
5625
5626
Eric Andersencb57d552001-06-28 07:25:16 +00005627/*
Eric Andersen90898442003-08-06 11:20:52 +00005628 * Do metacharacter (i.e. *, ?, [...]) expansion.
5629 */
5630
5631static void
5632expmeta(char *enddir, char *name)
5633{
5634 char *p;
5635 const char *cp;
5636 char *start;
5637 char *endname;
5638 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005639 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005640 DIR *dirp;
5641 struct dirent *dp;
5642 int atend;
5643 int matchdot;
5644
5645 metaflag = 0;
5646 start = name;
5647 for (p = name; *p; p++) {
5648 if (*p == '*' || *p == '?')
5649 metaflag = 1;
5650 else if (*p == '[') {
5651 char *q = p + 1;
5652 if (*q == '!')
5653 q++;
5654 for (;;) {
5655 if (*q == '\\')
5656 q++;
5657 if (*q == '/' || *q == '\0')
5658 break;
5659 if (*++q == ']') {
5660 metaflag = 1;
5661 break;
5662 }
5663 }
5664 } else if (*p == '\\')
5665 p++;
5666 else if (*p == '/') {
5667 if (metaflag)
5668 goto out;
5669 start = p + 1;
5670 }
5671 }
5672out:
5673 if (metaflag == 0) { /* we've reached the end of the file name */
5674 if (enddir != expdir)
5675 metaflag++;
5676 p = name;
5677 do {
5678 if (*p == '\\')
5679 p++;
5680 *enddir++ = *p;
5681 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005682 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005683 addfname(expdir);
5684 return;
5685 }
5686 endname = p;
5687 if (name < start) {
5688 p = name;
5689 do {
5690 if (*p == '\\')
5691 p++;
5692 *enddir++ = *p++;
5693 } while (p < start);
5694 }
5695 if (enddir == expdir) {
5696 cp = ".";
5697 } else if (enddir == expdir + 1 && *expdir == '/') {
5698 cp = "/";
5699 } else {
5700 cp = expdir;
5701 enddir[-1] = '\0';
5702 }
5703 if ((dirp = opendir(cp)) == NULL)
5704 return;
5705 if (enddir != expdir)
5706 enddir[-1] = '/';
5707 if (*endname == 0) {
5708 atend = 1;
5709 } else {
5710 atend = 0;
5711 *endname++ = '\0';
5712 }
5713 matchdot = 0;
5714 p = start;
5715 if (*p == '\\')
5716 p++;
5717 if (*p == '.')
5718 matchdot++;
5719 while (! intpending && (dp = readdir(dirp)) != NULL) {
5720 if (dp->d_name[0] == '.' && ! matchdot)
5721 continue;
5722 if (pmatch(start, dp->d_name)) {
5723 if (atend) {
5724 scopy(dp->d_name, enddir);
5725 addfname(expdir);
5726 } else {
5727 for (p = enddir, cp = dp->d_name;
5728 (*p++ = *cp++) != '\0';)
5729 continue;
5730 p[-1] = '/';
5731 expmeta(p, endname);
5732 }
5733 }
5734 }
5735 closedir(dirp);
5736 if (! atend)
5737 endname[-1] = '/';
5738}
5739
5740/*
5741 * Sort the results of file name expansion. It calculates the number of
5742 * strings to sort and then calls msort (short for merge sort) to do the
5743 * work.
5744 */
5745
5746static struct strlist *
5747expsort(struct strlist *str)
5748{
5749 int len;
5750 struct strlist *sp;
5751
5752 len = 0;
5753 for (sp = str ; sp ; sp = sp->next)
5754 len++;
5755 return msort(str, len);
5756}
5757
5758
5759static struct strlist *
5760msort(struct strlist *list, int len)
5761{
5762 struct strlist *p, *q = NULL;
5763 struct strlist **lpp;
5764 int half;
5765 int n;
5766
5767 if (len <= 1)
5768 return list;
5769 half = len >> 1;
5770 p = list;
5771 for (n = half ; --n >= 0 ; ) {
5772 q = p;
5773 p = p->next;
5774 }
5775 q->next = NULL; /* terminate first half of list */
5776 q = msort(list, half); /* sort first half of list */
5777 p = msort(p, len - half); /* sort second half */
5778 lpp = &list;
5779 for (;;) {
5780#ifdef CONFIG_LOCALE_SUPPORT
5781 if (strcoll(p->text, q->text) < 0)
5782#else
5783 if (strcmp(p->text, q->text) < 0)
5784#endif
5785 {
5786 *lpp = p;
5787 lpp = &p->next;
5788 if ((p = *lpp) == NULL) {
5789 *lpp = q;
5790 break;
5791 }
5792 } else {
5793 *lpp = q;
5794 lpp = &q->next;
5795 if ((q = *lpp) == NULL) {
5796 *lpp = p;
5797 break;
5798 }
5799 }
5800 }
5801 return list;
5802}
5803
5804
5805/*
Eric Andersencb57d552001-06-28 07:25:16 +00005806 * Returns true if the pattern matches the string.
5807 */
5808
Eric Andersenc470f442003-07-28 09:56:35 +00005809static inline int
5810patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005811{
Eric Andersenc470f442003-07-28 09:56:35 +00005812 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005813}
5814
5815
Eric Andersencb57d552001-06-28 07:25:16 +00005816/*
5817 * Remove any CTLESC characters from a string.
5818 */
5819
Eric Andersenc470f442003-07-28 09:56:35 +00005820static char *
5821_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005822{
5823 char *p, *q, *r;
5824 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005825 unsigned inquotes;
5826 int notescaped;
5827 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005828
5829 p = strpbrk(str, qchars);
5830 if (!p) {
5831 return str;
5832 }
5833 q = p;
5834 r = str;
5835 if (flag & RMESCAPE_ALLOC) {
5836 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005837 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005838
Eric Andersenc470f442003-07-28 09:56:35 +00005839 if (flag & RMESCAPE_GROW) {
5840 r = makestrspace(fulllen, expdest);
5841 } else if (flag & RMESCAPE_HEAP) {
5842 r = ckmalloc(fulllen);
5843 } else {
5844 r = stalloc(fulllen);
5845 }
5846 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005847 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005848 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005849 }
5850 }
Eric Andersenc470f442003-07-28 09:56:35 +00005851 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5852 globbing = flag & RMESCAPE_GLOB;
5853 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005854 while (*p) {
5855 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005856 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005857 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005858 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005859 continue;
5860 }
Eric Andersenc470f442003-07-28 09:56:35 +00005861 if (*p == '\\') {
5862 /* naked back slash */
5863 notescaped = 0;
5864 goto copy;
5865 }
Eric Andersencb57d552001-06-28 07:25:16 +00005866 if (*p == CTLESC) {
5867 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005868 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005869 *q++ = '\\';
5870 }
5871 }
Eric Andersenc470f442003-07-28 09:56:35 +00005872 notescaped = globbing;
5873copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005874 *q++ = *p++;
5875 }
5876 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005877 if (flag & RMESCAPE_GROW) {
5878 expdest = r;
5879 STADJUST(q - r + 1, expdest);
5880 }
Eric Andersencb57d552001-06-28 07:25:16 +00005881 return r;
5882}
Eric Andersencb57d552001-06-28 07:25:16 +00005883
5884
Eric Andersencb57d552001-06-28 07:25:16 +00005885/*
5886 * See if a pattern matches in a case statement.
5887 */
5888
Eric Andersenc470f442003-07-28 09:56:35 +00005889int
5890casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005891{
Eric Andersencb57d552001-06-28 07:25:16 +00005892 struct stackmark smark;
5893 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005894
5895 setstackmark(&smark);
5896 argbackq = pattern->narg.backquote;
5897 STARTSTACKSTR(expdest);
5898 ifslastp = NULL;
5899 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005900 STACKSTRNUL(expdest);
5901 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005902 popstackmark(&smark);
5903 return result;
5904}
5905
5906/*
5907 * Our own itoa().
5908 */
5909
Eric Andersenc470f442003-07-28 09:56:35 +00005910static int
5911cvtnum(long num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005912{
Eric Andersencb57d552001-06-28 07:25:16 +00005913 int len;
5914
Eric Andersenc470f442003-07-28 09:56:35 +00005915 expdest = makestrspace(32, expdest);
5916 len = fmtstr(expdest, 32, "%ld", num);
5917 STADJUST(len, expdest);
5918 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005919}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005920
Eric Andersenc470f442003-07-28 09:56:35 +00005921static void
5922varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005923{
Eric Andersenc470f442003-07-28 09:56:35 +00005924 const char *msg;
5925 const char *tail;
5926
5927 tail = nullstr;
5928 msg = "parameter not set";
5929 if (umsg) {
5930 if (*end == CTLENDVAR) {
5931 if (varflags & VSNUL)
5932 tail = " or null";
5933 } else
5934 msg = umsg;
5935 }
5936 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005937}
Eric Andersen90898442003-08-06 11:20:52 +00005938
5939
Eric Andersenc470f442003-07-28 09:56:35 +00005940/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005941
Eric Andersencb57d552001-06-28 07:25:16 +00005942/*
Eric Andersen90898442003-08-06 11:20:52 +00005943 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005944 */
5945
Eric Andersenc470f442003-07-28 09:56:35 +00005946#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5947#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005948
Eric Andersenc470f442003-07-28 09:56:35 +00005949static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005950
Eric Andersencb57d552001-06-28 07:25:16 +00005951/*
5952 * Read a line from the script.
5953 */
5954
Eric Andersenc470f442003-07-28 09:56:35 +00005955static inline char *
5956pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005957{
5958 char *p = line;
5959 int nleft = len;
5960 int c;
5961
5962 while (--nleft > 0) {
5963 c = pgetc2();
5964 if (c == PEOF) {
5965 if (p == line)
5966 return NULL;
5967 break;
5968 }
5969 *p++ = c;
5970 if (c == '\n')
5971 break;
5972 }
5973 *p = '\0';
5974 return line;
5975}
5976
Eric Andersenc470f442003-07-28 09:56:35 +00005977
5978/*
5979 * Read a character from the script, returning PEOF on end of file.
5980 * Nul characters in the input are silently discarded.
5981 */
5982
5983#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5984
5985#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5986#define pgetc_macro() pgetc()
5987static int
5988pgetc(void)
5989{
5990 return pgetc_as_macro();
5991}
5992#else
5993#define pgetc_macro() pgetc_as_macro()
5994static int
5995pgetc(void)
5996{
5997 return pgetc_macro();
5998}
5999#endif
6000
6001
6002/*
6003 * Same as pgetc(), but ignores PEOA.
6004 */
6005#ifdef CONFIG_ASH_ALIAS
6006static int pgetc2(void)
6007{
6008 int c;
6009
6010 do {
6011 c = pgetc_macro();
6012 } while (c == PEOA);
6013 return c;
6014}
6015#else
6016static inline int pgetc2(void)
6017{
6018 return pgetc_macro();
6019}
6020#endif
6021
6022
6023#ifdef CONFIG_FEATURE_COMMAND_EDITING
6024static const char *cmdedit_prompt;
6025static inline void putprompt(const char *s)
6026{
6027 cmdedit_prompt = s;
6028}
6029#else
6030static inline void putprompt(const char *s)
6031{
6032 out2str(s);
6033}
6034#endif
6035
6036static inline int
6037preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006038{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006039 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006040 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006041 parsenextc = buf;
6042
Eric Andersenc470f442003-07-28 09:56:35 +00006043retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006044#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006045 if (!iflag || parsefile->fd)
6046 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6047 else {
Eric Andersenfa06a772004-02-06 10:33:19 +00006048 cmdedit_path_lookup = pathval();
Eric Andersenc470f442003-07-28 09:56:35 +00006049 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6050 if(nr == 0) {
6051 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006052 if(trap[SIGINT]) {
6053 buf[0] = '\n';
6054 buf[1] = 0;
6055 raise(SIGINT);
6056 return 1;
6057 }
Eric Andersenc470f442003-07-28 09:56:35 +00006058 goto retry;
6059 }
6060 if(nr < 0) {
6061 /* Ctrl+D presend */
6062 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006063 }
Eric Andersencb57d552001-06-28 07:25:16 +00006064 }
6065#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006066 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006067#endif
6068
6069 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006070 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6071 int flags = fcntl(0, F_GETFL, 0);
6072 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006073 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006074 if (fcntl(0, F_SETFL, flags) >= 0) {
6075 out2str("sh: turning off NDELAY mode\n");
6076 goto retry;
6077 }
6078 }
6079 }
6080 }
6081 return nr;
6082}
6083
6084/*
6085 * Refill the input buffer and return the next input character:
6086 *
6087 * 1) If a string was pushed back on the input, pop it;
6088 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6089 * from a string so we can't refill the buffer, return EOF.
6090 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6091 * 4) Process input up to the next newline, deleting nul characters.
6092 */
6093
Eric Andersenc470f442003-07-28 09:56:35 +00006094int
6095preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006096{
6097 char *p, *q;
6098 int more;
6099 char savec;
6100
6101 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006102#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006103 if (parsenleft == -1 && parsefile->strpush->ap &&
6104 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006105 return PEOA;
6106 }
Eric Andersen2870d962001-07-02 17:27:21 +00006107#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006108 popstring();
6109 if (--parsenleft >= 0)
6110 return (*parsenextc++);
6111 }
6112 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6113 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006114 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006115
Eric Andersenc470f442003-07-28 09:56:35 +00006116again:
Eric Andersencb57d552001-06-28 07:25:16 +00006117 if (parselleft <= 0) {
6118 if ((parselleft = preadfd()) <= 0) {
6119 parselleft = parsenleft = EOF_NLEFT;
6120 return PEOF;
6121 }
6122 }
6123
6124 q = p = parsenextc;
6125
6126 /* delete nul characters */
6127 for (more = 1; more;) {
6128 switch (*p) {
6129 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006130 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006131 goto check;
6132
Eric Andersencb57d552001-06-28 07:25:16 +00006133 case '\n':
6134 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006135 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006136 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006137
Eric Andersencb57d552001-06-28 07:25:16 +00006138 }
6139
6140 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006141check:
Eric Andersencb57d552001-06-28 07:25:16 +00006142 if (--parselleft <= 0 && more) {
6143 parsenleft = q - parsenextc - 1;
6144 if (parsenleft < 0)
6145 goto again;
6146 more = 0;
6147 }
6148 }
6149
6150 savec = *q;
6151 *q = '\0';
6152
6153 if (vflag) {
6154 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006155 }
6156
6157 *q = savec;
6158
6159 return *parsenextc++;
6160}
6161
Eric Andersenc470f442003-07-28 09:56:35 +00006162/*
6163 * Undo the last call to pgetc. Only one character may be pushed back.
6164 * PEOF may be pushed back.
6165 */
6166
6167void
6168pungetc(void)
6169{
6170 parsenleft++;
6171 parsenextc--;
6172}
Eric Andersencb57d552001-06-28 07:25:16 +00006173
6174/*
6175 * Push a string back onto the input at this current parsefile level.
6176 * We handle aliases this way.
6177 */
Eric Andersenc470f442003-07-28 09:56:35 +00006178void
6179pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006180{
Eric Andersencb57d552001-06-28 07:25:16 +00006181 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006182 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006183
Eric Andersenc470f442003-07-28 09:56:35 +00006184 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006185 INTOFF;
6186/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6187 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006188 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006189 sp->prev = parsefile->strpush;
6190 parsefile->strpush = sp;
6191 } else
6192 sp = parsefile->strpush = &(parsefile->basestrpush);
6193 sp->prevstring = parsenextc;
6194 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006195#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006196 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006197 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006198 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006199 sp->string = s;
6200 }
Eric Andersen2870d962001-07-02 17:27:21 +00006201#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006202 parsenextc = s;
6203 parsenleft = len;
6204 INTON;
6205}
6206
Eric Andersenc470f442003-07-28 09:56:35 +00006207void
6208popstring(void)
6209{
6210 struct strpush *sp = parsefile->strpush;
6211
6212 INTOFF;
6213#ifdef CONFIG_ASH_ALIAS
6214 if (sp->ap) {
6215 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6216 checkkwd |= CHKALIAS;
6217 }
6218 if (sp->string != sp->ap->val) {
6219 ckfree(sp->string);
6220 }
6221 sp->ap->flag &= ~ALIASINUSE;
6222 if (sp->ap->flag & ALIASDEAD) {
6223 unalias(sp->ap->name);
6224 }
6225 }
6226#endif
6227 parsenextc = sp->prevstring;
6228 parsenleft = sp->prevnleft;
6229/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6230 parsefile->strpush = sp->prev;
6231 if (sp != &(parsefile->basestrpush))
6232 ckfree(sp);
6233 INTON;
6234}
6235
6236/*
6237 * Set the input to take input from a file. If push is set, push the
6238 * old input onto the stack first.
6239 */
6240
6241void
6242setinputfile(const char *fname, int push)
6243{
6244 int fd;
6245 int fd2;
6246
6247 INTOFF;
6248 if ((fd = open(fname, O_RDONLY)) < 0)
6249 error("Can't open %s", fname);
6250 if (fd < 10) {
6251 fd2 = copyfd(fd, 10);
6252 close(fd);
6253 if (fd2 < 0)
6254 error("Out of file descriptors");
6255 fd = fd2;
6256 }
6257 setinputfd(fd, push);
6258 INTON;
6259}
6260
6261
6262/*
6263 * Like setinputfile, but takes an open file descriptor. Call this with
6264 * interrupts off.
6265 */
6266
6267static void
6268setinputfd(int fd, int push)
6269{
6270 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6271 if (push) {
6272 pushfile();
6273 parsefile->buf = 0;
6274 }
6275 parsefile->fd = fd;
6276 if (parsefile->buf == NULL)
6277 parsefile->buf = ckmalloc(IBUFSIZ);
6278 parselleft = parsenleft = 0;
6279 plinno = 1;
6280}
6281
Eric Andersencb57d552001-06-28 07:25:16 +00006282
Eric Andersencb57d552001-06-28 07:25:16 +00006283/*
6284 * Like setinputfile, but takes input from a string.
6285 */
6286
Eric Andersenc470f442003-07-28 09:56:35 +00006287static void
6288setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006289{
Eric Andersencb57d552001-06-28 07:25:16 +00006290 INTOFF;
6291 pushfile();
6292 parsenextc = string;
6293 parsenleft = strlen(string);
6294 parsefile->buf = NULL;
6295 plinno = 1;
6296 INTON;
6297}
6298
6299
Eric Andersencb57d552001-06-28 07:25:16 +00006300/*
6301 * To handle the "." command, a stack of input files is used. Pushfile
6302 * adds a new entry to the stack and popfile restores the previous level.
6303 */
6304
Eric Andersenc470f442003-07-28 09:56:35 +00006305static void
6306pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006307{
Eric Andersencb57d552001-06-28 07:25:16 +00006308 struct parsefile *pf;
6309
6310 parsefile->nleft = parsenleft;
6311 parsefile->lleft = parselleft;
6312 parsefile->nextc = parsenextc;
6313 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006314 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006315 pf->prev = parsefile;
6316 pf->fd = -1;
6317 pf->strpush = NULL;
6318 pf->basestrpush.prev = NULL;
6319 parsefile = pf;
6320}
6321
Eric Andersenc470f442003-07-28 09:56:35 +00006322
6323static void
6324popfile(void)
6325{
6326 struct parsefile *pf = parsefile;
6327
6328 INTOFF;
6329 if (pf->fd >= 0)
6330 close(pf->fd);
6331 if (pf->buf)
6332 ckfree(pf->buf);
6333 while (pf->strpush)
6334 popstring();
6335 parsefile = pf->prev;
6336 ckfree(pf);
6337 parsenleft = parsefile->nleft;
6338 parselleft = parsefile->lleft;
6339 parsenextc = parsefile->nextc;
6340 plinno = parsefile->linno;
6341 INTON;
6342}
Eric Andersencb57d552001-06-28 07:25:16 +00006343
6344
Eric Andersen2870d962001-07-02 17:27:21 +00006345/*
Eric Andersenc470f442003-07-28 09:56:35 +00006346 * Return to top level.
6347 */
Eric Andersen2870d962001-07-02 17:27:21 +00006348
Eric Andersenc470f442003-07-28 09:56:35 +00006349static void
6350popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006351{
Eric Andersenc470f442003-07-28 09:56:35 +00006352 while (parsefile != &basepf)
6353 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006354}
6355
Eric Andersen2870d962001-07-02 17:27:21 +00006356
Eric Andersenc470f442003-07-28 09:56:35 +00006357/*
6358 * Close the file(s) that the shell is reading commands from. Called
6359 * after a fork is done.
6360 */
6361
6362static void
6363closescript(void)
6364{
6365 popallfiles();
6366 if (parsefile->fd > 0) {
6367 close(parsefile->fd);
6368 parsefile->fd = 0;
6369 }
6370}
Eric Andersenc470f442003-07-28 09:56:35 +00006371
Eric Andersen90898442003-08-06 11:20:52 +00006372/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006373
6374/* mode flags for set_curjob */
6375#define CUR_DELETE 2
6376#define CUR_RUNNING 1
6377#define CUR_STOPPED 0
6378
6379/* mode flags for dowait */
6380#define DOWAIT_NORMAL 0
6381#define DOWAIT_BLOCK 1
6382
6383/* array of jobs */
6384static struct job *jobtab;
6385/* size of array */
6386static unsigned njobs;
6387#if JOBS
6388/* pgrp of shell on invocation */
6389static int initialpgrp;
6390static int ttyfd = -1;
6391#endif
6392/* current job */
6393static struct job *curjob;
6394/* number of presumed living untracked jobs */
6395static int jobless;
6396
6397static void set_curjob(struct job *, unsigned);
6398#if JOBS
6399static int restartjob(struct job *, int);
6400static void xtcsetpgrp(int, pid_t);
6401static char *commandtext(union node *);
6402static void cmdlist(union node *, int);
6403static void cmdtxt(union node *);
6404static void cmdputs(const char *);
6405static void showpipe(struct job *, FILE *);
6406#endif
6407static int sprint_status(char *, int, int);
6408static void freejob(struct job *);
6409static struct job *getjob(const char *, int);
6410static struct job *growjobtab(void);
6411static void forkchild(struct job *, union node *, int);
6412static void forkparent(struct job *, union node *, int, pid_t);
6413static int dowait(int, struct job *);
6414static int getstatus(struct job *);
6415
6416static void
6417set_curjob(struct job *jp, unsigned mode)
6418{
6419 struct job *jp1;
6420 struct job **jpp, **curp;
6421
6422 /* first remove from list */
6423 jpp = curp = &curjob;
6424 do {
6425 jp1 = *jpp;
6426 if (jp1 == jp)
6427 break;
6428 jpp = &jp1->prev_job;
6429 } while (1);
6430 *jpp = jp1->prev_job;
6431
6432 /* Then re-insert in correct position */
6433 jpp = curp;
6434 switch (mode) {
6435 default:
6436#ifdef DEBUG
6437 abort();
6438#endif
6439 case CUR_DELETE:
6440 /* job being deleted */
6441 break;
6442 case CUR_RUNNING:
6443 /* newly created job or backgrounded job,
6444 put after all stopped jobs. */
6445 do {
6446 jp1 = *jpp;
6447#ifdef JOBS
6448 if (!jp1 || jp1->state != JOBSTOPPED)
6449#endif
6450 break;
6451 jpp = &jp1->prev_job;
6452 } while (1);
6453 /* FALLTHROUGH */
6454#ifdef JOBS
6455 case CUR_STOPPED:
6456#endif
6457 /* newly stopped job - becomes curjob */
6458 jp->prev_job = *jpp;
6459 *jpp = jp;
6460 break;
6461 }
6462}
6463
6464#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006465/*
6466 * Turn job control on and off.
6467 *
6468 * Note: This code assumes that the third arg to ioctl is a character
6469 * pointer, which is true on Berkeley systems but not System V. Since
6470 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006471 *
6472 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006473 */
6474
Eric Andersenc470f442003-07-28 09:56:35 +00006475void
6476setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006477{
Eric Andersenc470f442003-07-28 09:56:35 +00006478 int fd;
6479 int pgrp;
6480
6481 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006482 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006483 if (on) {
6484 int ofd;
6485 ofd = fd = open(_PATH_TTY, O_RDWR);
6486 if (fd < 0) {
6487 fd += 3;
6488 while (!isatty(fd) && --fd >= 0)
6489 ;
6490 }
6491 fd = fcntl(fd, F_DUPFD, 10);
6492 close(ofd);
6493 if (fd < 0)
6494 goto out;
6495 fcntl(fd, F_SETFD, FD_CLOEXEC);
6496 do { /* while we are in the background */
6497 if ((pgrp = tcgetpgrp(fd)) < 0) {
6498out:
6499 sh_warnx("can't access tty; job control turned off");
6500 mflag = on = 0;
6501 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006502 }
Eric Andersenc470f442003-07-28 09:56:35 +00006503 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006504 break;
6505 killpg(0, SIGTTIN);
6506 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006507 initialpgrp = pgrp;
6508
Eric Andersencb57d552001-06-28 07:25:16 +00006509 setsignal(SIGTSTP);
6510 setsignal(SIGTTOU);
6511 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006512 pgrp = rootpid;
6513 setpgid(0, pgrp);
6514 xtcsetpgrp(fd, pgrp);
6515 } else {
6516 /* turning job control off */
6517 fd = ttyfd;
6518 pgrp = initialpgrp;
6519 xtcsetpgrp(fd, pgrp);
6520 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006521 setsignal(SIGTSTP);
6522 setsignal(SIGTTOU);
6523 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006524close:
6525 close(fd);
6526 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006527 }
Eric Andersenc470f442003-07-28 09:56:35 +00006528 ttyfd = fd;
6529 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006530}
Eric Andersencb57d552001-06-28 07:25:16 +00006531
Eric Andersenc470f442003-07-28 09:56:35 +00006532static int
Eric Andersen90898442003-08-06 11:20:52 +00006533killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006534{
6535 int signo = -1;
6536 int list = 0;
6537 int i;
6538 pid_t pid;
6539 struct job *jp;
6540
6541 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006542usage:
6543 error(
6544"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6545"kill -l [exitstatus]"
6546 );
Eric Andersencb57d552001-06-28 07:25:16 +00006547 }
6548
Eric Andersenc470f442003-07-28 09:56:35 +00006549 if (**++argv == '-') {
6550 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006551 if (signo < 0) {
6552 int c;
6553
6554 while ((c = nextopt("ls:")) != '\0')
6555 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006556 default:
6557#ifdef DEBUG
6558 abort();
6559#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006560 case 'l':
6561 list = 1;
6562 break;
6563 case 's':
6564 signo = decode_signal(optionarg, 1);
6565 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006566 error(
6567 "invalid signal number or name: %s",
6568 optionarg
6569 );
Eric Andersencb57d552001-06-28 07:25:16 +00006570 }
Eric Andersen2870d962001-07-02 17:27:21 +00006571 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006572 }
Eric Andersenc470f442003-07-28 09:56:35 +00006573 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006574 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006575 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006576 }
6577
6578 if (!list && signo < 0)
6579 signo = SIGTERM;
6580
Eric Andersenc470f442003-07-28 09:56:35 +00006581 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006582 goto usage;
6583 }
6584
6585 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006586 const char *name;
6587
Eric Andersenc470f442003-07-28 09:56:35 +00006588 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006589 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006590 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006591 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006592 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006593 }
6594 return 0;
6595 }
Eric Andersen34506362001-08-02 05:02:46 +00006596 name = u_signal_names(*argptr, &signo, -1);
6597 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006598 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006599 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006600 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006601 return 0;
6602 }
6603
Eric Andersenc470f442003-07-28 09:56:35 +00006604 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006605 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006606 if (**argv == '%') {
6607 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006608 pid = -jp->ps[0].pid;
6609 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006610 pid = number(*argv);
6611 if (kill(pid, signo) != 0) {
6612 sh_warnx("%m\n");
6613 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006614 }
Eric Andersenc470f442003-07-28 09:56:35 +00006615 } while (*++argv);
6616
6617 return i;
6618}
6619#endif /* JOBS */
6620
6621#if defined(JOBS) || defined(DEBUG)
6622static int
6623jobno(const struct job *jp)
6624{
6625 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006626}
6627#endif
6628
Eric Andersenc470f442003-07-28 09:56:35 +00006629#ifdef JOBS
6630static int
6631fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006632{
Eric Andersenc470f442003-07-28 09:56:35 +00006633 struct job *jp;
6634 FILE *out;
6635 int mode;
6636 int retval;
6637
6638 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6639 nextopt(nullstr);
6640 argv = argptr;
6641 out = stdout;
6642 do {
6643 jp = getjob(*argv, 1);
6644 if (mode == FORK_BG) {
6645 set_curjob(jp, CUR_RUNNING);
6646 fprintf(out, "[%d] ", jobno(jp));
6647 }
6648 outstr(jp->ps->cmd, out);
6649 showpipe(jp, out);
6650 retval = restartjob(jp, mode);
6651 } while (*argv && *++argv);
6652 return retval;
6653}
6654
6655static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6656
6657
6658static int
6659restartjob(struct job *jp, int mode)
6660{
6661 struct procstat *ps;
6662 int i;
6663 int status;
6664 pid_t pgid;
6665
6666 INTOFF;
6667 if (jp->state == JOBDONE)
6668 goto out;
6669 jp->state = JOBRUNNING;
6670 pgid = jp->ps->pid;
6671 if (mode == FORK_FG)
6672 xtcsetpgrp(ttyfd, pgid);
6673 killpg(pgid, SIGCONT);
6674 ps = jp->ps;
6675 i = jp->nprocs;
6676 do {
6677 if (WIFSTOPPED(ps->status)) {
6678 ps->status = -1;
6679 }
6680 } while (ps++, --i);
6681out:
6682 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6683 INTON;
6684 return status;
6685}
6686#endif
6687
6688static int
6689sprint_status(char *s, int status, int sigonly)
6690{
6691 int col;
6692 int st;
6693
6694 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006695 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006696#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006697 if (WIFSTOPPED(status))
6698 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006699 else
Eric Andersenc470f442003-07-28 09:56:35 +00006700#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006701 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006702 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006703 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006704 goto out;
6705#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006706 if (WIFSTOPPED(status))
6707 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006708#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006709 }
6710 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006711 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006712 if (WCOREDUMP(status)) {
6713 col += fmtstr(s + col, 16, " (core dumped)");
6714 }
6715 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006716 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006717 if (st)
6718 col = fmtstr(s, 16, "Done(%d)", st);
6719 else
6720 col = fmtstr(s, 16, "Done");
6721 }
6722
6723out:
6724 return col;
6725}
6726
6727#if JOBS
6728static void
6729showjob(FILE *out, struct job *jp, int mode)
6730{
6731 struct procstat *ps;
6732 struct procstat *psend;
6733 int col;
6734 int indent;
6735 char s[80];
6736
6737 ps = jp->ps;
6738
6739 if (mode & SHOW_PGID) {
6740 /* just output process (group) id of pipeline */
6741 fprintf(out, "%d\n", ps->pid);
6742 return;
6743 }
6744
6745 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6746 indent = col;
6747
6748 if (jp == curjob)
6749 s[col - 2] = '+';
6750 else if (curjob && jp == curjob->prev_job)
6751 s[col - 2] = '-';
6752
6753 if (mode & SHOW_PID)
6754 col += fmtstr(s + col, 16, "%d ", ps->pid);
6755
6756 psend = ps + jp->nprocs;
6757
6758 if (jp->state == JOBRUNNING) {
6759 scopy("Running", s + col);
6760 col += strlen("Running");
6761 } else {
6762 int status = psend[-1].status;
6763#if JOBS
6764 if (jp->state == JOBSTOPPED)
6765 status = jp->stopstatus;
6766#endif
6767 col += sprint_status(s + col, status, 0);
6768 }
6769
6770 goto start;
6771
6772 do {
6773 /* for each process */
6774 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6775
6776start:
Eric Andersen90898442003-08-06 11:20:52 +00006777 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006778 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6779 );
6780 if (!(mode & SHOW_PID)) {
6781 showpipe(jp, out);
6782 break;
6783 }
6784 if (++ps == psend) {
6785 outcslow('\n', out);
6786 break;
6787 }
6788 } while (1);
6789
6790 jp->changed = 0;
6791
6792 if (jp->state == JOBDONE) {
6793 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6794 freejob(jp);
6795 }
6796}
6797
6798
6799static int
6800jobscmd(int argc, char **argv)
6801{
6802 int mode, m;
6803 FILE *out;
6804
6805 mode = 0;
6806 while ((m = nextopt("lp")))
6807 if (m == 'l')
6808 mode = SHOW_PID;
6809 else
6810 mode = SHOW_PGID;
6811
6812 out = stdout;
6813 argv = argptr;
6814 if (*argv)
6815 do
6816 showjob(out, getjob(*argv,0), mode);
6817 while (*++argv);
6818 else
6819 showjobs(out, mode);
6820
Eric Andersencb57d552001-06-28 07:25:16 +00006821 return 0;
6822}
6823
6824
6825/*
6826 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6827 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006828 */
6829
Eric Andersenc470f442003-07-28 09:56:35 +00006830static void
6831showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006832{
Eric Andersencb57d552001-06-28 07:25:16 +00006833 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006834
Eric Andersenc470f442003-07-28 09:56:35 +00006835 TRACE(("showjobs(%x) called\n", mode));
6836
6837 /* If not even one one job changed, there is nothing to do */
6838 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6839 continue;
6840
6841 for (jp = curjob; jp; jp = jp->prev_job) {
6842 if (!(mode & SHOW_CHANGED) || jp->changed)
6843 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006844 }
6845}
Eric Andersenc470f442003-07-28 09:56:35 +00006846#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006847
6848/*
6849 * Mark a job structure as unused.
6850 */
6851
Eric Andersenc470f442003-07-28 09:56:35 +00006852static void
6853freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006854{
Eric Andersenc470f442003-07-28 09:56:35 +00006855 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006856 int i;
6857
6858 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006859 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006860 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006861 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006862 }
6863 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006864 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006865 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006866 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006867 INTON;
6868}
6869
6870
Eric Andersenc470f442003-07-28 09:56:35 +00006871static int
6872waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006873{
6874 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006875 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006876 struct job *jp;
6877
Eric Andersenc470f442003-07-28 09:56:35 +00006878 EXSIGON();
6879
6880 nextopt(nullstr);
6881 retval = 0;
6882
6883 argv = argptr;
6884 if (!*argv) {
6885 /* wait for all jobs */
6886 for (;;) {
6887 jp = curjob;
6888 while (1) {
6889 if (!jp) {
6890 /* no running procs */
6891 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006892 }
Eric Andersenc470f442003-07-28 09:56:35 +00006893 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006894 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006895 jp->waited = 1;
6896 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006897 }
Eric Andersenc470f442003-07-28 09:56:35 +00006898 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006899 }
6900 }
Eric Andersenc470f442003-07-28 09:56:35 +00006901
6902 retval = 127;
6903 do {
6904 if (**argv != '%') {
6905 pid_t pid = number(*argv);
6906 job = curjob;
6907 goto start;
6908 do {
6909 if (job->ps[job->nprocs - 1].pid == pid)
6910 break;
6911 job = job->prev_job;
6912start:
6913 if (!job)
6914 goto repeat;
6915 } while (1);
6916 } else
6917 job = getjob(*argv, 0);
6918 /* loop until process terminated or stopped */
6919 while (job->state == JOBRUNNING)
6920 dowait(DOWAIT_BLOCK, 0);
6921 job->waited = 1;
6922 retval = getstatus(job);
6923repeat:
6924 ;
6925 } while (*++argv);
6926
6927out:
6928 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006929}
6930
6931
Eric Andersencb57d552001-06-28 07:25:16 +00006932/*
6933 * Convert a job name to a job structure.
6934 */
6935
Eric Andersenc470f442003-07-28 09:56:35 +00006936static struct job *
6937getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006938{
Eric Andersencb57d552001-06-28 07:25:16 +00006939 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006940 struct job *found;
6941 const char *err_msg = "No such job: %s";
6942 unsigned num;
6943 int c;
6944 const char *p;
6945 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006946
Eric Andersenc470f442003-07-28 09:56:35 +00006947 jp = curjob;
6948 p = name;
6949 if (!p)
6950 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006951
Eric Andersenc470f442003-07-28 09:56:35 +00006952 if (*p != '%')
6953 goto err;
6954
6955 c = *++p;
6956 if (!c)
6957 goto currentjob;
6958
6959 if (!p[1]) {
6960 if (c == '+' || c == '%') {
6961currentjob:
6962 err_msg = "No current job";
6963 goto check;
6964 } else if (c == '-') {
6965 if (jp)
6966 jp = jp->prev_job;
6967 err_msg = "No previous job";
6968check:
6969 if (!jp)
6970 goto err;
6971 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006972 }
6973 }
Eric Andersenc470f442003-07-28 09:56:35 +00006974
6975 if (is_number(p)) {
6976 num = atoi(p);
6977 if (num < njobs) {
6978 jp = jobtab + num - 1;
6979 if (jp->used)
6980 goto gotit;
6981 goto err;
6982 }
6983 }
6984
6985 match = prefix;
6986 if (*p == '?') {
6987 match = strstr;
6988 p++;
6989 }
6990
6991 found = 0;
6992 while (1) {
6993 if (!jp)
6994 goto err;
6995 if (match(jp->ps[0].cmd, p)) {
6996 if (found)
6997 goto err;
6998 found = jp;
6999 err_msg = "%s: ambiguous";
7000 }
7001 jp = jp->prev_job;
7002 }
7003
7004gotit:
7005#if JOBS
7006 err_msg = "job %s not created under job control";
7007 if (getctl && jp->jobctl == 0)
7008 goto err;
7009#endif
7010 return jp;
7011err:
7012 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007013}
7014
7015
Eric Andersencb57d552001-06-28 07:25:16 +00007016/*
Eric Andersenc470f442003-07-28 09:56:35 +00007017 * Return a new job structure.
7018 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007019 */
7020
Eric Andersenc470f442003-07-28 09:56:35 +00007021static struct job *
7022makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007023{
7024 int i;
7025 struct job *jp;
7026
Eric Andersenc470f442003-07-28 09:56:35 +00007027 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007028 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007029 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007030 break;
7031 }
7032 if (jp->used == 0)
7033 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007034 if (jp->state != JOBDONE || !jp->waited)
7035 continue;
7036#if JOBS
7037 if (jobctl)
7038 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007039#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007040 freejob(jp);
7041 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007042 }
Eric Andersenc470f442003-07-28 09:56:35 +00007043 memset(jp, 0, sizeof(*jp));
7044#if JOBS
7045 if (jobctl)
7046 jp->jobctl = 1;
7047#endif
7048 jp->prev_job = curjob;
7049 curjob = jp;
7050 jp->used = 1;
7051 jp->ps = &jp->ps0;
7052 if (nprocs > 1) {
7053 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7054 }
7055 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7056 jobno(jp)));
7057 return jp;
7058}
7059
7060static struct job *
7061growjobtab(void)
7062{
7063 size_t len;
7064 ptrdiff_t offset;
7065 struct job *jp, *jq;
7066
7067 len = njobs * sizeof(*jp);
7068 jq = jobtab;
7069 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7070
7071 offset = (char *)jp - (char *)jq;
7072 if (offset) {
7073 /* Relocate pointers */
7074 size_t l = len;
7075
7076 jq = (struct job *)((char *)jq + l);
7077 while (l) {
7078 l -= sizeof(*jp);
7079 jq--;
7080#define joff(p) ((struct job *)((char *)(p) + l))
7081#define jmove(p) (p) = (void *)((char *)(p) + offset)
7082 if (likely(joff(jp)->ps == &jq->ps0))
7083 jmove(joff(jp)->ps);
7084 if (joff(jp)->prev_job)
7085 jmove(joff(jp)->prev_job);
7086 }
7087 if (curjob)
7088 jmove(curjob);
7089#undef joff
7090#undef jmove
7091 }
7092
7093 njobs += 4;
7094 jobtab = jp;
7095 jp = (struct job *)((char *)jp + len);
7096 jq = jp + 3;
7097 do {
7098 jq->used = 0;
7099 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007100 return jp;
7101}
7102
7103
7104/*
Eric Andersenc470f442003-07-28 09:56:35 +00007105 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007106 * own process group. Jp is a job structure that the job is to be added to.
7107 * N is the command that will be evaluated by the child. Both jp and n may
7108 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007109 * FORK_FG - Fork off a foreground process.
7110 * FORK_BG - Fork off a background process.
7111 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7112 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007113 *
7114 * When job control is turned off, background processes have their standard
7115 * input redirected to /dev/null (except for the second and later processes
7116 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007117 *
7118 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007119 */
7120
Eric Andersenc470f442003-07-28 09:56:35 +00007121static inline void
7122forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007123{
Eric Andersenc470f442003-07-28 09:56:35 +00007124 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007125
Eric Andersenc470f442003-07-28 09:56:35 +00007126 TRACE(("Child shell %d\n", getpid()));
7127 wasroot = rootshell;
7128 rootshell = 0;
7129
7130 closescript();
7131 clear_traps();
7132#if JOBS
7133 /* do job control only in root shell */
7134 jobctl = 0;
7135 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7136 pid_t pgrp;
7137
7138 if (jp->nprocs == 0)
7139 pgrp = getpid();
7140 else
7141 pgrp = jp->ps[0].pid;
7142 /* This can fail because we are doing it in the parent also */
7143 (void)setpgid(0, pgrp);
7144 if (mode == FORK_FG)
7145 xtcsetpgrp(ttyfd, pgrp);
7146 setsignal(SIGTSTP);
7147 setsignal(SIGTTOU);
7148 } else
Eric Andersen62483552001-07-10 06:09:16 +00007149#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007150 if (mode == FORK_BG) {
7151 ignoresig(SIGINT);
7152 ignoresig(SIGQUIT);
7153 if (jp->nprocs == 0) {
7154 close(0);
7155 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7156 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007157 }
Eric Andersencb57d552001-06-28 07:25:16 +00007158 }
Eric Andersenc470f442003-07-28 09:56:35 +00007159 if (wasroot && iflag) {
7160 setsignal(SIGINT);
7161 setsignal(SIGQUIT);
7162 setsignal(SIGTERM);
7163 }
7164 for (jp = curjob; jp; jp = jp->prev_job)
7165 freejob(jp);
7166 jobless = 0;
7167}
7168
7169static inline void
7170forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7171{
7172 TRACE(("In parent shell: child = %d\n", pid));
7173 if (!jp) {
7174 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7175 jobless++;
7176 return;
7177 }
7178#if JOBS
7179 if (mode != FORK_NOJOB && jp->jobctl) {
7180 int pgrp;
7181
7182 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007183 pgrp = pid;
7184 else
7185 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007186 /* This can fail because we are doing it in the child also */
7187 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007188 }
Eric Andersen62483552001-07-10 06:09:16 +00007189#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007190 if (mode == FORK_BG) {
7191 backgndpid = pid; /* set $! */
7192 set_curjob(jp, CUR_RUNNING);
7193 }
Eric Andersencb57d552001-06-28 07:25:16 +00007194 if (jp) {
7195 struct procstat *ps = &jp->ps[jp->nprocs++];
7196 ps->pid = pid;
7197 ps->status = -1;
7198 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007199#if JOBS
7200 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007201 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007202#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007203 }
Eric Andersencb57d552001-06-28 07:25:16 +00007204}
7205
Eric Andersenc470f442003-07-28 09:56:35 +00007206static int
7207forkshell(struct job *jp, union node *n, int mode)
7208{
7209 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007210
Eric Andersenc470f442003-07-28 09:56:35 +00007211 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7212 pid = fork();
7213 if (pid < 0) {
7214 TRACE(("Fork failed, errno=%d", errno));
7215 if (jp)
7216 freejob(jp);
7217 error("Cannot fork");
7218 }
7219 if (pid == 0)
7220 forkchild(jp, n, mode);
7221 else
7222 forkparent(jp, n, mode, pid);
7223 return pid;
7224}
Eric Andersencb57d552001-06-28 07:25:16 +00007225
7226/*
7227 * Wait for job to finish.
7228 *
7229 * Under job control we have the problem that while a child process is
7230 * running interrupts generated by the user are sent to the child but not
7231 * to the shell. This means that an infinite loop started by an inter-
7232 * active user may be hard to kill. With job control turned off, an
7233 * interactive user may place an interactive program inside a loop. If
7234 * the interactive program catches interrupts, the user doesn't want
7235 * these interrupts to also abort the loop. The approach we take here
7236 * is to have the shell ignore interrupt signals while waiting for a
7237 * forground process to terminate, and then send itself an interrupt
7238 * signal if the child process was terminated by an interrupt signal.
7239 * Unfortunately, some programs want to do a bit of cleanup and then
7240 * exit on interrupt; unless these processes terminate themselves by
7241 * sending a signal to themselves (instead of calling exit) they will
7242 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007243 *
7244 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007245 */
7246
Eric Andersenc470f442003-07-28 09:56:35 +00007247int
7248waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007249{
Eric Andersencb57d552001-06-28 07:25:16 +00007250 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007251
Eric Andersenc470f442003-07-28 09:56:35 +00007252 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7253 while (jp->state == JOBRUNNING) {
7254 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007255 }
Eric Andersenc470f442003-07-28 09:56:35 +00007256 st = getstatus(jp);
7257#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007258 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007259 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007260 /*
7261 * This is truly gross.
7262 * If we're doing job control, then we did a TIOCSPGRP which
7263 * caused us (the shell) to no longer be in the controlling
7264 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7265 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007266 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007267 */
Eric Andersenc470f442003-07-28 09:56:35 +00007268 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007269 raise(SIGINT);
7270 }
Eric Andersen2870d962001-07-02 17:27:21 +00007271 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007272#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007273 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007274 return st;
7275}
7276
7277
Eric Andersen62483552001-07-10 06:09:16 +00007278/*
7279 * Do a wait system call. If job control is compiled in, we accept
7280 * stopped processes. If block is zero, we return a value of zero
7281 * rather than blocking.
7282 *
7283 * System V doesn't have a non-blocking wait system call. It does
7284 * have a SIGCLD signal that is sent to a process when one of it's
7285 * children dies. The obvious way to use SIGCLD would be to install
7286 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7287 * was received, and have waitproc bump another counter when it got
7288 * the status of a process. Waitproc would then know that a wait
7289 * system call would not block if the two counters were different.
7290 * This approach doesn't work because if a process has children that
7291 * have not been waited for, System V will send it a SIGCLD when it
7292 * installs a signal handler for SIGCLD. What this means is that when
7293 * a child exits, the shell will be sent SIGCLD signals continuously
7294 * until is runs out of stack space, unless it does a wait call before
7295 * restoring the signal handler. The code below takes advantage of
7296 * this (mis)feature by installing a signal handler for SIGCLD and
7297 * then checking to see whether it was called. If there are any
7298 * children to be waited for, it will be.
7299 *
Eric Andersenc470f442003-07-28 09:56:35 +00007300 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7301 * waits at all. In this case, the user will not be informed when
7302 * a background process until the next time she runs a real program
7303 * (as opposed to running a builtin command or just typing return),
7304 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007305 */
7306
Eric Andersenc470f442003-07-28 09:56:35 +00007307static inline int
7308waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007309{
Eric Andersenc470f442003-07-28 09:56:35 +00007310 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007311
Eric Andersenc470f442003-07-28 09:56:35 +00007312#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007313 if (jobctl)
7314 flags |= WUNTRACED;
7315#endif
7316 if (block == 0)
7317 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007318 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007319}
7320
Eric Andersenc470f442003-07-28 09:56:35 +00007321/*
7322 * Wait for a process to terminate.
7323 */
7324
7325static int
7326dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007327{
7328 int pid;
7329 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007330 struct job *jp;
7331 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007332 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007333
7334 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007335 pid = waitproc(block, &status);
7336 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007337 if (pid <= 0)
7338 return pid;
7339 INTOFF;
7340 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007341 for (jp = curjob; jp; jp = jp->prev_job) {
7342 struct procstat *sp;
7343 struct procstat *spend;
7344 if (jp->state == JOBDONE)
7345 continue;
7346 state = JOBDONE;
7347 spend = jp->ps + jp->nprocs;
7348 sp = jp->ps;
7349 do {
7350 if (sp->pid == pid) {
7351 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7352 sp->status = status;
7353 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007354 }
Eric Andersenc470f442003-07-28 09:56:35 +00007355 if (sp->status == -1)
7356 state = JOBRUNNING;
7357#ifdef JOBS
7358 if (state == JOBRUNNING)
7359 continue;
7360 if (WIFSTOPPED(sp->status)) {
7361 jp->stopstatus = sp->status;
7362 state = JOBSTOPPED;
7363 }
Eric Andersencb57d552001-06-28 07:25:16 +00007364#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007365 } while (++sp < spend);
7366 if (thisjob)
7367 goto gotjob;
7368 }
7369#ifdef JOBS
7370 if (!WIFSTOPPED(status))
7371#endif
7372
7373 jobless--;
7374 goto out;
7375
7376gotjob:
7377 if (state != JOBRUNNING) {
7378 thisjob->changed = 1;
7379
7380 if (thisjob->state != state) {
7381 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7382 thisjob->state = state;
7383#ifdef JOBS
7384 if (state == JOBSTOPPED) {
7385 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007386 }
Eric Andersenc470f442003-07-28 09:56:35 +00007387#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007388 }
7389 }
Eric Andersencb57d552001-06-28 07:25:16 +00007390
Eric Andersenc470f442003-07-28 09:56:35 +00007391out:
7392 INTON;
7393
7394 if (thisjob && thisjob == job) {
7395 char s[48 + 1];
7396 int len;
7397
7398 len = sprint_status(s, status, 1);
7399 if (len) {
7400 s[len] = '\n';
7401 s[len + 1] = 0;
7402 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007403 }
Eric Andersencb57d552001-06-28 07:25:16 +00007404 }
7405 return pid;
7406}
7407
7408
Eric Andersencb57d552001-06-28 07:25:16 +00007409/*
7410 * return 1 if there are stopped jobs, otherwise 0
7411 */
Eric Andersen90898442003-08-06 11:20:52 +00007412
Eric Andersenc470f442003-07-28 09:56:35 +00007413int
7414stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007415{
Eric Andersencb57d552001-06-28 07:25:16 +00007416 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007417 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007418
Eric Andersenc470f442003-07-28 09:56:35 +00007419 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007420 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007421 goto out;
7422 jp = curjob;
7423 if (jp && jp->state == JOBSTOPPED) {
7424 out2str("You have stopped jobs.\n");
7425 job_warning = 2;
7426 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007427 }
7428
Eric Andersenc470f442003-07-28 09:56:35 +00007429out:
7430 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007431}
7432
7433/*
7434 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007435 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007436 */
7437
Eric Andersenc470f442003-07-28 09:56:35 +00007438#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007439static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007440
Eric Andersenc470f442003-07-28 09:56:35 +00007441static char *
7442commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007443{
Eric Andersenc470f442003-07-28 09:56:35 +00007444 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007445
Eric Andersenc470f442003-07-28 09:56:35 +00007446 STARTSTACKSTR(cmdnextc);
7447 cmdtxt(n);
7448 name = stackblock();
7449 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7450 name, cmdnextc, cmdnextc));
7451 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007452}
7453
Eric Andersenc470f442003-07-28 09:56:35 +00007454static void
7455cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007456{
Eric Andersencb57d552001-06-28 07:25:16 +00007457 union node *np;
7458 struct nodelist *lp;
7459 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007460 char s[2];
7461
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007462 if (!n)
7463 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007464 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007465 default:
7466#if DEBUG
7467 abort();
7468#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007469 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007470 lp = n->npipe.cmdlist;
7471 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007472 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007473 lp = lp->next;
7474 if (!lp)
7475 break;
7476 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007477 }
7478 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007479 case NSEMI:
7480 p = "; ";
7481 goto binop;
7482 case NAND:
7483 p = " && ";
7484 goto binop;
7485 case NOR:
7486 p = " || ";
7487binop:
7488 cmdtxt(n->nbinary.ch1);
7489 cmdputs(p);
7490 n = n->nbinary.ch2;
7491 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007492 case NREDIR:
7493 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007494 n = n->nredir.n;
7495 goto donode;
7496 case NNOT:
7497 cmdputs("!");
7498 n = n->nnot.com;
7499donode:
7500 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007501 break;
7502 case NIF:
7503 cmdputs("if ");
7504 cmdtxt(n->nif.test);
7505 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007506 n = n->nif.ifpart;
7507 if (n->nif.elsepart) {
7508 cmdtxt(n);
7509 cmdputs("; else ");
7510 n = n->nif.elsepart;
7511 }
7512 p = "; fi";
7513 goto dotail;
7514 case NSUBSHELL:
7515 cmdputs("(");
7516 n = n->nredir.n;
7517 p = ")";
7518 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007519 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007520 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007521 goto until;
7522 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007523 p = "until ";
7524until:
7525 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007526 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007527 n = n->nbinary.ch2;
7528 p = "; done";
7529dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007530 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007531dotail:
7532 cmdtxt(n);
7533 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007534 case NFOR:
7535 cmdputs("for ");
7536 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007537 cmdputs(" in ");
7538 cmdlist(n->nfor.args, 1);
7539 n = n->nfor.body;
7540 p = "; done";
7541 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007542 case NDEFUN:
7543 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007544 p = "() { ... }";
7545 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007546 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007547 cmdlist(n->ncmd.args, 1);
7548 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007549 break;
7550 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007551 p = n->narg.text;
7552dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007553 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007554 break;
7555 case NHERE:
7556 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007557 p = "<<...";
7558 goto dotail2;
7559 case NCASE:
7560 cmdputs("case ");
7561 cmdputs(n->ncase.expr->narg.text);
7562 cmdputs(" in ");
7563 for (np = n->ncase.cases; np; np = np->nclist.next) {
7564 cmdtxt(np->nclist.pattern);
7565 cmdputs(") ");
7566 cmdtxt(np->nclist.body);
7567 cmdputs(";; ");
7568 }
7569 p = "esac";
7570 goto dotail2;
7571 case NTO:
7572 p = ">";
7573 goto redir;
7574 case NCLOBBER:
7575 p = ">|";
7576 goto redir;
7577 case NAPPEND:
7578 p = ">>";
7579 goto redir;
7580 case NTOFD:
7581 p = ">&";
7582 goto redir;
7583 case NFROM:
7584 p = "<";
7585 goto redir;
7586 case NFROMFD:
7587 p = "<&";
7588 goto redir;
7589 case NFROMTO:
7590 p = "<>";
7591redir:
7592 s[0] = n->nfile.fd + '0';
7593 s[1] = '\0';
7594 cmdputs(s);
7595 cmdputs(p);
7596 if (n->type == NTOFD || n->type == NFROMFD) {
7597 s[0] = n->ndup.dupfd + '0';
7598 p = s;
7599 goto dotail2;
7600 } else {
7601 n = n->nfile.fname;
7602 goto donode;
7603 }
Eric Andersencb57d552001-06-28 07:25:16 +00007604 }
7605}
Eric Andersencb57d552001-06-28 07:25:16 +00007606
Eric Andersenc470f442003-07-28 09:56:35 +00007607static void
7608cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007609{
Eric Andersenc470f442003-07-28 09:56:35 +00007610 for (; np; np = np->narg.next) {
7611 if (!sep)
7612 cmdputs(spcstr);
7613 cmdtxt(np);
7614 if (sep && np->narg.next)
7615 cmdputs(spcstr);
7616 }
Eric Andersencb57d552001-06-28 07:25:16 +00007617}
7618
Eric Andersenc470f442003-07-28 09:56:35 +00007619static void
7620cmdputs(const char *s)
7621{
7622 const char *p, *str;
7623 char c, cc[2] = " ";
7624 char *nextc;
7625 int subtype = 0;
7626 int quoted = 0;
7627 static const char *const vstype[16] = {
7628 nullstr, "}", "-", "+", "?", "=",
Eric Andersenc7bda1c2004-03-15 08:29:22 +00007629 "%", "%%", "#", "##", nullstr
Eric Andersenc470f442003-07-28 09:56:35 +00007630 };
7631
7632 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7633 p = s;
7634 while ((c = *p++) != 0) {
7635 str = 0;
7636 switch (c) {
7637 case CTLESC:
7638 c = *p++;
7639 break;
7640 case CTLVAR:
7641 subtype = *p++;
7642 if ((subtype & VSTYPE) == VSLENGTH)
7643 str = "${#";
7644 else
7645 str = "${";
7646 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7647 quoted ^= 1;
7648 c = '"';
7649 } else
7650 goto dostr;
7651 break;
7652 case CTLENDVAR:
7653 quoted >>= 1;
7654 subtype = 0;
7655 if (quoted & 1) {
7656 str = "\"}";
7657 goto dostr;
7658 }
7659 c = '}';
7660 break;
7661 case CTLBACKQ:
7662 str = "$(...)";
7663 goto dostr;
7664 case CTLBACKQ+CTLQUOTE:
7665 str = "\"$(...)\"";
7666 goto dostr;
7667#ifdef CONFIG_ASH_MATH_SUPPORT
7668 case CTLARI:
7669 str = "$((";
7670 goto dostr;
7671 case CTLENDARI:
7672 str = "))";
7673 goto dostr;
7674#endif
7675 case CTLQUOTEMARK:
7676 quoted ^= 1;
7677 c = '"';
7678 break;
7679 case '=':
7680 if (subtype == 0)
7681 break;
7682 str = vstype[subtype & VSTYPE];
7683 if (subtype & VSNUL)
7684 c = ':';
7685 else
7686 c = *str++;
7687 if (c != '}')
7688 quoted <<= 1;
7689 break;
7690 case '\'':
7691 case '\\':
7692 case '"':
7693 case '$':
7694 /* These can only happen inside quotes */
7695 cc[0] = c;
7696 str = cc;
7697 c = '\\';
7698 break;
7699 default:
7700 break;
7701 }
7702 USTPUTC(c, nextc);
7703 if (!str)
7704 continue;
7705dostr:
7706 while ((c = *str++)) {
7707 USTPUTC(c, nextc);
7708 }
7709 }
7710 if (quoted & 1) {
7711 USTPUTC('"', nextc);
7712 }
7713 *nextc = 0;
7714 cmdnextc = nextc;
7715}
7716
7717
7718static void
7719showpipe(struct job *jp, FILE *out)
7720{
7721 struct procstat *sp;
7722 struct procstat *spend;
7723
7724 spend = jp->ps + jp->nprocs;
7725 for (sp = jp->ps + 1; sp < spend; sp++)
7726 fprintf(out, " | %s", sp->cmd);
7727 outcslow('\n', out);
7728 flushall();
7729}
7730
7731static void
7732xtcsetpgrp(int fd, pid_t pgrp)
7733{
7734 if (tcsetpgrp(fd, pgrp))
7735 error("Cannot set tty process group (%m)");
7736}
7737#endif /* JOBS */
7738
7739static int
7740getstatus(struct job *job) {
7741 int status;
7742 int retval;
7743
7744 status = job->ps[job->nprocs - 1].status;
7745 retval = WEXITSTATUS(status);
7746 if (!WIFEXITED(status)) {
7747#if JOBS
7748 retval = WSTOPSIG(status);
7749 if (!WIFSTOPPED(status))
7750#endif
7751 {
7752 /* XXX: limits number of signals */
7753 retval = WTERMSIG(status);
7754#if JOBS
7755 if (retval == SIGINT)
7756 job->sigint = 1;
7757#endif
7758 }
7759 retval += 128;
7760 }
7761 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7762 jobno(job), job->nprocs, status, retval));
7763 return retval;
7764}
7765
Eric Andersend35c5df2002-01-09 15:37:36 +00007766#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007767/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007768
Eric Andersencb57d552001-06-28 07:25:16 +00007769/*
Eric Andersenc470f442003-07-28 09:56:35 +00007770 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007771 */
7772
Eric Andersencb57d552001-06-28 07:25:16 +00007773#define MAXMBOXES 10
7774
Eric Andersenc470f442003-07-28 09:56:35 +00007775/* times of mailboxes */
7776static time_t mailtime[MAXMBOXES];
7777/* Set if MAIL or MAILPATH is changed. */
7778static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007779
7780
7781
7782/*
Eric Andersenc470f442003-07-28 09:56:35 +00007783 * Print appropriate message(s) if mail has arrived.
7784 * If mail_var_path_changed is set,
7785 * then the value of MAIL has mail_var_path_changed,
7786 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007787 */
7788
Eric Andersenc470f442003-07-28 09:56:35 +00007789static void
7790chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007791{
Eric Andersencb57d552001-06-28 07:25:16 +00007792 const char *mpath;
7793 char *p;
7794 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007795 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007796 struct stackmark smark;
7797 struct stat statb;
7798
Eric Andersencb57d552001-06-28 07:25:16 +00007799 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007800 mpath = mpathset() ? mpathval() : mailval();
7801 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007802 p = padvance(&mpath, nullstr);
7803 if (p == NULL)
7804 break;
7805 if (*p == '\0')
7806 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007807 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007808#ifdef DEBUG
7809 if (q[-1] != '/')
7810 abort();
7811#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007812 q[-1] = '\0'; /* delete trailing '/' */
7813 if (stat(p, &statb) < 0) {
7814 *mtp = 0;
7815 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007816 }
Eric Andersenc470f442003-07-28 09:56:35 +00007817 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7818 fprintf(
7819 stderr, snlfmt,
7820 pathopt ? pathopt : "you have mail"
7821 );
7822 }
7823 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007824 }
Eric Andersenc470f442003-07-28 09:56:35 +00007825 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007826 popstackmark(&smark);
7827}
Eric Andersencb57d552001-06-28 07:25:16 +00007828
Eric Andersenec074692001-10-31 11:05:49 +00007829
Eric Andersenc470f442003-07-28 09:56:35 +00007830static void
7831changemail(const char *val)
7832{
7833 mail_var_path_changed++;
7834}
7835
7836#endif /* CONFIG_ASH_MAIL */
7837
7838/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7839
Eric Andersencb57d552001-06-28 07:25:16 +00007840
Eric Andersencb57d552001-06-28 07:25:16 +00007841#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007842static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007843extern int etext();
7844#endif
7845
Eric Andersenc470f442003-07-28 09:56:35 +00007846static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007847
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007848static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007849
Eric Andersencb57d552001-06-28 07:25:16 +00007850/*
7851 * Main routine. We initialize things, parse the arguments, execute
7852 * profiles if we're a login shell, and then call cmdloop to execute
7853 * commands. The setjmp call sets up the location to jump to when an
7854 * exception occurs. When an exception occurs the variable "state"
7855 * is used to figure out how far we had gotten.
7856 */
7857
Eric Andersenc470f442003-07-28 09:56:35 +00007858int
7859ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007860{
Eric Andersenc470f442003-07-28 09:56:35 +00007861 char *shinit;
7862 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007863 struct jmploc jmploc;
7864 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007865
Eric Andersenc470f442003-07-28 09:56:35 +00007866#ifdef __GLIBC__
7867 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007868#endif
7869
Eric Andersencb57d552001-06-28 07:25:16 +00007870#if PROFILE
7871 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7872#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007873 state = 0;
7874 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007875 int status;
7876 int e;
7877
Eric Andersencb57d552001-06-28 07:25:16 +00007878 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007879
7880 e = exception;
7881 switch (exception) {
7882 case EXEXEC:
7883 status = exerrno;
7884 break;
7885
7886 case EXERROR:
7887 status = 2;
7888 break;
7889
7890 default:
7891 status = exitstatus;
7892 break;
7893 }
7894 exitstatus = status;
7895
7896 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7897 exitshell();
7898
Eric Andersen90898442003-08-06 11:20:52 +00007899 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007900 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007901 }
7902 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007903 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007904 if (state == 1)
7905 goto state1;
7906 else if (state == 2)
7907 goto state2;
7908 else if (state == 3)
7909 goto state3;
7910 else
7911 goto state4;
7912 }
7913 handler = &jmploc;
7914#ifdef DEBUG
7915 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007916 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007917#endif
7918 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007919
7920#ifdef CONFIG_ASH_RANDOM_SUPPORT
7921 rseed = rootpid + ((time_t)time((time_t *)0));
7922#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007923 rootshell = 1;
7924 init();
7925 setstackmark(&smark);
7926 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007927#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7928 if ( iflag ) {
7929 const char *hp = lookupvar("HISTFILE");
7930
7931 if(hp == NULL ) {
7932 hp = lookupvar("HOME");
7933 if(hp != NULL) {
7934 char *defhp = concat_path_file(hp, ".ash_history");
7935 setvar("HISTFILE", defhp, 0);
7936 free(defhp);
7937 }
7938 }
7939 }
7940#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007941 if (argv[0] && argv[0][0] == '-')
7942 isloginsh = 1;
7943 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007944 state = 1;
7945 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007946state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007947 state = 2;
7948 read_profile(".profile");
7949 }
Eric Andersenc470f442003-07-28 09:56:35 +00007950state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007951 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007952 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007953#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007954 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007955#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007956 iflag
7957 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007958 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007959 read_profile(shinit);
7960 }
Eric Andersencb57d552001-06-28 07:25:16 +00007961 }
Eric Andersenc470f442003-07-28 09:56:35 +00007962state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007963 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007964 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007965 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007966
7967 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007968#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007969 if ( iflag ) {
7970 const char *hp = lookupvar("HISTFILE");
7971
7972 if(hp != NULL )
7973 load_history ( hp );
7974 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007975#endif
Eric Andersen90898442003-08-06 11:20:52 +00007976state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007977 cmdloop(1);
7978 }
7979#if PROFILE
7980 monitor(0);
7981#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007982#if GPROF
7983 {
7984 extern void _mcleanup(void);
7985 _mcleanup();
7986 }
7987#endif
7988 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007989 /* NOTREACHED */
7990}
7991
7992
7993/*
7994 * Read and execute commands. "Top" is nonzero for the top level command
7995 * loop; it turns on prompting if the shell is interactive.
7996 */
7997
Eric Andersenc470f442003-07-28 09:56:35 +00007998static void
7999cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008000{
8001 union node *n;
8002 struct stackmark smark;
8003 int inter;
8004 int numeof = 0;
8005
8006 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008007 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00008008 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00008009 if (pendingsigs)
8010 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00008011#if JOBS
8012 if (jobctl)
8013 showjobs(stderr, SHOW_CHANGED);
8014#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008015 inter = 0;
8016 if (iflag && top) {
8017 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008018#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008019 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008020#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008021 }
8022 n = parsecmd(inter);
8023 /* showtree(n); DEBUG */
8024 if (n == NEOF) {
8025 if (!top || numeof >= 50)
8026 break;
8027 if (!stoppedjobs()) {
8028 if (!Iflag)
8029 break;
8030 out2str("\nUse \"exit\" to leave shell.\n");
8031 }
8032 numeof++;
8033 } else if (n != NULL && nflag == 0) {
8034 job_warning = (job_warning == 2) ? 1 : 0;
8035 numeof = 0;
8036 evaltree(n, 0);
8037 }
8038 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008039 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008040 evalskip = 0;
8041 break;
8042 }
8043 }
Eric Andersencb57d552001-06-28 07:25:16 +00008044}
8045
8046
Eric Andersencb57d552001-06-28 07:25:16 +00008047/*
8048 * Read /etc/profile or .profile. Return on error.
8049 */
8050
Eric Andersenc470f442003-07-28 09:56:35 +00008051static void
8052read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008053{
8054 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008055 int xflag_set = 0;
8056 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008057
8058 INTOFF;
8059 if ((fd = open(name, O_RDONLY)) >= 0)
8060 setinputfd(fd, 1);
8061 INTON;
8062 if (fd < 0)
8063 return;
8064 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008065 if (qflag) {
8066 if (xflag)
8067 xflag = 0, xflag_set = 1;
8068 if (vflag)
8069 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008070 }
8071 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008072 if (qflag) {
8073 if (xflag_set)
8074 xflag = 1;
8075 if (vflag_set)
8076 vflag = 1;
8077 }
Eric Andersencb57d552001-06-28 07:25:16 +00008078 popfile();
8079}
8080
8081
Eric Andersencb57d552001-06-28 07:25:16 +00008082/*
8083 * Read a file containing shell functions.
8084 */
8085
Eric Andersenc470f442003-07-28 09:56:35 +00008086static void
8087readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008088{
8089 int fd;
8090
8091 INTOFF;
8092 if ((fd = open(name, O_RDONLY)) >= 0)
8093 setinputfd(fd, 1);
8094 else
8095 error("Can't open %s", name);
8096 INTON;
8097 cmdloop(0);
8098 popfile();
8099}
8100
8101
Eric Andersencb57d552001-06-28 07:25:16 +00008102/*
Eric Andersenc470f442003-07-28 09:56:35 +00008103 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008104 * search for the file, which is necessary to find sub-commands.
8105 */
8106
Eric Andersenc470f442003-07-28 09:56:35 +00008107static inline char *
8108find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008109{
8110 char *fullname;
8111 const char *path = pathval();
8112 struct stat statb;
8113
8114 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008115 if (strchr(name, '/'))
8116 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008117
Eric Andersenc470f442003-07-28 09:56:35 +00008118 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008119 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8120 /*
8121 * Don't bother freeing here, since it will
8122 * be freed by the caller.
8123 */
8124 return fullname;
8125 }
8126 stunalloc(fullname);
8127 }
8128
8129 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008130 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008131 /* NOTREACHED */
8132}
8133
Eric Andersenc470f442003-07-28 09:56:35 +00008134int
8135dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008136{
Eric Andersencb57d552001-06-28 07:25:16 +00008137 exitstatus = 0;
8138
Eric Andersenc470f442003-07-28 09:56:35 +00008139 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008140 char *fullname;
8141 struct stackmark smark;
8142
8143 setstackmark(&smark);
8144 fullname = find_dot_file(argv[1]);
8145 setinputfile(fullname, 1);
8146 commandname = fullname;
8147 cmdloop(0);
8148 popfile();
8149 popstackmark(&smark);
8150 }
8151 return exitstatus;
8152}
8153
8154
Eric Andersenc470f442003-07-28 09:56:35 +00008155static int
8156exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008157{
8158 if (stoppedjobs())
8159 return 0;
8160 if (argc > 1)
8161 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008162 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008163 /* NOTREACHED */
8164}
Eric Andersen62483552001-07-10 06:09:16 +00008165
Eric Andersenc470f442003-07-28 09:56:35 +00008166/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8167
8168/*
Eric Andersen90898442003-08-06 11:20:52 +00008169 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008170 */
8171
8172static pointer
8173ckrealloc(pointer p, size_t nbytes)
8174{
8175 p = realloc(p, nbytes);
8176 if (p == NULL)
8177 error(bb_msg_memory_exhausted);
8178 return p;
8179}
8180
Eric Andersen90898442003-08-06 11:20:52 +00008181static pointer
8182ckmalloc(size_t nbytes)
8183{
8184 return ckrealloc(NULL, nbytes);
8185}
Eric Andersenc470f442003-07-28 09:56:35 +00008186
8187/*
8188 * Make a copy of a string in safe storage.
8189 */
8190
8191static char *
8192savestr(const char *s)
8193{
8194 char *p = strdup(s);
8195 if (!p)
8196 error(bb_msg_memory_exhausted);
8197 return p;
8198}
8199
8200
8201/*
8202 * Parse trees for commands are allocated in lifo order, so we use a stack
8203 * to make this more efficient, and also to avoid all sorts of exception
8204 * handling code to handle interrupts in the middle of a parse.
8205 *
8206 * The size 504 was chosen because the Ultrix malloc handles that size
8207 * well.
8208 */
8209
8210
8211static pointer
8212stalloc(size_t nbytes)
8213{
8214 char *p;
8215 size_t aligned;
8216
8217 aligned = SHELL_ALIGN(nbytes);
8218 if (aligned > stacknleft) {
8219 size_t len;
8220 size_t blocksize;
8221 struct stack_block *sp;
8222
8223 blocksize = aligned;
8224 if (blocksize < MINSIZE)
8225 blocksize = MINSIZE;
8226 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8227 if (len < blocksize)
8228 error(bb_msg_memory_exhausted);
8229 INTOFF;
8230 sp = ckmalloc(len);
8231 sp->prev = stackp;
8232 stacknxt = sp->space;
8233 stacknleft = blocksize;
8234 sstrend = stacknxt + blocksize;
8235 stackp = sp;
8236 INTON;
8237 }
8238 p = stacknxt;
8239 stacknxt += aligned;
8240 stacknleft -= aligned;
8241 return p;
8242}
8243
8244
8245void
8246stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008247{
Eric Andersencb57d552001-06-28 07:25:16 +00008248#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008249 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008250 write(2, "stunalloc\n", 10);
8251 abort();
8252 }
8253#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008254 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008255 stacknxt = p;
8256}
8257
8258
Eric Andersenc470f442003-07-28 09:56:35 +00008259void
8260setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008261{
Eric Andersencb57d552001-06-28 07:25:16 +00008262 mark->stackp = stackp;
8263 mark->stacknxt = stacknxt;
8264 mark->stacknleft = stacknleft;
8265 mark->marknext = markp;
8266 markp = mark;
8267}
8268
8269
Eric Andersenc470f442003-07-28 09:56:35 +00008270void
8271popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008272{
Eric Andersencb57d552001-06-28 07:25:16 +00008273 struct stack_block *sp;
8274
8275 INTOFF;
8276 markp = mark->marknext;
8277 while (stackp != mark->stackp) {
8278 sp = stackp;
8279 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008280 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008281 }
8282 stacknxt = mark->stacknxt;
8283 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008284 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008285 INTON;
8286}
8287
8288
8289/*
8290 * When the parser reads in a string, it wants to stick the string on the
8291 * stack and only adjust the stack pointer when it knows how big the
8292 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8293 * of space on top of the stack and stackblocklen returns the length of
8294 * this block. Growstackblock will grow this space by at least one byte,
8295 * possibly moving it (like realloc). Grabstackblock actually allocates the
8296 * part of the block that has been used.
8297 */
8298
Eric Andersenc470f442003-07-28 09:56:35 +00008299void
8300growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008301{
Eric Andersenc470f442003-07-28 09:56:35 +00008302 size_t newlen;
8303
8304 newlen = stacknleft * 2;
8305 if (newlen < stacknleft)
8306 error(bb_msg_memory_exhausted);
8307 if (newlen < 128)
8308 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008309
8310 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008311 struct stack_block *oldstackp;
8312 struct stackmark *xmark;
8313 struct stack_block *sp;
8314 struct stack_block *prevstackp;
8315 size_t grosslen;
8316
Eric Andersencb57d552001-06-28 07:25:16 +00008317 INTOFF;
8318 oldstackp = stackp;
8319 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008320 prevstackp = sp->prev;
8321 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8322 sp = ckrealloc((pointer)sp, grosslen);
8323 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008324 stackp = sp;
8325 stacknxt = sp->space;
8326 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008327 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008328
Eric Andersenc470f442003-07-28 09:56:35 +00008329 /*
8330 * Stack marks pointing to the start of the old block
8331 * must be relocated to point to the new block
8332 */
8333 xmark = markp;
8334 while (xmark != NULL && xmark->stackp == oldstackp) {
8335 xmark->stackp = stackp;
8336 xmark->stacknxt = stacknxt;
8337 xmark->stacknleft = stacknleft;
8338 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008339 }
8340 INTON;
8341 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008342 char *oldspace = stacknxt;
8343 int oldlen = stacknleft;
8344 char *p = stalloc(newlen);
8345
8346 /* free the space we just allocated */
8347 stacknxt = memcpy(p, oldspace, oldlen);
8348 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008349 }
8350}
8351
Eric Andersenc470f442003-07-28 09:56:35 +00008352static inline void
8353grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008354{
Eric Andersenc470f442003-07-28 09:56:35 +00008355 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008356 stacknxt += len;
8357 stacknleft -= len;
8358}
8359
Eric Andersencb57d552001-06-28 07:25:16 +00008360/*
Eric Andersenc470f442003-07-28 09:56:35 +00008361 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008362 * The user declares a variable of type STACKSTR, which may be declared
8363 * to be a register. The macro STARTSTACKSTR initializes things. Then
8364 * the user uses the macro STPUTC to add characters to the string. In
8365 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8366 * grown as necessary. When the user is done, she can just leave the
8367 * string there and refer to it using stackblock(). Or she can allocate
8368 * the space for it using grabstackstr(). If it is necessary to allow
8369 * someone else to use the stack temporarily and then continue to grow
8370 * the string, the user should use grabstack to allocate the space, and
8371 * then call ungrabstr(p) to return to the previous mode of operation.
8372 *
8373 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8374 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8375 * is space for at least one character.
8376 */
8377
Eric Andersenc470f442003-07-28 09:56:35 +00008378void *
8379growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008380{
Eric Andersenc470f442003-07-28 09:56:35 +00008381 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008382 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008383 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008384 return stackblock();
8385 }
8386 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008387 return stackblock() + len;
8388}
8389
Eric Andersencb57d552001-06-28 07:25:16 +00008390/*
8391 * Called from CHECKSTRSPACE.
8392 */
8393
Eric Andersenc470f442003-07-28 09:56:35 +00008394char *
8395makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008396{
Eric Andersenc470f442003-07-28 09:56:35 +00008397 size_t len = p - stacknxt;
8398 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008399
Eric Andersenc470f442003-07-28 09:56:35 +00008400 for (;;) {
8401 size_t nleft;
8402
8403 size = stackblocksize();
8404 nleft = size - len;
8405 if (nleft >= newlen)
8406 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008407 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008408 }
Eric Andersencb57d552001-06-28 07:25:16 +00008409 return stackblock() + len;
8410}
8411
Eric Andersenc470f442003-07-28 09:56:35 +00008412char *
8413stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008414{
Eric Andersenc470f442003-07-28 09:56:35 +00008415 p = makestrspace(n, p);
8416 p = mempcpy(p, s, n);
8417 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008418}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008419
Eric Andersenc470f442003-07-28 09:56:35 +00008420char *
8421stputs(const char *s, char *p)
8422{
8423 return stnputs(s, strlen(s), p);
8424}
8425
8426/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8427
Eric Andersencb57d552001-06-28 07:25:16 +00008428/*
Eric Andersenc470f442003-07-28 09:56:35 +00008429 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008430 *
Eric Andersenc470f442003-07-28 09:56:35 +00008431 * number(s) Convert a string of digits to an integer.
8432 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008433 */
8434
Eric Andersencb57d552001-06-28 07:25:16 +00008435/*
8436 * prefix -- see if pfx is a prefix of string.
8437 */
8438
Eric Andersenc470f442003-07-28 09:56:35 +00008439char *
8440prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008441{
Eric Andersencb57d552001-06-28 07:25:16 +00008442 while (*pfx) {
8443 if (*pfx++ != *string++)
8444 return 0;
8445 }
Eric Andersenc470f442003-07-28 09:56:35 +00008446 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008447}
8448
8449
8450/*
8451 * Convert a string of digits to an integer, printing an error message on
8452 * failure.
8453 */
8454
Eric Andersenc470f442003-07-28 09:56:35 +00008455int
8456number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008457{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008458
Eric Andersenc470f442003-07-28 09:56:35 +00008459 if (! is_number(s))
8460 error(illnum, s);
8461 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008462}
8463
Eric Andersenc470f442003-07-28 09:56:35 +00008464
Eric Andersenc470f442003-07-28 09:56:35 +00008465/*
8466 * Check for a valid number. This should be elsewhere.
8467 */
8468
8469int
8470is_number(const char *p)
8471{
8472 do {
8473 if (! is_digit(*p))
8474 return 0;
8475 } while (*++p != '\0');
8476 return 1;
8477}
8478
8479
Eric Andersencb57d552001-06-28 07:25:16 +00008480/*
8481 * Produce a possibly single quoted string suitable as input to the shell.
8482 * The return string is allocated on the stack.
8483 */
8484
Eric Andersenc470f442003-07-28 09:56:35 +00008485char *
8486single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008487 char *p;
8488
8489 STARTSTACKSTR(p);
8490
8491 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008492 char *q;
8493 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008494
Eric Andersenc470f442003-07-28 09:56:35 +00008495 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008496
Eric Andersenc470f442003-07-28 09:56:35 +00008497 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008498
Eric Andersenc470f442003-07-28 09:56:35 +00008499 *q++ = '\'';
8500 q = mempcpy(q, s, len);
8501 *q++ = '\'';
8502 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008503
Eric Andersenc470f442003-07-28 09:56:35 +00008504 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008505
Eric Andersenc470f442003-07-28 09:56:35 +00008506 len = strspn(s, "'");
8507 if (!len)
8508 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008509
Eric Andersenc470f442003-07-28 09:56:35 +00008510 q = p = makestrspace(len + 3, p);
8511
8512 *q++ = '"';
8513 q = mempcpy(q, s, len);
8514 *q++ = '"';
8515 s += len;
8516
8517 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008518 } while (*s);
8519
8520 USTPUTC(0, p);
8521
Eric Andersenc470f442003-07-28 09:56:35 +00008522 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008523}
8524
8525/*
Eric Andersenc470f442003-07-28 09:56:35 +00008526 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008527 */
8528
Eric Andersenc470f442003-07-28 09:56:35 +00008529char *
8530sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008531{
Eric Andersenc470f442003-07-28 09:56:35 +00008532 size_t len = strlen(p) + 1;
8533 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008534}
Eric Andersenc470f442003-07-28 09:56:35 +00008535
8536
8537static void
8538calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008539{
Eric Andersenc470f442003-07-28 09:56:35 +00008540 if (n == NULL)
8541 return;
8542 funcblocksize += nodesize[n->type];
8543 switch (n->type) {
8544 case NCMD:
8545 calcsize(n->ncmd.redirect);
8546 calcsize(n->ncmd.args);
8547 calcsize(n->ncmd.assign);
8548 break;
8549 case NPIPE:
8550 sizenodelist(n->npipe.cmdlist);
8551 break;
8552 case NREDIR:
8553 case NBACKGND:
8554 case NSUBSHELL:
8555 calcsize(n->nredir.redirect);
8556 calcsize(n->nredir.n);
8557 break;
8558 case NAND:
8559 case NOR:
8560 case NSEMI:
8561 case NWHILE:
8562 case NUNTIL:
8563 calcsize(n->nbinary.ch2);
8564 calcsize(n->nbinary.ch1);
8565 break;
8566 case NIF:
8567 calcsize(n->nif.elsepart);
8568 calcsize(n->nif.ifpart);
8569 calcsize(n->nif.test);
8570 break;
8571 case NFOR:
8572 funcstringsize += strlen(n->nfor.var) + 1;
8573 calcsize(n->nfor.body);
8574 calcsize(n->nfor.args);
8575 break;
8576 case NCASE:
8577 calcsize(n->ncase.cases);
8578 calcsize(n->ncase.expr);
8579 break;
8580 case NCLIST:
8581 calcsize(n->nclist.body);
8582 calcsize(n->nclist.pattern);
8583 calcsize(n->nclist.next);
8584 break;
8585 case NDEFUN:
8586 case NARG:
8587 sizenodelist(n->narg.backquote);
8588 funcstringsize += strlen(n->narg.text) + 1;
8589 calcsize(n->narg.next);
8590 break;
8591 case NTO:
8592 case NCLOBBER:
8593 case NFROM:
8594 case NFROMTO:
8595 case NAPPEND:
8596 calcsize(n->nfile.fname);
8597 calcsize(n->nfile.next);
8598 break;
8599 case NTOFD:
8600 case NFROMFD:
8601 calcsize(n->ndup.vname);
8602 calcsize(n->ndup.next);
8603 break;
8604 case NHERE:
8605 case NXHERE:
8606 calcsize(n->nhere.doc);
8607 calcsize(n->nhere.next);
8608 break;
8609 case NNOT:
8610 calcsize(n->nnot.com);
8611 break;
8612 };
Eric Andersencb57d552001-06-28 07:25:16 +00008613}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008614
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008615
Eric Andersenc470f442003-07-28 09:56:35 +00008616static void
8617sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008618{
8619 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008620 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008621 calcsize(lp->n);
8622 lp = lp->next;
8623 }
8624}
Eric Andersencb57d552001-06-28 07:25:16 +00008625
8626
Eric Andersenc470f442003-07-28 09:56:35 +00008627static union node *
8628copynode(union node *n)
8629{
8630 union node *new;
8631
8632 if (n == NULL)
8633 return NULL;
8634 new = funcblock;
8635 funcblock = (char *) funcblock + nodesize[n->type];
8636 switch (n->type) {
8637 case NCMD:
8638 new->ncmd.redirect = copynode(n->ncmd.redirect);
8639 new->ncmd.args = copynode(n->ncmd.args);
8640 new->ncmd.assign = copynode(n->ncmd.assign);
8641 break;
8642 case NPIPE:
8643 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8644 new->npipe.backgnd = n->npipe.backgnd;
8645 break;
8646 case NREDIR:
8647 case NBACKGND:
8648 case NSUBSHELL:
8649 new->nredir.redirect = copynode(n->nredir.redirect);
8650 new->nredir.n = copynode(n->nredir.n);
8651 break;
8652 case NAND:
8653 case NOR:
8654 case NSEMI:
8655 case NWHILE:
8656 case NUNTIL:
8657 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8658 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8659 break;
8660 case NIF:
8661 new->nif.elsepart = copynode(n->nif.elsepart);
8662 new->nif.ifpart = copynode(n->nif.ifpart);
8663 new->nif.test = copynode(n->nif.test);
8664 break;
8665 case NFOR:
8666 new->nfor.var = nodesavestr(n->nfor.var);
8667 new->nfor.body = copynode(n->nfor.body);
8668 new->nfor.args = copynode(n->nfor.args);
8669 break;
8670 case NCASE:
8671 new->ncase.cases = copynode(n->ncase.cases);
8672 new->ncase.expr = copynode(n->ncase.expr);
8673 break;
8674 case NCLIST:
8675 new->nclist.body = copynode(n->nclist.body);
8676 new->nclist.pattern = copynode(n->nclist.pattern);
8677 new->nclist.next = copynode(n->nclist.next);
8678 break;
8679 case NDEFUN:
8680 case NARG:
8681 new->narg.backquote = copynodelist(n->narg.backquote);
8682 new->narg.text = nodesavestr(n->narg.text);
8683 new->narg.next = copynode(n->narg.next);
8684 break;
8685 case NTO:
8686 case NCLOBBER:
8687 case NFROM:
8688 case NFROMTO:
8689 case NAPPEND:
8690 new->nfile.fname = copynode(n->nfile.fname);
8691 new->nfile.fd = n->nfile.fd;
8692 new->nfile.next = copynode(n->nfile.next);
8693 break;
8694 case NTOFD:
8695 case NFROMFD:
8696 new->ndup.vname = copynode(n->ndup.vname);
8697 new->ndup.dupfd = n->ndup.dupfd;
8698 new->ndup.fd = n->ndup.fd;
8699 new->ndup.next = copynode(n->ndup.next);
8700 break;
8701 case NHERE:
8702 case NXHERE:
8703 new->nhere.doc = copynode(n->nhere.doc);
8704 new->nhere.fd = n->nhere.fd;
8705 new->nhere.next = copynode(n->nhere.next);
8706 break;
8707 case NNOT:
8708 new->nnot.com = copynode(n->nnot.com);
8709 break;
8710 };
8711 new->type = n->type;
8712 return new;
8713}
8714
8715
8716static struct nodelist *
8717copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008718{
8719 struct nodelist *start;
8720 struct nodelist **lpp;
8721
8722 lpp = &start;
8723 while (lp) {
8724 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008725 funcblock = (char *) funcblock +
8726 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008727 (*lpp)->n = copynode(lp->n);
8728 lp = lp->next;
8729 lpp = &(*lpp)->next;
8730 }
8731 *lpp = NULL;
8732 return start;
8733}
8734
8735
Eric Andersenc470f442003-07-28 09:56:35 +00008736static char *
8737nodesavestr(char *s)
8738{
8739 char *rtn = funcstring;
8740
8741 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008742 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008743}
8744
Eric Andersenc470f442003-07-28 09:56:35 +00008745
Eric Andersenc470f442003-07-28 09:56:35 +00008746/*
8747 * Free a parse tree.
8748 */
8749
8750static void
8751freefunc(struct funcnode *f)
8752{
8753 if (f && --f->count < 0)
8754 ckfree(f);
8755}
8756
8757
8758static void options(int);
8759static void setoption(int, int);
8760
Eric Andersencb57d552001-06-28 07:25:16 +00008761
Eric Andersencb57d552001-06-28 07:25:16 +00008762/*
8763 * Process the shell command line arguments.
8764 */
8765
Eric Andersenc470f442003-07-28 09:56:35 +00008766void
8767procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008768{
8769 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008770 const char *xminusc;
8771 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008772
Eric Andersenc470f442003-07-28 09:56:35 +00008773 xargv = argv;
8774 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008775 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008776 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008777 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008778 optlist[i] = 2;
8779 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008780 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008781 xargv = argptr;
8782 xminusc = minusc;
8783 if (*xargv == NULL) {
8784 if (xminusc)
8785 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008786 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008787 }
Eric Andersencb57d552001-06-28 07:25:16 +00008788 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8789 iflag = 1;
8790 if (mflag == 2)
8791 mflag = iflag;
8792 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008793 if (optlist[i] == 2)
8794 optlist[i] = 0;
8795#if DEBUG == 2
8796 debug = 1;
8797#endif
8798 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8799 if (xminusc) {
8800 minusc = *xargv++;
8801 if (*xargv)
8802 goto setarg0;
8803 } else if (!sflag) {
8804 setinputfile(*xargv, 0);
8805setarg0:
8806 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008807 commandname = arg0;
8808 }
Eric Andersencb57d552001-06-28 07:25:16 +00008809
Eric Andersenc470f442003-07-28 09:56:35 +00008810 shellparam.p = xargv;
8811#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008812 shellparam.optind = 1;
8813 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008814#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008815 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008816 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008817 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008818 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008819 }
8820 optschanged();
8821}
8822
8823
Eric Andersenc470f442003-07-28 09:56:35 +00008824void
8825optschanged(void)
8826{
8827#ifdef DEBUG
8828 opentrace();
8829#endif
8830 setinteractive(iflag);
8831 setjobctl(mflag);
8832}
Eric Andersencb57d552001-06-28 07:25:16 +00008833
Eric Andersenc470f442003-07-28 09:56:35 +00008834static inline void
8835minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008836{
8837 int i;
8838
8839 if (name == NULL) {
8840 out1str("Current option settings\n");
8841 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008842 out1fmt("%-16s%s\n", optnames(i),
8843 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008844 } else {
8845 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008846 if (equal(name, optnames(i))) {
8847 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008848 return;
8849 }
8850 error("Illegal option -o %s", name);
8851 }
8852}
8853
Eric Andersenc470f442003-07-28 09:56:35 +00008854/*
8855 * Process shell options. The global variable argptr contains a pointer
8856 * to the argument list; we advance it past the options.
8857 */
Eric Andersen62483552001-07-10 06:09:16 +00008858
Eric Andersenc470f442003-07-28 09:56:35 +00008859static void
8860options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008861{
8862 char *p;
8863 int val;
8864 int c;
8865
8866 if (cmdline)
8867 minusc = NULL;
8868 while ((p = *argptr) != NULL) {
8869 argptr++;
8870 if ((c = *p++) == '-') {
8871 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008872 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8873 if (!cmdline) {
8874 /* "-" means turn off -x and -v */
8875 if (p[0] == '\0')
8876 xflag = vflag = 0;
8877 /* "--" means reset params */
8878 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008879 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008880 }
Eric Andersenc470f442003-07-28 09:56:35 +00008881 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008882 }
8883 } else if (c == '+') {
8884 val = 0;
8885 } else {
8886 argptr--;
8887 break;
8888 }
8889 while ((c = *p++) != '\0') {
8890 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008891 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008892 } else if (c == 'o') {
8893 minus_o(*argptr, val);
8894 if (*argptr)
8895 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008896 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008897 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008898 isloginsh = 1;
8899 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008900 } else {
8901 setoption(c, val);
8902 }
8903 }
8904 }
8905}
8906
Eric Andersencb57d552001-06-28 07:25:16 +00008907
Eric Andersenc470f442003-07-28 09:56:35 +00008908static void
8909setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008910{
Eric Andersencb57d552001-06-28 07:25:16 +00008911 int i;
8912
8913 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008914 if (optletters(i) == flag) {
8915 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008916 return;
8917 }
8918 error("Illegal option -%c", flag);
8919 /* NOTREACHED */
8920}
8921
8922
8923
Eric Andersencb57d552001-06-28 07:25:16 +00008924/*
8925 * Set the shell parameters.
8926 */
8927
Eric Andersenc470f442003-07-28 09:56:35 +00008928void
8929setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008930{
Eric Andersencb57d552001-06-28 07:25:16 +00008931 char **newparam;
8932 char **ap;
8933 int nparam;
8934
Eric Andersenc470f442003-07-28 09:56:35 +00008935 for (nparam = 0 ; argv[nparam] ; nparam++);
8936 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008937 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008938 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008939 }
8940 *ap = NULL;
8941 freeparam(&shellparam);
8942 shellparam.malloc = 1;
8943 shellparam.nparam = nparam;
8944 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008945#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008946 shellparam.optind = 1;
8947 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008948#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008949}
8950
8951
8952/*
8953 * Free the list of positional parameters.
8954 */
8955
Eric Andersenc470f442003-07-28 09:56:35 +00008956void
8957freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008958{
Eric Andersencb57d552001-06-28 07:25:16 +00008959 char **ap;
8960
8961 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008962 for (ap = param->p ; *ap ; ap++)
8963 ckfree(*ap);
8964 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008965 }
8966}
8967
8968
8969
8970/*
8971 * The shift builtin command.
8972 */
8973
Eric Andersenc470f442003-07-28 09:56:35 +00008974int
8975shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008976{
8977 int n;
8978 char **ap1, **ap2;
8979
8980 n = 1;
8981 if (argc > 1)
8982 n = number(argv[1]);
8983 if (n > shellparam.nparam)
8984 error("can't shift that many");
8985 INTOFF;
8986 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008987 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008988 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008989 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008990 }
8991 ap2 = shellparam.p;
8992 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008993#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008994 shellparam.optind = 1;
8995 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008996#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008997 INTON;
8998 return 0;
8999}
9000
9001
9002
9003/*
9004 * The set command builtin.
9005 */
9006
Eric Andersenc470f442003-07-28 09:56:35 +00009007int
9008setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009009{
9010 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009011 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009012 INTOFF;
9013 options(0);
9014 optschanged();
9015 if (*argptr != NULL) {
9016 setparam(argptr);
9017 }
9018 INTON;
9019 return 0;
9020}
9021
9022
Eric Andersenc470f442003-07-28 09:56:35 +00009023#ifdef CONFIG_ASH_GETOPTS
9024static void
9025getoptsreset(value)
9026 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009027{
9028 shellparam.optind = number(value);
9029 shellparam.optoff = -1;
9030}
Eric Andersenc470f442003-07-28 09:56:35 +00009031#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009032
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009033#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009034static void change_lc_all(const char *value)
9035{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009036 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009037 setlocale(LC_ALL, value);
9038}
9039
9040static void change_lc_ctype(const char *value)
9041{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009042 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009043 setlocale(LC_CTYPE, value);
9044}
9045
9046#endif
9047
Eric Andersen16767e22004-03-16 05:14:10 +00009048#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009049/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009050static void change_random(const char *value)
9051{
Eric Andersen16767e22004-03-16 05:14:10 +00009052 if(value == NULL) {
9053 /* "get", generate */
9054 char buf[16];
9055
9056 rseed = rseed * 1103515245 + 12345;
9057 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9058 /* set without recursion */
9059 setvar(vrandom.text, buf, VNOFUNC);
9060 vrandom.flags &= ~VNOFUNC;
9061 } else {
9062 /* set/reset */
9063 rseed = strtoul(value, (char **)NULL, 10);
9064 }
Eric Andersenef02f822004-03-11 13:34:24 +00009065}
Eric Andersen16767e22004-03-16 05:14:10 +00009066#endif
9067
Eric Andersenef02f822004-03-11 13:34:24 +00009068
Eric Andersend35c5df2002-01-09 15:37:36 +00009069#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009070static int
Eric Andersenc470f442003-07-28 09:56:35 +00009071getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009072{
9073 char *p, *q;
9074 char c = '?';
9075 int done = 0;
9076 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009077 char s[12];
9078 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009079
Eric Andersena48b0a32003-10-22 10:56:47 +00009080 if(*param_optind < 1)
9081 return 1;
9082 optnext = optfirst + *param_optind - 1;
9083
9084 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009085 p = NULL;
9086 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009087 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009088 if (p == NULL || *p == '\0') {
9089 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009090 p = *optnext;
9091 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009092atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009093 p = NULL;
9094 done = 1;
9095 goto out;
9096 }
9097 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009098 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009099 goto atend;
9100 }
9101
9102 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009103 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009104 if (*q == '\0') {
9105 if (optstr[0] == ':') {
9106 s[0] = c;
9107 s[1] = '\0';
9108 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009109 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009110 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009111 (void) unsetvar("OPTARG");
9112 }
9113 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009114 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009115 }
9116 if (*++q == ':')
9117 q++;
9118 }
9119
9120 if (*++q == ':') {
9121 if (*p == '\0' && (p = *optnext) == NULL) {
9122 if (optstr[0] == ':') {
9123 s[0] = c;
9124 s[1] = '\0';
9125 err |= setvarsafe("OPTARG", s, 0);
9126 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009127 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009128 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009129 (void) unsetvar("OPTARG");
9130 c = '?';
9131 }
Eric Andersenc470f442003-07-28 09:56:35 +00009132 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009133 }
9134
9135 if (p == *optnext)
9136 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009137 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009138 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009139 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009140 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009141
Eric Andersenc470f442003-07-28 09:56:35 +00009142out:
Eric Andersencb57d552001-06-28 07:25:16 +00009143 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009144 *param_optind = optnext - optfirst + 1;
9145 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009146 err |= setvarsafe("OPTIND", s, VNOFUNC);
9147 s[0] = c;
9148 s[1] = '\0';
9149 err |= setvarsafe(optvar, s, 0);
9150 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009151 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009152 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009153 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009154 exraise(EXERROR);
9155 }
9156 return done;
9157}
Eric Andersenc470f442003-07-28 09:56:35 +00009158
9159/*
9160 * The getopts builtin. Shellparam.optnext points to the next argument
9161 * to be processed. Shellparam.optptr points to the next character to
9162 * be processed in the current argument. If shellparam.optnext is NULL,
9163 * then it's the first time getopts has been called.
9164 */
9165
9166int
9167getoptscmd(int argc, char **argv)
9168{
9169 char **optbase;
9170
9171 if (argc < 3)
9172 error("Usage: getopts optstring var [arg]");
9173 else if (argc == 3) {
9174 optbase = shellparam.p;
9175 if (shellparam.optind > shellparam.nparam + 1) {
9176 shellparam.optind = 1;
9177 shellparam.optoff = -1;
9178 }
9179 }
9180 else {
9181 optbase = &argv[3];
9182 if (shellparam.optind > argc - 2) {
9183 shellparam.optind = 1;
9184 shellparam.optoff = -1;
9185 }
9186 }
9187
9188 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9189 &shellparam.optoff);
9190}
9191#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009192
9193/*
9194 * XXX - should get rid of. have all builtins use getopt(3). the
9195 * library getopt must have the BSD extension static variable "optreset"
9196 * otherwise it can't be used within the shell safely.
9197 *
9198 * Standard option processing (a la getopt) for builtin routines. The
9199 * only argument that is passed to nextopt is the option string; the
9200 * other arguments are unnecessary. It return the character, or '\0' on
9201 * end of input.
9202 */
9203
Eric Andersenc470f442003-07-28 09:56:35 +00009204static int
9205nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009206{
Eric Andersencb57d552001-06-28 07:25:16 +00009207 char *p;
9208 const char *q;
9209 char c;
9210
9211 if ((p = optptr) == NULL || *p == '\0') {
9212 p = *argptr;
9213 if (p == NULL || *p != '-' || *++p == '\0')
9214 return '\0';
9215 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009216 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009217 return '\0';
9218 }
9219 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009220 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009221 if (*q == '\0')
9222 error("Illegal option -%c", c);
9223 if (*++q == ':')
9224 q++;
9225 }
9226 if (*++q == ':') {
9227 if (*p == '\0' && (p = *argptr++) == NULL)
9228 error("No arg for -%c option", c);
9229 optionarg = p;
9230 p = NULL;
9231 }
9232 optptr = p;
9233 return c;
9234}
9235
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009236
Eric Andersenc470f442003-07-28 09:56:35 +00009237/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9238
Eric Andersenc470f442003-07-28 09:56:35 +00009239void
9240outstr(const char *p, FILE *file)
9241{
9242 INTOFF;
9243 fputs(p, file);
9244 INTON;
9245}
9246
9247void
9248flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009249{
Eric Andersencb57d552001-06-28 07:25:16 +00009250 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009251 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009252 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009253 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009254}
9255
Eric Andersenc470f442003-07-28 09:56:35 +00009256void
Eric Andersen16767e22004-03-16 05:14:10 +00009257flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009258{
9259 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009260 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009261 INTON;
9262}
9263
9264static void
9265outcslow(int c, FILE *dest)
9266{
9267 INTOFF;
9268 putc(c, dest);
9269 fflush(dest);
9270 INTON;
9271}
9272
9273
9274static int
9275out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009276{
9277 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009278 int r;
9279
9280 INTOFF;
9281 va_start(ap, fmt);
9282 r = vprintf(fmt, ap);
9283 va_end(ap);
9284 INTON;
9285 return r;
9286}
9287
9288
9289int
9290fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9291{
9292 va_list ap;
9293 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009294
Eric Andersencb57d552001-06-28 07:25:16 +00009295 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009296 INTOFF;
9297 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009298 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009299 INTON;
9300 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009301}
9302
Eric Andersenc470f442003-07-28 09:56:35 +00009303
Eric Andersencb57d552001-06-28 07:25:16 +00009304
Eric Andersenc470f442003-07-28 09:56:35 +00009305/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9306
9307
Eric Andersencb57d552001-06-28 07:25:16 +00009308/*
9309 * Shell command parser.
9310 */
9311
9312#define EOFMARKLEN 79
9313
9314
Eric Andersencb57d552001-06-28 07:25:16 +00009315struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009316 struct heredoc *next; /* next here document in list */
9317 union node *here; /* redirection node */
9318 char *eofmark; /* string indicating end of input */
9319 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009320};
9321
9322
9323
Eric Andersenc470f442003-07-28 09:56:35 +00009324static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009325
9326
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009327static union node *list(int);
9328static union node *andor(void);
9329static union node *pipeline(void);
9330static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009331static union node *simplecmd(void);
9332static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009333static void parsefname(void);
9334static void parseheredoc(void);
9335static char peektoken(void);
9336static int readtoken(void);
9337static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009338static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009339static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009340static void synexpect(int) __attribute__((__noreturn__));
9341static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009342static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009343
9344
Eric Andersenc470f442003-07-28 09:56:35 +00009345
9346static inline int
9347isassignment(const char *p)
9348{
9349 const char *q = endofname(p);
9350 if (p == q)
9351 return 0;
9352 return *q == '=';
9353}
9354
9355
Eric Andersencb57d552001-06-28 07:25:16 +00009356/*
9357 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9358 * valid parse tree indicating a blank line.)
9359 */
9360
Eric Andersenc470f442003-07-28 09:56:35 +00009361union node *
9362parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009363{
9364 int t;
9365
9366 tokpushback = 0;
9367 doprompt = interact;
9368 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009369 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009370 needprompt = 0;
9371 t = readtoken();
9372 if (t == TEOF)
9373 return NEOF;
9374 if (t == TNL)
9375 return NULL;
9376 tokpushback++;
9377 return list(1);
9378}
9379
9380
Eric Andersenc470f442003-07-28 09:56:35 +00009381static union node *
9382list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009383{
9384 union node *n1, *n2, *n3;
9385 int tok;
9386
Eric Andersenc470f442003-07-28 09:56:35 +00009387 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9388 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009389 return NULL;
9390 n1 = NULL;
9391 for (;;) {
9392 n2 = andor();
9393 tok = readtoken();
9394 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009395 if (n2->type == NPIPE) {
9396 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009397 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009398 if (n2->type != NREDIR) {
9399 n3 = stalloc(sizeof(struct nredir));
9400 n3->nredir.n = n2;
9401 n3->nredir.redirect = NULL;
9402 n2 = n3;
9403 }
9404 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009405 }
9406 }
9407 if (n1 == NULL) {
9408 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009409 }
9410 else {
9411 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009412 n3->type = NSEMI;
9413 n3->nbinary.ch1 = n1;
9414 n3->nbinary.ch2 = n2;
9415 n1 = n3;
9416 }
9417 switch (tok) {
9418 case TBACKGND:
9419 case TSEMI:
9420 tok = readtoken();
9421 /* fall through */
9422 case TNL:
9423 if (tok == TNL) {
9424 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009425 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009426 return n1;
9427 } else {
9428 tokpushback++;
9429 }
Eric Andersenc470f442003-07-28 09:56:35 +00009430 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009431 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009432 return n1;
9433 break;
9434 case TEOF:
9435 if (heredoclist)
9436 parseheredoc();
9437 else
Eric Andersenc470f442003-07-28 09:56:35 +00009438 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009439 return n1;
9440 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009441 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009442 synexpect(-1);
9443 tokpushback++;
9444 return n1;
9445 }
9446 }
9447}
9448
9449
9450
Eric Andersenc470f442003-07-28 09:56:35 +00009451static union node *
9452andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009453{
Eric Andersencb57d552001-06-28 07:25:16 +00009454 union node *n1, *n2, *n3;
9455 int t;
9456
Eric Andersencb57d552001-06-28 07:25:16 +00009457 n1 = pipeline();
9458 for (;;) {
9459 if ((t = readtoken()) == TAND) {
9460 t = NAND;
9461 } else if (t == TOR) {
9462 t = NOR;
9463 } else {
9464 tokpushback++;
9465 return n1;
9466 }
Eric Andersenc470f442003-07-28 09:56:35 +00009467 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009468 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009469 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009470 n3->type = t;
9471 n3->nbinary.ch1 = n1;
9472 n3->nbinary.ch2 = n2;
9473 n1 = n3;
9474 }
9475}
9476
9477
9478
Eric Andersenc470f442003-07-28 09:56:35 +00009479static union node *
9480pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009481{
Eric Andersencb57d552001-06-28 07:25:16 +00009482 union node *n1, *n2, *pipenode;
9483 struct nodelist *lp, *prev;
9484 int negate;
9485
9486 negate = 0;
9487 TRACE(("pipeline: entered\n"));
9488 if (readtoken() == TNOT) {
9489 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009490 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009491 } else
9492 tokpushback++;
9493 n1 = command();
9494 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009495 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009496 pipenode->type = NPIPE;
9497 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009498 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009499 pipenode->npipe.cmdlist = lp;
9500 lp->n = n1;
9501 do {
9502 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009503 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9504 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009505 lp->n = command();
9506 prev->next = lp;
9507 } while (readtoken() == TPIPE);
9508 lp->next = NULL;
9509 n1 = pipenode;
9510 }
9511 tokpushback++;
9512 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009513 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009514 n2->type = NNOT;
9515 n2->nnot.com = n1;
9516 return n2;
9517 } else
9518 return n1;
9519}
9520
9521
9522
Eric Andersenc470f442003-07-28 09:56:35 +00009523static union node *
9524command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009525{
Eric Andersencb57d552001-06-28 07:25:16 +00009526 union node *n1, *n2;
9527 union node *ap, **app;
9528 union node *cp, **cpp;
9529 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009530 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009531 int t;
9532
9533 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009534 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009535
Eric Andersencb57d552001-06-28 07:25:16 +00009536 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009537 default:
9538 synexpect(-1);
9539 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009540 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009541 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009542 n1->type = NIF;
9543 n1->nif.test = list(0);
9544 if (readtoken() != TTHEN)
9545 synexpect(TTHEN);
9546 n1->nif.ifpart = list(0);
9547 n2 = n1;
9548 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009549 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009550 n2 = n2->nif.elsepart;
9551 n2->type = NIF;
9552 n2->nif.test = list(0);
9553 if (readtoken() != TTHEN)
9554 synexpect(TTHEN);
9555 n2->nif.ifpart = list(0);
9556 }
9557 if (lasttoken == TELSE)
9558 n2->nif.elsepart = list(0);
9559 else {
9560 n2->nif.elsepart = NULL;
9561 tokpushback++;
9562 }
Eric Andersenc470f442003-07-28 09:56:35 +00009563 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009564 break;
9565 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009566 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009567 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009568 n1 = (union node *)stalloc(sizeof (struct nbinary));
9569 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009570 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009571 if ((got=readtoken()) != TDO) {
9572TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009573 synexpect(TDO);
9574 }
9575 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009576 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009577 break;
9578 }
9579 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009580 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009581 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009582 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009583 n1->type = NFOR;
9584 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009585 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009586 if (readtoken() == TIN) {
9587 app = &ap;
9588 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009589 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009590 n2->type = NARG;
9591 n2->narg.text = wordtext;
9592 n2->narg.backquote = backquotelist;
9593 *app = n2;
9594 app = &n2->narg.next;
9595 }
9596 *app = NULL;
9597 n1->nfor.args = ap;
9598 if (lasttoken != TNL && lasttoken != TSEMI)
9599 synexpect(-1);
9600 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009601 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009602 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009603 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009604 n2->narg.backquote = NULL;
9605 n2->narg.next = NULL;
9606 n1->nfor.args = n2;
9607 /*
9608 * Newline or semicolon here is optional (but note
9609 * that the original Bourne shell only allowed NL).
9610 */
9611 if (lasttoken != TNL && lasttoken != TSEMI)
9612 tokpushback++;
9613 }
Eric Andersenc470f442003-07-28 09:56:35 +00009614 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009615 if (readtoken() != TDO)
9616 synexpect(TDO);
9617 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009618 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009619 break;
9620 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009621 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009622 n1->type = NCASE;
9623 if (readtoken() != TWORD)
9624 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009625 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009626 n2->type = NARG;
9627 n2->narg.text = wordtext;
9628 n2->narg.backquote = backquotelist;
9629 n2->narg.next = NULL;
9630 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009631 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009632 } while (readtoken() == TNL);
9633 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009634 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009635 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009636next_case:
9637 checkkwd = CHKNL | CHKKWD;
9638 t = readtoken();
9639 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009640 if (lasttoken == TLP)
9641 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009642 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009643 cp->type = NCLIST;
9644 app = &cp->nclist.pattern;
9645 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009646 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009647 ap->type = NARG;
9648 ap->narg.text = wordtext;
9649 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009650 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009651 break;
9652 app = &ap->narg.next;
9653 readtoken();
9654 }
9655 ap->narg.next = NULL;
9656 if (lasttoken != TRP)
9657 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009658 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009659
Eric Andersenc470f442003-07-28 09:56:35 +00009660 cpp = &cp->nclist.next;
9661
9662 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009663 if ((t = readtoken()) != TESAC) {
9664 if (t != TENDCASE)
9665 synexpect(TENDCASE);
9666 else
Eric Andersenc470f442003-07-28 09:56:35 +00009667 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009668 }
Eric Andersenc470f442003-07-28 09:56:35 +00009669 }
Eric Andersencb57d552001-06-28 07:25:16 +00009670 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009671 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009672 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009673 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009674 n1->type = NSUBSHELL;
9675 n1->nredir.n = list(0);
9676 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009677 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009678 break;
9679 case TBEGIN:
9680 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009681 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009682 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009683 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009684 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009685 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009686 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009687 }
9688
Eric Andersenc470f442003-07-28 09:56:35 +00009689 if (readtoken() != t)
9690 synexpect(t);
9691
9692redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009693 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009694 checkkwd = CHKKWD | CHKALIAS;
9695 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009696 while (readtoken() == TREDIR) {
9697 *rpp = n2 = redirnode;
9698 rpp = &n2->nfile.next;
9699 parsefname();
9700 }
9701 tokpushback++;
9702 *rpp = NULL;
9703 if (redir) {
9704 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009705 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009706 n2->type = NREDIR;
9707 n2->nredir.n = n1;
9708 n1 = n2;
9709 }
9710 n1->nredir.redirect = redir;
9711 }
9712
9713 return n1;
9714}
9715
9716
Eric Andersenc470f442003-07-28 09:56:35 +00009717static union node *
9718simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009719 union node *args, **app;
9720 union node *n = NULL;
9721 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009722 union node **rpp, *redir;
9723 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009724
9725 args = NULL;
9726 app = &args;
9727 vars = NULL;
9728 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009729 redir = NULL;
9730 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009731
Eric Andersenc470f442003-07-28 09:56:35 +00009732 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009733 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009734 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009735 switch (readtoken()) {
9736 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009737 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009738 n->type = NARG;
9739 n->narg.text = wordtext;
9740 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009741 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009742 *vpp = n;
9743 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009744 } else {
9745 *app = n;
9746 app = &n->narg.next;
9747 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009748 }
9749 break;
9750 case TREDIR:
9751 *rpp = n = redirnode;
9752 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009753 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009754 break;
9755 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009756 if (
9757 args && app == &args->narg.next &&
9758 !vars && !redir
9759 ) {
9760 struct builtincmd *bcmd;
9761 const char *name;
9762
Eric Andersencb57d552001-06-28 07:25:16 +00009763 /* We have a function */
9764 if (readtoken() != TRP)
9765 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009766 name = n->narg.text;
9767 if (
9768 !goodname(name) || (
9769 (bcmd = find_builtin(name)) &&
9770 IS_BUILTIN_SPECIAL(bcmd)
9771 )
9772 )
9773 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009774 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009775 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009776 n->narg.next = command();
9777 return n;
9778 }
9779 /* fall through */
9780 default:
9781 tokpushback++;
9782 goto out;
9783 }
9784 }
Eric Andersenc470f442003-07-28 09:56:35 +00009785out:
Eric Andersencb57d552001-06-28 07:25:16 +00009786 *app = NULL;
9787 *vpp = NULL;
9788 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009789 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009790 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009791 n->ncmd.args = args;
9792 n->ncmd.assign = vars;
9793 n->ncmd.redirect = redir;
9794 return n;
9795}
9796
Eric Andersenc470f442003-07-28 09:56:35 +00009797static union node *
9798makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009799{
Eric Andersencb57d552001-06-28 07:25:16 +00009800 union node *n;
9801
Eric Andersenc470f442003-07-28 09:56:35 +00009802 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009803 n->type = NARG;
9804 n->narg.next = NULL;
9805 n->narg.text = wordtext;
9806 n->narg.backquote = backquotelist;
9807 return n;
9808}
9809
Eric Andersenc470f442003-07-28 09:56:35 +00009810void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009811{
Eric Andersencb57d552001-06-28 07:25:16 +00009812 TRACE(("Fix redir %s %d\n", text, err));
9813 if (!err)
9814 n->ndup.vname = NULL;
9815
9816 if (is_digit(text[0]) && text[1] == '\0')
9817 n->ndup.dupfd = digit_val(text[0]);
9818 else if (text[0] == '-' && text[1] == '\0')
9819 n->ndup.dupfd = -1;
9820 else {
9821
9822 if (err)
9823 synerror("Bad fd number");
9824 else
9825 n->ndup.vname = makename();
9826 }
9827}
9828
9829
Eric Andersenc470f442003-07-28 09:56:35 +00009830static void
9831parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009832{
Eric Andersencb57d552001-06-28 07:25:16 +00009833 union node *n = redirnode;
9834
9835 if (readtoken() != TWORD)
9836 synexpect(-1);
9837 if (n->type == NHERE) {
9838 struct heredoc *here = heredoc;
9839 struct heredoc *p;
9840 int i;
9841
9842 if (quoteflag == 0)
9843 n->type = NXHERE;
9844 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009845 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009846 synerror("Illegal eof marker for << redirection");
9847 rmescapes(wordtext);
9848 here->eofmark = wordtext;
9849 here->next = NULL;
9850 if (heredoclist == NULL)
9851 heredoclist = here;
9852 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009853 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009854 p->next = here;
9855 }
9856 } else if (n->type == NTOFD || n->type == NFROMFD) {
9857 fixredir(n, wordtext, 0);
9858 } else {
9859 n->nfile.fname = makename();
9860 }
9861}
9862
9863
9864/*
9865 * Input any here documents.
9866 */
9867
Eric Andersenc470f442003-07-28 09:56:35 +00009868static void
9869parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009870{
Eric Andersencb57d552001-06-28 07:25:16 +00009871 struct heredoc *here;
9872 union node *n;
9873
Eric Andersenc470f442003-07-28 09:56:35 +00009874 here = heredoclist;
9875 heredoclist = 0;
9876
9877 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009878 if (needprompt) {
9879 setprompt(2);
9880 needprompt = 0;
9881 }
Eric Andersenc470f442003-07-28 09:56:35 +00009882 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9883 here->eofmark, here->striptabs);
9884 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009885 n->narg.type = NARG;
9886 n->narg.next = NULL;
9887 n->narg.text = wordtext;
9888 n->narg.backquote = backquotelist;
9889 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009890 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009891 }
9892}
9893
Eric Andersenc470f442003-07-28 09:56:35 +00009894static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009895{
Eric Andersencb57d552001-06-28 07:25:16 +00009896 int t;
9897
9898 t = readtoken();
9899 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009900 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009901}
9902
Eric Andersenc470f442003-07-28 09:56:35 +00009903static int
9904readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009905{
Eric Andersencb57d552001-06-28 07:25:16 +00009906 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009907#ifdef DEBUG
9908 int alreadyseen = tokpushback;
9909#endif
9910
Eric Andersend35c5df2002-01-09 15:37:36 +00009911#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009912top:
Eric Andersen2870d962001-07-02 17:27:21 +00009913#endif
9914
Eric Andersencb57d552001-06-28 07:25:16 +00009915 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009916
Eric Andersenc470f442003-07-28 09:56:35 +00009917 /*
9918 * eat newlines
9919 */
9920 if (checkkwd & CHKNL) {
9921 while (t == TNL) {
9922 parseheredoc();
9923 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009924 }
9925 }
9926
Eric Andersenc470f442003-07-28 09:56:35 +00009927 if (t != TWORD || quoteflag) {
9928 goto out;
9929 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009930
Eric Andersenc470f442003-07-28 09:56:35 +00009931 /*
9932 * check for keywords
9933 */
9934 if (checkkwd & CHKKWD) {
9935 const char *const *pp;
9936
9937 if ((pp = findkwd(wordtext))) {
9938 lasttoken = t = pp - tokname_array;
9939 TRACE(("keyword %s recognized\n", tokname(t)));
9940 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009941 }
Eric Andersenc470f442003-07-28 09:56:35 +00009942 }
9943
9944 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009945#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009946 struct alias *ap;
9947 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009948 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009949 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009950 }
Eric Andersencb57d552001-06-28 07:25:16 +00009951 goto top;
9952 }
Eric Andersen2870d962001-07-02 17:27:21 +00009953#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009954 }
Eric Andersenc470f442003-07-28 09:56:35 +00009955out:
9956 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009957#ifdef DEBUG
9958 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009959 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009960 else
Eric Andersenc470f442003-07-28 09:56:35 +00009961 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009962#endif
9963 return (t);
9964}
9965
9966
9967/*
9968 * Read the next input token.
9969 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009970 * backquotes. We set quoteflag to true if any part of the word was
9971 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009972 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009973 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009974 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009975 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009976 *
9977 * [Change comment: here documents and internal procedures]
9978 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9979 * word parsing code into a separate routine. In this case, readtoken
9980 * doesn't need to have any internal procedures, but parseword does.
9981 * We could also make parseoperator in essence the main routine, and
9982 * have parseword (readtoken1?) handle both words and redirection.]
9983 */
9984
Eric Andersen81fe1232003-07-29 06:38:40 +00009985#define NEW_xxreadtoken
9986#ifdef NEW_xxreadtoken
9987
9988/* singles must be first! */
9989static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9990
9991static const char xxreadtoken_tokens[] = {
9992 TNL, TLP, TRP, /* only single occurrence allowed */
9993 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9994 TEOF, /* corresponds to trailing nul */
9995 TAND, TOR, TENDCASE, /* if double occurrence */
9996};
9997
9998#define xxreadtoken_doubles \
9999 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10000#define xxreadtoken_singles \
10001 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10002
10003static int xxreadtoken()
10004{
10005 int c;
10006
10007 if (tokpushback) {
10008 tokpushback = 0;
10009 return lasttoken;
10010 }
10011 if (needprompt) {
10012 setprompt(2);
10013 needprompt = 0;
10014 }
10015 startlinno = plinno;
10016 for (;;) { /* until token or start of word found */
10017 c = pgetc_macro();
10018
10019 if ((c != ' ') && (c != '\t')
10020#ifdef CONFIG_ASH_ALIAS
10021 && (c != PEOA)
10022#endif
10023 ) {
10024 if (c == '#') {
10025 while ((c = pgetc()) != '\n' && c != PEOF);
10026 pungetc();
10027 } else if (c == '\\') {
10028 if (pgetc() != '\n') {
10029 pungetc();
10030 goto READTOKEN1;
10031 }
10032 startlinno = ++plinno;
10033 if (doprompt)
10034 setprompt(2);
10035 } else {
10036 const char *p
10037 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10038
10039 if (c != PEOF) {
10040 if (c == '\n') {
10041 plinno++;
10042 needprompt = doprompt;
10043 }
10044
10045 p = strchr(xxreadtoken_chars, c);
10046 if (p == NULL) {
10047 READTOKEN1:
10048 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10049 }
10050
10051 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10052 if (pgetc() == *p) { /* double occurrence? */
10053 p += xxreadtoken_doubles + 1;
10054 } else {
10055 pungetc();
10056 }
10057 }
10058 }
10059
10060 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10061 }
10062 }
10063 }
10064}
10065
10066
10067#else
Eric Andersen2870d962001-07-02 17:27:21 +000010068#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010069
Eric Andersenc470f442003-07-28 09:56:35 +000010070static int
10071xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010072{
Eric Andersencb57d552001-06-28 07:25:16 +000010073 int c;
10074
10075 if (tokpushback) {
10076 tokpushback = 0;
10077 return lasttoken;
10078 }
10079 if (needprompt) {
10080 setprompt(2);
10081 needprompt = 0;
10082 }
10083 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010084 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010085 c = pgetc_macro();
10086 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010087 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010088#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010089 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010090#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010091 continue;
10092 case '#':
10093 while ((c = pgetc()) != '\n' && c != PEOF);
10094 pungetc();
10095 continue;
10096 case '\\':
10097 if (pgetc() == '\n') {
10098 startlinno = ++plinno;
10099 if (doprompt)
10100 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010101 continue;
10102 }
10103 pungetc();
10104 goto breakloop;
10105 case '\n':
10106 plinno++;
10107 needprompt = doprompt;
10108 RETURN(TNL);
10109 case PEOF:
10110 RETURN(TEOF);
10111 case '&':
10112 if (pgetc() == '&')
10113 RETURN(TAND);
10114 pungetc();
10115 RETURN(TBACKGND);
10116 case '|':
10117 if (pgetc() == '|')
10118 RETURN(TOR);
10119 pungetc();
10120 RETURN(TPIPE);
10121 case ';':
10122 if (pgetc() == ';')
10123 RETURN(TENDCASE);
10124 pungetc();
10125 RETURN(TSEMI);
10126 case '(':
10127 RETURN(TLP);
10128 case ')':
10129 RETURN(TRP);
10130 default:
10131 goto breakloop;
10132 }
10133 }
Eric Andersenc470f442003-07-28 09:56:35 +000010134breakloop:
10135 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010136#undef RETURN
10137}
Eric Andersen81fe1232003-07-29 06:38:40 +000010138#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010139
Eric Andersencb57d552001-06-28 07:25:16 +000010140
Eric Andersencb57d552001-06-28 07:25:16 +000010141/*
10142 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10143 * is not NULL, read a here document. In the latter case, eofmark is the
10144 * word which marks the end of the document and striptabs is true if
10145 * leading tabs should be stripped from the document. The argument firstc
10146 * is the first character of the input token or document.
10147 *
10148 * Because C does not have internal subroutines, I have simulated them
10149 * using goto's to implement the subroutine linkage. The following macros
10150 * will run code that appears at the end of readtoken1.
10151 */
10152
Eric Andersen2870d962001-07-02 17:27:21 +000010153#define CHECKEND() {goto checkend; checkend_return:;}
10154#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10155#define PARSESUB() {goto parsesub; parsesub_return:;}
10156#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10157#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10158#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010159
10160static int
Eric Andersenc470f442003-07-28 09:56:35 +000010161readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010162{
Eric Andersencb57d552001-06-28 07:25:16 +000010163 int c = firstc;
10164 char *out;
10165 int len;
10166 char line[EOFMARKLEN + 1];
10167 struct nodelist *bqlist;
10168 int quotef;
10169 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010170 int varnest; /* levels of variables expansion */
10171 int arinest; /* levels of arithmetic expansion */
10172 int parenlevel; /* levels of parens in arithmetic */
10173 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010174 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010175 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010176#if __GNUC__
10177 /* Avoid longjmp clobbering */
10178 (void) &out;
10179 (void) &quotef;
10180 (void) &dblquote;
10181 (void) &varnest;
10182 (void) &arinest;
10183 (void) &parenlevel;
10184 (void) &dqvarnest;
10185 (void) &oldstyle;
10186 (void) &prevsyntax;
10187 (void) &syntax;
10188#endif
10189
10190 startlinno = plinno;
10191 dblquote = 0;
10192 if (syntax == DQSYNTAX)
10193 dblquote = 1;
10194 quotef = 0;
10195 bqlist = NULL;
10196 varnest = 0;
10197 arinest = 0;
10198 parenlevel = 0;
10199 dqvarnest = 0;
10200
10201 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010202 loop: { /* for each line, until end of word */
10203 CHECKEND(); /* set c to PEOF if at end of here document */
10204 for (;;) { /* until end of line or end of word */
10205 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10206 switch(SIT(c, syntax)) {
10207 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010208 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010209 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010210 USTPUTC(c, out);
10211 plinno++;
10212 if (doprompt)
10213 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010214 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010215 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010216 case CWORD:
10217 USTPUTC(c, out);
10218 break;
10219 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010220 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010221 USTPUTC(CTLESC, out);
10222 USTPUTC(c, out);
10223 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010224 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010225 c = pgetc2();
10226 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010227 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010228 USTPUTC('\\', out);
10229 pungetc();
10230 } else if (c == '\n') {
10231 if (doprompt)
10232 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010233 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010234 if (
10235 dblquote &&
10236 c != '\\' && c != '`' &&
10237 c != '$' && (
10238 c != '"' ||
10239 eofmark != NULL
10240 )
10241 ) {
10242 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010243 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010244 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010245 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010246 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010247 USTPUTC(c, out);
10248 quotef++;
10249 }
10250 break;
10251 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010252 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010253quotemark:
10254 if (eofmark == NULL) {
10255 USTPUTC(CTLQUOTEMARK, out);
10256 }
Eric Andersencb57d552001-06-28 07:25:16 +000010257 break;
10258 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010259 syntax = DQSYNTAX;
10260 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010261 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010262 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010263 if (eofmark != NULL && arinest == 0 &&
10264 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010265 USTPUTC(c, out);
10266 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010267 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010268 syntax = BASESYNTAX;
10269 dblquote = 0;
10270 }
10271 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010272 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010273 }
10274 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010275 case CVAR: /* '$' */
10276 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010277 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010278 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010279 if (varnest > 0) {
10280 varnest--;
10281 if (dqvarnest > 0) {
10282 dqvarnest--;
10283 }
10284 USTPUTC(CTLENDVAR, out);
10285 } else {
10286 USTPUTC(c, out);
10287 }
10288 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010289#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010290 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010291 parenlevel++;
10292 USTPUTC(c, out);
10293 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010294 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010295 if (parenlevel > 0) {
10296 USTPUTC(c, out);
10297 --parenlevel;
10298 } else {
10299 if (pgetc() == ')') {
10300 if (--arinest == 0) {
10301 USTPUTC(CTLENDARI, out);
10302 syntax = prevsyntax;
10303 if (syntax == DQSYNTAX)
10304 dblquote = 1;
10305 else
10306 dblquote = 0;
10307 } else
10308 USTPUTC(')', out);
10309 } else {
10310 /*
10311 * unbalanced parens
10312 * (don't 2nd guess - no error)
10313 */
10314 pungetc();
10315 USTPUTC(')', out);
10316 }
10317 }
10318 break;
10319#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010320 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010321 PARSEBACKQOLD();
10322 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010323 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010324 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010325 case CIGN:
10326 break;
10327 default:
10328 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010329 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010330#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010331 if (c != PEOA)
10332#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010333 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010334
Eric Andersencb57d552001-06-28 07:25:16 +000010335 }
10336 c = pgetc_macro();
10337 }
10338 }
Eric Andersenc470f442003-07-28 09:56:35 +000010339endword:
10340#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010341 if (syntax == ARISYNTAX)
10342 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010343#endif
10344 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010345 synerror("Unterminated quoted string");
10346 if (varnest != 0) {
10347 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010348 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010349 synerror("Missing '}'");
10350 }
10351 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010352 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010353 out = stackblock();
10354 if (eofmark == NULL) {
10355 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010356 && quotef == 0
10357 && len <= 2
10358 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010359 PARSEREDIR();
10360 return lasttoken = TREDIR;
10361 } else {
10362 pungetc();
10363 }
10364 }
10365 quoteflag = quotef;
10366 backquotelist = bqlist;
10367 grabstackblock(len);
10368 wordtext = out;
10369 return lasttoken = TWORD;
10370/* end of readtoken routine */
10371
10372
10373
10374/*
10375 * Check to see whether we are at the end of the here document. When this
10376 * is called, c is set to the first character of the next input line. If
10377 * we are at the end of the here document, this routine sets the c to PEOF.
10378 */
10379
Eric Andersenc470f442003-07-28 09:56:35 +000010380checkend: {
10381 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010382#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010383 if (c == PEOA) {
10384 c = pgetc2();
10385 }
10386#endif
10387 if (striptabs) {
10388 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010389 c = pgetc2();
10390 }
Eric Andersenc470f442003-07-28 09:56:35 +000010391 }
10392 if (c == *eofmark) {
10393 if (pfgets(line, sizeof line) != NULL) {
10394 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010395
Eric Andersenc470f442003-07-28 09:56:35 +000010396 p = line;
10397 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10398 if (*p == '\n' && *q == '\0') {
10399 c = PEOF;
10400 plinno++;
10401 needprompt = doprompt;
10402 } else {
10403 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010404 }
10405 }
10406 }
10407 }
Eric Andersenc470f442003-07-28 09:56:35 +000010408 goto checkend_return;
10409}
Eric Andersencb57d552001-06-28 07:25:16 +000010410
10411
10412/*
10413 * Parse a redirection operator. The variable "out" points to a string
10414 * specifying the fd to be redirected. The variable "c" contains the
10415 * first character of the redirection operator.
10416 */
10417
Eric Andersenc470f442003-07-28 09:56:35 +000010418parseredir: {
10419 char fd = *out;
10420 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010421
Eric Andersenc470f442003-07-28 09:56:35 +000010422 np = (union node *)stalloc(sizeof (struct nfile));
10423 if (c == '>') {
10424 np->nfile.fd = 1;
10425 c = pgetc();
10426 if (c == '>')
10427 np->type = NAPPEND;
10428 else if (c == '|')
10429 np->type = NCLOBBER;
10430 else if (c == '&')
10431 np->type = NTOFD;
10432 else {
10433 np->type = NTO;
10434 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010435 }
Eric Andersenc470f442003-07-28 09:56:35 +000010436 } else { /* c == '<' */
10437 np->nfile.fd = 0;
10438 switch (c = pgetc()) {
10439 case '<':
10440 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10441 np = (union node *)stalloc(sizeof (struct nhere));
10442 np->nfile.fd = 0;
10443 }
10444 np->type = NHERE;
10445 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10446 heredoc->here = np;
10447 if ((c = pgetc()) == '-') {
10448 heredoc->striptabs = 1;
10449 } else {
10450 heredoc->striptabs = 0;
10451 pungetc();
10452 }
10453 break;
10454
10455 case '&':
10456 np->type = NFROMFD;
10457 break;
10458
10459 case '>':
10460 np->type = NFROMTO;
10461 break;
10462
10463 default:
10464 np->type = NFROM;
10465 pungetc();
10466 break;
10467 }
Eric Andersencb57d552001-06-28 07:25:16 +000010468 }
Eric Andersenc470f442003-07-28 09:56:35 +000010469 if (fd != '\0')
10470 np->nfile.fd = digit_val(fd);
10471 redirnode = np;
10472 goto parseredir_return;
10473}
Eric Andersencb57d552001-06-28 07:25:16 +000010474
10475
10476/*
10477 * Parse a substitution. At this point, we have read the dollar sign
10478 * and nothing else.
10479 */
10480
Eric Andersenc470f442003-07-28 09:56:35 +000010481parsesub: {
10482 int subtype;
10483 int typeloc;
10484 int flags;
10485 char *p;
10486 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010487
Eric Andersenc470f442003-07-28 09:56:35 +000010488 c = pgetc();
10489 if (
10490 c <= PEOA_OR_PEOF ||
10491 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10492 ) {
10493 USTPUTC('$', out);
10494 pungetc();
10495 } else if (c == '(') { /* $(command) or $((arith)) */
10496 if (pgetc() == '(') {
10497#ifdef CONFIG_ASH_MATH_SUPPORT
10498 PARSEARITH();
10499#else
10500 synerror("We unsupport $((arith))");
10501#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010502 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010503 pungetc();
10504 PARSEBACKQNEW();
10505 }
10506 } else {
10507 USTPUTC(CTLVAR, out);
10508 typeloc = out - (char *)stackblock();
10509 USTPUTC(VSNORMAL, out);
10510 subtype = VSNORMAL;
10511 if (c == '{') {
10512 c = pgetc();
10513 if (c == '#') {
10514 if ((c = pgetc()) == '}')
10515 c = '#';
10516 else
10517 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010518 }
Eric Andersenc470f442003-07-28 09:56:35 +000010519 else
10520 subtype = 0;
10521 }
10522 if (c > PEOA_OR_PEOF && is_name(c)) {
10523 do {
10524 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010525 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010526 } while (c > PEOA_OR_PEOF && is_in_name(c));
10527 } else if (is_digit(c)) {
10528 do {
10529 STPUTC(c, out);
10530 c = pgetc();
10531 } while (is_digit(c));
10532 }
10533 else if (is_special(c)) {
10534 USTPUTC(c, out);
10535 c = pgetc();
10536 }
10537 else
10538badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010539
Eric Andersenc470f442003-07-28 09:56:35 +000010540 STPUTC('=', out);
10541 flags = 0;
10542 if (subtype == 0) {
10543 switch (c) {
10544 case ':':
10545 flags = VSNUL;
10546 c = pgetc();
10547 /*FALLTHROUGH*/
10548 default:
10549 p = strchr(types, c);
10550 if (p == NULL)
10551 goto badsub;
10552 subtype = p - types + VSNORMAL;
10553 break;
10554 case '%':
10555 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010556 {
10557 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010558 subtype = c == '#' ? VSTRIMLEFT :
10559 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010560 c = pgetc();
10561 if (c == cc)
10562 subtype++;
10563 else
10564 pungetc();
10565 break;
10566 }
10567 }
Eric Andersenc470f442003-07-28 09:56:35 +000010568 } else {
10569 pungetc();
10570 }
10571 if (dblquote || arinest)
10572 flags |= VSQUOTE;
10573 *((char *)stackblock() + typeloc) = subtype | flags;
10574 if (subtype != VSNORMAL) {
10575 varnest++;
10576 if (dblquote || arinest) {
10577 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010578 }
10579 }
10580 }
Eric Andersenc470f442003-07-28 09:56:35 +000010581 goto parsesub_return;
10582}
Eric Andersencb57d552001-06-28 07:25:16 +000010583
10584
10585/*
10586 * Called to parse command substitutions. Newstyle is set if the command
10587 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10588 * list of commands (passed by reference), and savelen is the number of
10589 * characters on the top of the stack which must be preserved.
10590 */
10591
Eric Andersenc470f442003-07-28 09:56:35 +000010592parsebackq: {
10593 struct nodelist **nlpp;
10594 int savepbq;
10595 union node *n;
10596 char *volatile str;
10597 struct jmploc jmploc;
10598 struct jmploc *volatile savehandler;
10599 size_t savelen;
10600 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010601#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010602 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010603#endif
10604
Eric Andersenc470f442003-07-28 09:56:35 +000010605 savepbq = parsebackquote;
10606 if (setjmp(jmploc.loc)) {
10607 if (str)
10608 ckfree(str);
10609 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010610 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010611 longjmp(handler->loc, 1);
10612 }
10613 INTOFF;
10614 str = NULL;
10615 savelen = out - (char *)stackblock();
10616 if (savelen > 0) {
10617 str = ckmalloc(savelen);
10618 memcpy(str, stackblock(), savelen);
10619 }
10620 savehandler = handler;
10621 handler = &jmploc;
10622 INTON;
10623 if (oldstyle) {
10624 /* We must read until the closing backquote, giving special
10625 treatment to some slashes, and then push the string and
10626 reread it as input, interpreting it normally. */
10627 char *pout;
10628 int pc;
10629 size_t psavelen;
10630 char *pstr;
10631
10632
10633 STARTSTACKSTR(pout);
10634 for (;;) {
10635 if (needprompt) {
10636 setprompt(2);
10637 needprompt = 0;
10638 }
10639 switch (pc = pgetc()) {
10640 case '`':
10641 goto done;
10642
10643 case '\\':
10644 if ((pc = pgetc()) == '\n') {
10645 plinno++;
10646 if (doprompt)
10647 setprompt(2);
10648 /*
10649 * If eating a newline, avoid putting
10650 * the newline into the new character
10651 * stream (via the STPUTC after the
10652 * switch).
10653 */
10654 continue;
10655 }
10656 if (pc != '\\' && pc != '`' && pc != '$'
10657 && (!dblquote || pc != '"'))
10658 STPUTC('\\', pout);
10659 if (pc > PEOA_OR_PEOF) {
10660 break;
10661 }
10662 /* fall through */
10663
10664 case PEOF:
10665#ifdef CONFIG_ASH_ALIAS
10666 case PEOA:
10667#endif
10668 startlinno = plinno;
10669 synerror("EOF in backquote substitution");
10670
10671 case '\n':
10672 plinno++;
10673 needprompt = doprompt;
10674 break;
10675
10676 default:
10677 break;
10678 }
10679 STPUTC(pc, pout);
10680 }
10681done:
10682 STPUTC('\0', pout);
10683 psavelen = pout - (char *)stackblock();
10684 if (psavelen > 0) {
10685 pstr = grabstackstr(pout);
10686 setinputstring(pstr);
10687 }
10688 }
10689 nlpp = &bqlist;
10690 while (*nlpp)
10691 nlpp = &(*nlpp)->next;
10692 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10693 (*nlpp)->next = NULL;
10694 parsebackquote = oldstyle;
10695
10696 if (oldstyle) {
10697 saveprompt = doprompt;
10698 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010699 }
10700
Eric Andersenc470f442003-07-28 09:56:35 +000010701 n = list(2);
10702
10703 if (oldstyle)
10704 doprompt = saveprompt;
10705 else {
10706 if (readtoken() != TRP)
10707 synexpect(TRP);
10708 }
10709
10710 (*nlpp)->n = n;
10711 if (oldstyle) {
10712 /*
10713 * Start reading from old file again, ignoring any pushed back
10714 * tokens left from the backquote parsing
10715 */
10716 popfile();
10717 tokpushback = 0;
10718 }
10719 while (stackblocksize() <= savelen)
10720 growstackblock();
10721 STARTSTACKSTR(out);
10722 if (str) {
10723 memcpy(out, str, savelen);
10724 STADJUST(savelen, out);
10725 INTOFF;
10726 ckfree(str);
10727 str = NULL;
10728 INTON;
10729 }
10730 parsebackquote = savepbq;
10731 handler = savehandler;
10732 if (arinest || dblquote)
10733 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10734 else
10735 USTPUTC(CTLBACKQ, out);
10736 if (oldstyle)
10737 goto parsebackq_oldreturn;
10738 else
10739 goto parsebackq_newreturn;
10740}
10741
10742#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010743/*
10744 * Parse an arithmetic expansion (indicate start of one and set state)
10745 */
Eric Andersenc470f442003-07-28 09:56:35 +000010746parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010747
Eric Andersenc470f442003-07-28 09:56:35 +000010748 if (++arinest == 1) {
10749 prevsyntax = syntax;
10750 syntax = ARISYNTAX;
10751 USTPUTC(CTLARI, out);
10752 if (dblquote)
10753 USTPUTC('"',out);
10754 else
10755 USTPUTC(' ',out);
10756 } else {
10757 /*
10758 * we collapse embedded arithmetic expansion to
10759 * parenthesis, which should be equivalent
10760 */
10761 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010762 }
Eric Andersenc470f442003-07-28 09:56:35 +000010763 goto parsearith_return;
10764}
10765#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010766
Eric Andersenc470f442003-07-28 09:56:35 +000010767} /* end of readtoken */
10768
Eric Andersencb57d552001-06-28 07:25:16 +000010769
10770
Eric Andersencb57d552001-06-28 07:25:16 +000010771/*
10772 * Returns true if the text contains nothing to expand (no dollar signs
10773 * or backquotes).
10774 */
10775
Eric Andersenc470f442003-07-28 09:56:35 +000010776static int
10777noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010778{
Eric Andersencb57d552001-06-28 07:25:16 +000010779 char *p;
10780 char c;
10781
10782 p = text;
10783 while ((c = *p++) != '\0') {
10784 if (c == CTLQUOTEMARK)
10785 continue;
10786 if (c == CTLESC)
10787 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010788 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010789 return 0;
10790 }
10791 return 1;
10792}
10793
10794
10795/*
Eric Andersenc470f442003-07-28 09:56:35 +000010796 * Return of a legal variable name (a letter or underscore followed by zero or
10797 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010798 */
10799
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010800static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010801endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010802{
Eric Andersenc470f442003-07-28 09:56:35 +000010803 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010804
Eric Andersenc470f442003-07-28 09:56:35 +000010805 p = (char *) name;
10806 if (! is_name(*p))
10807 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010808 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010809 if (! is_in_name(*p))
10810 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010811 }
Eric Andersenc470f442003-07-28 09:56:35 +000010812 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010813}
10814
10815
10816/*
10817 * Called when an unexpected token is read during the parse. The argument
10818 * is the token that is expected, or -1 if more than one type of token can
10819 * occur at this point.
10820 */
10821
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010822static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010823{
10824 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010825 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010826
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010827 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10828 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010829 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010830 synerror(msg);
10831 /* NOTREACHED */
10832}
10833
Eric Andersenc470f442003-07-28 09:56:35 +000010834static void
10835synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010836{
Eric Andersenc470f442003-07-28 09:56:35 +000010837 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010838 /* NOTREACHED */
10839}
10840
Eric Andersencb57d552001-06-28 07:25:16 +000010841
10842/*
10843 * called by editline -- any expansions to the prompt
10844 * should be added here.
10845 */
Eric Andersenc470f442003-07-28 09:56:35 +000010846
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010847static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010848{
Eric Andersenc470f442003-07-28 09:56:35 +000010849 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010850
10851 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010852 case 1:
10853 prompt = ps1val();
10854 break;
10855 case 2:
10856 prompt = ps2val();
10857 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010858 default: /* 0 */
10859 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010860 }
10861 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010862}
10863
Eric Andersencb57d552001-06-28 07:25:16 +000010864
Eric Andersenc470f442003-07-28 09:56:35 +000010865static const char *const *findkwd(const char *s)
10866{
10867 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010868 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010869 sizeof(const char *), pstrcmp);
10870}
10871
10872/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10873
Eric Andersencb57d552001-06-28 07:25:16 +000010874/*
10875 * Code for dealing with input/output redirection.
10876 */
10877
Eric Andersenc470f442003-07-28 09:56:35 +000010878#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010879#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010880# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010881#else
10882# define PIPESIZE PIPE_BUF
10883#endif
10884
Eric Andersen62483552001-07-10 06:09:16 +000010885/*
10886 * Open a file in noclobber mode.
10887 * The code was copied from bash.
10888 */
Eric Andersenc470f442003-07-28 09:56:35 +000010889static inline int
10890noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010891{
10892 int r, fd;
10893 struct stat finfo, finfo2;
10894
10895 /*
10896 * If the file exists and is a regular file, return an error
10897 * immediately.
10898 */
10899 r = stat(fname, &finfo);
10900 if (r == 0 && S_ISREG(finfo.st_mode)) {
10901 errno = EEXIST;
10902 return -1;
10903 }
10904
10905 /*
10906 * If the file was not present (r != 0), make sure we open it
10907 * exclusively so that if it is created before we open it, our open
10908 * will fail. Make sure that we do not truncate an existing file.
10909 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10910 * file was not a regular file, we leave O_EXCL off.
10911 */
10912 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010913 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10914 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010915
10916 /* If the open failed, return the file descriptor right away. */
10917 if (fd < 0)
10918 return fd;
10919
10920 /*
10921 * OK, the open succeeded, but the file may have been changed from a
10922 * non-regular file to a regular file between the stat and the open.
10923 * We are assuming that the O_EXCL open handles the case where FILENAME
10924 * did not exist and is symlinked to an existing file between the stat
10925 * and open.
10926 */
10927
10928 /*
10929 * If we can open it and fstat the file descriptor, and neither check
10930 * revealed that it was a regular file, and the file has not been
10931 * replaced, return the file descriptor.
10932 */
Eric Andersenc470f442003-07-28 09:56:35 +000010933 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10934 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010935 return fd;
10936
10937 /* The file has been replaced. badness. */
10938 close(fd);
10939 errno = EEXIST;
10940 return -1;
10941}
Eric Andersencb57d552001-06-28 07:25:16 +000010942
10943/*
Eric Andersen62483552001-07-10 06:09:16 +000010944 * Handle here documents. Normally we fork off a process to write the
10945 * data to a pipe. If the document is short, we can stuff the data in
10946 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010947 */
10948
Eric Andersenc470f442003-07-28 09:56:35 +000010949static inline int
10950openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010951{
10952 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010953 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010954
Eric Andersen62483552001-07-10 06:09:16 +000010955 if (pipe(pip) < 0)
10956 error("Pipe call failed");
10957 if (redir->type == NHERE) {
10958 len = strlen(redir->nhere.doc->narg.text);
10959 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010960 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010961 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010962 }
Eric Andersencb57d552001-06-28 07:25:16 +000010963 }
Eric Andersenc470f442003-07-28 09:56:35 +000010964 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010965 close(pip[0]);
10966 signal(SIGINT, SIG_IGN);
10967 signal(SIGQUIT, SIG_IGN);
10968 signal(SIGHUP, SIG_IGN);
10969#ifdef SIGTSTP
10970 signal(SIGTSTP, SIG_IGN);
10971#endif
10972 signal(SIGPIPE, SIG_DFL);
10973 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000010974 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010975 else
10976 expandhere(redir->nhere.doc, pip[1]);
10977 _exit(0);
10978 }
Eric Andersenc470f442003-07-28 09:56:35 +000010979out:
Eric Andersen62483552001-07-10 06:09:16 +000010980 close(pip[1]);
10981 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010982}
10983
Eric Andersenc470f442003-07-28 09:56:35 +000010984static int
10985openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010986{
Eric Andersencb57d552001-06-28 07:25:16 +000010987 char *fname;
10988 int f;
10989
10990 switch (redir->nfile.type) {
10991 case NFROM:
10992 fname = redir->nfile.expfname;
10993 if ((f = open(fname, O_RDONLY)) < 0)
10994 goto eopen;
10995 break;
10996 case NFROMTO:
10997 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010998 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010999 goto ecreate;
11000 break;
11001 case NTO:
11002 /* Take care of noclobber mode. */
11003 if (Cflag) {
11004 fname = redir->nfile.expfname;
11005 if ((f = noclobberopen(fname)) < 0)
11006 goto ecreate;
11007 break;
11008 }
Eric Andersenc470f442003-07-28 09:56:35 +000011009 /* FALLTHROUGH */
11010 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011011 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011012 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011013 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011014 break;
11015 case NAPPEND:
11016 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011017 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011018 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011019 break;
11020 default:
11021#ifdef DEBUG
11022 abort();
11023#endif
11024 /* Fall through to eliminate warning. */
11025 case NTOFD:
11026 case NFROMFD:
11027 f = -1;
11028 break;
11029 case NHERE:
11030 case NXHERE:
11031 f = openhere(redir);
11032 break;
11033 }
11034
11035 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011036ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011037 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011038eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011039 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11040}
11041
Eric Andersenc470f442003-07-28 09:56:35 +000011042static inline void
11043dupredirect(union node *redir, int f)
11044{
11045 int fd = redir->nfile.fd;
11046
11047 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11048 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11049 copyfd(redir->ndup.dupfd, fd);
11050 }
11051 return;
11052 }
11053
11054 if (f != fd) {
11055 copyfd(f, fd);
11056 close(f);
11057 }
11058 return;
11059}
Eric Andersencb57d552001-06-28 07:25:16 +000011060
Eric Andersen62483552001-07-10 06:09:16 +000011061/*
11062 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11063 * old file descriptors are stashed away so that the redirection can be
11064 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11065 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011066 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011067 */
11068
Eric Andersenc470f442003-07-28 09:56:35 +000011069static void
11070redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011071{
11072 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011073 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011074 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011075 int fd;
11076 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011077 int *p;
11078 nullredirs++;
11079 if (!redir) {
11080 return;
Eric Andersen62483552001-07-10 06:09:16 +000011081 }
Eric Andersenc470f442003-07-28 09:56:35 +000011082 sv = NULL;
11083 INTOFF;
11084 if (flags & REDIR_PUSH) {
11085 struct redirtab *q;
11086 q = ckmalloc(sizeof (struct redirtab));
11087 q->next = redirlist;
11088 redirlist = q;
11089 q->nullredirs = nullredirs - 1;
11090 for (i = 0 ; i < 10 ; i++)
11091 q->renamed[i] = EMPTY;
11092 nullredirs = 0;
11093 sv = q;
11094 }
11095 n = redir;
11096 do {
Eric Andersen62483552001-07-10 06:09:16 +000011097 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011098 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011099 n->ndup.dupfd == fd)
11100 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011101
Eric Andersen62483552001-07-10 06:09:16 +000011102 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011103 if (fd == newfd)
11104 continue;
11105 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11106 i = fcntl(fd, F_DUPFD, 10);
11107
11108 if (i == -1) {
11109 i = errno;
11110 if (i != EBADF) {
11111 close(newfd);
11112 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011113 error("%d: %m", fd);
11114 /* NOTREACHED */
11115 }
Eric Andersenc470f442003-07-28 09:56:35 +000011116 } else {
11117 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011118 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011119 }
Eric Andersenc470f442003-07-28 09:56:35 +000011120 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011121 close(fd);
11122 }
Eric Andersenc470f442003-07-28 09:56:35 +000011123 dupredirect(n, newfd);
11124 } while ((n = n->nfile.next));
11125 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011126 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11127 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011128}
11129
11130
Eric Andersencb57d552001-06-28 07:25:16 +000011131/*
11132 * Undo the effects of the last redirection.
11133 */
11134
Eric Andersenc470f442003-07-28 09:56:35 +000011135void
11136popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011137{
Eric Andersenc470f442003-07-28 09:56:35 +000011138 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011139 int i;
11140
Eric Andersenc470f442003-07-28 09:56:35 +000011141 if (--nullredirs >= 0)
11142 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011143 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011144 rp = redirlist;
11145 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011146 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011147 if (!drop) {
11148 close(i);
11149 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011150 }
Eric Andersenc470f442003-07-28 09:56:35 +000011151 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011152 }
11153 }
11154 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011155 nullredirs = rp->nullredirs;
11156 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011157 INTON;
11158}
11159
11160/*
Eric Andersenc470f442003-07-28 09:56:35 +000011161 * Undo all redirections. Called on error or interrupt.
11162 */
11163
11164/*
Eric Andersencb57d552001-06-28 07:25:16 +000011165 * Discard all saved file descriptors.
11166 */
11167
Eric Andersenc470f442003-07-28 09:56:35 +000011168void
11169clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011170{
Eric Andersenc470f442003-07-28 09:56:35 +000011171 for (;;) {
11172 nullredirs = 0;
11173 if (!redirlist)
11174 break;
11175 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011176 }
Eric Andersencb57d552001-06-28 07:25:16 +000011177}
11178
11179
Eric Andersencb57d552001-06-28 07:25:16 +000011180/*
11181 * Copy a file descriptor to be >= to. Returns -1
11182 * if the source file descriptor is closed, EMPTY if there are no unused
11183 * file descriptors left.
11184 */
11185
Eric Andersenc470f442003-07-28 09:56:35 +000011186int
11187copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011188{
11189 int newfd;
11190
11191 newfd = fcntl(from, F_DUPFD, to);
11192 if (newfd < 0) {
11193 if (errno == EMFILE)
11194 return EMPTY;
11195 else
Eric Andersen2870d962001-07-02 17:27:21 +000011196 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011197 }
11198 return newfd;
11199}
11200
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011201
Eric Andersenc470f442003-07-28 09:56:35 +000011202int
11203redirectsafe(union node *redir, int flags)
11204{
11205 int err;
11206 volatile int saveint;
11207 struct jmploc *volatile savehandler = handler;
11208 struct jmploc jmploc;
11209
11210 SAVEINT(saveint);
11211 if (!(err = setjmp(jmploc.loc) * 2)) {
11212 handler = &jmploc;
11213 redirect(redir, flags);
11214 }
11215 handler = savehandler;
11216 if (err && exception != EXERROR)
11217 longjmp(handler->loc, 1);
11218 RESTOREINT(saveint);
11219 return err;
11220}
11221
11222/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11223
11224#ifdef DEBUG
11225static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011226static void shcmd(union node *, FILE *);
11227static void sharg(union node *, FILE *);
11228static void indent(int, char *, FILE *);
11229static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011230
11231
Eric Andersenc470f442003-07-28 09:56:35 +000011232void
11233showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011234{
11235 trputs("showtree called\n");
11236 shtree(n, 1, NULL, stdout);
11237}
Eric Andersencb57d552001-06-28 07:25:16 +000011238
Eric Andersenc470f442003-07-28 09:56:35 +000011239
11240static void
11241shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011242{
11243 struct nodelist *lp;
11244 const char *s;
11245
11246 if (n == NULL)
11247 return;
11248
11249 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011250 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011251 case NSEMI:
11252 s = "; ";
11253 goto binop;
11254 case NAND:
11255 s = " && ";
11256 goto binop;
11257 case NOR:
11258 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011259binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011260 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011261 /* if (ind < 0) */
11262 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011263 shtree(n->nbinary.ch2, ind, NULL, fp);
11264 break;
11265 case NCMD:
11266 shcmd(n, fp);
11267 if (ind >= 0)
11268 putc('\n', fp);
11269 break;
11270 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011271 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011272 shcmd(lp->n, fp);
11273 if (lp->next)
11274 fputs(" | ", fp);
11275 }
11276 if (n->npipe.backgnd)
11277 fputs(" &", fp);
11278 if (ind >= 0)
11279 putc('\n', fp);
11280 break;
11281 default:
11282 fprintf(fp, "<node type %d>", n->type);
11283 if (ind >= 0)
11284 putc('\n', fp);
11285 break;
11286 }
11287}
11288
11289
Eric Andersenc470f442003-07-28 09:56:35 +000011290static void
11291shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011292{
11293 union node *np;
11294 int first;
11295 const char *s;
11296 int dftfd;
11297
11298 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011299 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11300 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011301 putchar(' ');
11302 sharg(np, fp);
11303 first = 0;
11304 }
Eric Andersenc470f442003-07-28 09:56:35 +000011305 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11306 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011307 putchar(' ');
11308 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011309 case NTO: s = ">"; dftfd = 1; break;
11310 case NCLOBBER: s = ">|"; dftfd = 1; break;
11311 case NAPPEND: s = ">>"; dftfd = 1; break;
11312 case NTOFD: s = ">&"; dftfd = 1; break;
11313 case NFROM: s = "<"; dftfd = 0; break;
11314 case NFROMFD: s = "<&"; dftfd = 0; break;
11315 case NFROMTO: s = "<>"; dftfd = 0; break;
11316 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011317 }
11318 if (np->nfile.fd != dftfd)
11319 fprintf(fp, "%d", np->nfile.fd);
11320 fputs(s, fp);
11321 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11322 fprintf(fp, "%d", np->ndup.dupfd);
11323 } else {
11324 sharg(np->nfile.fname, fp);
11325 }
11326 first = 0;
11327 }
11328}
11329
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011330
Eric Andersenc470f442003-07-28 09:56:35 +000011331
11332static void
11333sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011334{
Eric Andersencb57d552001-06-28 07:25:16 +000011335 char *p;
11336 struct nodelist *bqlist;
11337 int subtype;
11338
11339 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011340 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011341 abort();
11342 }
11343 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011344 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011345 switch (*p) {
11346 case CTLESC:
11347 putc(*++p, fp);
11348 break;
11349 case CTLVAR:
11350 putc('$', fp);
11351 putc('{', fp);
11352 subtype = *++p;
11353 if (subtype == VSLENGTH)
11354 putc('#', fp);
11355
11356 while (*p != '=')
11357 putc(*p++, fp);
11358
11359 if (subtype & VSNUL)
11360 putc(':', fp);
11361
11362 switch (subtype & VSTYPE) {
11363 case VSNORMAL:
11364 putc('}', fp);
11365 break;
11366 case VSMINUS:
11367 putc('-', fp);
11368 break;
11369 case VSPLUS:
11370 putc('+', fp);
11371 break;
11372 case VSQUESTION:
11373 putc('?', fp);
11374 break;
11375 case VSASSIGN:
11376 putc('=', fp);
11377 break;
11378 case VSTRIMLEFT:
11379 putc('#', fp);
11380 break;
11381 case VSTRIMLEFTMAX:
11382 putc('#', fp);
11383 putc('#', fp);
11384 break;
11385 case VSTRIMRIGHT:
11386 putc('%', fp);
11387 break;
11388 case VSTRIMRIGHTMAX:
11389 putc('%', fp);
11390 putc('%', fp);
11391 break;
11392 case VSLENGTH:
11393 break;
11394 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011395 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011396 }
11397 break;
11398 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011399 putc('}', fp);
11400 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011401 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011402 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011403 putc('$', fp);
11404 putc('(', fp);
11405 shtree(bqlist->n, -1, NULL, fp);
11406 putc(')', fp);
11407 break;
11408 default:
11409 putc(*p, fp);
11410 break;
11411 }
11412 }
11413}
11414
11415
Eric Andersenc470f442003-07-28 09:56:35 +000011416static void
11417indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011418{
11419 int i;
11420
Eric Andersenc470f442003-07-28 09:56:35 +000011421 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011422 if (pfx && i == amount - 1)
11423 fputs(pfx, fp);
11424 putc('\t', fp);
11425 }
11426}
Eric Andersencb57d552001-06-28 07:25:16 +000011427
Eric Andersenc470f442003-07-28 09:56:35 +000011428
11429
11430/*
11431 * Debugging stuff.
11432 */
11433
11434
Eric Andersencb57d552001-06-28 07:25:16 +000011435FILE *tracefile;
11436
Eric Andersencb57d552001-06-28 07:25:16 +000011437
Eric Andersenc470f442003-07-28 09:56:35 +000011438void
11439trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011440{
Eric Andersenc470f442003-07-28 09:56:35 +000011441 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011442 return;
11443 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011444}
11445
Eric Andersenc470f442003-07-28 09:56:35 +000011446void
11447trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011448{
11449 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011450
Eric Andersenc470f442003-07-28 09:56:35 +000011451 if (debug != 1)
11452 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011453 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011454 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011455 va_end(va);
11456}
11457
Eric Andersenc470f442003-07-28 09:56:35 +000011458void
11459tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011460{
Eric Andersenc470f442003-07-28 09:56:35 +000011461 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011462 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011463 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011464}
11465
11466
Eric Andersenc470f442003-07-28 09:56:35 +000011467void
11468trputs(const char *s)
11469{
11470 if (debug != 1)
11471 return;
11472 fputs(s, tracefile);
11473}
11474
11475
11476static void
11477trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011478{
11479 char *p;
11480 char c;
11481
Eric Andersenc470f442003-07-28 09:56:35 +000011482 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011483 return;
11484 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011485 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011486 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011487 case '\n': c = 'n'; goto backslash;
11488 case '\t': c = 't'; goto backslash;
11489 case '\r': c = 'r'; goto backslash;
11490 case '"': c = '"'; goto backslash;
11491 case '\\': c = '\\'; goto backslash;
11492 case CTLESC: c = 'e'; goto backslash;
11493 case CTLVAR: c = 'v'; goto backslash;
11494 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11495 case CTLBACKQ: c = 'q'; goto backslash;
11496 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11497backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011498 putc(c, tracefile);
11499 break;
11500 default:
11501 if (*p >= ' ' && *p <= '~')
11502 putc(*p, tracefile);
11503 else {
11504 putc('\\', tracefile);
11505 putc(*p >> 6 & 03, tracefile);
11506 putc(*p >> 3 & 07, tracefile);
11507 putc(*p & 07, tracefile);
11508 }
11509 break;
11510 }
11511 }
11512 putc('"', tracefile);
11513}
11514
11515
Eric Andersenc470f442003-07-28 09:56:35 +000011516void
11517trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011518{
Eric Andersenc470f442003-07-28 09:56:35 +000011519 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011520 return;
11521 while (*ap) {
11522 trstring(*ap++);
11523 if (*ap)
11524 putc(' ', tracefile);
11525 else
11526 putc('\n', tracefile);
11527 }
Eric Andersencb57d552001-06-28 07:25:16 +000011528}
11529
11530
Eric Andersenc470f442003-07-28 09:56:35 +000011531void
11532opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011533{
Eric Andersencb57d552001-06-28 07:25:16 +000011534 char s[100];
11535#ifdef O_APPEND
11536 int flags;
11537#endif
11538
Eric Andersenc470f442003-07-28 09:56:35 +000011539 if (debug != 1) {
11540 if (tracefile)
11541 fflush(tracefile);
11542 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011543 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011544 }
Eric Andersenc470f442003-07-28 09:56:35 +000011545 scopy("./trace", s);
11546 if (tracefile) {
11547 if (!freopen(s, "a", tracefile)) {
11548 fprintf(stderr, "Can't re-open %s\n", s);
11549 debug = 0;
11550 return;
11551 }
11552 } else {
11553 if ((tracefile = fopen(s, "a")) == NULL) {
11554 fprintf(stderr, "Can't open %s\n", s);
11555 debug = 0;
11556 return;
11557 }
11558 }
Eric Andersencb57d552001-06-28 07:25:16 +000011559#ifdef O_APPEND
11560 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11561 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11562#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011563 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011564 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011565}
Eric Andersenc470f442003-07-28 09:56:35 +000011566#endif /* DEBUG */
11567
11568
11569/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11570
11571/*
11572 * Sigmode records the current value of the signal handlers for the various
11573 * modes. A value of zero means that the current handler is not known.
11574 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11575 */
11576
11577#define S_DFL 1 /* default signal handling (SIG_DFL) */
11578#define S_CATCH 2 /* signal is caught */
11579#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11580#define S_HARD_IGN 4 /* signal is ignored permenantly */
11581#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11582
Eric Andersencb57d552001-06-28 07:25:16 +000011583
11584
11585/*
Eric Andersencb57d552001-06-28 07:25:16 +000011586 * The trap builtin.
11587 */
11588
Eric Andersenc470f442003-07-28 09:56:35 +000011589int
11590trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011591{
11592 char *action;
11593 char **ap;
11594 int signo;
11595
Eric Andersenc470f442003-07-28 09:56:35 +000011596 nextopt(nullstr);
11597 ap = argptr;
11598 if (!*ap) {
11599 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011600 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011601 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011602
Eric Andersenc470f442003-07-28 09:56:35 +000011603 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011604 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011605 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011606 out1fmt("trap -- %s %s\n",
11607 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011608 }
11609 }
11610 return 0;
11611 }
Eric Andersenc470f442003-07-28 09:56:35 +000011612 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011613 action = NULL;
11614 else
11615 action = *ap++;
11616 while (*ap) {
11617 if ((signo = decode_signal(*ap, 0)) < 0)
11618 error("%s: bad trap", *ap);
11619 INTOFF;
11620 if (action) {
11621 if (action[0] == '-' && action[1] == '\0')
11622 action = NULL;
11623 else
Eric Andersenc470f442003-07-28 09:56:35 +000011624 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011625 }
Eric Andersenc470f442003-07-28 09:56:35 +000011626 if (trap[signo])
11627 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011628 trap[signo] = action;
11629 if (signo != 0)
11630 setsignal(signo);
11631 INTON;
11632 ap++;
11633 }
11634 return 0;
11635}
11636
11637
Eric Andersenc470f442003-07-28 09:56:35 +000011638/*
11639 * Clear traps on a fork.
11640 */
11641
11642void
11643clear_traps(void)
11644{
11645 char **tp;
11646
11647 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11648 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11649 INTOFF;
11650 ckfree(*tp);
11651 *tp = NULL;
11652 if (tp != &trap[0])
11653 setsignal(tp - trap);
11654 INTON;
11655 }
11656 }
11657}
11658
11659
Eric Andersencb57d552001-06-28 07:25:16 +000011660/*
11661 * Set the signal handler for the specified signal. The routine figures
11662 * out what it should be set to.
11663 */
11664
Eric Andersenc470f442003-07-28 09:56:35 +000011665void
11666setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011667{
11668 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011669 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011670 struct sigaction act;
11671
11672 if ((t = trap[signo]) == NULL)
11673 action = S_DFL;
11674 else if (*t != '\0')
11675 action = S_CATCH;
11676 else
11677 action = S_IGN;
11678 if (rootshell && action == S_DFL) {
11679 switch (signo) {
11680 case SIGINT:
11681 if (iflag || minusc || sflag == 0)
11682 action = S_CATCH;
11683 break;
11684 case SIGQUIT:
11685#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011686 if (debug)
11687 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011688#endif
11689 /* FALLTHROUGH */
11690 case SIGTERM:
11691 if (iflag)
11692 action = S_IGN;
11693 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011694#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011695 case SIGTSTP:
11696 case SIGTTOU:
11697 if (mflag)
11698 action = S_IGN;
11699 break;
11700#endif
11701 }
11702 }
11703
11704 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011705 tsig = *t;
11706 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011707 /*
11708 * current setting unknown
11709 */
11710 if (sigaction(signo, 0, &act) == -1) {
11711 /*
11712 * Pretend it worked; maybe we should give a warning
11713 * here, but other shells don't. We don't alter
11714 * sigmode, so that we retry every time.
11715 */
11716 return;
11717 }
11718 if (act.sa_handler == SIG_IGN) {
11719 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011720 signo == SIGTTIN || signo == SIGTTOU)) {
11721 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011722 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011723 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011724 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011725 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011726 }
11727 }
Eric Andersenc470f442003-07-28 09:56:35 +000011728 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011729 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011730 switch (action) {
11731 case S_CATCH:
11732 act.sa_handler = onsig;
11733 break;
11734 case S_IGN:
11735 act.sa_handler = SIG_IGN;
11736 break;
11737 default:
11738 act.sa_handler = SIG_DFL;
11739 }
Eric Andersencb57d552001-06-28 07:25:16 +000011740 *t = action;
11741 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011742 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011743 sigaction(signo, &act, 0);
11744}
11745
11746/*
11747 * Ignore a signal.
11748 */
11749
Eric Andersenc470f442003-07-28 09:56:35 +000011750void
11751ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011752{
11753 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11754 signal(signo, SIG_IGN);
11755 }
11756 sigmode[signo - 1] = S_HARD_IGN;
11757}
11758
11759
Eric Andersencb57d552001-06-28 07:25:16 +000011760/*
11761 * Signal handler.
11762 */
11763
Eric Andersenc470f442003-07-28 09:56:35 +000011764void
11765onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011766{
Eric Andersencb57d552001-06-28 07:25:16 +000011767 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011768 pendingsigs = signo;
11769
11770 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11771 if (!suppressint)
11772 onint();
11773 intpending = 1;
11774 }
Eric Andersencb57d552001-06-28 07:25:16 +000011775}
11776
11777
Eric Andersencb57d552001-06-28 07:25:16 +000011778/*
11779 * Called to execute a trap. Perhaps we should avoid entering new trap
11780 * handlers while we are executing a trap handler.
11781 */
11782
Eric Andersenc470f442003-07-28 09:56:35 +000011783void
11784dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011785{
Eric Andersenc470f442003-07-28 09:56:35 +000011786 char *p;
11787 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011788 int savestatus;
11789
Eric Andersenc470f442003-07-28 09:56:35 +000011790 savestatus = exitstatus;
11791 q = gotsig;
11792 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11793 *p = 0;
11794 p = trap[p - q + 1];
11795 if (!p)
11796 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011797 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011798 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011799 }
Eric Andersencb57d552001-06-28 07:25:16 +000011800}
11801
Eric Andersenc470f442003-07-28 09:56:35 +000011802
Eric Andersenc470f442003-07-28 09:56:35 +000011803/*
11804 * Controls whether the shell is interactive or not.
11805 */
11806
Eric Andersenc470f442003-07-28 09:56:35 +000011807void
11808setinteractive(int on)
11809{
11810 static int is_interactive;
11811
11812 if (++on == is_interactive)
11813 return;
11814 is_interactive = on;
11815 setsignal(SIGINT);
11816 setsignal(SIGQUIT);
11817 setsignal(SIGTERM);
11818#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11819 if(is_interactive > 1) {
11820 /* Looks like they want an interactive shell */
11821 static int do_banner;
11822
11823 if(!do_banner) {
11824 out1fmt(
11825 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11826 "Enter 'help' for a list of built-in commands.\n\n");
11827 do_banner++;
11828 }
11829 }
11830#endif
11831}
11832
11833
11834#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11835/*** List the available builtins ***/
11836
11837static int helpcmd(int argc, char **argv)
11838{
11839 int col, i;
11840
11841 out1fmt("\nBuilt-in commands:\n-------------------\n");
11842 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11843 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11844 builtincmd[i].name + 1);
11845 if (col > 60) {
11846 out1fmt("\n");
11847 col = 0;
11848 }
11849 }
11850#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11851 {
11852 extern const struct BB_applet applets[];
11853 extern const size_t NUM_APPLETS;
11854
11855 for (i = 0; i < NUM_APPLETS; i++) {
11856
11857 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11858 if (col > 60) {
11859 out1fmt("\n");
11860 col = 0;
11861 }
11862 }
11863 }
11864#endif
11865 out1fmt("\n\n");
11866 return EXIT_SUCCESS;
11867}
11868#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11869
Eric Andersencb57d552001-06-28 07:25:16 +000011870/*
11871 * Called to exit the shell.
11872 */
11873
Eric Andersenc470f442003-07-28 09:56:35 +000011874void
11875exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011876{
Eric Andersenc470f442003-07-28 09:56:35 +000011877 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011878 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011879 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011880 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011881
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011882 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011883 status = exitstatus;
11884 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011885 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011886 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011887 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011888 if ((p = trap[0]) != NULL && *p != '\0') {
11889 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011890 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011891 }
Eric Andersencb57d552001-06-28 07:25:16 +000011892 flushall();
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011893#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11894 if (iflag && rootshell) {
11895 const char *hp = lookupvar("HISTFILE");
11896
11897 if(hp != NULL )
11898 save_history ( hp );
11899 }
11900#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011901out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011902 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011903 /* NOTREACHED */
11904}
11905
11906static int decode_signal(const char *string, int minsig)
11907{
11908 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011909 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011910
Eric Andersen34506362001-08-02 05:02:46 +000011911 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011912}
Eric Andersen34506362001-08-02 05:02:46 +000011913
Eric Andersenc470f442003-07-28 09:56:35 +000011914/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11915
11916static struct var *vartab[VTABSIZE];
11917
11918static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011919static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011920
11921/*
11922 * Initialize the varable symbol tables and import the environment
11923 */
11924
Eric Andersenc470f442003-07-28 09:56:35 +000011925
11926#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011927/*
Eric Andersenc470f442003-07-28 09:56:35 +000011928 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011929 */
11930
Eric Andersenc470f442003-07-28 09:56:35 +000011931int
11932setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011933{
Eric Andersenc470f442003-07-28 09:56:35 +000011934 int err;
11935 volatile int saveint;
11936 struct jmploc *volatile savehandler = handler;
11937 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011938
Eric Andersenc470f442003-07-28 09:56:35 +000011939 SAVEINT(saveint);
11940 if (setjmp(jmploc.loc))
11941 err = 1;
11942 else {
11943 handler = &jmploc;
11944 setvar(name, val, flags);
11945 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011946 }
Eric Andersenc470f442003-07-28 09:56:35 +000011947 handler = savehandler;
11948 RESTOREINT(saveint);
11949 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011950}
Eric Andersenc470f442003-07-28 09:56:35 +000011951#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011952
11953/*
11954 * Set the value of a variable. The flags argument is ored with the
11955 * flags of the variable. If val is NULL, the variable is unset.
11956 */
11957
Eric Andersenc470f442003-07-28 09:56:35 +000011958static void
11959setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011960{
Eric Andersenc470f442003-07-28 09:56:35 +000011961 char *p, *q;
11962 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011963 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011964 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011965
Eric Andersenc470f442003-07-28 09:56:35 +000011966 q = endofname(name);
11967 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011968 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011969 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011970 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011971 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011972 if (val == NULL) {
11973 flags |= VUNSET;
11974 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011975 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011976 }
11977 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011978 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11979 *p++ = '\0';
11980 if (vallen) {
11981 p[-1] = '=';
11982 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011983 }
Eric Andersenc470f442003-07-28 09:56:35 +000011984 *p = '\0';
11985 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011986 INTON;
11987}
11988
11989
Eric Andersencb57d552001-06-28 07:25:16 +000011990/*
11991 * Same as setvar except that the variable and value are passed in
11992 * the first argument as name=value. Since the first argument will
11993 * be actually stored in the table, it should not be a string that
11994 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000011995 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000011996 */
11997
Eric Andersenc470f442003-07-28 09:56:35 +000011998void
11999setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012000{
12001 struct var *vp, **vpp;
12002
12003 vpp = hashvar(s);
12004 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012005 vp = *findvar(vpp, s);
12006 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012007 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12008 const char *n;
12009
Eric Andersenc470f442003-07-28 09:56:35 +000012010 if (flags & VNOSAVE)
12011 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012012 n = vp->text;
12013 error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012014 }
Eric Andersenc470f442003-07-28 09:56:35 +000012015
12016 if (flags & VNOSET)
12017 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012018
12019 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012020 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012021
Eric Andersenc470f442003-07-28 09:56:35 +000012022 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12023 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012024
Eric Andersenc470f442003-07-28 09:56:35 +000012025 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12026 } else {
12027 if (flags & VNOSET)
12028 return;
12029 /* not found */
12030 vp = ckmalloc(sizeof (*vp));
12031 vp->next = *vpp;
12032 vp->func = NULL;
12033 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012034 }
Eric Andersenc470f442003-07-28 09:56:35 +000012035 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12036 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012037 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012038 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012039}
12040
12041
Eric Andersencb57d552001-06-28 07:25:16 +000012042/*
12043 * Process a linked list of variable assignments.
12044 */
12045
Eric Andersenc470f442003-07-28 09:56:35 +000012046static void
12047listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012048{
Eric Andersenc470f442003-07-28 09:56:35 +000012049 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012050
Eric Andersenc470f442003-07-28 09:56:35 +000012051 if (!lp)
12052 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012053 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012054 do {
12055 setvareq(lp->text, flags);
12056 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012057 INTON;
12058}
12059
12060
Eric Andersencb57d552001-06-28 07:25:16 +000012061/*
12062 * Find the value of a variable. Returns NULL if not set.
12063 */
12064
Eric Andersenc470f442003-07-28 09:56:35 +000012065static char *
12066lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012067{
Eric Andersencb57d552001-06-28 07:25:16 +000012068 struct var *v;
12069
Eric Andersen16767e22004-03-16 05:14:10 +000012070 if ((v = *findvar(hashvar(name), name))) {
12071#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012072 /*
12073 * Dynamic variables are implemented roughly the same way they are
12074 * in bash. Namely, they're "special" so long as they aren't unset.
12075 * As soon as they're unset, they're no longer dynamic, and dynamic
12076 * lookup will no longer happen at that point. -- PFM.
12077 */
Eric Andersen16767e22004-03-16 05:14:10 +000012078 if((v->flags & VDYNAMIC))
12079 (*v->func)(NULL);
12080#endif
12081 if(!(v->flags & VUNSET))
12082 return strchrnul(v->text, '=') + 1;
12083 }
Eric Andersenef02f822004-03-11 13:34:24 +000012084
Eric Andersencb57d552001-06-28 07:25:16 +000012085 return NULL;
12086}
12087
12088
Eric Andersencb57d552001-06-28 07:25:16 +000012089/*
12090 * Search the environment of a builtin command.
12091 */
12092
Eric Andersenc470f442003-07-28 09:56:35 +000012093static char *
12094bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012095{
Eric Andersenc470f442003-07-28 09:56:35 +000012096 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012097
Eric Andersenc470f442003-07-28 09:56:35 +000012098 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012099 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012100 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012101 }
12102 return lookupvar(name);
12103}
12104
12105
Eric Andersencb57d552001-06-28 07:25:16 +000012106/*
Eric Andersenc470f442003-07-28 09:56:35 +000012107 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012108 */
12109
Eric Andersenc470f442003-07-28 09:56:35 +000012110static char **
12111listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012112{
Eric Andersencb57d552001-06-28 07:25:16 +000012113 struct var **vpp;
12114 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012115 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012116 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012117
Eric Andersenc470f442003-07-28 09:56:35 +000012118 STARTSTACKSTR(ep);
12119 vpp = vartab;
12120 mask = on | off;
12121 do {
12122 for (vp = *vpp ; vp ; vp = vp->next)
12123 if ((vp->flags & mask) == on) {
12124 if (ep == stackstrend())
12125 ep = growstackstr();
12126 *ep++ = (char *) vp->text;
12127 }
12128 } while (++vpp < vartab + VTABSIZE);
12129 if (ep == stackstrend())
12130 ep = growstackstr();
12131 if (end)
12132 *end = ep;
12133 *ep++ = NULL;
12134 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012135}
12136
12137
12138/*
Eric Andersenc470f442003-07-28 09:56:35 +000012139 * POSIX requires that 'set' (but not export or readonly) output the
12140 * variables in lexicographic order - by the locale's collating order (sigh).
12141 * Maybe we could keep them in an ordered balanced binary tree
12142 * instead of hashed lists.
12143 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012144 */
12145
Eric Andersenc470f442003-07-28 09:56:35 +000012146static int
12147showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012148{
Eric Andersenc470f442003-07-28 09:56:35 +000012149 const char *sep;
12150 char **ep, **epend;
12151
12152 ep = listvars(on, off, &epend);
12153 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12154
12155 sep = *sep_prefix ? spcstr : sep_prefix;
12156
12157 for (; ep < epend; ep++) {
12158 const char *p;
12159 const char *q;
12160
12161 p = strchrnul(*ep, '=');
12162 q = nullstr;
12163 if (*p)
12164 q = single_quote(++p);
12165
12166 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12167 }
12168
Eric Andersencb57d552001-06-28 07:25:16 +000012169 return 0;
12170}
12171
12172
12173
12174/*
12175 * The export and readonly commands.
12176 */
12177
Eric Andersenc470f442003-07-28 09:56:35 +000012178static int
12179exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012180{
12181 struct var *vp;
12182 char *name;
12183 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012184 char **aptr;
12185 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12186 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012187
Eric Andersenc470f442003-07-28 09:56:35 +000012188 notp = nextopt("p") - 'p';
12189 if (notp && ((name = *(aptr = argptr)))) {
12190 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012191 if ((p = strchr(name, '=')) != NULL) {
12192 p++;
12193 } else {
12194 if ((vp = *findvar(hashvar(name), name))) {
12195 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012196 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012197 }
12198 }
12199 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012200 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012201 } else {
12202 showvars(argv[0], flag, 0);
12203 }
12204 return 0;
12205}
12206
Eric Andersen34506362001-08-02 05:02:46 +000012207
Eric Andersencb57d552001-06-28 07:25:16 +000012208/*
Eric Andersencb57d552001-06-28 07:25:16 +000012209 * Make a variable a local variable. When a variable is made local, it's
12210 * value and flags are saved in a localvar structure. The saved values
12211 * will be restored when the shell function returns. We handle the name
12212 * "-" as a special case.
12213 */
12214
Eric Andersenc470f442003-07-28 09:56:35 +000012215static inline void
12216mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012217{
Eric Andersencb57d552001-06-28 07:25:16 +000012218 struct localvar *lvp;
12219 struct var **vpp;
12220 struct var *vp;
12221
12222 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012223 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012224 if (name[0] == '-' && name[1] == '\0') {
12225 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012226 p = ckmalloc(sizeof(optlist));
12227 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012228 vp = NULL;
12229 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012230 char *eq;
12231
Eric Andersencb57d552001-06-28 07:25:16 +000012232 vpp = hashvar(name);
12233 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012234 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012235 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012236 if (eq)
12237 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012238 else
12239 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012240 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012241 lvp->flags = VUNSET;
12242 } else {
12243 lvp->text = vp->text;
12244 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012245 vp->flags |= VSTRFIXED|VTEXTFIXED;
12246 if (eq)
12247 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012248 }
12249 }
12250 lvp->vp = vp;
12251 lvp->next = localvars;
12252 localvars = lvp;
12253 INTON;
12254}
12255
Eric Andersenc470f442003-07-28 09:56:35 +000012256/*
12257 * The "local" command.
12258 */
12259
12260static int
12261localcmd(int argc, char **argv)
12262{
12263 char *name;
12264
12265 argv = argptr;
12266 while ((name = *argv++) != NULL) {
12267 mklocal(name);
12268 }
12269 return 0;
12270}
12271
12272
Eric Andersencb57d552001-06-28 07:25:16 +000012273/*
12274 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012275 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012276 */
12277
Eric Andersenc470f442003-07-28 09:56:35 +000012278static void
12279poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012280{
Eric Andersencb57d552001-06-28 07:25:16 +000012281 struct localvar *lvp;
12282 struct var *vp;
12283
12284 while ((lvp = localvars) != NULL) {
12285 localvars = lvp->next;
12286 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012287 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12288 if (vp == NULL) { /* $- saved */
12289 memcpy(optlist, lvp->text, sizeof(optlist));
12290 ckfree(lvp->text);
12291 optschanged();
12292 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12293 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012294 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012295 if (vp->func)
12296 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12297 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12298 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012299 vp->flags = lvp->flags;
12300 vp->text = lvp->text;
12301 }
Eric Andersenc470f442003-07-28 09:56:35 +000012302 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012303 }
12304}
12305
12306
Eric Andersencb57d552001-06-28 07:25:16 +000012307/*
12308 * The unset builtin command. We unset the function before we unset the
12309 * variable to allow a function to be unset when there is a readonly variable
12310 * with the same name.
12311 */
12312
Eric Andersenc470f442003-07-28 09:56:35 +000012313int
12314unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012315{
12316 char **ap;
12317 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012318 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012319 int ret = 0;
12320
12321 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012322 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012323 }
Eric Andersencb57d552001-06-28 07:25:16 +000012324
Eric Andersenc470f442003-07-28 09:56:35 +000012325 for (ap = argptr; *ap ; ap++) {
12326 if (flag != 'f') {
12327 i = unsetvar(*ap);
12328 ret |= i;
12329 if (!(i & 2))
12330 continue;
12331 }
12332 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012333 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012334 }
Eric Andersenc470f442003-07-28 09:56:35 +000012335 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012336}
12337
12338
12339/*
12340 * Unset the specified variable.
12341 */
12342
Eric Andersenc470f442003-07-28 09:56:35 +000012343int
12344unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012345{
Eric Andersencb57d552001-06-28 07:25:16 +000012346 struct var **vpp;
12347 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012348 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012349
12350 vpp = findvar(hashvar(s), s);
12351 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012352 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012353 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012354 int flags = vp->flags;
12355
12356 retval = 1;
12357 if (flags & VREADONLY)
12358 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012359#ifdef DYNAMIC_VAR
12360 vp->flags &= ~VDYNAMIC;
12361#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012362 if (flags & VUNSET)
12363 goto ok;
12364 if ((flags & VSTRFIXED) == 0) {
12365 INTOFF;
12366 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12367 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012368 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012369 ckfree(vp);
12370 INTON;
12371 } else {
12372 setvar(s, 0, 0);
12373 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012374 }
Eric Andersenc470f442003-07-28 09:56:35 +000012375ok:
12376 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012377 }
12378
Eric Andersenc470f442003-07-28 09:56:35 +000012379out:
12380 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012381}
12382
12383
12384
12385/*
12386 * Find the appropriate entry in the hash table from the name.
12387 */
12388
Eric Andersenc470f442003-07-28 09:56:35 +000012389static struct var **
12390hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012391{
Eric Andersencb57d552001-06-28 07:25:16 +000012392 unsigned int hashval;
12393
12394 hashval = ((unsigned char) *p) << 4;
12395 while (*p && *p != '=')
12396 hashval += (unsigned char) *p++;
12397 return &vartab[hashval % VTABSIZE];
12398}
12399
12400
12401
12402/*
Eric Andersenc470f442003-07-28 09:56:35 +000012403 * Compares two strings up to the first = or '\0'. The first
12404 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012405 * either '=' or '\0'.
12406 */
12407
Eric Andersenc470f442003-07-28 09:56:35 +000012408int
12409varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012410{
Eric Andersenc470f442003-07-28 09:56:35 +000012411 int c, d;
12412
12413 while ((c = *p) == (d = *q)) {
12414 if (!c || c == '=')
12415 goto out;
12416 p++;
12417 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012418 }
Eric Andersenc470f442003-07-28 09:56:35 +000012419 if (c == '=')
12420 c = 0;
12421 if (d == '=')
12422 d = 0;
12423out:
12424 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012425}
12426
Eric Andersenc470f442003-07-28 09:56:35 +000012427static int
12428vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012429{
Eric Andersenc470f442003-07-28 09:56:35 +000012430 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012431}
12432
Eric Andersenc470f442003-07-28 09:56:35 +000012433static struct var **
12434findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012435{
12436 for (; *vpp; vpp = &(*vpp)->next) {
12437 if (varequal((*vpp)->text, name)) {
12438 break;
12439 }
12440 }
12441 return vpp;
12442}
Eric Andersenc470f442003-07-28 09:56:35 +000012443/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012444
Eric Andersenc470f442003-07-28 09:56:35 +000012445#include <sys/times.h>
12446
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012447static const unsigned char timescmd_str[] = {
12448 ' ', offsetof(struct tms, tms_utime),
12449 '\n', offsetof(struct tms, tms_stime),
12450 ' ', offsetof(struct tms, tms_cutime),
12451 '\n', offsetof(struct tms, tms_cstime),
12452 0
12453};
Eric Andersencb57d552001-06-28 07:25:16 +000012454
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012455static int timescmd(int ac, char **av)
12456{
12457 long int clk_tck, s, t;
12458 const unsigned char *p;
12459 struct tms buf;
12460
12461 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012462 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012463
12464 p = timescmd_str;
12465 do {
12466 t = *(clock_t *)(((char *) &buf) + p[1]);
12467 s = t / clk_tck;
12468 out1fmt("%ldm%ld.%.3lds%c",
12469 s/60, s%60,
12470 ((t - s * clk_tck) * 1000) / clk_tck,
12471 p[0]);
12472 } while (*(p += 2));
12473
Eric Andersencb57d552001-06-28 07:25:16 +000012474 return 0;
12475}
12476
Eric Andersend35c5df2002-01-09 15:37:36 +000012477#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen009617f2004-04-05 13:24:07 +000012478static long
Eric Andersenc470f442003-07-28 09:56:35 +000012479dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012480{
Eric Andersen90898442003-08-06 11:20:52 +000012481 long result;
Eric Andersenc470f442003-07-28 09:56:35 +000012482 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012483
Eric Andersenc470f442003-07-28 09:56:35 +000012484 INTOFF;
12485 result = arith(s, &errcode);
12486 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012487 if (errcode == -3)
12488 error("exponent less than 0");
12489 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012490 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012491 else if (errcode == -5)
12492 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012493 else
12494 synerror(s);
12495 }
12496 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012497
Eric Andersenc470f442003-07-28 09:56:35 +000012498 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012499}
Eric Andersenc470f442003-07-28 09:56:35 +000012500
12501
12502/*
Eric Andersen90898442003-08-06 11:20:52 +000012503 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12504 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12505 *
12506 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012507 */
Eric Andersen90898442003-08-06 11:20:52 +000012508
Eric Andersenc470f442003-07-28 09:56:35 +000012509static int
Eric Andersen90898442003-08-06 11:20:52 +000012510letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012511{
Eric Andersenc470f442003-07-28 09:56:35 +000012512 char **ap;
12513 long i;
12514
Eric Andersen90898442003-08-06 11:20:52 +000012515 ap = argv + 1;
12516 if(!*ap)
12517 error("expression expected");
12518 for (ap = argv + 1; *ap; ap++) {
12519 i = dash_arith(*ap);
12520 }
Eric Andersenc470f442003-07-28 09:56:35 +000012521
Eric Andersen90898442003-08-06 11:20:52 +000012522 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012523}
12524#endif /* CONFIG_ASH_MATH_SUPPORT */
12525
12526/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12527
12528/*
12529 * Miscelaneous builtins.
12530 */
12531
12532#undef rflag
12533
12534#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012535#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012536typedef enum __rlimit_resource rlim_t;
12537#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012538#endif
12539
12540
Eric Andersenc470f442003-07-28 09:56:35 +000012541/*
12542 * The read builtin. The -e option causes backslashes to escape the
12543 * following character.
12544 *
12545 * This uses unbuffered input, which may be avoidable in some cases.
12546 */
12547
12548static int
12549readcmd(int argc, char **argv)
12550{
12551 char **ap;
12552 int backslash;
12553 char c;
12554 int rflag;
12555 char *prompt;
12556 const char *ifs;
12557 char *p;
12558 int startword;
12559 int status;
12560 int i;
12561
12562 rflag = 0;
12563 prompt = NULL;
12564 while ((i = nextopt("p:r")) != '\0') {
12565 if (i == 'p')
12566 prompt = optionarg;
12567 else
12568 rflag = 1;
12569 }
12570 if (prompt && isatty(0)) {
12571 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012572 }
12573 if (*(ap = argptr) == NULL)
12574 error("arg count");
12575 if ((ifs = bltinlookup("IFS")) == NULL)
12576 ifs = defifs;
12577 status = 0;
12578 startword = 1;
12579 backslash = 0;
12580 STARTSTACKSTR(p);
12581 for (;;) {
12582 if (read(0, &c, 1) != 1) {
12583 status = 1;
12584 break;
12585 }
12586 if (c == '\0')
12587 continue;
12588 if (backslash) {
12589 backslash = 0;
12590 if (c != '\n')
12591 goto put;
12592 continue;
12593 }
12594 if (!rflag && c == '\\') {
12595 backslash++;
12596 continue;
12597 }
12598 if (c == '\n')
12599 break;
12600 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12601 continue;
12602 }
12603 startword = 0;
12604 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12605 STACKSTRNUL(p);
12606 setvar(*ap, stackblock(), 0);
12607 ap++;
12608 startword = 1;
12609 STARTSTACKSTR(p);
12610 } else {
12611put:
12612 STPUTC(c, p);
12613 }
12614 }
12615 STACKSTRNUL(p);
12616 /* Remove trailing blanks */
12617 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12618 *p = '\0';
12619 setvar(*ap, stackblock(), 0);
12620 while (*++ap != NULL)
12621 setvar(*ap, nullstr, 0);
12622 return status;
12623}
12624
12625
12626static int umaskcmd(int argc, char **argv)
12627{
12628 static const char permuser[3] = "ugo";
12629 static const char permmode[3] = "rwx";
12630 static const short int permmask[] = {
12631 S_IRUSR, S_IWUSR, S_IXUSR,
12632 S_IRGRP, S_IWGRP, S_IXGRP,
12633 S_IROTH, S_IWOTH, S_IXOTH
12634 };
12635
12636 char *ap;
12637 mode_t mask;
12638 int i;
12639 int symbolic_mode = 0;
12640
12641 while (nextopt("S") != '\0') {
12642 symbolic_mode = 1;
12643 }
12644
12645 INTOFF;
12646 mask = umask(0);
12647 umask(mask);
12648 INTON;
12649
12650 if ((ap = *argptr) == NULL) {
12651 if (symbolic_mode) {
12652 char buf[18];
12653 char *p = buf;
12654
12655 for (i = 0; i < 3; i++) {
12656 int j;
12657
12658 *p++ = permuser[i];
12659 *p++ = '=';
12660 for (j = 0; j < 3; j++) {
12661 if ((mask & permmask[3 * i + j]) == 0) {
12662 *p++ = permmode[j];
12663 }
12664 }
12665 *p++ = ',';
12666 }
12667 *--p = 0;
12668 puts(buf);
12669 } else {
12670 out1fmt("%.4o\n", mask);
12671 }
12672 } else {
12673 if (is_digit((unsigned char) *ap)) {
12674 mask = 0;
12675 do {
12676 if (*ap >= '8' || *ap < '0')
12677 error(illnum, argv[1]);
12678 mask = (mask << 3) + (*ap - '0');
12679 } while (*++ap != '\0');
12680 umask(mask);
12681 } else {
12682 mask = ~mask & 0777;
12683 if (!bb_parse_mode(ap, &mask)) {
12684 error("Illegal mode: %s", ap);
12685 }
12686 umask(~mask & 0777);
12687 }
12688 }
12689 return 0;
12690}
12691
12692/*
12693 * ulimit builtin
12694 *
12695 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12696 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12697 * ash by J.T. Conklin.
12698 *
12699 * Public domain.
12700 */
12701
12702struct limits {
12703 const char *name;
12704 int cmd;
12705 int factor; /* multiply by to get rlim_{cur,max} values */
12706 char option;
12707};
12708
12709static const struct limits limits[] = {
12710#ifdef RLIMIT_CPU
12711 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12712#endif
12713#ifdef RLIMIT_FSIZE
12714 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12715#endif
12716#ifdef RLIMIT_DATA
12717 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12718#endif
12719#ifdef RLIMIT_STACK
12720 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12721#endif
12722#ifdef RLIMIT_CORE
12723 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12724#endif
12725#ifdef RLIMIT_RSS
12726 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12727#endif
12728#ifdef RLIMIT_MEMLOCK
12729 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12730#endif
12731#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012732 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012733#endif
12734#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012735 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012736#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012737#ifdef RLIMIT_AS
12738 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012739#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012740#ifdef RLIMIT_LOCKS
12741 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012742#endif
12743 { (char *) 0, 0, 0, '\0' }
12744};
12745
Glenn L McGrath76620622004-01-13 10:19:37 +000012746enum limtype { SOFT = 0x1, HARD = 0x2 };
12747
12748static void printlim(enum limtype how, const struct rlimit *limit,
12749 const struct limits *l)
12750{
12751 rlim_t val;
12752
12753 val = limit->rlim_max;
12754 if (how & SOFT)
12755 val = limit->rlim_cur;
12756
12757 if (val == RLIM_INFINITY)
12758 out1fmt("unlimited\n");
12759 else {
12760 val /= l->factor;
12761 out1fmt("%lld\n", (long long) val);
12762 }
12763}
12764
Eric Andersenc470f442003-07-28 09:56:35 +000012765int
12766ulimitcmd(int argc, char **argv)
12767{
12768 int c;
12769 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012770 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012771 const struct limits *l;
12772 int set, all = 0;
12773 int optc, what;
12774 struct rlimit limit;
12775
12776 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012777 while ((optc = nextopt("HSa"
12778#ifdef RLIMIT_CPU
12779 "t"
12780#endif
12781#ifdef RLIMIT_FSIZE
12782 "f"
12783#endif
12784#ifdef RLIMIT_DATA
12785 "d"
12786#endif
12787#ifdef RLIMIT_STACK
12788 "s"
12789#endif
12790#ifdef RLIMIT_CORE
12791 "c"
12792#endif
12793#ifdef RLIMIT_RSS
12794 "m"
12795#endif
12796#ifdef RLIMIT_MEMLOCK
12797 "l"
12798#endif
12799#ifdef RLIMIT_NPROC
12800 "p"
12801#endif
12802#ifdef RLIMIT_NOFILE
12803 "n"
12804#endif
12805#ifdef RLIMIT_AS
12806 "v"
12807#endif
12808#ifdef RLIMIT_LOCKS
12809 "w"
12810#endif
12811 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012812 switch (optc) {
12813 case 'H':
12814 how = HARD;
12815 break;
12816 case 'S':
12817 how = SOFT;
12818 break;
12819 case 'a':
12820 all = 1;
12821 break;
12822 default:
12823 what = optc;
12824 }
12825
Glenn L McGrath76620622004-01-13 10:19:37 +000012826 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012827 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012828
12829 set = *argptr ? 1 : 0;
12830 if (set) {
12831 char *p = *argptr;
12832
12833 if (all || argptr[1])
12834 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012835 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012836 val = RLIM_INFINITY;
12837 else {
12838 val = (rlim_t) 0;
12839
12840 while ((c = *p++) >= '0' && c <= '9')
12841 {
12842 val = (val * 10) + (long)(c - '0');
12843 if (val < (rlim_t) 0)
12844 break;
12845 }
12846 if (c)
12847 error("bad number");
12848 val *= l->factor;
12849 }
12850 }
12851 if (all) {
12852 for (l = limits; l->name; l++) {
12853 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012854 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012855 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012856 }
12857 return 0;
12858 }
12859
12860 getrlimit(l->cmd, &limit);
12861 if (set) {
12862 if (how & HARD)
12863 limit.rlim_max = val;
12864 if (how & SOFT)
12865 limit.rlim_cur = val;
12866 if (setrlimit(l->cmd, &limit) < 0)
12867 error("error setting limit (%m)");
12868 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012869 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012870 }
12871 return 0;
12872}
12873
Eric Andersen90898442003-08-06 11:20:52 +000012874
12875#ifdef CONFIG_ASH_MATH_SUPPORT
12876
12877/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12878
12879 Permission is hereby granted, free of charge, to any person obtaining
12880 a copy of this software and associated documentation files (the
12881 "Software"), to deal in the Software without restriction, including
12882 without limitation the rights to use, copy, modify, merge, publish,
12883 distribute, sublicense, and/or sell copies of the Software, and to
12884 permit persons to whom the Software is furnished to do so, subject to
12885 the following conditions:
12886
12887 The above copyright notice and this permission notice shall be
12888 included in all copies or substantial portions of the Software.
12889
12890 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12891 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12892 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12893 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12894 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12895 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12896 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12897*/
12898
12899/* This is my infix parser/evaluator. It is optimized for size, intended
12900 * as a replacement for yacc-based parsers. However, it may well be faster
12901 * than a comparable parser writen in yacc. The supported operators are
12902 * listed in #defines below. Parens, order of operations, and error handling
12903 * are supported. This code is threadsafe. The exact expression format should
12904 * be that which POSIX specifies for shells. */
12905
12906/* The code uses a simple two-stack algorithm. See
12907 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12908 * for a detailed explaination of the infix-to-postfix algorithm on which
12909 * this is based (this code differs in that it applies operators immediately
12910 * to the stack instead of adding them to a queue to end up with an
12911 * expression). */
12912
12913/* To use the routine, call it with an expression string and error return
12914 * pointer */
12915
12916/*
12917 * Aug 24, 2001 Manuel Novoa III
12918 *
12919 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12920 *
12921 * 1) In arith_apply():
12922 * a) Cached values of *numptr and &(numptr[-1]).
12923 * b) Removed redundant test for zero denominator.
12924 *
12925 * 2) In arith():
12926 * a) Eliminated redundant code for processing operator tokens by moving
12927 * to a table-based implementation. Also folded handling of parens
12928 * into the table.
12929 * b) Combined all 3 loops which called arith_apply to reduce generated
12930 * code size at the cost of speed.
12931 *
12932 * 3) The following expressions were treated as valid by the original code:
12933 * 1() , 0! , 1 ( *3 ) .
12934 * These bugs have been fixed by internally enclosing the expression in
12935 * parens and then checking that all binary ops and right parens are
12936 * preceded by a valid expression (NUM_TOKEN).
12937 *
12938 * Note: It may be desireable to replace Aaron's test for whitespace with
12939 * ctype's isspace() if it is used by another busybox applet or if additional
12940 * whitespace chars should be considered. Look below the "#include"s for a
12941 * precompiler test.
12942 */
12943
12944/*
12945 * Aug 26, 2001 Manuel Novoa III
12946 *
12947 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12948 *
12949 * Merge in Aaron's comments previously posted to the busybox list,
12950 * modified slightly to take account of my changes to the code.
12951 *
12952 */
12953
12954/*
12955 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12956 *
12957 * - allow access to variable,
12958 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12959 * - realize assign syntax (VAR=expr, +=, *= etc)
12960 * - realize exponentiation (** operator)
12961 * - realize comma separated - expr, expr
12962 * - realise ++expr --expr expr++ expr--
12963 * - realise expr ? expr : expr (but, second expr calculate always)
12964 * - allow hexdecimal and octal numbers
12965 * - was restored loses XOR operator
12966 * - remove one goto label, added three ;-)
12967 * - protect $((num num)) as true zero expr (Manuel`s error)
12968 * - always use special isspace(), see comment from bash ;-)
12969 */
12970
12971
12972#define arith_isspace(arithval) \
12973 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12974
12975
12976typedef unsigned char operator;
12977
12978/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12979 * precedence, and 3 high bits are an ID unique accross operators of that
12980 * precedence. The ID portion is so that multiple operators can have the
12981 * same precedence, ensuring that the leftmost one is evaluated first.
12982 * Consider * and /. */
12983
12984#define tok_decl(prec,id) (((id)<<5)|(prec))
12985#define PREC(op) ((op) & 0x1F)
12986
12987#define TOK_LPAREN tok_decl(0,0)
12988
12989#define TOK_COMMA tok_decl(1,0)
12990
12991#define TOK_ASSIGN tok_decl(2,0)
12992#define TOK_AND_ASSIGN tok_decl(2,1)
12993#define TOK_OR_ASSIGN tok_decl(2,2)
12994#define TOK_XOR_ASSIGN tok_decl(2,3)
12995#define TOK_PLUS_ASSIGN tok_decl(2,4)
12996#define TOK_MINUS_ASSIGN tok_decl(2,5)
12997#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12998#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12999
13000#define TOK_MUL_ASSIGN tok_decl(3,0)
13001#define TOK_DIV_ASSIGN tok_decl(3,1)
13002#define TOK_REM_ASSIGN tok_decl(3,2)
13003
13004/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13005#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13006
13007/* conditional is right associativity too */
13008#define TOK_CONDITIONAL tok_decl(4,0)
13009#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13010
13011#define TOK_OR tok_decl(5,0)
13012
13013#define TOK_AND tok_decl(6,0)
13014
13015#define TOK_BOR tok_decl(7,0)
13016
13017#define TOK_BXOR tok_decl(8,0)
13018
13019#define TOK_BAND tok_decl(9,0)
13020
13021#define TOK_EQ tok_decl(10,0)
13022#define TOK_NE tok_decl(10,1)
13023
13024#define TOK_LT tok_decl(11,0)
13025#define TOK_GT tok_decl(11,1)
13026#define TOK_GE tok_decl(11,2)
13027#define TOK_LE tok_decl(11,3)
13028
13029#define TOK_LSHIFT tok_decl(12,0)
13030#define TOK_RSHIFT tok_decl(12,1)
13031
13032#define TOK_ADD tok_decl(13,0)
13033#define TOK_SUB tok_decl(13,1)
13034
13035#define TOK_MUL tok_decl(14,0)
13036#define TOK_DIV tok_decl(14,1)
13037#define TOK_REM tok_decl(14,2)
13038
13039/* exponent is right associativity */
13040#define TOK_EXPONENT tok_decl(15,1)
13041
13042/* For now unary operators. */
13043#define UNARYPREC 16
13044#define TOK_BNOT tok_decl(UNARYPREC,0)
13045#define TOK_NOT tok_decl(UNARYPREC,1)
13046
13047#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13048#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13049
13050#define PREC_PRE (UNARYPREC+2)
13051
13052#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13053#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13054
13055#define PREC_POST (UNARYPREC+3)
13056
13057#define TOK_POST_INC tok_decl(PREC_POST, 0)
13058#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13059
13060#define SPEC_PREC (UNARYPREC+4)
13061
13062#define TOK_NUM tok_decl(SPEC_PREC, 0)
13063#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13064
13065#define NUMPTR (*numstackptr)
13066
13067static inline int tok_have_assign(operator op)
13068{
13069 operator prec = PREC(op);
13070
13071 convert_prec_is_assing(prec);
13072 return (prec == PREC(TOK_ASSIGN) ||
13073 prec == PREC_PRE || prec == PREC_POST);
13074}
13075
13076static inline int is_right_associativity(operator prec)
13077{
13078 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13079 prec == PREC(TOK_CONDITIONAL));
13080}
13081
13082
13083typedef struct ARITCH_VAR_NUM {
13084 long val;
13085 long contidional_second_val;
13086 char contidional_second_val_initialized;
13087 char *var; /* if NULL then is regular number,
13088 else is varable name */
13089} v_n_t;
13090
13091
13092typedef struct CHK_VAR_RECURSIVE_LOOPED {
13093 const char *var;
13094 struct CHK_VAR_RECURSIVE_LOOPED *next;
13095} chk_var_recursive_looped_t;
13096
13097static chk_var_recursive_looped_t *prev_chk_var_recursive;
13098
13099
13100static int arith_lookup_val(v_n_t *t)
13101{
13102 if(t->var) {
13103 const char * p = lookupvar(t->var);
13104
13105 if(p) {
13106 int errcode;
13107
13108 /* recursive try as expression */
13109 chk_var_recursive_looped_t *cur;
13110 chk_var_recursive_looped_t cur_save;
13111
13112 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13113 if(strcmp(cur->var, t->var) == 0) {
13114 /* expression recursion loop detected */
13115 return -5;
13116 }
13117 }
13118 /* save current lookuped var name */
13119 cur = prev_chk_var_recursive;
13120 cur_save.var = t->var;
13121 cur_save.next = cur;
13122 prev_chk_var_recursive = &cur_save;
13123
13124 t->val = arith (p, &errcode);
13125 /* restore previous ptr after recursiving */
13126 prev_chk_var_recursive = cur;
13127 return errcode;
13128 } else {
13129 /* allow undefined var as 0 */
13130 t->val = 0;
13131 }
13132 }
13133 return 0;
13134}
13135
13136/* "applying" a token means performing it on the top elements on the integer
13137 * stack. For a unary operator it will only change the top element, but a
13138 * binary operator will pop two arguments and push a result */
13139static inline int
13140arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13141{
13142 long numptr_val;
13143 v_n_t *numptr_m1;
13144 long rez;
13145 int ret_arith_lookup_val;
13146
13147 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13148 without arguments */
13149 numptr_m1 = NUMPTR - 1;
13150
13151 /* check operand is var with noninteger value */
13152 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13153 if(ret_arith_lookup_val)
13154 return ret_arith_lookup_val;
13155
13156 rez = numptr_m1->val;
13157 if (op == TOK_UMINUS)
13158 rez *= -1;
13159 else if (op == TOK_NOT)
13160 rez = !rez;
13161 else if (op == TOK_BNOT)
13162 rez = ~rez;
13163 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13164 rez++;
13165 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13166 rez--;
13167 else if (op != TOK_UPLUS) {
13168 /* Binary operators */
13169
13170 /* check and binary operators need two arguments */
13171 if (numptr_m1 == numstack) goto err;
13172
13173 /* ... and they pop one */
13174 --NUMPTR;
13175 numptr_val = rez;
13176 if (op == TOK_CONDITIONAL) {
13177 if(! numptr_m1->contidional_second_val_initialized) {
13178 /* protect $((expr1 ? expr2)) without ": expr" */
13179 goto err;
13180 }
13181 rez = numptr_m1->contidional_second_val;
13182 } else if(numptr_m1->contidional_second_val_initialized) {
13183 /* protect $((expr1 : expr2)) without "expr ? " */
13184 goto err;
13185 }
13186 numptr_m1 = NUMPTR - 1;
13187 if(op != TOK_ASSIGN) {
13188 /* check operand is var with noninteger value for not '=' */
13189 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13190 if(ret_arith_lookup_val)
13191 return ret_arith_lookup_val;
13192 }
13193 if (op == TOK_CONDITIONAL) {
13194 numptr_m1->contidional_second_val = rez;
13195 }
13196 rez = numptr_m1->val;
13197 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13198 rez |= numptr_val;
13199 else if (op == TOK_OR)
13200 rez = numptr_val || rez;
13201 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13202 rez &= numptr_val;
13203 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13204 rez ^= numptr_val;
13205 else if (op == TOK_AND)
13206 rez = rez && numptr_val;
13207 else if (op == TOK_EQ)
13208 rez = (rez == numptr_val);
13209 else if (op == TOK_NE)
13210 rez = (rez != numptr_val);
13211 else if (op == TOK_GE)
13212 rez = (rez >= numptr_val);
13213 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13214 rez >>= numptr_val;
13215 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13216 rez <<= numptr_val;
13217 else if (op == TOK_GT)
13218 rez = (rez > numptr_val);
13219 else if (op == TOK_LT)
13220 rez = (rez < numptr_val);
13221 else if (op == TOK_LE)
13222 rez = (rez <= numptr_val);
13223 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13224 rez *= numptr_val;
13225 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13226 rez += numptr_val;
13227 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13228 rez -= numptr_val;
13229 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13230 rez = numptr_val;
13231 else if (op == TOK_CONDITIONAL_SEP) {
13232 if (numptr_m1 == numstack) {
13233 /* protect $((expr : expr)) without "expr ? " */
13234 goto err;
13235 }
13236 numptr_m1->contidional_second_val_initialized = op;
13237 numptr_m1->contidional_second_val = numptr_val;
13238 }
13239 else if (op == TOK_CONDITIONAL) {
13240 rez = rez ?
13241 numptr_val : numptr_m1->contidional_second_val;
13242 }
13243 else if(op == TOK_EXPONENT) {
13244 if(numptr_val < 0)
13245 return -3; /* exponent less than 0 */
13246 else {
13247 long c = 1;
13248
13249 if(numptr_val)
13250 while(numptr_val--)
13251 c *= rez;
13252 rez = c;
13253 }
13254 }
13255 else if(numptr_val==0) /* zero divisor check */
13256 return -2;
13257 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13258 rez /= numptr_val;
13259 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13260 rez %= numptr_val;
13261 }
13262 if(tok_have_assign(op)) {
13263 char buf[32];
13264
13265 if(numptr_m1->var == NULL) {
13266 /* Hmm, 1=2 ? */
13267 goto err;
13268 }
13269 /* save to shell variable */
13270 sprintf(buf, "%ld", rez);
13271 setvar(numptr_m1->var, buf, 0);
13272 /* after saving, make previous value for v++ or v-- */
13273 if(op == TOK_POST_INC)
13274 rez--;
13275 else if(op == TOK_POST_DEC)
13276 rez++;
13277 }
13278 numptr_m1->val = rez;
13279 /* protect geting var value, is number now */
13280 numptr_m1->var = NULL;
13281 return 0;
13282err: return(-1);
13283}
13284
13285/* longest must first */
13286static const char op_tokens[] = {
13287 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13288 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13289 '<','<', 0, TOK_LSHIFT,
13290 '>','>', 0, TOK_RSHIFT,
13291 '|','|', 0, TOK_OR,
13292 '&','&', 0, TOK_AND,
13293 '!','=', 0, TOK_NE,
13294 '<','=', 0, TOK_LE,
13295 '>','=', 0, TOK_GE,
13296 '=','=', 0, TOK_EQ,
13297 '|','=', 0, TOK_OR_ASSIGN,
13298 '&','=', 0, TOK_AND_ASSIGN,
13299 '*','=', 0, TOK_MUL_ASSIGN,
13300 '/','=', 0, TOK_DIV_ASSIGN,
13301 '%','=', 0, TOK_REM_ASSIGN,
13302 '+','=', 0, TOK_PLUS_ASSIGN,
13303 '-','=', 0, TOK_MINUS_ASSIGN,
13304 '-','-', 0, TOK_POST_DEC,
13305 '^','=', 0, TOK_XOR_ASSIGN,
13306 '+','+', 0, TOK_POST_INC,
13307 '*','*', 0, TOK_EXPONENT,
13308 '!', 0, TOK_NOT,
13309 '<', 0, TOK_LT,
13310 '>', 0, TOK_GT,
13311 '=', 0, TOK_ASSIGN,
13312 '|', 0, TOK_BOR,
13313 '&', 0, TOK_BAND,
13314 '*', 0, TOK_MUL,
13315 '/', 0, TOK_DIV,
13316 '%', 0, TOK_REM,
13317 '+', 0, TOK_ADD,
13318 '-', 0, TOK_SUB,
13319 '^', 0, TOK_BXOR,
13320 /* uniq */
13321 '~', 0, TOK_BNOT,
13322 ',', 0, TOK_COMMA,
13323 '?', 0, TOK_CONDITIONAL,
13324 ':', 0, TOK_CONDITIONAL_SEP,
13325 ')', 0, TOK_RPAREN,
13326 '(', 0, TOK_LPAREN,
13327 0
13328};
13329/* ptr to ")" */
13330#define endexpression &op_tokens[sizeof(op_tokens)-7]
13331
13332
13333extern long arith (const char *expr, int *perrcode)
13334{
13335 register char arithval; /* Current character under analysis */
13336 operator lasttok, op;
13337 operator prec;
13338
13339 const char *p = endexpression;
13340 int errcode;
13341
13342 size_t datasizes = strlen(expr) + 2;
13343
13344 /* Stack of integers */
13345 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13346 * in any given correct or incorrect expression is left as an excersize to
13347 * the reader. */
13348 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13349 *numstackptr = numstack;
13350 /* Stack of operator tokens */
13351 operator *stack = alloca((datasizes) * sizeof(operator)),
13352 *stackptr = stack;
13353
13354 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13355 *perrcode = errcode = 0;
13356
13357 while(1) {
13358 if ((arithval = *expr) == 0) {
13359 if (p == endexpression) {
13360 /* Null expression. */
13361 return 0;
13362 }
13363
13364 /* This is only reached after all tokens have been extracted from the
13365 * input stream. If there are still tokens on the operator stack, they
13366 * are to be applied in order. At the end, there should be a final
13367 * result on the integer stack */
13368
13369 if (expr != endexpression + 1) {
13370 /* If we haven't done so already, */
13371 /* append a closing right paren */
13372 expr = endexpression;
13373 /* and let the loop process it. */
13374 continue;
13375 }
13376 /* At this point, we're done with the expression. */
13377 if (numstackptr != numstack+1) {
13378 /* ... but if there isn't, it's bad */
13379 err:
13380 return (*perrcode = -1);
13381 }
13382 if(numstack->var) {
13383 /* expression is $((var)) only, lookup now */
13384 errcode = arith_lookup_val(numstack);
13385 }
13386 ret:
13387 *perrcode = errcode;
13388 return numstack->val;
13389 } else {
13390 /* Continue processing the expression. */
13391 if (arith_isspace(arithval)) {
13392 /* Skip whitespace */
13393 goto prologue;
13394 }
13395 if((p = endofname(expr)) != expr) {
13396 int var_name_size = (p-expr) + 1; /* trailing zero */
13397
13398 numstackptr->var = alloca(var_name_size);
13399 safe_strncpy(numstackptr->var, expr, var_name_size);
13400 expr = p;
13401 num:
13402 numstackptr->contidional_second_val_initialized = 0;
13403 numstackptr++;
13404 lasttok = TOK_NUM;
13405 continue;
13406 } else if (is_digit(arithval)) {
13407 numstackptr->var = NULL;
13408 numstackptr->val = strtol(expr, (char **) &expr, 0);
13409 goto num;
13410 }
13411 for(p = op_tokens; ; p++) {
13412 const char *o;
13413
13414 if(*p == 0) {
13415 /* strange operator not found */
13416 goto err;
13417 }
13418 for(o = expr; *p && *o == *p; p++)
13419 o++;
13420 if(! *p) {
13421 /* found */
13422 expr = o - 1;
13423 break;
13424 }
13425 /* skip tail uncompared token */
13426 while(*p)
13427 p++;
13428 /* skip zero delim */
13429 p++;
13430 }
13431 op = p[1];
13432
13433 /* post grammar: a++ reduce to num */
13434 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13435 lasttok = TOK_NUM;
13436
13437 /* Plus and minus are binary (not unary) _only_ if the last
13438 * token was as number, or a right paren (which pretends to be
13439 * a number, since it evaluates to one). Think about it.
13440 * It makes sense. */
13441 if (lasttok != TOK_NUM) {
13442 switch(op) {
13443 case TOK_ADD:
13444 op = TOK_UPLUS;
13445 break;
13446 case TOK_SUB:
13447 op = TOK_UMINUS;
13448 break;
13449 case TOK_POST_INC:
13450 op = TOK_PRE_INC;
13451 break;
13452 case TOK_POST_DEC:
13453 op = TOK_PRE_DEC;
13454 break;
13455 }
13456 }
13457 /* We don't want a unary operator to cause recursive descent on the
13458 * stack, because there can be many in a row and it could cause an
13459 * operator to be evaluated before its argument is pushed onto the
13460 * integer stack. */
13461 /* But for binary operators, "apply" everything on the operator
13462 * stack until we find an operator with a lesser priority than the
13463 * one we have just extracted. */
13464 /* Left paren is given the lowest priority so it will never be
13465 * "applied" in this way.
13466 * if associativity is right and priority eq, applied also skip
13467 */
13468 prec = PREC(op);
13469 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13470 /* not left paren or unary */
13471 if (lasttok != TOK_NUM) {
13472 /* binary op must be preceded by a num */
13473 goto err;
13474 }
13475 while (stackptr != stack) {
13476 if (op == TOK_RPAREN) {
13477 /* The algorithm employed here is simple: while we don't
13478 * hit an open paren nor the bottom of the stack, pop
13479 * tokens and apply them */
13480 if (stackptr[-1] == TOK_LPAREN) {
13481 --stackptr;
13482 /* Any operator directly after a */
13483 lasttok = TOK_NUM;
13484 /* close paren should consider itself binary */
13485 goto prologue;
13486 }
13487 } else {
13488 operator prev_prec = PREC(stackptr[-1]);
13489
13490 convert_prec_is_assing(prec);
13491 convert_prec_is_assing(prev_prec);
13492 if (prev_prec < prec)
13493 break;
13494 /* check right assoc */
13495 if(prev_prec == prec && is_right_associativity(prec))
13496 break;
13497 }
13498 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13499 if(errcode) goto ret;
13500 }
13501 if (op == TOK_RPAREN) {
13502 goto err;
13503 }
13504 }
13505
13506 /* Push this operator to the stack and remember it. */
13507 *stackptr++ = lasttok = op;
13508
13509 prologue:
13510 ++expr;
13511 }
13512 }
13513}
13514#endif /* CONFIG_ASH_MATH_SUPPORT */
13515
13516
Eric Andersenc470f442003-07-28 09:56:35 +000013517#ifdef DEBUG
13518const char *bb_applet_name = "debug stuff usage";
13519int main(int argc, char **argv)
13520{
13521 return ash_main(argc, argv);
13522}
13523#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013524
Eric Andersendf82f612001-06-28 07:46:40 +000013525/*-
13526 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013527 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013528 *
13529 * This code is derived from software contributed to Berkeley by
13530 * Kenneth Almquist.
13531 *
13532 * Redistribution and use in source and binary forms, with or without
13533 * modification, are permitted provided that the following conditions
13534 * are met:
13535 * 1. Redistributions of source code must retain the above copyright
13536 * notice, this list of conditions and the following disclaimer.
13537 * 2. Redistributions in binary form must reproduce the above copyright
13538 * notice, this list of conditions and the following disclaimer in the
13539 * documentation and/or other materials provided with the distribution.
13540 *
Eric Andersen2870d962001-07-02 17:27:21 +000013541 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13542 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013543 *
13544 * 4. Neither the name of the University nor the names of its contributors
13545 * may be used to endorse or promote products derived from this software
13546 * without specific prior written permission.
13547 *
13548 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13549 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13550 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13551 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13552 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13553 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13554 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13555 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13556 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13557 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13558 * SUCH DAMAGE.
13559 */