blob: e2205efd24f95de01593ad4016afe6ffa1830af3 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
Eric Andersen81fe1232003-07-29 06:38:40 +00008 * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9 * was re-ported from NetBSD and debianized.
10 *
11 *
Eric Andersencb57d552001-06-28 07:25:16 +000012 * This code is derived from software contributed to Berkeley by
13 * Kenneth Almquist.
14 *
Eric Andersendf82f612001-06-28 07:46:40 +000015 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000019 *
Eric Andersendf82f612001-06-28 07:46:40 +000020 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
Eric Andersen81fe1232003-07-29 06:38:40 +000029 * Original BSD copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000030 */
31
Eric Andersenc470f442003-07-28 09:56:35 +000032/*
Eric Andersen90898442003-08-06 11:20:52 +000033 * rewrite arith.y to micro stack based cryptic algorithm by
34 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
35 *
Eric Andersenef02f822004-03-11 13:34:24 +000036 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
37 * dynamic variables.
Eric Andersen16767e22004-03-16 05:14:10 +000038 *
39 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be
40 * used in busybox and size optimizations,
41 * rewrote arith (see notes to this), added locale support,
42 * rewrote dynamic variables.
43 *
Eric Andersen90898442003-08-06 11:20:52 +000044 */
45
46
47/*
Eric Andersenc470f442003-07-28 09:56:35 +000048 * The follow should be set to reflect the type of system you have:
49 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
50 * define SYSV if you are running under System V.
51 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
52 * define DEBUG=2 to compile in and turn on debugging.
53 *
54 * When debugging is on, debugging info will be written to ./trace and
55 * a quit signal will generate a core dump.
56 */
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058
Eric Andersenc470f442003-07-28 09:56:35 +000059
Eric Andersen5bb16772001-09-06 18:00:41 +000060#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000061
Eric Andersenc470f442003-07-28 09:56:35 +000062#define PROFILE 0
63
64#ifdef DEBUG
65#define _GNU_SOURCE
66#endif
67
68#include <sys/types.h>
69#include <sys/cdefs.h>
70#include <sys/ioctl.h>
71#include <sys/param.h>
72#include <sys/resource.h>
73#include <sys/stat.h>
74#include <sys/time.h>
75#include <sys/wait.h>
76
77#include <stdio.h>
78#include <stdlib.h>
79#include <string.h>
80#include <unistd.h>
81
82#include <stdarg.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000083#include <stddef.h>
Eric Andersenc470f442003-07-28 09:56:35 +000084#include <assert.h>
Eric Andersencb57d552001-06-28 07:25:16 +000085#include <ctype.h>
86#include <dirent.h>
87#include <errno.h>
88#include <fcntl.h>
89#include <limits.h>
90#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000091#include <setjmp.h>
92#include <signal.h>
Eric Andersenc470f442003-07-28 09:56:35 +000093#include <stdint.h>
Eric Andersencb57d552001-06-28 07:25:16 +000094#include <sysexits.h>
Eric Andersenef02f822004-03-11 13:34:24 +000095#include <time.h>
Eric Andersenc470f442003-07-28 09:56:35 +000096#include <fnmatch.h>
Eric Andersenc470f442003-07-28 09:56:35 +000097
98
Robert Grieblea1a63a2002-06-04 20:10:23 +000099#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +0000100#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +0000101
Eric Andersend35c5df2002-01-09 15:37:36 +0000102#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +0000103#define JOBS 1
104#else
Eric Andersenca162042003-07-29 07:15:17 +0000105#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +0000106#endif
107
108#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000109#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000110#endif
111
Eric Andersen2870d962001-07-02 17:27:21 +0000112#include "cmdedit.h"
113
Eric Andersenc470f442003-07-28 09:56:35 +0000114#ifdef __GLIBC__
115/* glibc sucks */
116static int *dash_errno;
117#undef errno
118#define errno (*dash_errno)
119#endif
120
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000121#if defined(__uClinux__)
122#error "Do not even bother, ash will not run on uClinux"
123#endif
124
Eric Andersenc470f442003-07-28 09:56:35 +0000125#ifdef DEBUG
126#define _DIAGASSERT(assert_expr) assert(assert_expr)
127#else
128#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000129#endif
130
Eric Andersen2870d962001-07-02 17:27:21 +0000131
Eric Andersenc470f442003-07-28 09:56:35 +0000132#ifdef CONFIG_ASH_ALIAS
133/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
134
135#define ALIASINUSE 1
136#define ALIASDEAD 2
137
138struct alias {
139 struct alias *next;
140 char *name;
141 char *val;
142 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000143};
144
Eric Andersenc470f442003-07-28 09:56:35 +0000145static struct alias *lookupalias(const char *, int);
146static int aliascmd(int, char **);
147static int unaliascmd(int, char **);
148static void rmaliases(void);
149static int unalias(const char *);
150static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000151#endif
152
Eric Andersenc470f442003-07-28 09:56:35 +0000153/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
154
155
156static void setpwd(const char *, int);
157
158/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
159
160
161/*
162 * Types of operations (passed to the errmsg routine).
163 */
164
165
166static const char not_found_msg[] = "%s: not found";
167
168
169#define E_OPEN "No such file" /* opening a file */
170#define E_CREAT "Directory nonexistent" /* creating a file */
171#define E_EXEC not_found_msg+4 /* executing a program */
172
173/*
174 * We enclose jmp_buf in a structure so that we can declare pointers to
175 * jump locations. The global variable handler contains the location to
176 * jump to when an exception occurs, and the global variable exception
Eric Andersenaff114c2004-04-14 17:51:38 +0000177 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000178 * exception handlers, the user should save the value of handler on entry
179 * to an inner scope, set handler to point to a jmploc structure for the
180 * inner scope, and restore handler on exit from the scope.
181 */
182
183struct jmploc {
184 jmp_buf loc;
185};
186
187static struct jmploc *handler;
188static int exception;
189static volatile int suppressint;
190static volatile sig_atomic_t intpending;
191
192static int exerrno; /* Last exec error, error for EXEXEC */
193
194/* exceptions */
195#define EXINT 0 /* SIGINT received */
196#define EXERROR 1 /* a generic error */
197#define EXSHELLPROC 2 /* execute a shell procedure */
198#define EXEXEC 3 /* command execution failed */
199#define EXEXIT 4 /* exit the shell */
200#define EXSIG 5 /* trapped signal in wait(1) */
201
202
203/* do we generate EXSIG events */
204static int exsig;
205/* last pending signal */
206static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000207
208/*
209 * These macros allow the user to suspend the handling of interrupt signals
210 * over a period of time. This is similar to SIGHOLD to or sigblock, but
211 * much more efficient and portable. (But hacking the kernel is so much
212 * more fun than worrying about efficiency and portability. :-))
213 */
214
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/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002705 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002706 */
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
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003720 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3721 flg_bb = 1;
3722 }
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003723 if(flg_bb) {
3724 char **ap;
3725 char **new;
3726
3727 *argv = name;
3728 if(strcmp(name, "busybox")) {
3729 for (ap = argv; *ap; ap++);
3730 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3731 *ap++ = cmd = "/bin/busybox";
3732 while ((*ap++ = *argv++));
3733 argv = new;
3734 repeated++;
3735 } else {
3736 cmd = "/bin/busybox";
3737 }
3738 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003739#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003740
3741repeat:
3742#ifdef SYSV
3743 do {
3744 execve(cmd, argv, envp);
3745 } while (errno == EINTR);
3746#else
Eric Andersencb57d552001-06-28 07:25:16 +00003747 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003748#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003749 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003750 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003751 } else if (errno == ENOEXEC) {
3752 char **ap;
3753 char **new;
3754
Eric Andersenc470f442003-07-28 09:56:35 +00003755 for (ap = argv; *ap; ap++)
3756 ;
3757 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003758 ap[1] = cmd;
3759 *ap = cmd = (char *)DEFAULT_SHELL;
3760 ap += 2;
3761 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003762 while ((*ap++ = *argv++))
3763 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003764 argv = new;
3765 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003766 }
Eric Andersencb57d552001-06-28 07:25:16 +00003767}
3768
Eric Andersenc470f442003-07-28 09:56:35 +00003769
Eric Andersencb57d552001-06-28 07:25:16 +00003770
3771/*
3772 * Do a path search. The variable path (passed by reference) should be
3773 * set to the start of the path before the first call; padvance will update
3774 * this value as it proceeds. Successive calls to padvance will return
3775 * the possible path expansions in sequence. If an option (indicated by
3776 * a percent sign) appears in the path entry then the global variable
3777 * pathopt will be set to point to it; otherwise pathopt will be set to
3778 * NULL.
3779 */
3780
Eric Andersenc470f442003-07-28 09:56:35 +00003781static char *
3782padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003783{
Eric Andersencb57d552001-06-28 07:25:16 +00003784 const char *p;
3785 char *q;
3786 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003787 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003788
3789 if (*path == NULL)
3790 return NULL;
3791 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003792 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3793 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003794 while (stackblocksize() < len)
3795 growstackblock();
3796 q = stackblock();
3797 if (p != start) {
3798 memcpy(q, start, p - start);
3799 q += p - start;
3800 *q++ = '/';
3801 }
3802 strcpy(q, name);
3803 pathopt = NULL;
3804 if (*p == '%') {
3805 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003806 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003807 }
3808 if (*p == ':')
3809 *path = p + 1;
3810 else
3811 *path = NULL;
3812 return stalloc(len);
3813}
3814
3815
Eric Andersencb57d552001-06-28 07:25:16 +00003816/*** Command hashing code ***/
3817
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003818static void
3819printentry(struct tblentry *cmdp)
3820{
3821 int idx;
3822 const char *path;
3823 char *name;
3824
3825 idx = cmdp->param.index;
3826 path = pathval();
3827 do {
3828 name = padvance(&path, cmdp->cmdname);
3829 stunalloc(name);
3830 } while (--idx >= 0);
3831 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3832}
3833
Eric Andersenc470f442003-07-28 09:56:35 +00003834
3835static int
3836hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003837{
3838 struct tblentry **pp;
3839 struct tblentry *cmdp;
3840 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003841 struct cmdentry entry;
3842 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003843
Eric Andersenc470f442003-07-28 09:56:35 +00003844 while ((c = nextopt("r")) != '\0') {
3845 clearcmdentry(0);
3846 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003847 }
3848 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003849 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3850 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3851 if (cmdp->cmdtype == CMDNORMAL)
3852 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003853 }
3854 }
3855 return 0;
3856 }
3857 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003858 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003859 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003860 && (cmdp->cmdtype == CMDNORMAL
3861 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003862 delete_cmd_entry();
3863 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003864 if (entry.cmdtype == CMDUNKNOWN)
3865 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003866 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003867 }
3868 return c;
3869}
3870
Eric Andersenc470f442003-07-28 09:56:35 +00003871
Eric Andersencb57d552001-06-28 07:25:16 +00003872/*
3873 * Resolve a command name. If you change this routine, you may have to
3874 * change the shellexec routine as well.
3875 */
3876
3877static void
Eric Andersenc470f442003-07-28 09:56:35 +00003878find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003879{
3880 struct tblentry *cmdp;
3881 int idx;
3882 int prev;
3883 char *fullname;
3884 struct stat statb;
3885 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003886 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003887 struct builtincmd *bcmd;
3888
Eric Andersenc470f442003-07-28 09:56:35 +00003889 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003890 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003891 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003892 if (act & DO_ABS) {
3893 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003894#ifdef SYSV
3895 if (errno == EINTR)
3896 continue;
3897#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003898 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003899 return;
3900 }
Eric Andersencb57d552001-06-28 07:25:16 +00003901 }
3902 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003903 return;
3904 }
3905
Eric Andersenbf8bf102002-09-17 08:41:08 +00003906#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3907 if (find_applet_by_name(name)) {
3908 entry->cmdtype = CMDNORMAL;
3909 entry->u.index = -1;
3910 return;
3911 }
3912#endif
3913
Eric Andersenc470f442003-07-28 09:56:35 +00003914 updatetbl = (path == pathval());
3915 if (!updatetbl) {
3916 act |= DO_ALTPATH;
3917 if (strstr(path, "%builtin") != NULL)
3918 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003919 }
3920
Eric Andersenc470f442003-07-28 09:56:35 +00003921 /* If name is in the table, check answer will be ok */
3922 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3923 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003924
Eric Andersenc470f442003-07-28 09:56:35 +00003925 switch (cmdp->cmdtype) {
3926 default:
3927#if DEBUG
3928 abort();
3929#endif
3930 case CMDNORMAL:
3931 bit = DO_ALTPATH;
3932 break;
3933 case CMDFUNCTION:
3934 bit = DO_NOFUNC;
3935 break;
3936 case CMDBUILTIN:
3937 bit = DO_ALTBLTIN;
3938 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003939 }
Eric Andersenc470f442003-07-28 09:56:35 +00003940 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003941 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003942 cmdp = NULL;
3943 } else if (cmdp->rehash == 0)
3944 /* if not invalidated by cd, we're done */
3945 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003946 }
3947
3948 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003949 bcmd = find_builtin(name);
3950 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3951 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3952 )))
3953 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003954
3955 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003956 prev = -1; /* where to start */
3957 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003958 if (cmdp->cmdtype == CMDBUILTIN)
3959 prev = builtinloc;
3960 else
3961 prev = cmdp->param.index;
3962 }
3963
3964 e = ENOENT;
3965 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003966loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003967 while ((fullname = padvance(&path, name)) != NULL) {
3968 stunalloc(fullname);
3969 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003970 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003971 if (prefix(pathopt, "builtin")) {
3972 if (bcmd)
3973 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003974 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003975 } else if (!(act & DO_NOFUNC) &&
3976 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003977 /* handled below */
3978 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003979 /* ignore unimplemented options */
3980 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003981 }
3982 }
3983 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003984 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003985 if (idx < prev)
3986 continue;
3987 TRACE(("searchexec \"%s\": no change\n", name));
3988 goto success;
3989 }
3990 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003991#ifdef SYSV
3992 if (errno == EINTR)
3993 continue;
3994#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003995 if (errno != ENOENT && errno != ENOTDIR)
3996 e = errno;
3997 goto loop;
3998 }
Eric Andersenc470f442003-07-28 09:56:35 +00003999 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004000 if (!S_ISREG(statb.st_mode))
4001 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004002 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004003 stalloc(strlen(fullname) + 1);
4004 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004005 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4006 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004007 error("%s not defined in %s", name, fullname);
4008 stunalloc(fullname);
4009 goto success;
4010 }
Eric Andersencb57d552001-06-28 07:25:16 +00004011 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004012 if (!updatetbl) {
4013 entry->cmdtype = CMDNORMAL;
4014 entry->u.index = idx;
4015 return;
4016 }
4017 INTOFF;
4018 cmdp = cmdlookup(name, 1);
4019 cmdp->cmdtype = CMDNORMAL;
4020 cmdp->param.index = idx;
4021 INTON;
4022 goto success;
4023 }
4024
4025 /* We failed. If there was an entry for this command, delete it */
4026 if (cmdp && updatetbl)
4027 delete_cmd_entry();
4028 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004029 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004030 entry->cmdtype = CMDUNKNOWN;
4031 return;
4032
Eric Andersenc470f442003-07-28 09:56:35 +00004033builtin_success:
4034 if (!updatetbl) {
4035 entry->cmdtype = CMDBUILTIN;
4036 entry->u.cmd = bcmd;
4037 return;
4038 }
4039 INTOFF;
4040 cmdp = cmdlookup(name, 1);
4041 cmdp->cmdtype = CMDBUILTIN;
4042 cmdp->param.cmd = bcmd;
4043 INTON;
4044success:
Eric Andersencb57d552001-06-28 07:25:16 +00004045 cmdp->rehash = 0;
4046 entry->cmdtype = cmdp->cmdtype;
4047 entry->u = cmdp->param;
4048}
4049
4050
Eric Andersenc470f442003-07-28 09:56:35 +00004051/*
4052 * Wrapper around strcmp for qsort/bsearch/...
4053 */
4054static int pstrcmp(const void *a, const void *b)
4055{
4056 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4057}
Eric Andersencb57d552001-06-28 07:25:16 +00004058
4059/*
4060 * Search the table of builtin commands.
4061 */
4062
Eric Andersenc470f442003-07-28 09:56:35 +00004063static struct builtincmd *
4064find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004065{
4066 struct builtincmd *bp;
4067
Eric Andersenc470f442003-07-28 09:56:35 +00004068 bp = bsearch(
4069 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4070 pstrcmp
4071 );
Eric Andersencb57d552001-06-28 07:25:16 +00004072 return bp;
4073}
4074
4075
Eric Andersenc470f442003-07-28 09:56:35 +00004076
Eric Andersencb57d552001-06-28 07:25:16 +00004077/*
4078 * Called when a cd is done. Marks all commands so the next time they
4079 * are executed they will be rehashed.
4080 */
4081
Eric Andersenc470f442003-07-28 09:56:35 +00004082static void
4083hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004084{
Eric Andersencb57d552001-06-28 07:25:16 +00004085 struct tblentry **pp;
4086 struct tblentry *cmdp;
4087
Eric Andersenc470f442003-07-28 09:56:35 +00004088 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4089 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4090 if (cmdp->cmdtype == CMDNORMAL || (
4091 cmdp->cmdtype == CMDBUILTIN &&
4092 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4093 builtinloc > 0
4094 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004095 cmdp->rehash = 1;
4096 }
4097 }
4098}
4099
4100
4101
4102/*
Eric Andersenc470f442003-07-28 09:56:35 +00004103 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004104 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004105 * pathval() still returns the old value at this point.
4106 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004107 */
4108
Eric Andersenc470f442003-07-28 09:56:35 +00004109static void
4110changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004111{
Eric Andersenc470f442003-07-28 09:56:35 +00004112 const char *old, *new;
4113 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004114 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004115 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004116
Eric Andersenc470f442003-07-28 09:56:35 +00004117 old = pathval();
4118 new = newval;
4119 firstchange = 9999; /* assume no change */
4120 idx = 0;
4121 idx_bltin = -1;
4122 for (;;) {
4123 if (*old != *new) {
4124 firstchange = idx;
4125 if ((*old == '\0' && *new == ':')
4126 || (*old == ':' && *new == '\0'))
4127 firstchange++;
4128 old = new; /* ignore subsequent differences */
4129 }
4130 if (*new == '\0')
4131 break;
4132 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4133 idx_bltin = idx;
4134 if (*new == ':') {
4135 idx++;
4136 }
4137 new++, old++;
4138 }
4139 if (builtinloc < 0 && idx_bltin >= 0)
4140 builtinloc = idx_bltin; /* zap builtins */
4141 if (builtinloc >= 0 && idx_bltin < 0)
4142 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004143 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004144 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004145}
4146
4147
4148/*
4149 * Clear out command entries. The argument specifies the first entry in
4150 * PATH which has changed.
4151 */
4152
Eric Andersenc470f442003-07-28 09:56:35 +00004153static void
4154clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004155{
4156 struct tblentry **tblp;
4157 struct tblentry **pp;
4158 struct tblentry *cmdp;
4159
4160 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004161 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004162 pp = tblp;
4163 while ((cmdp = *pp) != NULL) {
4164 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004165 cmdp->param.index >= firstchange)
4166 || (cmdp->cmdtype == CMDBUILTIN &&
4167 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004168 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004169 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004170 } else {
4171 pp = &cmdp->next;
4172 }
4173 }
4174 }
4175 INTON;
4176}
4177
4178
Eric Andersenc470f442003-07-28 09:56:35 +00004179
Eric Andersencb57d552001-06-28 07:25:16 +00004180/*
Eric Andersencb57d552001-06-28 07:25:16 +00004181 * Locate a command in the command hash table. If "add" is nonzero,
4182 * add the command to the table if it is not already present. The
4183 * variable "lastcmdentry" is set to point to the address of the link
4184 * pointing to the entry, so that delete_cmd_entry can delete the
4185 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004186 *
4187 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004188 */
4189
Eric Andersen2870d962001-07-02 17:27:21 +00004190static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004191
Eric Andersenc470f442003-07-28 09:56:35 +00004192
4193static struct tblentry *
4194cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004195{
Eric Andersenc470f442003-07-28 09:56:35 +00004196 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004197 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004198 struct tblentry *cmdp;
4199 struct tblentry **pp;
4200
4201 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004202 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004203 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004204 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004205 hashval &= 0x7FFF;
4206 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004207 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004208 if (equal(cmdp->cmdname, name))
4209 break;
4210 pp = &cmdp->next;
4211 }
4212 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004213 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4214 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004215 cmdp->next = NULL;
4216 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004217 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004218 }
4219 lastcmdentry = pp;
4220 return cmdp;
4221}
4222
4223/*
4224 * Delete the command entry returned on the last lookup.
4225 */
4226
Eric Andersenc470f442003-07-28 09:56:35 +00004227static void
4228delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004229{
Eric Andersencb57d552001-06-28 07:25:16 +00004230 struct tblentry *cmdp;
4231
4232 INTOFF;
4233 cmdp = *lastcmdentry;
4234 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004235 if (cmdp->cmdtype == CMDFUNCTION)
4236 freefunc(cmdp->param.func);
4237 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004238 INTON;
4239}
4240
4241
Eric Andersenc470f442003-07-28 09:56:35 +00004242/*
4243 * Add a new command entry, replacing any existing command entry for
4244 * the same name - except special builtins.
4245 */
Eric Andersencb57d552001-06-28 07:25:16 +00004246
Eric Andersenc470f442003-07-28 09:56:35 +00004247static inline void
4248addcmdentry(char *name, struct cmdentry *entry)
4249{
4250 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004251
Eric Andersenc470f442003-07-28 09:56:35 +00004252 cmdp = cmdlookup(name, 1);
4253 if (cmdp->cmdtype == CMDFUNCTION) {
4254 freefunc(cmdp->param.func);
4255 }
4256 cmdp->cmdtype = entry->cmdtype;
4257 cmdp->param = entry->u;
4258 cmdp->rehash = 0;
4259}
Eric Andersencb57d552001-06-28 07:25:16 +00004260
Eric Andersenc470f442003-07-28 09:56:35 +00004261/*
4262 * Make a copy of a parse tree.
4263 */
Eric Andersencb57d552001-06-28 07:25:16 +00004264
Eric Andersenc470f442003-07-28 09:56:35 +00004265static inline struct funcnode *
4266copyfunc(union node *n)
4267{
4268 struct funcnode *f;
4269 size_t blocksize;
4270
4271 funcblocksize = offsetof(struct funcnode, n);
4272 funcstringsize = 0;
4273 calcsize(n);
4274 blocksize = funcblocksize;
4275 f = ckmalloc(blocksize + funcstringsize);
4276 funcblock = (char *) f + offsetof(struct funcnode, n);
4277 funcstring = (char *) f + blocksize;
4278 copynode(n);
4279 f->count = 0;
4280 return f;
4281}
4282
4283/*
4284 * Define a shell function.
4285 */
4286
4287static void
4288defun(char *name, union node *func)
4289{
4290 struct cmdentry entry;
4291
4292 INTOFF;
4293 entry.cmdtype = CMDFUNCTION;
4294 entry.u.func = copyfunc(func);
4295 addcmdentry(name, &entry);
4296 INTON;
4297}
Eric Andersencb57d552001-06-28 07:25:16 +00004298
4299
4300/*
4301 * Delete a function if it exists.
4302 */
4303
Eric Andersenc470f442003-07-28 09:56:35 +00004304static void
4305unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004306{
Eric Andersencb57d552001-06-28 07:25:16 +00004307 struct tblentry *cmdp;
4308
Eric Andersenc470f442003-07-28 09:56:35 +00004309 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4310 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004311 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004312}
4313
Eric Andersen2870d962001-07-02 17:27:21 +00004314/*
Eric Andersencb57d552001-06-28 07:25:16 +00004315 * Locate and print what a word is...
4316 */
4317
Eric Andersenc470f442003-07-28 09:56:35 +00004318
4319#ifdef CONFIG_ASH_CMDCMD
4320static int
4321describe_command(char *command, int describe_command_verbose)
4322#else
4323#define describe_command_verbose 1
4324static int
4325describe_command(char *command)
4326#endif
4327{
4328 struct cmdentry entry;
4329 struct tblentry *cmdp;
4330#ifdef CONFIG_ASH_ALIAS
4331 const struct alias *ap;
4332#endif
4333 const char *path = pathval();
4334
4335 if (describe_command_verbose) {
4336 out1str(command);
4337 }
4338
4339 /* First look at the keywords */
4340 if (findkwd(command)) {
4341 out1str(describe_command_verbose ? " is a shell keyword" : command);
4342 goto out;
4343 }
4344
4345#ifdef CONFIG_ASH_ALIAS
4346 /* Then look at the aliases */
4347 if ((ap = lookupalias(command, 0)) != NULL) {
4348 if (describe_command_verbose) {
4349 out1fmt(" is an alias for %s", ap->val);
4350 } else {
4351 out1str("alias ");
4352 printalias(ap);
4353 return 0;
4354 }
4355 goto out;
4356 }
4357#endif
4358 /* Then check if it is a tracked alias */
4359 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4360 entry.cmdtype = cmdp->cmdtype;
4361 entry.u = cmdp->param;
4362 } else {
4363 /* Finally use brute force */
4364 find_command(command, &entry, DO_ABS, path);
4365 }
4366
4367 switch (entry.cmdtype) {
4368 case CMDNORMAL: {
4369 int j = entry.u.index;
4370 char *p;
4371 if (j == -1) {
4372 p = command;
4373 } else {
4374 do {
4375 p = padvance(&path, command);
4376 stunalloc(p);
4377 } while (--j >= 0);
4378 }
4379 if (describe_command_verbose) {
4380 out1fmt(" is%s %s",
4381 (cmdp ? " a tracked alias for" : nullstr), p
4382 );
4383 } else {
4384 out1str(p);
4385 }
4386 break;
4387 }
4388
4389 case CMDFUNCTION:
4390 if (describe_command_verbose) {
4391 out1str(" is a shell function");
4392 } else {
4393 out1str(command);
4394 }
4395 break;
4396
4397 case CMDBUILTIN:
4398 if (describe_command_verbose) {
4399 out1fmt(" is a %sshell builtin",
4400 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4401 "special " : nullstr
4402 );
4403 } else {
4404 out1str(command);
4405 }
4406 break;
4407
4408 default:
4409 if (describe_command_verbose) {
4410 out1str(": not found\n");
4411 }
4412 return 127;
4413 }
4414
4415out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004416 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004417 return 0;
4418}
4419
4420static int
4421typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004422{
4423 int i;
4424 int err = 0;
4425
4426 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004427#ifdef CONFIG_ASH_CMDCMD
4428 err |= describe_command(argv[i], 1);
4429#else
4430 err |= describe_command(argv[i]);
4431#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004432 }
4433 return err;
4434}
4435
Eric Andersend35c5df2002-01-09 15:37:36 +00004436#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004437static int
4438commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004439{
4440 int c;
4441 int default_path = 0;
4442 int verify_only = 0;
4443 int verbose_verify_only = 0;
4444
4445 while ((c = nextopt("pvV")) != '\0')
4446 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004447 default:
4448#ifdef DEBUG
4449 fprintf(stderr,
4450"command: nextopt returned character code 0%o\n", c);
4451 return EX_SOFTWARE;
4452#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004453 case 'p':
4454 default_path = 1;
4455 break;
4456 case 'v':
4457 verify_only = 1;
4458 break;
4459 case 'V':
4460 verbose_verify_only = 1;
4461 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004462 }
4463
Eric Andersenc470f442003-07-28 09:56:35 +00004464 if (default_path + verify_only + verbose_verify_only > 1 ||
4465 !*argptr) {
4466 fprintf(stderr,
4467 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004468 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004469 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004470 }
4471
Eric Andersencb57d552001-06-28 07:25:16 +00004472 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004473 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004474 }
Eric Andersencb57d552001-06-28 07:25:16 +00004475
4476 return 0;
4477}
Eric Andersen2870d962001-07-02 17:27:21 +00004478#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004479
Eric Andersenc470f442003-07-28 09:56:35 +00004480/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004481
Eric Andersencb57d552001-06-28 07:25:16 +00004482/*
4483 * Routines to expand arguments to commands. We have to deal with
4484 * backquotes, shell variables, and file metacharacters.
4485 */
Eric Andersenc470f442003-07-28 09:56:35 +00004486
Eric Andersencb57d552001-06-28 07:25:16 +00004487/*
4488 * _rmescape() flags
4489 */
Eric Andersenc470f442003-07-28 09:56:35 +00004490#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4491#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4492#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4493#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4494#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004495
4496/*
4497 * Structure specifying which parts of the string should be searched
4498 * for IFS characters.
4499 */
4500
4501struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004502 struct ifsregion *next; /* next region in list */
4503 int begoff; /* offset of start of region */
4504 int endoff; /* offset of end of region */
4505 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004506};
4507
Eric Andersenc470f442003-07-28 09:56:35 +00004508/* output of current string */
4509static char *expdest;
4510/* list of back quote expressions */
4511static struct nodelist *argbackq;
4512/* first struct in list of ifs regions */
4513static struct ifsregion ifsfirst;
4514/* last struct in list */
4515static struct ifsregion *ifslastp;
4516/* holds expanded arg list */
4517static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004518
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004519static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004520static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004521static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004522static const char *subevalvar(char *, char *, int, int, int, int, int);
4523static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004524static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004525static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004526static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004527static void recordregion(int, int, int);
4528static void removerecordregions(int);
4529static void ifsbreakup(char *, struct arglist *);
4530static void ifsfree(void);
4531static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004532static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004533
Eric Andersenc470f442003-07-28 09:56:35 +00004534static int cvtnum(long);
4535static size_t esclen(const char *, const char *);
4536static char *scanleft(char *, char *, char *, char *, int, int);
4537static char *scanright(char *, char *, char *, char *, int, int);
4538static void varunset(const char *, const char *, const char *, int)
4539 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004540
Eric Andersenc470f442003-07-28 09:56:35 +00004541
4542#define pmatch(a, b) !fnmatch((a), (b), 0)
4543/*
Eric Andersen90898442003-08-06 11:20:52 +00004544 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004545 *
4546 * Returns an stalloced string.
4547 */
4548
4549static inline char *
4550preglob(const char *pattern, int quoted, int flag) {
4551 flag |= RMESCAPE_GLOB;
4552 if (quoted) {
4553 flag |= RMESCAPE_QUOTED;
4554 }
4555 return _rmescapes((char *)pattern, flag);
4556}
4557
4558
4559static size_t
4560esclen(const char *start, const char *p) {
4561 size_t esc = 0;
4562
4563 while (p > start && *--p == CTLESC) {
4564 esc++;
4565 }
4566 return esc;
4567}
4568
Eric Andersencb57d552001-06-28 07:25:16 +00004569
4570/*
4571 * Expand shell variables and backquotes inside a here document.
4572 */
4573
Eric Andersenc470f442003-07-28 09:56:35 +00004574static inline void
4575expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004576{
Eric Andersencb57d552001-06-28 07:25:16 +00004577 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004578 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004579 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004580}
4581
4582
4583/*
4584 * Perform variable substitution and command substitution on an argument,
4585 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4586 * perform splitting and file name expansion. When arglist is NULL, perform
4587 * here document expansion.
4588 */
4589
Eric Andersenc470f442003-07-28 09:56:35 +00004590void
4591expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004592{
4593 struct strlist *sp;
4594 char *p;
4595
4596 argbackq = arg->narg.backquote;
4597 STARTSTACKSTR(expdest);
4598 ifsfirst.next = NULL;
4599 ifslastp = NULL;
4600 argstr(arg->narg.text, flag);
4601 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004602 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004603 }
4604 STPUTC('\0', expdest);
4605 p = grabstackstr(expdest);
4606 exparg.lastp = &exparg.list;
4607 /*
4608 * TODO - EXP_REDIR
4609 */
4610 if (flag & EXP_FULL) {
4611 ifsbreakup(p, &exparg);
4612 *exparg.lastp = NULL;
4613 exparg.lastp = &exparg.list;
4614 expandmeta(exparg.list, flag);
4615 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004616 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004617 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004618 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004619 sp->text = p;
4620 *exparg.lastp = sp;
4621 exparg.lastp = &sp->next;
4622 }
Eric Andersenc470f442003-07-28 09:56:35 +00004623 if (ifsfirst.next)
4624 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004625 *exparg.lastp = NULL;
4626 if (exparg.list) {
4627 *arglist->lastp = exparg.list;
4628 arglist->lastp = exparg.lastp;
4629 }
4630}
4631
4632
Eric Andersenc470f442003-07-28 09:56:35 +00004633/*
4634 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4635 * characters to allow for further processing. Otherwise treat
4636 * $@ like $* since no splitting will be performed.
4637 */
4638
4639static void
4640argstr(char *p, int flag)
4641{
4642 static const char spclchars[] = {
4643 '=',
4644 ':',
4645 CTLQUOTEMARK,
4646 CTLENDVAR,
4647 CTLESC,
4648 CTLVAR,
4649 CTLBACKQ,
4650 CTLBACKQ | CTLQUOTE,
4651#ifdef CONFIG_ASH_MATH_SUPPORT
4652 CTLENDARI,
4653#endif
4654 0
4655 };
4656 const char *reject = spclchars;
4657 int c;
4658 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4659 int breakall = flag & EXP_WORD;
4660 int inquotes;
4661 size_t length;
4662 int startloc;
4663
4664 if (!(flag & EXP_VARTILDE)) {
4665 reject += 2;
4666 } else if (flag & EXP_VARTILDE2) {
4667 reject++;
4668 }
4669 inquotes = 0;
4670 length = 0;
4671 if (flag & EXP_TILDE) {
4672 char *q;
4673
4674 flag &= ~EXP_TILDE;
4675tilde:
4676 q = p;
4677 if (*q == CTLESC && (flag & EXP_QWORD))
4678 q++;
4679 if (*q == '~')
4680 p = exptilde(p, q, flag);
4681 }
4682start:
4683 startloc = expdest - (char *)stackblock();
4684 for (;;) {
4685 length += strcspn(p + length, reject);
4686 c = p[length];
4687 if (c && (!(c & 0x80)
4688#ifdef CONFIG_ASH_MATH_SUPPORT
4689 || c == CTLENDARI
4690#endif
4691 )) {
4692 /* c == '=' || c == ':' || c == CTLENDARI */
4693 length++;
4694 }
4695 if (length > 0) {
4696 int newloc;
4697 expdest = stnputs(p, length, expdest);
4698 newloc = expdest - (char *)stackblock();
4699 if (breakall && !inquotes && newloc > startloc) {
4700 recordregion(startloc, newloc, 0);
4701 }
4702 startloc = newloc;
4703 }
4704 p += length + 1;
4705 length = 0;
4706
4707 switch (c) {
4708 case '\0':
4709 goto breakloop;
4710 case '=':
4711 if (flag & EXP_VARTILDE2) {
4712 p--;
4713 continue;
4714 }
4715 flag |= EXP_VARTILDE2;
4716 reject++;
4717 /* fall through */
4718 case ':':
4719 /*
4720 * sort of a hack - expand tildes in variable
4721 * assignments (after the first '=' and after ':'s).
4722 */
4723 if (*--p == '~') {
4724 goto tilde;
4725 }
4726 continue;
4727 }
4728
4729 switch (c) {
4730 case CTLENDVAR: /* ??? */
4731 goto breakloop;
4732 case CTLQUOTEMARK:
4733 /* "$@" syntax adherence hack */
4734 if (
4735 !inquotes &&
4736 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4737 (p[4] == CTLQUOTEMARK || (
4738 p[4] == CTLENDVAR &&
4739 p[5] == CTLQUOTEMARK
4740 ))
4741 ) {
4742 p = evalvar(p + 1, flag) + 1;
4743 goto start;
4744 }
4745 inquotes = !inquotes;
4746addquote:
4747 if (quotes) {
4748 p--;
4749 length++;
4750 startloc++;
4751 }
4752 break;
4753 case CTLESC:
4754 startloc++;
4755 length++;
4756 goto addquote;
4757 case CTLVAR:
4758 p = evalvar(p, flag);
4759 goto start;
4760 case CTLBACKQ:
4761 c = 0;
4762 case CTLBACKQ|CTLQUOTE:
4763 expbackq(argbackq->n, c, quotes);
4764 argbackq = argbackq->next;
4765 goto start;
4766#ifdef CONFIG_ASH_MATH_SUPPORT
4767 case CTLENDARI:
4768 p--;
4769 expari(quotes);
4770 goto start;
4771#endif
4772 }
4773 }
4774breakloop:
4775 ;
4776}
4777
4778static char *
4779exptilde(char *startp, char *p, int flag)
4780{
4781 char c;
4782 char *name;
4783 struct passwd *pw;
4784 const char *home;
4785 int quotes = flag & (EXP_FULL | EXP_CASE);
4786 int startloc;
4787
4788 name = p + 1;
4789
4790 while ((c = *++p) != '\0') {
4791 switch(c) {
4792 case CTLESC:
4793 return (startp);
4794 case CTLQUOTEMARK:
4795 return (startp);
4796 case ':':
4797 if (flag & EXP_VARTILDE)
4798 goto done;
4799 break;
4800 case '/':
4801 case CTLENDVAR:
4802 goto done;
4803 }
4804 }
4805done:
4806 *p = '\0';
4807 if (*name == '\0') {
4808 if ((home = lookupvar(homestr)) == NULL)
4809 goto lose;
4810 } else {
4811 if ((pw = getpwnam(name)) == NULL)
4812 goto lose;
4813 home = pw->pw_dir;
4814 }
4815 if (*home == '\0')
4816 goto lose;
4817 *p = c;
4818 startloc = expdest - (char *)stackblock();
4819 strtodest(home, SQSYNTAX, quotes);
4820 recordregion(startloc, expdest - (char *)stackblock(), 0);
4821 return (p);
4822lose:
4823 *p = c;
4824 return (startp);
4825}
4826
4827
4828static void
4829removerecordregions(int endoff)
4830{
4831 if (ifslastp == NULL)
4832 return;
4833
4834 if (ifsfirst.endoff > endoff) {
4835 while (ifsfirst.next != NULL) {
4836 struct ifsregion *ifsp;
4837 INTOFF;
4838 ifsp = ifsfirst.next->next;
4839 ckfree(ifsfirst.next);
4840 ifsfirst.next = ifsp;
4841 INTON;
4842 }
4843 if (ifsfirst.begoff > endoff)
4844 ifslastp = NULL;
4845 else {
4846 ifslastp = &ifsfirst;
4847 ifsfirst.endoff = endoff;
4848 }
4849 return;
4850 }
4851
4852 ifslastp = &ifsfirst;
4853 while (ifslastp->next && ifslastp->next->begoff < endoff)
4854 ifslastp=ifslastp->next;
4855 while (ifslastp->next != NULL) {
4856 struct ifsregion *ifsp;
4857 INTOFF;
4858 ifsp = ifslastp->next->next;
4859 ckfree(ifslastp->next);
4860 ifslastp->next = ifsp;
4861 INTON;
4862 }
4863 if (ifslastp->endoff > endoff)
4864 ifslastp->endoff = endoff;
4865}
4866
4867
4868#ifdef CONFIG_ASH_MATH_SUPPORT
4869/*
4870 * Expand arithmetic expression. Backup to start of expression,
4871 * evaluate, place result in (backed up) result, adjust string position.
4872 */
4873void
4874expari(int quotes)
4875{
4876 char *p, *start;
4877 int begoff;
4878 int flag;
4879 int len;
4880
4881 /* ifsfree(); */
4882
4883 /*
4884 * This routine is slightly over-complicated for
4885 * efficiency. Next we scan backwards looking for the
4886 * start of arithmetic.
4887 */
4888 start = stackblock();
4889 p = expdest - 1;
4890 *p = '\0';
4891 p--;
4892 do {
4893 int esc;
4894
4895 while (*p != CTLARI) {
4896 p--;
4897#ifdef DEBUG
4898 if (p < start) {
4899 error("missing CTLARI (shouldn't happen)");
4900 }
4901#endif
4902 }
4903
4904 esc = esclen(start, p);
4905 if (!(esc % 2)) {
4906 break;
4907 }
4908
4909 p -= esc + 1;
4910 } while (1);
4911
4912 begoff = p - start;
4913
4914 removerecordregions(begoff);
4915
4916 flag = p[1];
4917
4918 expdest = p;
4919
4920 if (quotes)
4921 rmescapes(p + 2);
4922
4923 len = cvtnum(dash_arith(p + 2));
4924
4925 if (flag != '"')
4926 recordregion(begoff, begoff + len, 0);
4927}
4928#endif
4929
4930/*
4931 * Expand stuff in backwards quotes.
4932 */
4933
4934static void
4935expbackq(union node *cmd, int quoted, int quotes)
4936{
4937 struct backcmd in;
4938 int i;
4939 char buf[128];
4940 char *p;
4941 char *dest;
4942 int startloc;
4943 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4944 struct stackmark smark;
4945
4946 INTOFF;
4947 setstackmark(&smark);
4948 dest = expdest;
4949 startloc = dest - (char *)stackblock();
4950 grabstackstr(dest);
4951 evalbackcmd(cmd, (struct backcmd *) &in);
4952 popstackmark(&smark);
4953
4954 p = in.buf;
4955 i = in.nleft;
4956 if (i == 0)
4957 goto read;
4958 for (;;) {
4959 memtodest(p, i, syntax, quotes);
4960read:
4961 if (in.fd < 0)
4962 break;
4963 i = safe_read(in.fd, buf, sizeof buf);
4964 TRACE(("expbackq: read returns %d\n", i));
4965 if (i <= 0)
4966 break;
4967 p = buf;
4968 }
4969
4970 if (in.buf)
4971 ckfree(in.buf);
4972 if (in.fd >= 0) {
4973 close(in.fd);
4974 back_exitstatus = waitforjob(in.jp);
4975 }
4976 INTON;
4977
4978 /* Eat all trailing newlines */
4979 dest = expdest;
4980 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4981 STUNPUTC(dest);
4982 expdest = dest;
4983
4984 if (quoted == 0)
4985 recordregion(startloc, dest - (char *)stackblock(), 0);
4986 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4987 (dest - (char *)stackblock()) - startloc,
4988 (dest - (char *)stackblock()) - startloc,
4989 stackblock() + startloc));
4990}
4991
4992
4993static char *
Eric Andersen90898442003-08-06 11:20:52 +00004994scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4995 int zero)
4996{
Eric Andersenc470f442003-07-28 09:56:35 +00004997 char *loc;
4998 char *loc2;
4999 char c;
5000
5001 loc = startp;
5002 loc2 = rmesc;
5003 do {
5004 int match;
5005 const char *s = loc2;
5006 c = *loc2;
5007 if (zero) {
5008 *loc2 = '\0';
5009 s = rmesc;
5010 }
5011 match = pmatch(str, s);
5012 *loc2 = c;
5013 if (match)
5014 return loc;
5015 if (quotes && *loc == CTLESC)
5016 loc++;
5017 loc++;
5018 loc2++;
5019 } while (c);
5020 return 0;
5021}
5022
5023
5024static char *
Eric Andersen90898442003-08-06 11:20:52 +00005025scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5026 int zero)
5027{
Eric Andersenc470f442003-07-28 09:56:35 +00005028 int esc = 0;
5029 char *loc;
5030 char *loc2;
5031
5032 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5033 int match;
5034 char c = *loc2;
5035 const char *s = loc2;
5036 if (zero) {
5037 *loc2 = '\0';
5038 s = rmesc;
5039 }
5040 match = pmatch(str, s);
5041 *loc2 = c;
5042 if (match)
5043 return loc;
5044 loc--;
5045 if (quotes) {
5046 if (--esc < 0) {
5047 esc = esclen(startp, loc);
5048 }
5049 if (esc % 2) {
5050 esc--;
5051 loc--;
5052 }
5053 }
5054 }
5055 return 0;
5056}
5057
5058static const char *
5059subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5060{
5061 char *startp;
5062 char *loc;
5063 int saveherefd = herefd;
5064 struct nodelist *saveargbackq = argbackq;
5065 int amount;
5066 char *rmesc, *rmescend;
5067 int zero;
5068 char *(*scan)(char *, char *, char *, char *, int , int);
5069
5070 herefd = -1;
5071 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5072 STPUTC('\0', expdest);
5073 herefd = saveherefd;
5074 argbackq = saveargbackq;
5075 startp = stackblock() + startloc;
5076
5077 switch (subtype) {
5078 case VSASSIGN:
5079 setvar(str, startp, 0);
5080 amount = startp - expdest;
5081 STADJUST(amount, expdest);
5082 return startp;
5083
5084 case VSQUESTION:
5085 varunset(p, str, startp, varflags);
5086 /* NOTREACHED */
5087 }
5088
5089 subtype -= VSTRIMRIGHT;
5090#ifdef DEBUG
5091 if (subtype < 0 || subtype > 3)
5092 abort();
5093#endif
5094
5095 rmesc = startp;
5096 rmescend = stackblock() + strloc;
5097 if (quotes) {
5098 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5099 if (rmesc != startp) {
5100 rmescend = expdest;
5101 startp = stackblock() + startloc;
5102 }
5103 }
5104 rmescend--;
5105 str = stackblock() + strloc;
5106 preglob(str, varflags & VSQUOTE, 0);
5107
5108 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5109 zero = subtype >> 1;
5110 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5111 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5112
5113 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5114 if (loc) {
5115 if (zero) {
5116 memmove(startp, loc, str - loc);
5117 loc = startp + (str - loc) - 1;
5118 }
5119 *loc = '\0';
5120 amount = loc - expdest;
5121 STADJUST(amount, expdest);
5122 }
5123 return loc;
5124}
5125
5126
Eric Andersen62483552001-07-10 06:09:16 +00005127/*
5128 * Expand a variable, and return a pointer to the next character in the
5129 * input string.
5130 */
Eric Andersenc470f442003-07-28 09:56:35 +00005131static char *
5132evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005133{
5134 int subtype;
5135 int varflags;
5136 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005137 int patloc;
5138 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005139 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005140 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005141 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005142 int quotes;
5143 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005144
Eric Andersenc470f442003-07-28 09:56:35 +00005145 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005146 varflags = *p++;
5147 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005148 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005149 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005150 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005151 startloc = expdest - (char *)stackblock();
5152 p = strchr(p, '=') + 1;
5153
Eric Andersenc470f442003-07-28 09:56:35 +00005154again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005155 varlen = varvalue(var, varflags, flag);
5156 if (varflags & VSNUL)
5157 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005158
Glenn L McGrath76620622004-01-13 10:19:37 +00005159 if (subtype == VSPLUS) {
5160 varlen = -1 - varlen;
5161 goto vsplus;
5162 }
Eric Andersen62483552001-07-10 06:09:16 +00005163
Eric Andersenc470f442003-07-28 09:56:35 +00005164 if (subtype == VSMINUS) {
5165vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005166 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005167 argstr(
5168 p, flag | EXP_TILDE |
5169 (quoted ? EXP_QWORD : EXP_WORD)
5170 );
5171 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005172 }
5173 if (easy)
5174 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005175 goto end;
5176 }
Eric Andersen62483552001-07-10 06:09:16 +00005177
Eric Andersenc470f442003-07-28 09:56:35 +00005178 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005179 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005180 if (subevalvar(p, var, 0, subtype, startloc,
5181 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005182 varflags &= ~VSNUL;
5183 /*
5184 * Remove any recorded regions beyond
5185 * start of variable
5186 */
5187 removerecordregions(startloc);
5188 goto again;
5189 }
Eric Andersenc470f442003-07-28 09:56:35 +00005190 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005191 }
5192 if (easy)
5193 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005194 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005195 }
5196
Glenn L McGrath76620622004-01-13 10:19:37 +00005197 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005198 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005199
Eric Andersenc470f442003-07-28 09:56:35 +00005200 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005201 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005202 goto record;
5203 }
5204
5205 if (subtype == VSNORMAL) {
5206 if (!easy)
5207 goto end;
5208record:
5209 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5210 goto end;
5211 }
5212
5213#ifdef DEBUG
5214 switch (subtype) {
5215 case VSTRIMLEFT:
5216 case VSTRIMLEFTMAX:
5217 case VSTRIMRIGHT:
5218 case VSTRIMRIGHTMAX:
5219 break;
5220 default:
5221 abort();
5222 }
5223#endif
5224
Glenn L McGrath76620622004-01-13 10:19:37 +00005225 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005226 /*
5227 * Terminate the string and start recording the pattern
5228 * right after it
5229 */
5230 STPUTC('\0', expdest);
5231 patloc = expdest - (char *)stackblock();
5232 if (subevalvar(p, NULL, patloc, subtype,
5233 startloc, varflags, quotes) == 0) {
5234 int amount = expdest - (
5235 (char *)stackblock() + patloc - 1
5236 );
5237 STADJUST(-amount, expdest);
5238 }
5239 /* Remove any recorded regions beyond start of variable */
5240 removerecordregions(startloc);
5241 goto record;
5242 }
5243
5244end:
5245 if (subtype != VSNORMAL) { /* skip to end of alternative */
5246 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005247 for (;;) {
5248 if ((c = *p++) == CTLESC)
5249 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005250 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005251 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005252 argbackq = argbackq->next;
5253 } else if (c == CTLVAR) {
5254 if ((*p++ & VSTYPE) != VSNORMAL)
5255 nesting++;
5256 } else if (c == CTLENDVAR) {
5257 if (--nesting == 0)
5258 break;
5259 }
5260 }
5261 }
5262 return p;
5263}
5264
Eric Andersencb57d552001-06-28 07:25:16 +00005265
Eric Andersencb57d552001-06-28 07:25:16 +00005266/*
5267 * Put a string on the stack.
5268 */
5269
Eric Andersenc470f442003-07-28 09:56:35 +00005270static void
5271memtodest(const char *p, size_t len, int syntax, int quotes) {
5272 char *q = expdest;
5273
5274 q = makestrspace(len * 2, q);
5275
5276 while (len--) {
5277 int c = *p++;
5278 if (!c)
5279 continue;
5280 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5281 USTPUTC(CTLESC, q);
5282 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005283 }
Eric Andersenc470f442003-07-28 09:56:35 +00005284
5285 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005286}
5287
Eric Andersenc470f442003-07-28 09:56:35 +00005288
5289static void
5290strtodest(const char *p, int syntax, int quotes)
5291{
5292 memtodest(p, strlen(p), syntax, quotes);
5293}
5294
5295
Eric Andersencb57d552001-06-28 07:25:16 +00005296/*
5297 * Add the value of a specialized variable to the stack string.
5298 */
5299
Glenn L McGrath76620622004-01-13 10:19:37 +00005300static ssize_t
5301varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005302{
5303 int num;
5304 char *p;
5305 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005306 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005307 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005308 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005309 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005310 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005311 int quoted = varflags & VSQUOTE;
5312 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005313 int quotes = flags & (EXP_FULL | EXP_CASE);
5314
Glenn L McGrath76620622004-01-13 10:19:37 +00005315 if (quoted && (flags & EXP_FULL))
5316 sep = 1 << CHAR_BIT;
5317
Eric Andersencb57d552001-06-28 07:25:16 +00005318 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5319 switch (*name) {
5320 case '$':
5321 num = rootpid;
5322 goto numvar;
5323 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005324 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005325 goto numvar;
5326 case '#':
5327 num = shellparam.nparam;
5328 goto numvar;
5329 case '!':
5330 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005331 if (num == 0)
5332 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005333numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005334 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005335 break;
5336 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005337 p = makestrspace(NOPTS, expdest);
5338 for (i = NOPTS - 1; i >= 0; i--) {
5339 if (optlist[i]) {
5340 USTPUTC(optletters(i), p);
5341 len++;
5342 }
Eric Andersencb57d552001-06-28 07:25:16 +00005343 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005344 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005345 break;
5346 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005347 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005348 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005349 /* fall through */
5350 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005351 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005352 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5353 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005354param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005355 if (!(ap = shellparam.p))
5356 return -1;
5357 while ((p = *ap++)) {
5358 size_t partlen;
5359
5360 partlen = strlen(p);
5361
5362 len += partlen;
5363 if (len > partlen && sep) {
5364 char *q;
5365
5366 len++;
5367 if (subtype == VSPLUS || subtype == VSLENGTH) {
5368 continue;
5369 }
5370 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005371 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005372 STPUTC(CTLESC, q);
5373 STPUTC(sep, q);
5374 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005375 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005376
5377 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5378 memtodest(p, partlen, syntax, quotes);
Eric Andersencb57d552001-06-28 07:25:16 +00005379 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005380 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005381 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005382 case '1':
5383 case '2':
5384 case '3':
5385 case '4':
5386 case '5':
5387 case '6':
5388 case '7':
5389 case '8':
5390 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005391 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005392 if (num < 0 || num > shellparam.nparam)
5393 return -1;
5394 p = num ? shellparam.p[num - 1] : arg0;
5395 goto value;
5396 default:
5397 p = lookupvar(name);
5398value:
5399 if (!p)
5400 return -1;
5401
5402 len = strlen(p);
5403 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5404 memtodest(p, len, syntax, quotes);
5405 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005406 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005407
5408 if (subtype == VSPLUS || subtype == VSLENGTH)
5409 STADJUST(-len, expdest);
5410 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005411}
5412
5413
Eric Andersencb57d552001-06-28 07:25:16 +00005414/*
5415 * Record the fact that we have to scan this region of the
5416 * string for IFS characters.
5417 */
5418
Eric Andersenc470f442003-07-28 09:56:35 +00005419static void
5420recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005421{
5422 struct ifsregion *ifsp;
5423
5424 if (ifslastp == NULL) {
5425 ifsp = &ifsfirst;
5426 } else {
5427 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005428 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005429 ifsp->next = NULL;
5430 ifslastp->next = ifsp;
5431 INTON;
5432 }
5433 ifslastp = ifsp;
5434 ifslastp->begoff = start;
5435 ifslastp->endoff = end;
5436 ifslastp->nulonly = nulonly;
5437}
5438
5439
Eric Andersencb57d552001-06-28 07:25:16 +00005440/*
5441 * Break the argument string into pieces based upon IFS and add the
5442 * strings to the argument list. The regions of the string to be
5443 * searched for IFS characters have been stored by recordregion.
5444 */
Eric Andersenc470f442003-07-28 09:56:35 +00005445static void
5446ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005447{
Eric Andersencb57d552001-06-28 07:25:16 +00005448 struct ifsregion *ifsp;
5449 struct strlist *sp;
5450 char *start;
5451 char *p;
5452 char *q;
5453 const char *ifs, *realifs;
5454 int ifsspc;
5455 int nulonly;
5456
5457
5458 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005459 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005460 ifsspc = 0;
5461 nulonly = 0;
5462 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005463 ifsp = &ifsfirst;
5464 do {
5465 p = string + ifsp->begoff;
5466 nulonly = ifsp->nulonly;
5467 ifs = nulonly ? nullstr : realifs;
5468 ifsspc = 0;
5469 while (p < string + ifsp->endoff) {
5470 q = p;
5471 if (*p == CTLESC)
5472 p++;
5473 if (strchr(ifs, *p)) {
5474 if (!nulonly)
5475 ifsspc = (strchr(defifs, *p) != NULL);
5476 /* Ignore IFS whitespace at start */
5477 if (q == start && ifsspc) {
5478 p++;
5479 start = p;
5480 continue;
5481 }
5482 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005483 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005484 sp->text = start;
5485 *arglist->lastp = sp;
5486 arglist->lastp = &sp->next;
5487 p++;
5488 if (!nulonly) {
5489 for (;;) {
5490 if (p >= string + ifsp->endoff) {
5491 break;
5492 }
5493 q = p;
5494 if (*p == CTLESC)
5495 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005496 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005497 p = q;
5498 break;
5499 } else if (strchr(defifs, *p) == NULL) {
5500 if (ifsspc) {
5501 p++;
5502 ifsspc = 0;
5503 } else {
5504 p = q;
5505 break;
5506 }
5507 } else
5508 p++;
5509 }
5510 }
5511 start = p;
5512 } else
5513 p++;
5514 }
5515 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005516 if (nulonly)
5517 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005518 }
5519
Eric Andersenc470f442003-07-28 09:56:35 +00005520 if (!*start)
5521 return;
5522
5523add:
5524 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005525 sp->text = start;
5526 *arglist->lastp = sp;
5527 arglist->lastp = &sp->next;
5528}
5529
Eric Andersenc470f442003-07-28 09:56:35 +00005530static void
5531ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005532{
Eric Andersenc470f442003-07-28 09:56:35 +00005533 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005534
Eric Andersenc470f442003-07-28 09:56:35 +00005535 INTOFF;
5536 p = ifsfirst.next;
5537 do {
5538 struct ifsregion *ifsp;
5539 ifsp = p->next;
5540 ckfree(p);
5541 p = ifsp;
5542 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005543 ifslastp = NULL;
5544 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005545 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005546}
5547
Eric Andersen90898442003-08-06 11:20:52 +00005548static void expmeta(char *, char *);
5549static struct strlist *expsort(struct strlist *);
5550static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005551
Eric Andersen90898442003-08-06 11:20:52 +00005552static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005553
Eric Andersencb57d552001-06-28 07:25:16 +00005554
Eric Andersenc470f442003-07-28 09:56:35 +00005555static void
Eric Andersen90898442003-08-06 11:20:52 +00005556expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005557{
Eric Andersen90898442003-08-06 11:20:52 +00005558 static const char metachars[] = {
5559 '*', '?', '[', 0
5560 };
Eric Andersencb57d552001-06-28 07:25:16 +00005561 /* TODO - EXP_REDIR */
5562
5563 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005564 struct strlist **savelastp;
5565 struct strlist *sp;
5566 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005567
Eric Andersencb57d552001-06-28 07:25:16 +00005568 if (fflag)
5569 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005570 if (!strpbrk(str->text, metachars))
5571 goto nometa;
5572 savelastp = exparg.lastp;
5573
Eric Andersencb57d552001-06-28 07:25:16 +00005574 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005575 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005576 {
5577 int i = strlen(str->text);
5578 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5579 }
5580
5581 expmeta(expdir, p);
5582 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005583 if (p != str->text)
5584 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005585 INTON;
5586 if (exparg.lastp == savelastp) {
5587 /*
5588 * no matches
5589 */
Eric Andersenc470f442003-07-28 09:56:35 +00005590nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005591 *exparg.lastp = str;
5592 rmescapes(str->text);
5593 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005594 } else {
5595 *exparg.lastp = NULL;
5596 *savelastp = sp = expsort(*savelastp);
5597 while (sp->next != NULL)
5598 sp = sp->next;
5599 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005600 }
5601 str = str->next;
5602 }
5603}
5604
Eric Andersencb57d552001-06-28 07:25:16 +00005605/*
Eric Andersenc470f442003-07-28 09:56:35 +00005606 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005607 */
5608
Eric Andersenc470f442003-07-28 09:56:35 +00005609static void
Eric Andersen90898442003-08-06 11:20:52 +00005610addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005611{
Eric Andersencb57d552001-06-28 07:25:16 +00005612 struct strlist *sp;
5613
Eric Andersenc470f442003-07-28 09:56:35 +00005614 sp = (struct strlist *)stalloc(sizeof *sp);
5615 sp->text = sstrdup(name);
5616 *exparg.lastp = sp;
5617 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005618}
5619
5620
Eric Andersencb57d552001-06-28 07:25:16 +00005621/*
Eric Andersen90898442003-08-06 11:20:52 +00005622 * Do metacharacter (i.e. *, ?, [...]) expansion.
5623 */
5624
5625static void
5626expmeta(char *enddir, char *name)
5627{
5628 char *p;
5629 const char *cp;
5630 char *start;
5631 char *endname;
5632 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005633 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005634 DIR *dirp;
5635 struct dirent *dp;
5636 int atend;
5637 int matchdot;
5638
5639 metaflag = 0;
5640 start = name;
5641 for (p = name; *p; p++) {
5642 if (*p == '*' || *p == '?')
5643 metaflag = 1;
5644 else if (*p == '[') {
5645 char *q = p + 1;
5646 if (*q == '!')
5647 q++;
5648 for (;;) {
5649 if (*q == '\\')
5650 q++;
5651 if (*q == '/' || *q == '\0')
5652 break;
5653 if (*++q == ']') {
5654 metaflag = 1;
5655 break;
5656 }
5657 }
5658 } else if (*p == '\\')
5659 p++;
5660 else if (*p == '/') {
5661 if (metaflag)
5662 goto out;
5663 start = p + 1;
5664 }
5665 }
5666out:
5667 if (metaflag == 0) { /* we've reached the end of the file name */
5668 if (enddir != expdir)
5669 metaflag++;
5670 p = name;
5671 do {
5672 if (*p == '\\')
5673 p++;
5674 *enddir++ = *p;
5675 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005676 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005677 addfname(expdir);
5678 return;
5679 }
5680 endname = p;
5681 if (name < start) {
5682 p = name;
5683 do {
5684 if (*p == '\\')
5685 p++;
5686 *enddir++ = *p++;
5687 } while (p < start);
5688 }
5689 if (enddir == expdir) {
5690 cp = ".";
5691 } else if (enddir == expdir + 1 && *expdir == '/') {
5692 cp = "/";
5693 } else {
5694 cp = expdir;
5695 enddir[-1] = '\0';
5696 }
5697 if ((dirp = opendir(cp)) == NULL)
5698 return;
5699 if (enddir != expdir)
5700 enddir[-1] = '/';
5701 if (*endname == 0) {
5702 atend = 1;
5703 } else {
5704 atend = 0;
5705 *endname++ = '\0';
5706 }
5707 matchdot = 0;
5708 p = start;
5709 if (*p == '\\')
5710 p++;
5711 if (*p == '.')
5712 matchdot++;
5713 while (! intpending && (dp = readdir(dirp)) != NULL) {
5714 if (dp->d_name[0] == '.' && ! matchdot)
5715 continue;
5716 if (pmatch(start, dp->d_name)) {
5717 if (atend) {
5718 scopy(dp->d_name, enddir);
5719 addfname(expdir);
5720 } else {
5721 for (p = enddir, cp = dp->d_name;
5722 (*p++ = *cp++) != '\0';)
5723 continue;
5724 p[-1] = '/';
5725 expmeta(p, endname);
5726 }
5727 }
5728 }
5729 closedir(dirp);
5730 if (! atend)
5731 endname[-1] = '/';
5732}
5733
5734/*
5735 * Sort the results of file name expansion. It calculates the number of
5736 * strings to sort and then calls msort (short for merge sort) to do the
5737 * work.
5738 */
5739
5740static struct strlist *
5741expsort(struct strlist *str)
5742{
5743 int len;
5744 struct strlist *sp;
5745
5746 len = 0;
5747 for (sp = str ; sp ; sp = sp->next)
5748 len++;
5749 return msort(str, len);
5750}
5751
5752
5753static struct strlist *
5754msort(struct strlist *list, int len)
5755{
5756 struct strlist *p, *q = NULL;
5757 struct strlist **lpp;
5758 int half;
5759 int n;
5760
5761 if (len <= 1)
5762 return list;
5763 half = len >> 1;
5764 p = list;
5765 for (n = half ; --n >= 0 ; ) {
5766 q = p;
5767 p = p->next;
5768 }
5769 q->next = NULL; /* terminate first half of list */
5770 q = msort(list, half); /* sort first half of list */
5771 p = msort(p, len - half); /* sort second half */
5772 lpp = &list;
5773 for (;;) {
5774#ifdef CONFIG_LOCALE_SUPPORT
5775 if (strcoll(p->text, q->text) < 0)
5776#else
5777 if (strcmp(p->text, q->text) < 0)
5778#endif
5779 {
5780 *lpp = p;
5781 lpp = &p->next;
5782 if ((p = *lpp) == NULL) {
5783 *lpp = q;
5784 break;
5785 }
5786 } else {
5787 *lpp = q;
5788 lpp = &q->next;
5789 if ((q = *lpp) == NULL) {
5790 *lpp = p;
5791 break;
5792 }
5793 }
5794 }
5795 return list;
5796}
5797
5798
5799/*
Eric Andersencb57d552001-06-28 07:25:16 +00005800 * Returns true if the pattern matches the string.
5801 */
5802
Eric Andersenc470f442003-07-28 09:56:35 +00005803static inline int
5804patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005805{
Eric Andersenc470f442003-07-28 09:56:35 +00005806 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005807}
5808
5809
Eric Andersencb57d552001-06-28 07:25:16 +00005810/*
5811 * Remove any CTLESC characters from a string.
5812 */
5813
Eric Andersenc470f442003-07-28 09:56:35 +00005814static char *
5815_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005816{
5817 char *p, *q, *r;
5818 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005819 unsigned inquotes;
5820 int notescaped;
5821 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005822
5823 p = strpbrk(str, qchars);
5824 if (!p) {
5825 return str;
5826 }
5827 q = p;
5828 r = str;
5829 if (flag & RMESCAPE_ALLOC) {
5830 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005831 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005832
Eric Andersenc470f442003-07-28 09:56:35 +00005833 if (flag & RMESCAPE_GROW) {
5834 r = makestrspace(fulllen, expdest);
5835 } else if (flag & RMESCAPE_HEAP) {
5836 r = ckmalloc(fulllen);
5837 } else {
5838 r = stalloc(fulllen);
5839 }
5840 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005841 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005842 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005843 }
5844 }
Eric Andersenc470f442003-07-28 09:56:35 +00005845 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5846 globbing = flag & RMESCAPE_GLOB;
5847 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005848 while (*p) {
5849 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005850 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005851 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005852 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005853 continue;
5854 }
Eric Andersenc470f442003-07-28 09:56:35 +00005855 if (*p == '\\') {
5856 /* naked back slash */
5857 notescaped = 0;
5858 goto copy;
5859 }
Eric Andersencb57d552001-06-28 07:25:16 +00005860 if (*p == CTLESC) {
5861 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005862 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005863 *q++ = '\\';
5864 }
5865 }
Eric Andersenc470f442003-07-28 09:56:35 +00005866 notescaped = globbing;
5867copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005868 *q++ = *p++;
5869 }
5870 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005871 if (flag & RMESCAPE_GROW) {
5872 expdest = r;
5873 STADJUST(q - r + 1, expdest);
5874 }
Eric Andersencb57d552001-06-28 07:25:16 +00005875 return r;
5876}
Eric Andersencb57d552001-06-28 07:25:16 +00005877
5878
Eric Andersencb57d552001-06-28 07:25:16 +00005879/*
5880 * See if a pattern matches in a case statement.
5881 */
5882
Eric Andersenc470f442003-07-28 09:56:35 +00005883int
5884casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005885{
Eric Andersencb57d552001-06-28 07:25:16 +00005886 struct stackmark smark;
5887 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005888
5889 setstackmark(&smark);
5890 argbackq = pattern->narg.backquote;
5891 STARTSTACKSTR(expdest);
5892 ifslastp = NULL;
5893 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005894 STACKSTRNUL(expdest);
5895 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005896 popstackmark(&smark);
5897 return result;
5898}
5899
5900/*
5901 * Our own itoa().
5902 */
5903
Eric Andersenc470f442003-07-28 09:56:35 +00005904static int
5905cvtnum(long num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005906{
Eric Andersencb57d552001-06-28 07:25:16 +00005907 int len;
5908
Eric Andersenc470f442003-07-28 09:56:35 +00005909 expdest = makestrspace(32, expdest);
5910 len = fmtstr(expdest, 32, "%ld", num);
5911 STADJUST(len, expdest);
5912 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005913}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005914
Eric Andersenc470f442003-07-28 09:56:35 +00005915static void
5916varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005917{
Eric Andersenc470f442003-07-28 09:56:35 +00005918 const char *msg;
5919 const char *tail;
5920
5921 tail = nullstr;
5922 msg = "parameter not set";
5923 if (umsg) {
5924 if (*end == CTLENDVAR) {
5925 if (varflags & VSNUL)
5926 tail = " or null";
5927 } else
5928 msg = umsg;
5929 }
5930 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005931}
Eric Andersen90898442003-08-06 11:20:52 +00005932
5933
Eric Andersenc470f442003-07-28 09:56:35 +00005934/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005935
Eric Andersencb57d552001-06-28 07:25:16 +00005936/*
Eric Andersen90898442003-08-06 11:20:52 +00005937 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005938 */
5939
Eric Andersenc470f442003-07-28 09:56:35 +00005940#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5941#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005942
Eric Andersenc470f442003-07-28 09:56:35 +00005943static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005944
Eric Andersencb57d552001-06-28 07:25:16 +00005945/*
5946 * Read a line from the script.
5947 */
5948
Eric Andersenc470f442003-07-28 09:56:35 +00005949static inline char *
5950pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005951{
5952 char *p = line;
5953 int nleft = len;
5954 int c;
5955
5956 while (--nleft > 0) {
5957 c = pgetc2();
5958 if (c == PEOF) {
5959 if (p == line)
5960 return NULL;
5961 break;
5962 }
5963 *p++ = c;
5964 if (c == '\n')
5965 break;
5966 }
5967 *p = '\0';
5968 return line;
5969}
5970
Eric Andersenc470f442003-07-28 09:56:35 +00005971
5972/*
5973 * Read a character from the script, returning PEOF on end of file.
5974 * Nul characters in the input are silently discarded.
5975 */
5976
5977#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5978
5979#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5980#define pgetc_macro() pgetc()
5981static int
5982pgetc(void)
5983{
5984 return pgetc_as_macro();
5985}
5986#else
5987#define pgetc_macro() pgetc_as_macro()
5988static int
5989pgetc(void)
5990{
5991 return pgetc_macro();
5992}
5993#endif
5994
5995
5996/*
5997 * Same as pgetc(), but ignores PEOA.
5998 */
5999#ifdef CONFIG_ASH_ALIAS
6000static int pgetc2(void)
6001{
6002 int c;
6003
6004 do {
6005 c = pgetc_macro();
6006 } while (c == PEOA);
6007 return c;
6008}
6009#else
6010static inline int pgetc2(void)
6011{
6012 return pgetc_macro();
6013}
6014#endif
6015
6016
6017#ifdef CONFIG_FEATURE_COMMAND_EDITING
6018static const char *cmdedit_prompt;
6019static inline void putprompt(const char *s)
6020{
6021 cmdedit_prompt = s;
6022}
6023#else
6024static inline void putprompt(const char *s)
6025{
6026 out2str(s);
6027}
6028#endif
6029
6030static inline int
6031preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006032{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006033 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006034 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006035 parsenextc = buf;
6036
Eric Andersenc470f442003-07-28 09:56:35 +00006037retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006038#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006039 if (!iflag || parsefile->fd)
6040 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6041 else {
Eric Andersenfa06a772004-02-06 10:33:19 +00006042 cmdedit_path_lookup = pathval();
Eric Andersenc470f442003-07-28 09:56:35 +00006043 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6044 if(nr == 0) {
6045 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006046 if(trap[SIGINT]) {
6047 buf[0] = '\n';
6048 buf[1] = 0;
6049 raise(SIGINT);
6050 return 1;
6051 }
Eric Andersenc470f442003-07-28 09:56:35 +00006052 goto retry;
6053 }
6054 if(nr < 0) {
6055 /* Ctrl+D presend */
6056 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006057 }
Eric Andersencb57d552001-06-28 07:25:16 +00006058 }
6059#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006060 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006061#endif
6062
6063 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006064 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6065 int flags = fcntl(0, F_GETFL, 0);
6066 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006067 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006068 if (fcntl(0, F_SETFL, flags) >= 0) {
6069 out2str("sh: turning off NDELAY mode\n");
6070 goto retry;
6071 }
6072 }
6073 }
6074 }
6075 return nr;
6076}
6077
6078/*
6079 * Refill the input buffer and return the next input character:
6080 *
6081 * 1) If a string was pushed back on the input, pop it;
6082 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6083 * from a string so we can't refill the buffer, return EOF.
6084 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6085 * 4) Process input up to the next newline, deleting nul characters.
6086 */
6087
Eric Andersenc470f442003-07-28 09:56:35 +00006088int
6089preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006090{
6091 char *p, *q;
6092 int more;
6093 char savec;
6094
6095 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006096#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006097 if (parsenleft == -1 && parsefile->strpush->ap &&
6098 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006099 return PEOA;
6100 }
Eric Andersen2870d962001-07-02 17:27:21 +00006101#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006102 popstring();
6103 if (--parsenleft >= 0)
6104 return (*parsenextc++);
6105 }
6106 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6107 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006108 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006109
Eric Andersenc470f442003-07-28 09:56:35 +00006110again:
Eric Andersencb57d552001-06-28 07:25:16 +00006111 if (parselleft <= 0) {
6112 if ((parselleft = preadfd()) <= 0) {
6113 parselleft = parsenleft = EOF_NLEFT;
6114 return PEOF;
6115 }
6116 }
6117
6118 q = p = parsenextc;
6119
6120 /* delete nul characters */
6121 for (more = 1; more;) {
6122 switch (*p) {
6123 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006124 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006125 goto check;
6126
Eric Andersencb57d552001-06-28 07:25:16 +00006127 case '\n':
6128 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006129 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006130 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006131
Eric Andersencb57d552001-06-28 07:25:16 +00006132 }
6133
6134 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006135check:
Eric Andersencb57d552001-06-28 07:25:16 +00006136 if (--parselleft <= 0 && more) {
6137 parsenleft = q - parsenextc - 1;
6138 if (parsenleft < 0)
6139 goto again;
6140 more = 0;
6141 }
6142 }
6143
6144 savec = *q;
6145 *q = '\0';
6146
6147 if (vflag) {
6148 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006149 }
6150
6151 *q = savec;
6152
6153 return *parsenextc++;
6154}
6155
Eric Andersenc470f442003-07-28 09:56:35 +00006156/*
6157 * Undo the last call to pgetc. Only one character may be pushed back.
6158 * PEOF may be pushed back.
6159 */
6160
6161void
6162pungetc(void)
6163{
6164 parsenleft++;
6165 parsenextc--;
6166}
Eric Andersencb57d552001-06-28 07:25:16 +00006167
6168/*
6169 * Push a string back onto the input at this current parsefile level.
6170 * We handle aliases this way.
6171 */
Eric Andersenc470f442003-07-28 09:56:35 +00006172void
6173pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006174{
Eric Andersencb57d552001-06-28 07:25:16 +00006175 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006176 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006177
Eric Andersenc470f442003-07-28 09:56:35 +00006178 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006179 INTOFF;
6180/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6181 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006182 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006183 sp->prev = parsefile->strpush;
6184 parsefile->strpush = sp;
6185 } else
6186 sp = parsefile->strpush = &(parsefile->basestrpush);
6187 sp->prevstring = parsenextc;
6188 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006189#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006190 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006191 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006192 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006193 sp->string = s;
6194 }
Eric Andersen2870d962001-07-02 17:27:21 +00006195#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006196 parsenextc = s;
6197 parsenleft = len;
6198 INTON;
6199}
6200
Eric Andersenc470f442003-07-28 09:56:35 +00006201void
6202popstring(void)
6203{
6204 struct strpush *sp = parsefile->strpush;
6205
6206 INTOFF;
6207#ifdef CONFIG_ASH_ALIAS
6208 if (sp->ap) {
6209 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6210 checkkwd |= CHKALIAS;
6211 }
6212 if (sp->string != sp->ap->val) {
6213 ckfree(sp->string);
6214 }
6215 sp->ap->flag &= ~ALIASINUSE;
6216 if (sp->ap->flag & ALIASDEAD) {
6217 unalias(sp->ap->name);
6218 }
6219 }
6220#endif
6221 parsenextc = sp->prevstring;
6222 parsenleft = sp->prevnleft;
6223/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6224 parsefile->strpush = sp->prev;
6225 if (sp != &(parsefile->basestrpush))
6226 ckfree(sp);
6227 INTON;
6228}
6229
6230/*
6231 * Set the input to take input from a file. If push is set, push the
6232 * old input onto the stack first.
6233 */
6234
6235void
6236setinputfile(const char *fname, int push)
6237{
6238 int fd;
6239 int fd2;
6240
6241 INTOFF;
6242 if ((fd = open(fname, O_RDONLY)) < 0)
6243 error("Can't open %s", fname);
6244 if (fd < 10) {
6245 fd2 = copyfd(fd, 10);
6246 close(fd);
6247 if (fd2 < 0)
6248 error("Out of file descriptors");
6249 fd = fd2;
6250 }
6251 setinputfd(fd, push);
6252 INTON;
6253}
6254
6255
6256/*
6257 * Like setinputfile, but takes an open file descriptor. Call this with
6258 * interrupts off.
6259 */
6260
6261static void
6262setinputfd(int fd, int push)
6263{
6264 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6265 if (push) {
6266 pushfile();
6267 parsefile->buf = 0;
6268 }
6269 parsefile->fd = fd;
6270 if (parsefile->buf == NULL)
6271 parsefile->buf = ckmalloc(IBUFSIZ);
6272 parselleft = parsenleft = 0;
6273 plinno = 1;
6274}
6275
Eric Andersencb57d552001-06-28 07:25:16 +00006276
Eric Andersencb57d552001-06-28 07:25:16 +00006277/*
6278 * Like setinputfile, but takes input from a string.
6279 */
6280
Eric Andersenc470f442003-07-28 09:56:35 +00006281static void
6282setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006283{
Eric Andersencb57d552001-06-28 07:25:16 +00006284 INTOFF;
6285 pushfile();
6286 parsenextc = string;
6287 parsenleft = strlen(string);
6288 parsefile->buf = NULL;
6289 plinno = 1;
6290 INTON;
6291}
6292
6293
Eric Andersencb57d552001-06-28 07:25:16 +00006294/*
6295 * To handle the "." command, a stack of input files is used. Pushfile
6296 * adds a new entry to the stack and popfile restores the previous level.
6297 */
6298
Eric Andersenc470f442003-07-28 09:56:35 +00006299static void
6300pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006301{
Eric Andersencb57d552001-06-28 07:25:16 +00006302 struct parsefile *pf;
6303
6304 parsefile->nleft = parsenleft;
6305 parsefile->lleft = parselleft;
6306 parsefile->nextc = parsenextc;
6307 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006308 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006309 pf->prev = parsefile;
6310 pf->fd = -1;
6311 pf->strpush = NULL;
6312 pf->basestrpush.prev = NULL;
6313 parsefile = pf;
6314}
6315
Eric Andersenc470f442003-07-28 09:56:35 +00006316
6317static void
6318popfile(void)
6319{
6320 struct parsefile *pf = parsefile;
6321
6322 INTOFF;
6323 if (pf->fd >= 0)
6324 close(pf->fd);
6325 if (pf->buf)
6326 ckfree(pf->buf);
6327 while (pf->strpush)
6328 popstring();
6329 parsefile = pf->prev;
6330 ckfree(pf);
6331 parsenleft = parsefile->nleft;
6332 parselleft = parsefile->lleft;
6333 parsenextc = parsefile->nextc;
6334 plinno = parsefile->linno;
6335 INTON;
6336}
Eric Andersencb57d552001-06-28 07:25:16 +00006337
6338
Eric Andersen2870d962001-07-02 17:27:21 +00006339/*
Eric Andersenc470f442003-07-28 09:56:35 +00006340 * Return to top level.
6341 */
Eric Andersen2870d962001-07-02 17:27:21 +00006342
Eric Andersenc470f442003-07-28 09:56:35 +00006343static void
6344popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006345{
Eric Andersenc470f442003-07-28 09:56:35 +00006346 while (parsefile != &basepf)
6347 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006348}
6349
Eric Andersen2870d962001-07-02 17:27:21 +00006350
Eric Andersenc470f442003-07-28 09:56:35 +00006351/*
6352 * Close the file(s) that the shell is reading commands from. Called
6353 * after a fork is done.
6354 */
6355
6356static void
6357closescript(void)
6358{
6359 popallfiles();
6360 if (parsefile->fd > 0) {
6361 close(parsefile->fd);
6362 parsefile->fd = 0;
6363 }
6364}
Eric Andersenc470f442003-07-28 09:56:35 +00006365
Eric Andersen90898442003-08-06 11:20:52 +00006366/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006367
6368/* mode flags for set_curjob */
6369#define CUR_DELETE 2
6370#define CUR_RUNNING 1
6371#define CUR_STOPPED 0
6372
6373/* mode flags for dowait */
6374#define DOWAIT_NORMAL 0
6375#define DOWAIT_BLOCK 1
6376
6377/* array of jobs */
6378static struct job *jobtab;
6379/* size of array */
6380static unsigned njobs;
6381#if JOBS
6382/* pgrp of shell on invocation */
6383static int initialpgrp;
6384static int ttyfd = -1;
6385#endif
6386/* current job */
6387static struct job *curjob;
6388/* number of presumed living untracked jobs */
6389static int jobless;
6390
6391static void set_curjob(struct job *, unsigned);
6392#if JOBS
6393static int restartjob(struct job *, int);
6394static void xtcsetpgrp(int, pid_t);
6395static char *commandtext(union node *);
6396static void cmdlist(union node *, int);
6397static void cmdtxt(union node *);
6398static void cmdputs(const char *);
6399static void showpipe(struct job *, FILE *);
6400#endif
6401static int sprint_status(char *, int, int);
6402static void freejob(struct job *);
6403static struct job *getjob(const char *, int);
6404static struct job *growjobtab(void);
6405static void forkchild(struct job *, union node *, int);
6406static void forkparent(struct job *, union node *, int, pid_t);
6407static int dowait(int, struct job *);
6408static int getstatus(struct job *);
6409
6410static void
6411set_curjob(struct job *jp, unsigned mode)
6412{
6413 struct job *jp1;
6414 struct job **jpp, **curp;
6415
6416 /* first remove from list */
6417 jpp = curp = &curjob;
6418 do {
6419 jp1 = *jpp;
6420 if (jp1 == jp)
6421 break;
6422 jpp = &jp1->prev_job;
6423 } while (1);
6424 *jpp = jp1->prev_job;
6425
6426 /* Then re-insert in correct position */
6427 jpp = curp;
6428 switch (mode) {
6429 default:
6430#ifdef DEBUG
6431 abort();
6432#endif
6433 case CUR_DELETE:
6434 /* job being deleted */
6435 break;
6436 case CUR_RUNNING:
6437 /* newly created job or backgrounded job,
6438 put after all stopped jobs. */
6439 do {
6440 jp1 = *jpp;
6441#ifdef JOBS
6442 if (!jp1 || jp1->state != JOBSTOPPED)
6443#endif
6444 break;
6445 jpp = &jp1->prev_job;
6446 } while (1);
6447 /* FALLTHROUGH */
6448#ifdef JOBS
6449 case CUR_STOPPED:
6450#endif
6451 /* newly stopped job - becomes curjob */
6452 jp->prev_job = *jpp;
6453 *jpp = jp;
6454 break;
6455 }
6456}
6457
6458#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006459/*
6460 * Turn job control on and off.
6461 *
6462 * Note: This code assumes that the third arg to ioctl is a character
6463 * pointer, which is true on Berkeley systems but not System V. Since
6464 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006465 *
6466 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006467 */
6468
Eric Andersenc470f442003-07-28 09:56:35 +00006469void
6470setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006471{
Eric Andersenc470f442003-07-28 09:56:35 +00006472 int fd;
6473 int pgrp;
6474
6475 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006476 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006477 if (on) {
6478 int ofd;
6479 ofd = fd = open(_PATH_TTY, O_RDWR);
6480 if (fd < 0) {
6481 fd += 3;
6482 while (!isatty(fd) && --fd >= 0)
6483 ;
6484 }
6485 fd = fcntl(fd, F_DUPFD, 10);
6486 close(ofd);
6487 if (fd < 0)
6488 goto out;
6489 fcntl(fd, F_SETFD, FD_CLOEXEC);
6490 do { /* while we are in the background */
6491 if ((pgrp = tcgetpgrp(fd)) < 0) {
6492out:
6493 sh_warnx("can't access tty; job control turned off");
6494 mflag = on = 0;
6495 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006496 }
Eric Andersenc470f442003-07-28 09:56:35 +00006497 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006498 break;
6499 killpg(0, SIGTTIN);
6500 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006501 initialpgrp = pgrp;
6502
Eric Andersencb57d552001-06-28 07:25:16 +00006503 setsignal(SIGTSTP);
6504 setsignal(SIGTTOU);
6505 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006506 pgrp = rootpid;
6507 setpgid(0, pgrp);
6508 xtcsetpgrp(fd, pgrp);
6509 } else {
6510 /* turning job control off */
6511 fd = ttyfd;
6512 pgrp = initialpgrp;
6513 xtcsetpgrp(fd, pgrp);
6514 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006515 setsignal(SIGTSTP);
6516 setsignal(SIGTTOU);
6517 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006518close:
6519 close(fd);
6520 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006521 }
Eric Andersenc470f442003-07-28 09:56:35 +00006522 ttyfd = fd;
6523 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006524}
Eric Andersencb57d552001-06-28 07:25:16 +00006525
Eric Andersenc470f442003-07-28 09:56:35 +00006526static int
Eric Andersen90898442003-08-06 11:20:52 +00006527killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006528{
6529 int signo = -1;
6530 int list = 0;
6531 int i;
6532 pid_t pid;
6533 struct job *jp;
6534
6535 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006536usage:
6537 error(
6538"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6539"kill -l [exitstatus]"
6540 );
Eric Andersencb57d552001-06-28 07:25:16 +00006541 }
6542
Eric Andersenc470f442003-07-28 09:56:35 +00006543 if (**++argv == '-') {
6544 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006545 if (signo < 0) {
6546 int c;
6547
6548 while ((c = nextopt("ls:")) != '\0')
6549 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006550 default:
6551#ifdef DEBUG
6552 abort();
6553#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006554 case 'l':
6555 list = 1;
6556 break;
6557 case 's':
6558 signo = decode_signal(optionarg, 1);
6559 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006560 error(
6561 "invalid signal number or name: %s",
6562 optionarg
6563 );
Eric Andersencb57d552001-06-28 07:25:16 +00006564 }
Eric Andersen2870d962001-07-02 17:27:21 +00006565 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006566 }
Eric Andersenc470f442003-07-28 09:56:35 +00006567 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006568 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006569 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006570 }
6571
6572 if (!list && signo < 0)
6573 signo = SIGTERM;
6574
Eric Andersenc470f442003-07-28 09:56:35 +00006575 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006576 goto usage;
6577 }
6578
6579 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006580 const char *name;
6581
Eric Andersenc470f442003-07-28 09:56:35 +00006582 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006583 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006584 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006585 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006586 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006587 }
6588 return 0;
6589 }
Eric Andersen34506362001-08-02 05:02:46 +00006590 name = u_signal_names(*argptr, &signo, -1);
6591 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006592 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006593 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006594 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006595 return 0;
6596 }
6597
Eric Andersenc470f442003-07-28 09:56:35 +00006598 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006599 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006600 if (**argv == '%') {
6601 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006602 pid = -jp->ps[0].pid;
6603 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006604 pid = number(*argv);
6605 if (kill(pid, signo) != 0) {
6606 sh_warnx("%m\n");
6607 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006608 }
Eric Andersenc470f442003-07-28 09:56:35 +00006609 } while (*++argv);
6610
6611 return i;
6612}
6613#endif /* JOBS */
6614
6615#if defined(JOBS) || defined(DEBUG)
6616static int
6617jobno(const struct job *jp)
6618{
6619 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006620}
6621#endif
6622
Eric Andersenc470f442003-07-28 09:56:35 +00006623#ifdef JOBS
6624static int
6625fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006626{
Eric Andersenc470f442003-07-28 09:56:35 +00006627 struct job *jp;
6628 FILE *out;
6629 int mode;
6630 int retval;
6631
6632 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6633 nextopt(nullstr);
6634 argv = argptr;
6635 out = stdout;
6636 do {
6637 jp = getjob(*argv, 1);
6638 if (mode == FORK_BG) {
6639 set_curjob(jp, CUR_RUNNING);
6640 fprintf(out, "[%d] ", jobno(jp));
6641 }
6642 outstr(jp->ps->cmd, out);
6643 showpipe(jp, out);
6644 retval = restartjob(jp, mode);
6645 } while (*argv && *++argv);
6646 return retval;
6647}
6648
6649static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6650
6651
6652static int
6653restartjob(struct job *jp, int mode)
6654{
6655 struct procstat *ps;
6656 int i;
6657 int status;
6658 pid_t pgid;
6659
6660 INTOFF;
6661 if (jp->state == JOBDONE)
6662 goto out;
6663 jp->state = JOBRUNNING;
6664 pgid = jp->ps->pid;
6665 if (mode == FORK_FG)
6666 xtcsetpgrp(ttyfd, pgid);
6667 killpg(pgid, SIGCONT);
6668 ps = jp->ps;
6669 i = jp->nprocs;
6670 do {
6671 if (WIFSTOPPED(ps->status)) {
6672 ps->status = -1;
6673 }
6674 } while (ps++, --i);
6675out:
6676 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6677 INTON;
6678 return status;
6679}
6680#endif
6681
6682static int
6683sprint_status(char *s, int status, int sigonly)
6684{
6685 int col;
6686 int st;
6687
6688 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006689 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006690#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006691 if (WIFSTOPPED(status))
6692 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006693 else
Eric Andersenc470f442003-07-28 09:56:35 +00006694#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006695 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006696 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006697 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006698 goto out;
6699#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006700 if (WIFSTOPPED(status))
6701 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006702#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006703 }
6704 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006705 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006706 if (WCOREDUMP(status)) {
6707 col += fmtstr(s + col, 16, " (core dumped)");
6708 }
6709 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006710 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006711 if (st)
6712 col = fmtstr(s, 16, "Done(%d)", st);
6713 else
6714 col = fmtstr(s, 16, "Done");
6715 }
6716
6717out:
6718 return col;
6719}
6720
6721#if JOBS
6722static void
6723showjob(FILE *out, struct job *jp, int mode)
6724{
6725 struct procstat *ps;
6726 struct procstat *psend;
6727 int col;
6728 int indent;
6729 char s[80];
6730
6731 ps = jp->ps;
6732
6733 if (mode & SHOW_PGID) {
6734 /* just output process (group) id of pipeline */
6735 fprintf(out, "%d\n", ps->pid);
6736 return;
6737 }
6738
6739 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6740 indent = col;
6741
6742 if (jp == curjob)
6743 s[col - 2] = '+';
6744 else if (curjob && jp == curjob->prev_job)
6745 s[col - 2] = '-';
6746
6747 if (mode & SHOW_PID)
6748 col += fmtstr(s + col, 16, "%d ", ps->pid);
6749
6750 psend = ps + jp->nprocs;
6751
6752 if (jp->state == JOBRUNNING) {
6753 scopy("Running", s + col);
6754 col += strlen("Running");
6755 } else {
6756 int status = psend[-1].status;
6757#if JOBS
6758 if (jp->state == JOBSTOPPED)
6759 status = jp->stopstatus;
6760#endif
6761 col += sprint_status(s + col, status, 0);
6762 }
6763
6764 goto start;
6765
6766 do {
6767 /* for each process */
6768 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6769
6770start:
Eric Andersen90898442003-08-06 11:20:52 +00006771 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006772 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6773 );
6774 if (!(mode & SHOW_PID)) {
6775 showpipe(jp, out);
6776 break;
6777 }
6778 if (++ps == psend) {
6779 outcslow('\n', out);
6780 break;
6781 }
6782 } while (1);
6783
6784 jp->changed = 0;
6785
6786 if (jp->state == JOBDONE) {
6787 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6788 freejob(jp);
6789 }
6790}
6791
6792
6793static int
6794jobscmd(int argc, char **argv)
6795{
6796 int mode, m;
6797 FILE *out;
6798
6799 mode = 0;
6800 while ((m = nextopt("lp")))
6801 if (m == 'l')
6802 mode = SHOW_PID;
6803 else
6804 mode = SHOW_PGID;
6805
6806 out = stdout;
6807 argv = argptr;
6808 if (*argv)
6809 do
6810 showjob(out, getjob(*argv,0), mode);
6811 while (*++argv);
6812 else
6813 showjobs(out, mode);
6814
Eric Andersencb57d552001-06-28 07:25:16 +00006815 return 0;
6816}
6817
6818
6819/*
6820 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6821 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006822 */
6823
Eric Andersenc470f442003-07-28 09:56:35 +00006824static void
6825showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006826{
Eric Andersencb57d552001-06-28 07:25:16 +00006827 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006828
Eric Andersenc470f442003-07-28 09:56:35 +00006829 TRACE(("showjobs(%x) called\n", mode));
6830
6831 /* If not even one one job changed, there is nothing to do */
6832 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6833 continue;
6834
6835 for (jp = curjob; jp; jp = jp->prev_job) {
6836 if (!(mode & SHOW_CHANGED) || jp->changed)
6837 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006838 }
6839}
Eric Andersenc470f442003-07-28 09:56:35 +00006840#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006841
6842/*
6843 * Mark a job structure as unused.
6844 */
6845
Eric Andersenc470f442003-07-28 09:56:35 +00006846static void
6847freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006848{
Eric Andersenc470f442003-07-28 09:56:35 +00006849 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006850 int i;
6851
6852 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006853 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006854 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006855 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006856 }
6857 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006858 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006859 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006860 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006861 INTON;
6862}
6863
6864
Eric Andersenc470f442003-07-28 09:56:35 +00006865static int
6866waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006867{
6868 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006869 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006870 struct job *jp;
6871
Eric Andersenc470f442003-07-28 09:56:35 +00006872 EXSIGON();
6873
6874 nextopt(nullstr);
6875 retval = 0;
6876
6877 argv = argptr;
6878 if (!*argv) {
6879 /* wait for all jobs */
6880 for (;;) {
6881 jp = curjob;
6882 while (1) {
6883 if (!jp) {
6884 /* no running procs */
6885 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006886 }
Eric Andersenc470f442003-07-28 09:56:35 +00006887 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006888 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006889 jp->waited = 1;
6890 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006891 }
Eric Andersenc470f442003-07-28 09:56:35 +00006892 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006893 }
6894 }
Eric Andersenc470f442003-07-28 09:56:35 +00006895
6896 retval = 127;
6897 do {
6898 if (**argv != '%') {
6899 pid_t pid = number(*argv);
6900 job = curjob;
6901 goto start;
6902 do {
6903 if (job->ps[job->nprocs - 1].pid == pid)
6904 break;
6905 job = job->prev_job;
6906start:
6907 if (!job)
6908 goto repeat;
6909 } while (1);
6910 } else
6911 job = getjob(*argv, 0);
6912 /* loop until process terminated or stopped */
6913 while (job->state == JOBRUNNING)
6914 dowait(DOWAIT_BLOCK, 0);
6915 job->waited = 1;
6916 retval = getstatus(job);
6917repeat:
6918 ;
6919 } while (*++argv);
6920
6921out:
6922 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006923}
6924
6925
Eric Andersencb57d552001-06-28 07:25:16 +00006926/*
6927 * Convert a job name to a job structure.
6928 */
6929
Eric Andersenc470f442003-07-28 09:56:35 +00006930static struct job *
6931getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006932{
Eric Andersencb57d552001-06-28 07:25:16 +00006933 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006934 struct job *found;
6935 const char *err_msg = "No such job: %s";
6936 unsigned num;
6937 int c;
6938 const char *p;
6939 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006940
Eric Andersenc470f442003-07-28 09:56:35 +00006941 jp = curjob;
6942 p = name;
6943 if (!p)
6944 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006945
Eric Andersenc470f442003-07-28 09:56:35 +00006946 if (*p != '%')
6947 goto err;
6948
6949 c = *++p;
6950 if (!c)
6951 goto currentjob;
6952
6953 if (!p[1]) {
6954 if (c == '+' || c == '%') {
6955currentjob:
6956 err_msg = "No current job";
6957 goto check;
6958 } else if (c == '-') {
6959 if (jp)
6960 jp = jp->prev_job;
6961 err_msg = "No previous job";
6962check:
6963 if (!jp)
6964 goto err;
6965 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006966 }
6967 }
Eric Andersenc470f442003-07-28 09:56:35 +00006968
6969 if (is_number(p)) {
6970 num = atoi(p);
6971 if (num < njobs) {
6972 jp = jobtab + num - 1;
6973 if (jp->used)
6974 goto gotit;
6975 goto err;
6976 }
6977 }
6978
6979 match = prefix;
6980 if (*p == '?') {
6981 match = strstr;
6982 p++;
6983 }
6984
6985 found = 0;
6986 while (1) {
6987 if (!jp)
6988 goto err;
6989 if (match(jp->ps[0].cmd, p)) {
6990 if (found)
6991 goto err;
6992 found = jp;
6993 err_msg = "%s: ambiguous";
6994 }
6995 jp = jp->prev_job;
6996 }
6997
6998gotit:
6999#if JOBS
7000 err_msg = "job %s not created under job control";
7001 if (getctl && jp->jobctl == 0)
7002 goto err;
7003#endif
7004 return jp;
7005err:
7006 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007007}
7008
7009
Eric Andersencb57d552001-06-28 07:25:16 +00007010/*
Eric Andersenc470f442003-07-28 09:56:35 +00007011 * Return a new job structure.
7012 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007013 */
7014
Eric Andersenc470f442003-07-28 09:56:35 +00007015static struct job *
7016makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007017{
7018 int i;
7019 struct job *jp;
7020
Eric Andersenc470f442003-07-28 09:56:35 +00007021 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007022 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007023 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007024 break;
7025 }
7026 if (jp->used == 0)
7027 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007028 if (jp->state != JOBDONE || !jp->waited)
7029 continue;
7030#if JOBS
7031 if (jobctl)
7032 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007033#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007034 freejob(jp);
7035 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007036 }
Eric Andersenc470f442003-07-28 09:56:35 +00007037 memset(jp, 0, sizeof(*jp));
7038#if JOBS
7039 if (jobctl)
7040 jp->jobctl = 1;
7041#endif
7042 jp->prev_job = curjob;
7043 curjob = jp;
7044 jp->used = 1;
7045 jp->ps = &jp->ps0;
7046 if (nprocs > 1) {
7047 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7048 }
7049 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7050 jobno(jp)));
7051 return jp;
7052}
7053
7054static struct job *
7055growjobtab(void)
7056{
7057 size_t len;
7058 ptrdiff_t offset;
7059 struct job *jp, *jq;
7060
7061 len = njobs * sizeof(*jp);
7062 jq = jobtab;
7063 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7064
7065 offset = (char *)jp - (char *)jq;
7066 if (offset) {
7067 /* Relocate pointers */
7068 size_t l = len;
7069
7070 jq = (struct job *)((char *)jq + l);
7071 while (l) {
7072 l -= sizeof(*jp);
7073 jq--;
7074#define joff(p) ((struct job *)((char *)(p) + l))
7075#define jmove(p) (p) = (void *)((char *)(p) + offset)
7076 if (likely(joff(jp)->ps == &jq->ps0))
7077 jmove(joff(jp)->ps);
7078 if (joff(jp)->prev_job)
7079 jmove(joff(jp)->prev_job);
7080 }
7081 if (curjob)
7082 jmove(curjob);
7083#undef joff
7084#undef jmove
7085 }
7086
7087 njobs += 4;
7088 jobtab = jp;
7089 jp = (struct job *)((char *)jp + len);
7090 jq = jp + 3;
7091 do {
7092 jq->used = 0;
7093 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007094 return jp;
7095}
7096
7097
7098/*
Eric Andersenc470f442003-07-28 09:56:35 +00007099 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007100 * own process group. Jp is a job structure that the job is to be added to.
7101 * N is the command that will be evaluated by the child. Both jp and n may
7102 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007103 * FORK_FG - Fork off a foreground process.
7104 * FORK_BG - Fork off a background process.
7105 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7106 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007107 *
7108 * When job control is turned off, background processes have their standard
7109 * input redirected to /dev/null (except for the second and later processes
7110 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007111 *
7112 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007113 */
7114
Eric Andersenc470f442003-07-28 09:56:35 +00007115static inline void
7116forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007117{
Eric Andersenc470f442003-07-28 09:56:35 +00007118 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007119
Eric Andersenc470f442003-07-28 09:56:35 +00007120 TRACE(("Child shell %d\n", getpid()));
7121 wasroot = rootshell;
7122 rootshell = 0;
7123
7124 closescript();
7125 clear_traps();
7126#if JOBS
7127 /* do job control only in root shell */
7128 jobctl = 0;
7129 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7130 pid_t pgrp;
7131
7132 if (jp->nprocs == 0)
7133 pgrp = getpid();
7134 else
7135 pgrp = jp->ps[0].pid;
7136 /* This can fail because we are doing it in the parent also */
7137 (void)setpgid(0, pgrp);
7138 if (mode == FORK_FG)
7139 xtcsetpgrp(ttyfd, pgrp);
7140 setsignal(SIGTSTP);
7141 setsignal(SIGTTOU);
7142 } else
Eric Andersen62483552001-07-10 06:09:16 +00007143#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007144 if (mode == FORK_BG) {
7145 ignoresig(SIGINT);
7146 ignoresig(SIGQUIT);
7147 if (jp->nprocs == 0) {
7148 close(0);
7149 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7150 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007151 }
Eric Andersencb57d552001-06-28 07:25:16 +00007152 }
Eric Andersenc470f442003-07-28 09:56:35 +00007153 if (wasroot && iflag) {
7154 setsignal(SIGINT);
7155 setsignal(SIGQUIT);
7156 setsignal(SIGTERM);
7157 }
7158 for (jp = curjob; jp; jp = jp->prev_job)
7159 freejob(jp);
7160 jobless = 0;
7161}
7162
7163static inline void
7164forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7165{
7166 TRACE(("In parent shell: child = %d\n", pid));
7167 if (!jp) {
7168 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7169 jobless++;
7170 return;
7171 }
7172#if JOBS
7173 if (mode != FORK_NOJOB && jp->jobctl) {
7174 int pgrp;
7175
7176 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007177 pgrp = pid;
7178 else
7179 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007180 /* This can fail because we are doing it in the child also */
7181 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007182 }
Eric Andersen62483552001-07-10 06:09:16 +00007183#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007184 if (mode == FORK_BG) {
7185 backgndpid = pid; /* set $! */
7186 set_curjob(jp, CUR_RUNNING);
7187 }
Eric Andersencb57d552001-06-28 07:25:16 +00007188 if (jp) {
7189 struct procstat *ps = &jp->ps[jp->nprocs++];
7190 ps->pid = pid;
7191 ps->status = -1;
7192 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007193#if JOBS
7194 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007195 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007196#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007197 }
Eric Andersencb57d552001-06-28 07:25:16 +00007198}
7199
Eric Andersenc470f442003-07-28 09:56:35 +00007200static int
7201forkshell(struct job *jp, union node *n, int mode)
7202{
7203 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007204
Eric Andersenc470f442003-07-28 09:56:35 +00007205 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7206 pid = fork();
7207 if (pid < 0) {
7208 TRACE(("Fork failed, errno=%d", errno));
7209 if (jp)
7210 freejob(jp);
7211 error("Cannot fork");
7212 }
7213 if (pid == 0)
7214 forkchild(jp, n, mode);
7215 else
7216 forkparent(jp, n, mode, pid);
7217 return pid;
7218}
Eric Andersencb57d552001-06-28 07:25:16 +00007219
7220/*
7221 * Wait for job to finish.
7222 *
7223 * Under job control we have the problem that while a child process is
7224 * running interrupts generated by the user are sent to the child but not
7225 * to the shell. This means that an infinite loop started by an inter-
7226 * active user may be hard to kill. With job control turned off, an
7227 * interactive user may place an interactive program inside a loop. If
7228 * the interactive program catches interrupts, the user doesn't want
7229 * these interrupts to also abort the loop. The approach we take here
7230 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007231 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007232 * signal if the child process was terminated by an interrupt signal.
7233 * Unfortunately, some programs want to do a bit of cleanup and then
7234 * exit on interrupt; unless these processes terminate themselves by
7235 * sending a signal to themselves (instead of calling exit) they will
7236 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007237 *
7238 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007239 */
7240
Eric Andersenc470f442003-07-28 09:56:35 +00007241int
7242waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007243{
Eric Andersencb57d552001-06-28 07:25:16 +00007244 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007245
Eric Andersenc470f442003-07-28 09:56:35 +00007246 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7247 while (jp->state == JOBRUNNING) {
7248 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007249 }
Eric Andersenc470f442003-07-28 09:56:35 +00007250 st = getstatus(jp);
7251#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007252 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007253 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007254 /*
7255 * This is truly gross.
7256 * If we're doing job control, then we did a TIOCSPGRP which
7257 * caused us (the shell) to no longer be in the controlling
7258 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7259 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007260 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007261 */
Eric Andersenc470f442003-07-28 09:56:35 +00007262 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007263 raise(SIGINT);
7264 }
Eric Andersen2870d962001-07-02 17:27:21 +00007265 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007266#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007267 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007268 return st;
7269}
7270
7271
Eric Andersen62483552001-07-10 06:09:16 +00007272/*
7273 * Do a wait system call. If job control is compiled in, we accept
7274 * stopped processes. If block is zero, we return a value of zero
7275 * rather than blocking.
7276 *
7277 * System V doesn't have a non-blocking wait system call. It does
7278 * have a SIGCLD signal that is sent to a process when one of it's
7279 * children dies. The obvious way to use SIGCLD would be to install
7280 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7281 * was received, and have waitproc bump another counter when it got
7282 * the status of a process. Waitproc would then know that a wait
7283 * system call would not block if the two counters were different.
7284 * This approach doesn't work because if a process has children that
7285 * have not been waited for, System V will send it a SIGCLD when it
7286 * installs a signal handler for SIGCLD. What this means is that when
7287 * a child exits, the shell will be sent SIGCLD signals continuously
7288 * until is runs out of stack space, unless it does a wait call before
7289 * restoring the signal handler. The code below takes advantage of
7290 * this (mis)feature by installing a signal handler for SIGCLD and
7291 * then checking to see whether it was called. If there are any
7292 * children to be waited for, it will be.
7293 *
Eric Andersenc470f442003-07-28 09:56:35 +00007294 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7295 * waits at all. In this case, the user will not be informed when
7296 * a background process until the next time she runs a real program
7297 * (as opposed to running a builtin command or just typing return),
7298 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007299 */
7300
Eric Andersenc470f442003-07-28 09:56:35 +00007301static inline int
7302waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007303{
Eric Andersenc470f442003-07-28 09:56:35 +00007304 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007305
Eric Andersenc470f442003-07-28 09:56:35 +00007306#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007307 if (jobctl)
7308 flags |= WUNTRACED;
7309#endif
7310 if (block == 0)
7311 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007312 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007313}
7314
Eric Andersenc470f442003-07-28 09:56:35 +00007315/*
7316 * Wait for a process to terminate.
7317 */
7318
7319static int
7320dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007321{
7322 int pid;
7323 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007324 struct job *jp;
7325 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007326 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007327
7328 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007329 pid = waitproc(block, &status);
7330 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007331 if (pid <= 0)
7332 return pid;
7333 INTOFF;
7334 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007335 for (jp = curjob; jp; jp = jp->prev_job) {
7336 struct procstat *sp;
7337 struct procstat *spend;
7338 if (jp->state == JOBDONE)
7339 continue;
7340 state = JOBDONE;
7341 spend = jp->ps + jp->nprocs;
7342 sp = jp->ps;
7343 do {
7344 if (sp->pid == pid) {
7345 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7346 sp->status = status;
7347 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007348 }
Eric Andersenc470f442003-07-28 09:56:35 +00007349 if (sp->status == -1)
7350 state = JOBRUNNING;
7351#ifdef JOBS
7352 if (state == JOBRUNNING)
7353 continue;
7354 if (WIFSTOPPED(sp->status)) {
7355 jp->stopstatus = sp->status;
7356 state = JOBSTOPPED;
7357 }
Eric Andersencb57d552001-06-28 07:25:16 +00007358#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007359 } while (++sp < spend);
7360 if (thisjob)
7361 goto gotjob;
7362 }
7363#ifdef JOBS
7364 if (!WIFSTOPPED(status))
7365#endif
7366
7367 jobless--;
7368 goto out;
7369
7370gotjob:
7371 if (state != JOBRUNNING) {
7372 thisjob->changed = 1;
7373
7374 if (thisjob->state != state) {
7375 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7376 thisjob->state = state;
7377#ifdef JOBS
7378 if (state == JOBSTOPPED) {
7379 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007380 }
Eric Andersenc470f442003-07-28 09:56:35 +00007381#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007382 }
7383 }
Eric Andersencb57d552001-06-28 07:25:16 +00007384
Eric Andersenc470f442003-07-28 09:56:35 +00007385out:
7386 INTON;
7387
7388 if (thisjob && thisjob == job) {
7389 char s[48 + 1];
7390 int len;
7391
7392 len = sprint_status(s, status, 1);
7393 if (len) {
7394 s[len] = '\n';
7395 s[len + 1] = 0;
7396 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007397 }
Eric Andersencb57d552001-06-28 07:25:16 +00007398 }
7399 return pid;
7400}
7401
7402
Eric Andersencb57d552001-06-28 07:25:16 +00007403/*
7404 * return 1 if there are stopped jobs, otherwise 0
7405 */
Eric Andersen90898442003-08-06 11:20:52 +00007406
Eric Andersenc470f442003-07-28 09:56:35 +00007407int
7408stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007409{
Eric Andersencb57d552001-06-28 07:25:16 +00007410 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007411 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007412
Eric Andersenc470f442003-07-28 09:56:35 +00007413 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007414 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007415 goto out;
7416 jp = curjob;
7417 if (jp && jp->state == JOBSTOPPED) {
7418 out2str("You have stopped jobs.\n");
7419 job_warning = 2;
7420 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007421 }
7422
Eric Andersenc470f442003-07-28 09:56:35 +00007423out:
7424 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007425}
7426
7427/*
7428 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007429 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007430 */
7431
Eric Andersenc470f442003-07-28 09:56:35 +00007432#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007433static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007434
Eric Andersenc470f442003-07-28 09:56:35 +00007435static char *
7436commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007437{
Eric Andersenc470f442003-07-28 09:56:35 +00007438 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007439
Eric Andersenc470f442003-07-28 09:56:35 +00007440 STARTSTACKSTR(cmdnextc);
7441 cmdtxt(n);
7442 name = stackblock();
7443 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7444 name, cmdnextc, cmdnextc));
7445 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007446}
7447
Eric Andersenc470f442003-07-28 09:56:35 +00007448static void
7449cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007450{
Eric Andersencb57d552001-06-28 07:25:16 +00007451 union node *np;
7452 struct nodelist *lp;
7453 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007454 char s[2];
7455
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007456 if (!n)
7457 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007458 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007459 default:
7460#if DEBUG
7461 abort();
7462#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007463 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007464 lp = n->npipe.cmdlist;
7465 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007466 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007467 lp = lp->next;
7468 if (!lp)
7469 break;
7470 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007471 }
7472 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007473 case NSEMI:
7474 p = "; ";
7475 goto binop;
7476 case NAND:
7477 p = " && ";
7478 goto binop;
7479 case NOR:
7480 p = " || ";
7481binop:
7482 cmdtxt(n->nbinary.ch1);
7483 cmdputs(p);
7484 n = n->nbinary.ch2;
7485 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007486 case NREDIR:
7487 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007488 n = n->nredir.n;
7489 goto donode;
7490 case NNOT:
7491 cmdputs("!");
7492 n = n->nnot.com;
7493donode:
7494 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007495 break;
7496 case NIF:
7497 cmdputs("if ");
7498 cmdtxt(n->nif.test);
7499 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007500 n = n->nif.ifpart;
7501 if (n->nif.elsepart) {
7502 cmdtxt(n);
7503 cmdputs("; else ");
7504 n = n->nif.elsepart;
7505 }
7506 p = "; fi";
7507 goto dotail;
7508 case NSUBSHELL:
7509 cmdputs("(");
7510 n = n->nredir.n;
7511 p = ")";
7512 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007513 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007514 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007515 goto until;
7516 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007517 p = "until ";
7518until:
7519 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007520 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007521 n = n->nbinary.ch2;
7522 p = "; done";
7523dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007524 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007525dotail:
7526 cmdtxt(n);
7527 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007528 case NFOR:
7529 cmdputs("for ");
7530 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007531 cmdputs(" in ");
7532 cmdlist(n->nfor.args, 1);
7533 n = n->nfor.body;
7534 p = "; done";
7535 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007536 case NDEFUN:
7537 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007538 p = "() { ... }";
7539 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007540 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007541 cmdlist(n->ncmd.args, 1);
7542 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007543 break;
7544 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007545 p = n->narg.text;
7546dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007547 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007548 break;
7549 case NHERE:
7550 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007551 p = "<<...";
7552 goto dotail2;
7553 case NCASE:
7554 cmdputs("case ");
7555 cmdputs(n->ncase.expr->narg.text);
7556 cmdputs(" in ");
7557 for (np = n->ncase.cases; np; np = np->nclist.next) {
7558 cmdtxt(np->nclist.pattern);
7559 cmdputs(") ");
7560 cmdtxt(np->nclist.body);
7561 cmdputs(";; ");
7562 }
7563 p = "esac";
7564 goto dotail2;
7565 case NTO:
7566 p = ">";
7567 goto redir;
7568 case NCLOBBER:
7569 p = ">|";
7570 goto redir;
7571 case NAPPEND:
7572 p = ">>";
7573 goto redir;
7574 case NTOFD:
7575 p = ">&";
7576 goto redir;
7577 case NFROM:
7578 p = "<";
7579 goto redir;
7580 case NFROMFD:
7581 p = "<&";
7582 goto redir;
7583 case NFROMTO:
7584 p = "<>";
7585redir:
7586 s[0] = n->nfile.fd + '0';
7587 s[1] = '\0';
7588 cmdputs(s);
7589 cmdputs(p);
7590 if (n->type == NTOFD || n->type == NFROMFD) {
7591 s[0] = n->ndup.dupfd + '0';
7592 p = s;
7593 goto dotail2;
7594 } else {
7595 n = n->nfile.fname;
7596 goto donode;
7597 }
Eric Andersencb57d552001-06-28 07:25:16 +00007598 }
7599}
Eric Andersencb57d552001-06-28 07:25:16 +00007600
Eric Andersenc470f442003-07-28 09:56:35 +00007601static void
7602cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007603{
Eric Andersenc470f442003-07-28 09:56:35 +00007604 for (; np; np = np->narg.next) {
7605 if (!sep)
7606 cmdputs(spcstr);
7607 cmdtxt(np);
7608 if (sep && np->narg.next)
7609 cmdputs(spcstr);
7610 }
Eric Andersencb57d552001-06-28 07:25:16 +00007611}
7612
Eric Andersenc470f442003-07-28 09:56:35 +00007613static void
7614cmdputs(const char *s)
7615{
7616 const char *p, *str;
7617 char c, cc[2] = " ";
7618 char *nextc;
7619 int subtype = 0;
7620 int quoted = 0;
7621 static const char *const vstype[16] = {
7622 nullstr, "}", "-", "+", "?", "=",
Eric Andersenc7bda1c2004-03-15 08:29:22 +00007623 "%", "%%", "#", "##", nullstr
Eric Andersenc470f442003-07-28 09:56:35 +00007624 };
7625
7626 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7627 p = s;
7628 while ((c = *p++) != 0) {
7629 str = 0;
7630 switch (c) {
7631 case CTLESC:
7632 c = *p++;
7633 break;
7634 case CTLVAR:
7635 subtype = *p++;
7636 if ((subtype & VSTYPE) == VSLENGTH)
7637 str = "${#";
7638 else
7639 str = "${";
7640 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7641 quoted ^= 1;
7642 c = '"';
7643 } else
7644 goto dostr;
7645 break;
7646 case CTLENDVAR:
7647 quoted >>= 1;
7648 subtype = 0;
7649 if (quoted & 1) {
7650 str = "\"}";
7651 goto dostr;
7652 }
7653 c = '}';
7654 break;
7655 case CTLBACKQ:
7656 str = "$(...)";
7657 goto dostr;
7658 case CTLBACKQ+CTLQUOTE:
7659 str = "\"$(...)\"";
7660 goto dostr;
7661#ifdef CONFIG_ASH_MATH_SUPPORT
7662 case CTLARI:
7663 str = "$((";
7664 goto dostr;
7665 case CTLENDARI:
7666 str = "))";
7667 goto dostr;
7668#endif
7669 case CTLQUOTEMARK:
7670 quoted ^= 1;
7671 c = '"';
7672 break;
7673 case '=':
7674 if (subtype == 0)
7675 break;
7676 str = vstype[subtype & VSTYPE];
7677 if (subtype & VSNUL)
7678 c = ':';
7679 else
7680 c = *str++;
7681 if (c != '}')
7682 quoted <<= 1;
7683 break;
7684 case '\'':
7685 case '\\':
7686 case '"':
7687 case '$':
7688 /* These can only happen inside quotes */
7689 cc[0] = c;
7690 str = cc;
7691 c = '\\';
7692 break;
7693 default:
7694 break;
7695 }
7696 USTPUTC(c, nextc);
7697 if (!str)
7698 continue;
7699dostr:
7700 while ((c = *str++)) {
7701 USTPUTC(c, nextc);
7702 }
7703 }
7704 if (quoted & 1) {
7705 USTPUTC('"', nextc);
7706 }
7707 *nextc = 0;
7708 cmdnextc = nextc;
7709}
7710
7711
7712static void
7713showpipe(struct job *jp, FILE *out)
7714{
7715 struct procstat *sp;
7716 struct procstat *spend;
7717
7718 spend = jp->ps + jp->nprocs;
7719 for (sp = jp->ps + 1; sp < spend; sp++)
7720 fprintf(out, " | %s", sp->cmd);
7721 outcslow('\n', out);
7722 flushall();
7723}
7724
7725static void
7726xtcsetpgrp(int fd, pid_t pgrp)
7727{
7728 if (tcsetpgrp(fd, pgrp))
7729 error("Cannot set tty process group (%m)");
7730}
7731#endif /* JOBS */
7732
7733static int
7734getstatus(struct job *job) {
7735 int status;
7736 int retval;
7737
7738 status = job->ps[job->nprocs - 1].status;
7739 retval = WEXITSTATUS(status);
7740 if (!WIFEXITED(status)) {
7741#if JOBS
7742 retval = WSTOPSIG(status);
7743 if (!WIFSTOPPED(status))
7744#endif
7745 {
7746 /* XXX: limits number of signals */
7747 retval = WTERMSIG(status);
7748#if JOBS
7749 if (retval == SIGINT)
7750 job->sigint = 1;
7751#endif
7752 }
7753 retval += 128;
7754 }
7755 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7756 jobno(job), job->nprocs, status, retval));
7757 return retval;
7758}
7759
Eric Andersend35c5df2002-01-09 15:37:36 +00007760#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007761/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007762
Eric Andersencb57d552001-06-28 07:25:16 +00007763/*
Eric Andersenc470f442003-07-28 09:56:35 +00007764 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007765 */
7766
Eric Andersencb57d552001-06-28 07:25:16 +00007767#define MAXMBOXES 10
7768
Eric Andersenc470f442003-07-28 09:56:35 +00007769/* times of mailboxes */
7770static time_t mailtime[MAXMBOXES];
7771/* Set if MAIL or MAILPATH is changed. */
7772static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007773
7774
7775
7776/*
Eric Andersenc470f442003-07-28 09:56:35 +00007777 * Print appropriate message(s) if mail has arrived.
7778 * If mail_var_path_changed is set,
7779 * then the value of MAIL has mail_var_path_changed,
7780 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007781 */
7782
Eric Andersenc470f442003-07-28 09:56:35 +00007783static void
7784chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007785{
Eric Andersencb57d552001-06-28 07:25:16 +00007786 const char *mpath;
7787 char *p;
7788 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007789 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007790 struct stackmark smark;
7791 struct stat statb;
7792
Eric Andersencb57d552001-06-28 07:25:16 +00007793 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007794 mpath = mpathset() ? mpathval() : mailval();
7795 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007796 p = padvance(&mpath, nullstr);
7797 if (p == NULL)
7798 break;
7799 if (*p == '\0')
7800 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007801 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007802#ifdef DEBUG
7803 if (q[-1] != '/')
7804 abort();
7805#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007806 q[-1] = '\0'; /* delete trailing '/' */
7807 if (stat(p, &statb) < 0) {
7808 *mtp = 0;
7809 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007810 }
Eric Andersenc470f442003-07-28 09:56:35 +00007811 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7812 fprintf(
7813 stderr, snlfmt,
7814 pathopt ? pathopt : "you have mail"
7815 );
7816 }
7817 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007818 }
Eric Andersenc470f442003-07-28 09:56:35 +00007819 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007820 popstackmark(&smark);
7821}
Eric Andersencb57d552001-06-28 07:25:16 +00007822
Eric Andersenec074692001-10-31 11:05:49 +00007823
Eric Andersenc470f442003-07-28 09:56:35 +00007824static void
7825changemail(const char *val)
7826{
7827 mail_var_path_changed++;
7828}
7829
7830#endif /* CONFIG_ASH_MAIL */
7831
7832/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7833
Eric Andersencb57d552001-06-28 07:25:16 +00007834
Eric Andersencb57d552001-06-28 07:25:16 +00007835#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007836static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007837extern int etext();
7838#endif
7839
Eric Andersenc470f442003-07-28 09:56:35 +00007840static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007841
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007842static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007843
Eric Andersencb57d552001-06-28 07:25:16 +00007844/*
7845 * Main routine. We initialize things, parse the arguments, execute
7846 * profiles if we're a login shell, and then call cmdloop to execute
7847 * commands. The setjmp call sets up the location to jump to when an
7848 * exception occurs. When an exception occurs the variable "state"
7849 * is used to figure out how far we had gotten.
7850 */
7851
Eric Andersenc470f442003-07-28 09:56:35 +00007852int
7853ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007854{
Eric Andersenc470f442003-07-28 09:56:35 +00007855 char *shinit;
7856 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007857 struct jmploc jmploc;
7858 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007859
Eric Andersenc470f442003-07-28 09:56:35 +00007860#ifdef __GLIBC__
7861 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007862#endif
7863
Eric Andersencb57d552001-06-28 07:25:16 +00007864#if PROFILE
7865 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7866#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007867 state = 0;
7868 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007869 int status;
7870 int e;
7871
Eric Andersencb57d552001-06-28 07:25:16 +00007872 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007873
7874 e = exception;
7875 switch (exception) {
7876 case EXEXEC:
7877 status = exerrno;
7878 break;
7879
7880 case EXERROR:
7881 status = 2;
7882 break;
7883
7884 default:
7885 status = exitstatus;
7886 break;
7887 }
7888 exitstatus = status;
7889
7890 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7891 exitshell();
7892
Eric Andersen90898442003-08-06 11:20:52 +00007893 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007894 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007895 }
7896 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007897 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007898 if (state == 1)
7899 goto state1;
7900 else if (state == 2)
7901 goto state2;
7902 else if (state == 3)
7903 goto state3;
7904 else
7905 goto state4;
7906 }
7907 handler = &jmploc;
7908#ifdef DEBUG
7909 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007910 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007911#endif
7912 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007913
7914#ifdef CONFIG_ASH_RANDOM_SUPPORT
7915 rseed = rootpid + ((time_t)time((time_t *)0));
7916#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007917 rootshell = 1;
7918 init();
7919 setstackmark(&smark);
7920 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007921#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7922 if ( iflag ) {
7923 const char *hp = lookupvar("HISTFILE");
7924
7925 if(hp == NULL ) {
7926 hp = lookupvar("HOME");
7927 if(hp != NULL) {
7928 char *defhp = concat_path_file(hp, ".ash_history");
7929 setvar("HISTFILE", defhp, 0);
7930 free(defhp);
7931 }
7932 }
7933 }
7934#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007935 if (argv[0] && argv[0][0] == '-')
7936 isloginsh = 1;
7937 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007938 state = 1;
7939 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007940state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007941 state = 2;
7942 read_profile(".profile");
7943 }
Eric Andersenc470f442003-07-28 09:56:35 +00007944state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007945 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007946 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007947#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007948 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007949#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007950 iflag
7951 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007952 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007953 read_profile(shinit);
7954 }
Eric Andersencb57d552001-06-28 07:25:16 +00007955 }
Eric Andersenc470f442003-07-28 09:56:35 +00007956state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007957 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007958 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007959 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007960
7961 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007962#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007963 if ( iflag ) {
7964 const char *hp = lookupvar("HISTFILE");
7965
7966 if(hp != NULL )
7967 load_history ( hp );
7968 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007969#endif
Eric Andersen90898442003-08-06 11:20:52 +00007970state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007971 cmdloop(1);
7972 }
7973#if PROFILE
7974 monitor(0);
7975#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007976#if GPROF
7977 {
7978 extern void _mcleanup(void);
7979 _mcleanup();
7980 }
7981#endif
7982 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007983 /* NOTREACHED */
7984}
7985
7986
7987/*
7988 * Read and execute commands. "Top" is nonzero for the top level command
7989 * loop; it turns on prompting if the shell is interactive.
7990 */
7991
Eric Andersenc470f442003-07-28 09:56:35 +00007992static void
7993cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007994{
7995 union node *n;
7996 struct stackmark smark;
7997 int inter;
7998 int numeof = 0;
7999
8000 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008001 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00008002 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00008003 if (pendingsigs)
8004 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00008005#if JOBS
8006 if (jobctl)
8007 showjobs(stderr, SHOW_CHANGED);
8008#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008009 inter = 0;
8010 if (iflag && top) {
8011 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008012#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008013 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008014#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008015 }
8016 n = parsecmd(inter);
8017 /* showtree(n); DEBUG */
8018 if (n == NEOF) {
8019 if (!top || numeof >= 50)
8020 break;
8021 if (!stoppedjobs()) {
8022 if (!Iflag)
8023 break;
8024 out2str("\nUse \"exit\" to leave shell.\n");
8025 }
8026 numeof++;
8027 } else if (n != NULL && nflag == 0) {
8028 job_warning = (job_warning == 2) ? 1 : 0;
8029 numeof = 0;
8030 evaltree(n, 0);
8031 }
8032 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008033 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008034 evalskip = 0;
8035 break;
8036 }
8037 }
Eric Andersencb57d552001-06-28 07:25:16 +00008038}
8039
8040
Eric Andersencb57d552001-06-28 07:25:16 +00008041/*
8042 * Read /etc/profile or .profile. Return on error.
8043 */
8044
Eric Andersenc470f442003-07-28 09:56:35 +00008045static void
8046read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008047{
8048 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008049 int xflag_set = 0;
8050 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008051
8052 INTOFF;
8053 if ((fd = open(name, O_RDONLY)) >= 0)
8054 setinputfd(fd, 1);
8055 INTON;
8056 if (fd < 0)
8057 return;
8058 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008059 if (qflag) {
8060 if (xflag)
8061 xflag = 0, xflag_set = 1;
8062 if (vflag)
8063 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008064 }
8065 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008066 if (qflag) {
8067 if (xflag_set)
8068 xflag = 1;
8069 if (vflag_set)
8070 vflag = 1;
8071 }
Eric Andersencb57d552001-06-28 07:25:16 +00008072 popfile();
8073}
8074
8075
Eric Andersencb57d552001-06-28 07:25:16 +00008076/*
8077 * Read a file containing shell functions.
8078 */
8079
Eric Andersenc470f442003-07-28 09:56:35 +00008080static void
8081readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008082{
8083 int fd;
8084
8085 INTOFF;
8086 if ((fd = open(name, O_RDONLY)) >= 0)
8087 setinputfd(fd, 1);
8088 else
8089 error("Can't open %s", name);
8090 INTON;
8091 cmdloop(0);
8092 popfile();
8093}
8094
8095
Eric Andersencb57d552001-06-28 07:25:16 +00008096/*
Eric Andersenc470f442003-07-28 09:56:35 +00008097 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008098 * search for the file, which is necessary to find sub-commands.
8099 */
8100
Eric Andersenc470f442003-07-28 09:56:35 +00008101static inline char *
8102find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008103{
8104 char *fullname;
8105 const char *path = pathval();
8106 struct stat statb;
8107
8108 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008109 if (strchr(name, '/'))
8110 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008111
Eric Andersenc470f442003-07-28 09:56:35 +00008112 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008113 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8114 /*
8115 * Don't bother freeing here, since it will
8116 * be freed by the caller.
8117 */
8118 return fullname;
8119 }
8120 stunalloc(fullname);
8121 }
8122
8123 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008124 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008125 /* NOTREACHED */
8126}
8127
Eric Andersen1e6aba92004-04-12 19:12:13 +00008128static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008129{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008130 struct strlist *sp;
8131 volatile struct shparam saveparam;
8132
Eric Andersencb57d552001-06-28 07:25:16 +00008133 exitstatus = 0;
8134
Eric Andersen1e6aba92004-04-12 19:12:13 +00008135 for (sp = cmdenviron; sp; sp = sp->next)
8136 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8137
8138 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008139 char *fullname;
8140 struct stackmark smark;
8141
8142 setstackmark(&smark);
8143 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008144
8145 if (argc > 2) {
8146 saveparam = shellparam;
8147 shellparam.malloc = 0;
8148 shellparam.nparam = argc - 2;
8149 shellparam.p = argv + 2;
8150 };
8151
Eric Andersencb57d552001-06-28 07:25:16 +00008152 setinputfile(fullname, 1);
8153 commandname = fullname;
8154 cmdloop(0);
8155 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008156
8157 if (argc > 2) {
8158 freeparam(&shellparam);
8159 shellparam = saveparam;
8160 };
8161
Eric Andersencb57d552001-06-28 07:25:16 +00008162 popstackmark(&smark);
8163 }
8164 return exitstatus;
8165}
8166
8167
Eric Andersenc470f442003-07-28 09:56:35 +00008168static int
8169exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008170{
8171 if (stoppedjobs())
8172 return 0;
8173 if (argc > 1)
8174 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008175 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008176 /* NOTREACHED */
8177}
Eric Andersen62483552001-07-10 06:09:16 +00008178
Eric Andersenc470f442003-07-28 09:56:35 +00008179/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8180
8181/*
Eric Andersen90898442003-08-06 11:20:52 +00008182 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008183 */
8184
8185static pointer
8186ckrealloc(pointer p, size_t nbytes)
8187{
8188 p = realloc(p, nbytes);
8189 if (p == NULL)
8190 error(bb_msg_memory_exhausted);
8191 return p;
8192}
8193
Eric Andersen90898442003-08-06 11:20:52 +00008194static pointer
8195ckmalloc(size_t nbytes)
8196{
8197 return ckrealloc(NULL, nbytes);
8198}
Eric Andersenc470f442003-07-28 09:56:35 +00008199
8200/*
8201 * Make a copy of a string in safe storage.
8202 */
8203
8204static char *
8205savestr(const char *s)
8206{
8207 char *p = strdup(s);
8208 if (!p)
8209 error(bb_msg_memory_exhausted);
8210 return p;
8211}
8212
8213
8214/*
8215 * Parse trees for commands are allocated in lifo order, so we use a stack
8216 * to make this more efficient, and also to avoid all sorts of exception
8217 * handling code to handle interrupts in the middle of a parse.
8218 *
8219 * The size 504 was chosen because the Ultrix malloc handles that size
8220 * well.
8221 */
8222
8223
8224static pointer
8225stalloc(size_t nbytes)
8226{
8227 char *p;
8228 size_t aligned;
8229
8230 aligned = SHELL_ALIGN(nbytes);
8231 if (aligned > stacknleft) {
8232 size_t len;
8233 size_t blocksize;
8234 struct stack_block *sp;
8235
8236 blocksize = aligned;
8237 if (blocksize < MINSIZE)
8238 blocksize = MINSIZE;
8239 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8240 if (len < blocksize)
8241 error(bb_msg_memory_exhausted);
8242 INTOFF;
8243 sp = ckmalloc(len);
8244 sp->prev = stackp;
8245 stacknxt = sp->space;
8246 stacknleft = blocksize;
8247 sstrend = stacknxt + blocksize;
8248 stackp = sp;
8249 INTON;
8250 }
8251 p = stacknxt;
8252 stacknxt += aligned;
8253 stacknleft -= aligned;
8254 return p;
8255}
8256
8257
8258void
8259stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008260{
Eric Andersencb57d552001-06-28 07:25:16 +00008261#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008262 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008263 write(2, "stunalloc\n", 10);
8264 abort();
8265 }
8266#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008267 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008268 stacknxt = p;
8269}
8270
8271
Eric Andersenc470f442003-07-28 09:56:35 +00008272void
8273setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008274{
Eric Andersencb57d552001-06-28 07:25:16 +00008275 mark->stackp = stackp;
8276 mark->stacknxt = stacknxt;
8277 mark->stacknleft = stacknleft;
8278 mark->marknext = markp;
8279 markp = mark;
8280}
8281
8282
Eric Andersenc470f442003-07-28 09:56:35 +00008283void
8284popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008285{
Eric Andersencb57d552001-06-28 07:25:16 +00008286 struct stack_block *sp;
8287
8288 INTOFF;
8289 markp = mark->marknext;
8290 while (stackp != mark->stackp) {
8291 sp = stackp;
8292 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008293 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008294 }
8295 stacknxt = mark->stacknxt;
8296 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008297 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008298 INTON;
8299}
8300
8301
8302/*
8303 * When the parser reads in a string, it wants to stick the string on the
8304 * stack and only adjust the stack pointer when it knows how big the
8305 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8306 * of space on top of the stack and stackblocklen returns the length of
8307 * this block. Growstackblock will grow this space by at least one byte,
8308 * possibly moving it (like realloc). Grabstackblock actually allocates the
8309 * part of the block that has been used.
8310 */
8311
Eric Andersenc470f442003-07-28 09:56:35 +00008312void
8313growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008314{
Eric Andersenc470f442003-07-28 09:56:35 +00008315 size_t newlen;
8316
8317 newlen = stacknleft * 2;
8318 if (newlen < stacknleft)
8319 error(bb_msg_memory_exhausted);
8320 if (newlen < 128)
8321 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008322
8323 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008324 struct stack_block *oldstackp;
8325 struct stackmark *xmark;
8326 struct stack_block *sp;
8327 struct stack_block *prevstackp;
8328 size_t grosslen;
8329
Eric Andersencb57d552001-06-28 07:25:16 +00008330 INTOFF;
8331 oldstackp = stackp;
8332 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008333 prevstackp = sp->prev;
8334 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8335 sp = ckrealloc((pointer)sp, grosslen);
8336 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008337 stackp = sp;
8338 stacknxt = sp->space;
8339 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008340 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008341
Eric Andersenc470f442003-07-28 09:56:35 +00008342 /*
8343 * Stack marks pointing to the start of the old block
8344 * must be relocated to point to the new block
8345 */
8346 xmark = markp;
8347 while (xmark != NULL && xmark->stackp == oldstackp) {
8348 xmark->stackp = stackp;
8349 xmark->stacknxt = stacknxt;
8350 xmark->stacknleft = stacknleft;
8351 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008352 }
8353 INTON;
8354 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008355 char *oldspace = stacknxt;
8356 int oldlen = stacknleft;
8357 char *p = stalloc(newlen);
8358
8359 /* free the space we just allocated */
8360 stacknxt = memcpy(p, oldspace, oldlen);
8361 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008362 }
8363}
8364
Eric Andersenc470f442003-07-28 09:56:35 +00008365static inline void
8366grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008367{
Eric Andersenc470f442003-07-28 09:56:35 +00008368 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008369 stacknxt += len;
8370 stacknleft -= len;
8371}
8372
Eric Andersencb57d552001-06-28 07:25:16 +00008373/*
Eric Andersenc470f442003-07-28 09:56:35 +00008374 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008375 * The user declares a variable of type STACKSTR, which may be declared
8376 * to be a register. The macro STARTSTACKSTR initializes things. Then
8377 * the user uses the macro STPUTC to add characters to the string. In
8378 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8379 * grown as necessary. When the user is done, she can just leave the
8380 * string there and refer to it using stackblock(). Or she can allocate
8381 * the space for it using grabstackstr(). If it is necessary to allow
8382 * someone else to use the stack temporarily and then continue to grow
8383 * the string, the user should use grabstack to allocate the space, and
8384 * then call ungrabstr(p) to return to the previous mode of operation.
8385 *
8386 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8387 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8388 * is space for at least one character.
8389 */
8390
Eric Andersenc470f442003-07-28 09:56:35 +00008391void *
8392growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008393{
Eric Andersenc470f442003-07-28 09:56:35 +00008394 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008395 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008396 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008397 return stackblock();
8398 }
8399 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008400 return stackblock() + len;
8401}
8402
Eric Andersencb57d552001-06-28 07:25:16 +00008403/*
8404 * Called from CHECKSTRSPACE.
8405 */
8406
Eric Andersenc470f442003-07-28 09:56:35 +00008407char *
8408makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008409{
Eric Andersenc470f442003-07-28 09:56:35 +00008410 size_t len = p - stacknxt;
8411 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008412
Eric Andersenc470f442003-07-28 09:56:35 +00008413 for (;;) {
8414 size_t nleft;
8415
8416 size = stackblocksize();
8417 nleft = size - len;
8418 if (nleft >= newlen)
8419 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008420 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008421 }
Eric Andersencb57d552001-06-28 07:25:16 +00008422 return stackblock() + len;
8423}
8424
Eric Andersenc470f442003-07-28 09:56:35 +00008425char *
8426stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008427{
Eric Andersenc470f442003-07-28 09:56:35 +00008428 p = makestrspace(n, p);
8429 p = mempcpy(p, s, n);
8430 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008431}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008432
Eric Andersenc470f442003-07-28 09:56:35 +00008433char *
8434stputs(const char *s, char *p)
8435{
8436 return stnputs(s, strlen(s), p);
8437}
8438
8439/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8440
Eric Andersencb57d552001-06-28 07:25:16 +00008441/*
Eric Andersenc470f442003-07-28 09:56:35 +00008442 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008443 *
Eric Andersenc470f442003-07-28 09:56:35 +00008444 * number(s) Convert a string of digits to an integer.
8445 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008446 */
8447
Eric Andersencb57d552001-06-28 07:25:16 +00008448/*
8449 * prefix -- see if pfx is a prefix of string.
8450 */
8451
Eric Andersenc470f442003-07-28 09:56:35 +00008452char *
8453prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008454{
Eric Andersencb57d552001-06-28 07:25:16 +00008455 while (*pfx) {
8456 if (*pfx++ != *string++)
8457 return 0;
8458 }
Eric Andersenc470f442003-07-28 09:56:35 +00008459 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008460}
8461
8462
8463/*
8464 * Convert a string of digits to an integer, printing an error message on
8465 * failure.
8466 */
8467
Eric Andersenc470f442003-07-28 09:56:35 +00008468int
8469number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008470{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008471
Eric Andersenc470f442003-07-28 09:56:35 +00008472 if (! is_number(s))
8473 error(illnum, s);
8474 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008475}
8476
Eric Andersenc470f442003-07-28 09:56:35 +00008477
Eric Andersenc470f442003-07-28 09:56:35 +00008478/*
8479 * Check for a valid number. This should be elsewhere.
8480 */
8481
8482int
8483is_number(const char *p)
8484{
8485 do {
8486 if (! is_digit(*p))
8487 return 0;
8488 } while (*++p != '\0');
8489 return 1;
8490}
8491
8492
Eric Andersencb57d552001-06-28 07:25:16 +00008493/*
8494 * Produce a possibly single quoted string suitable as input to the shell.
8495 * The return string is allocated on the stack.
8496 */
8497
Eric Andersenc470f442003-07-28 09:56:35 +00008498char *
8499single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008500 char *p;
8501
8502 STARTSTACKSTR(p);
8503
8504 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008505 char *q;
8506 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008507
Eric Andersenc470f442003-07-28 09:56:35 +00008508 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008509
Eric Andersenc470f442003-07-28 09:56:35 +00008510 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008511
Eric Andersenc470f442003-07-28 09:56:35 +00008512 *q++ = '\'';
8513 q = mempcpy(q, s, len);
8514 *q++ = '\'';
8515 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008516
Eric Andersenc470f442003-07-28 09:56:35 +00008517 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008518
Eric Andersenc470f442003-07-28 09:56:35 +00008519 len = strspn(s, "'");
8520 if (!len)
8521 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008522
Eric Andersenc470f442003-07-28 09:56:35 +00008523 q = p = makestrspace(len + 3, p);
8524
8525 *q++ = '"';
8526 q = mempcpy(q, s, len);
8527 *q++ = '"';
8528 s += len;
8529
8530 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008531 } while (*s);
8532
8533 USTPUTC(0, p);
8534
Eric Andersenc470f442003-07-28 09:56:35 +00008535 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008536}
8537
8538/*
Eric Andersenc470f442003-07-28 09:56:35 +00008539 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008540 */
8541
Eric Andersenc470f442003-07-28 09:56:35 +00008542char *
8543sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008544{
Eric Andersenc470f442003-07-28 09:56:35 +00008545 size_t len = strlen(p) + 1;
8546 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008547}
Eric Andersenc470f442003-07-28 09:56:35 +00008548
8549
8550static void
8551calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008552{
Eric Andersenc470f442003-07-28 09:56:35 +00008553 if (n == NULL)
8554 return;
8555 funcblocksize += nodesize[n->type];
8556 switch (n->type) {
8557 case NCMD:
8558 calcsize(n->ncmd.redirect);
8559 calcsize(n->ncmd.args);
8560 calcsize(n->ncmd.assign);
8561 break;
8562 case NPIPE:
8563 sizenodelist(n->npipe.cmdlist);
8564 break;
8565 case NREDIR:
8566 case NBACKGND:
8567 case NSUBSHELL:
8568 calcsize(n->nredir.redirect);
8569 calcsize(n->nredir.n);
8570 break;
8571 case NAND:
8572 case NOR:
8573 case NSEMI:
8574 case NWHILE:
8575 case NUNTIL:
8576 calcsize(n->nbinary.ch2);
8577 calcsize(n->nbinary.ch1);
8578 break;
8579 case NIF:
8580 calcsize(n->nif.elsepart);
8581 calcsize(n->nif.ifpart);
8582 calcsize(n->nif.test);
8583 break;
8584 case NFOR:
8585 funcstringsize += strlen(n->nfor.var) + 1;
8586 calcsize(n->nfor.body);
8587 calcsize(n->nfor.args);
8588 break;
8589 case NCASE:
8590 calcsize(n->ncase.cases);
8591 calcsize(n->ncase.expr);
8592 break;
8593 case NCLIST:
8594 calcsize(n->nclist.body);
8595 calcsize(n->nclist.pattern);
8596 calcsize(n->nclist.next);
8597 break;
8598 case NDEFUN:
8599 case NARG:
8600 sizenodelist(n->narg.backquote);
8601 funcstringsize += strlen(n->narg.text) + 1;
8602 calcsize(n->narg.next);
8603 break;
8604 case NTO:
8605 case NCLOBBER:
8606 case NFROM:
8607 case NFROMTO:
8608 case NAPPEND:
8609 calcsize(n->nfile.fname);
8610 calcsize(n->nfile.next);
8611 break;
8612 case NTOFD:
8613 case NFROMFD:
8614 calcsize(n->ndup.vname);
8615 calcsize(n->ndup.next);
8616 break;
8617 case NHERE:
8618 case NXHERE:
8619 calcsize(n->nhere.doc);
8620 calcsize(n->nhere.next);
8621 break;
8622 case NNOT:
8623 calcsize(n->nnot.com);
8624 break;
8625 };
Eric Andersencb57d552001-06-28 07:25:16 +00008626}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008627
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008628
Eric Andersenc470f442003-07-28 09:56:35 +00008629static void
8630sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008631{
8632 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008633 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008634 calcsize(lp->n);
8635 lp = lp->next;
8636 }
8637}
Eric Andersencb57d552001-06-28 07:25:16 +00008638
8639
Eric Andersenc470f442003-07-28 09:56:35 +00008640static union node *
8641copynode(union node *n)
8642{
8643 union node *new;
8644
8645 if (n == NULL)
8646 return NULL;
8647 new = funcblock;
8648 funcblock = (char *) funcblock + nodesize[n->type];
8649 switch (n->type) {
8650 case NCMD:
8651 new->ncmd.redirect = copynode(n->ncmd.redirect);
8652 new->ncmd.args = copynode(n->ncmd.args);
8653 new->ncmd.assign = copynode(n->ncmd.assign);
8654 break;
8655 case NPIPE:
8656 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8657 new->npipe.backgnd = n->npipe.backgnd;
8658 break;
8659 case NREDIR:
8660 case NBACKGND:
8661 case NSUBSHELL:
8662 new->nredir.redirect = copynode(n->nredir.redirect);
8663 new->nredir.n = copynode(n->nredir.n);
8664 break;
8665 case NAND:
8666 case NOR:
8667 case NSEMI:
8668 case NWHILE:
8669 case NUNTIL:
8670 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8671 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8672 break;
8673 case NIF:
8674 new->nif.elsepart = copynode(n->nif.elsepart);
8675 new->nif.ifpart = copynode(n->nif.ifpart);
8676 new->nif.test = copynode(n->nif.test);
8677 break;
8678 case NFOR:
8679 new->nfor.var = nodesavestr(n->nfor.var);
8680 new->nfor.body = copynode(n->nfor.body);
8681 new->nfor.args = copynode(n->nfor.args);
8682 break;
8683 case NCASE:
8684 new->ncase.cases = copynode(n->ncase.cases);
8685 new->ncase.expr = copynode(n->ncase.expr);
8686 break;
8687 case NCLIST:
8688 new->nclist.body = copynode(n->nclist.body);
8689 new->nclist.pattern = copynode(n->nclist.pattern);
8690 new->nclist.next = copynode(n->nclist.next);
8691 break;
8692 case NDEFUN:
8693 case NARG:
8694 new->narg.backquote = copynodelist(n->narg.backquote);
8695 new->narg.text = nodesavestr(n->narg.text);
8696 new->narg.next = copynode(n->narg.next);
8697 break;
8698 case NTO:
8699 case NCLOBBER:
8700 case NFROM:
8701 case NFROMTO:
8702 case NAPPEND:
8703 new->nfile.fname = copynode(n->nfile.fname);
8704 new->nfile.fd = n->nfile.fd;
8705 new->nfile.next = copynode(n->nfile.next);
8706 break;
8707 case NTOFD:
8708 case NFROMFD:
8709 new->ndup.vname = copynode(n->ndup.vname);
8710 new->ndup.dupfd = n->ndup.dupfd;
8711 new->ndup.fd = n->ndup.fd;
8712 new->ndup.next = copynode(n->ndup.next);
8713 break;
8714 case NHERE:
8715 case NXHERE:
8716 new->nhere.doc = copynode(n->nhere.doc);
8717 new->nhere.fd = n->nhere.fd;
8718 new->nhere.next = copynode(n->nhere.next);
8719 break;
8720 case NNOT:
8721 new->nnot.com = copynode(n->nnot.com);
8722 break;
8723 };
8724 new->type = n->type;
8725 return new;
8726}
8727
8728
8729static struct nodelist *
8730copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008731{
8732 struct nodelist *start;
8733 struct nodelist **lpp;
8734
8735 lpp = &start;
8736 while (lp) {
8737 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008738 funcblock = (char *) funcblock +
8739 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008740 (*lpp)->n = copynode(lp->n);
8741 lp = lp->next;
8742 lpp = &(*lpp)->next;
8743 }
8744 *lpp = NULL;
8745 return start;
8746}
8747
8748
Eric Andersenc470f442003-07-28 09:56:35 +00008749static char *
8750nodesavestr(char *s)
8751{
8752 char *rtn = funcstring;
8753
8754 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008755 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008756}
8757
Eric Andersenc470f442003-07-28 09:56:35 +00008758
Eric Andersenc470f442003-07-28 09:56:35 +00008759/*
8760 * Free a parse tree.
8761 */
8762
8763static void
8764freefunc(struct funcnode *f)
8765{
8766 if (f && --f->count < 0)
8767 ckfree(f);
8768}
8769
8770
8771static void options(int);
8772static void setoption(int, int);
8773
Eric Andersencb57d552001-06-28 07:25:16 +00008774
Eric Andersencb57d552001-06-28 07:25:16 +00008775/*
8776 * Process the shell command line arguments.
8777 */
8778
Eric Andersenc470f442003-07-28 09:56:35 +00008779void
8780procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008781{
8782 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008783 const char *xminusc;
8784 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008785
Eric Andersenc470f442003-07-28 09:56:35 +00008786 xargv = argv;
8787 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008788 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008789 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008790 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008791 optlist[i] = 2;
8792 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008793 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008794 xargv = argptr;
8795 xminusc = minusc;
8796 if (*xargv == NULL) {
8797 if (xminusc)
8798 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008799 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008800 }
Eric Andersencb57d552001-06-28 07:25:16 +00008801 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8802 iflag = 1;
8803 if (mflag == 2)
8804 mflag = iflag;
8805 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008806 if (optlist[i] == 2)
8807 optlist[i] = 0;
8808#if DEBUG == 2
8809 debug = 1;
8810#endif
8811 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8812 if (xminusc) {
8813 minusc = *xargv++;
8814 if (*xargv)
8815 goto setarg0;
8816 } else if (!sflag) {
8817 setinputfile(*xargv, 0);
8818setarg0:
8819 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008820 commandname = arg0;
8821 }
Eric Andersencb57d552001-06-28 07:25:16 +00008822
Eric Andersenc470f442003-07-28 09:56:35 +00008823 shellparam.p = xargv;
8824#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008825 shellparam.optind = 1;
8826 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008827#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008828 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008829 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008830 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008831 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008832 }
8833 optschanged();
8834}
8835
8836
Eric Andersenc470f442003-07-28 09:56:35 +00008837void
8838optschanged(void)
8839{
8840#ifdef DEBUG
8841 opentrace();
8842#endif
8843 setinteractive(iflag);
8844 setjobctl(mflag);
8845}
Eric Andersencb57d552001-06-28 07:25:16 +00008846
Eric Andersenc470f442003-07-28 09:56:35 +00008847static inline void
8848minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008849{
8850 int i;
8851
8852 if (name == NULL) {
8853 out1str("Current option settings\n");
8854 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008855 out1fmt("%-16s%s\n", optnames(i),
8856 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008857 } else {
8858 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008859 if (equal(name, optnames(i))) {
8860 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008861 return;
8862 }
8863 error("Illegal option -o %s", name);
8864 }
8865}
8866
Eric Andersenc470f442003-07-28 09:56:35 +00008867/*
8868 * Process shell options. The global variable argptr contains a pointer
8869 * to the argument list; we advance it past the options.
8870 */
Eric Andersen62483552001-07-10 06:09:16 +00008871
Eric Andersenc470f442003-07-28 09:56:35 +00008872static void
8873options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008874{
8875 char *p;
8876 int val;
8877 int c;
8878
8879 if (cmdline)
8880 minusc = NULL;
8881 while ((p = *argptr) != NULL) {
8882 argptr++;
8883 if ((c = *p++) == '-') {
8884 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008885 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8886 if (!cmdline) {
8887 /* "-" means turn off -x and -v */
8888 if (p[0] == '\0')
8889 xflag = vflag = 0;
8890 /* "--" means reset params */
8891 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008892 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008893 }
Eric Andersenc470f442003-07-28 09:56:35 +00008894 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008895 }
8896 } else if (c == '+') {
8897 val = 0;
8898 } else {
8899 argptr--;
8900 break;
8901 }
8902 while ((c = *p++) != '\0') {
8903 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008904 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008905 } else if (c == 'o') {
8906 minus_o(*argptr, val);
8907 if (*argptr)
8908 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008909 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008910 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008911 isloginsh = 1;
8912 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008913 } else {
8914 setoption(c, val);
8915 }
8916 }
8917 }
8918}
8919
Eric Andersencb57d552001-06-28 07:25:16 +00008920
Eric Andersenc470f442003-07-28 09:56:35 +00008921static void
8922setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008923{
Eric Andersencb57d552001-06-28 07:25:16 +00008924 int i;
8925
8926 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008927 if (optletters(i) == flag) {
8928 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008929 return;
8930 }
8931 error("Illegal option -%c", flag);
8932 /* NOTREACHED */
8933}
8934
8935
8936
Eric Andersencb57d552001-06-28 07:25:16 +00008937/*
8938 * Set the shell parameters.
8939 */
8940
Eric Andersenc470f442003-07-28 09:56:35 +00008941void
8942setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008943{
Eric Andersencb57d552001-06-28 07:25:16 +00008944 char **newparam;
8945 char **ap;
8946 int nparam;
8947
Eric Andersenc470f442003-07-28 09:56:35 +00008948 for (nparam = 0 ; argv[nparam] ; nparam++);
8949 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008950 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008951 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008952 }
8953 *ap = NULL;
8954 freeparam(&shellparam);
8955 shellparam.malloc = 1;
8956 shellparam.nparam = nparam;
8957 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008958#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008959 shellparam.optind = 1;
8960 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008961#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008962}
8963
8964
8965/*
8966 * Free the list of positional parameters.
8967 */
8968
Eric Andersenc470f442003-07-28 09:56:35 +00008969void
8970freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008971{
Eric Andersencb57d552001-06-28 07:25:16 +00008972 char **ap;
8973
8974 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008975 for (ap = param->p ; *ap ; ap++)
8976 ckfree(*ap);
8977 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008978 }
8979}
8980
8981
8982
8983/*
8984 * The shift builtin command.
8985 */
8986
Eric Andersenc470f442003-07-28 09:56:35 +00008987int
8988shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008989{
8990 int n;
8991 char **ap1, **ap2;
8992
8993 n = 1;
8994 if (argc > 1)
8995 n = number(argv[1]);
8996 if (n > shellparam.nparam)
8997 error("can't shift that many");
8998 INTOFF;
8999 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009000 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009001 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009002 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009003 }
9004 ap2 = shellparam.p;
9005 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009006#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009007 shellparam.optind = 1;
9008 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009009#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009010 INTON;
9011 return 0;
9012}
9013
9014
9015
9016/*
9017 * The set command builtin.
9018 */
9019
Eric Andersenc470f442003-07-28 09:56:35 +00009020int
9021setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009022{
9023 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009024 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009025 INTOFF;
9026 options(0);
9027 optschanged();
9028 if (*argptr != NULL) {
9029 setparam(argptr);
9030 }
9031 INTON;
9032 return 0;
9033}
9034
9035
Eric Andersenc470f442003-07-28 09:56:35 +00009036#ifdef CONFIG_ASH_GETOPTS
9037static void
9038getoptsreset(value)
9039 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009040{
9041 shellparam.optind = number(value);
9042 shellparam.optoff = -1;
9043}
Eric Andersenc470f442003-07-28 09:56:35 +00009044#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009045
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009046#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009047static void change_lc_all(const char *value)
9048{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009049 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009050 setlocale(LC_ALL, value);
9051}
9052
9053static void change_lc_ctype(const char *value)
9054{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009055 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009056 setlocale(LC_CTYPE, value);
9057}
9058
9059#endif
9060
Eric Andersen16767e22004-03-16 05:14:10 +00009061#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009062/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009063static void change_random(const char *value)
9064{
Eric Andersen16767e22004-03-16 05:14:10 +00009065 if(value == NULL) {
9066 /* "get", generate */
9067 char buf[16];
9068
9069 rseed = rseed * 1103515245 + 12345;
9070 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9071 /* set without recursion */
9072 setvar(vrandom.text, buf, VNOFUNC);
9073 vrandom.flags &= ~VNOFUNC;
9074 } else {
9075 /* set/reset */
9076 rseed = strtoul(value, (char **)NULL, 10);
9077 }
Eric Andersenef02f822004-03-11 13:34:24 +00009078}
Eric Andersen16767e22004-03-16 05:14:10 +00009079#endif
9080
Eric Andersenef02f822004-03-11 13:34:24 +00009081
Eric Andersend35c5df2002-01-09 15:37:36 +00009082#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009083static int
Eric Andersenc470f442003-07-28 09:56:35 +00009084getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009085{
9086 char *p, *q;
9087 char c = '?';
9088 int done = 0;
9089 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009090 char s[12];
9091 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009092
Eric Andersena48b0a32003-10-22 10:56:47 +00009093 if(*param_optind < 1)
9094 return 1;
9095 optnext = optfirst + *param_optind - 1;
9096
9097 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009098 p = NULL;
9099 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009100 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009101 if (p == NULL || *p == '\0') {
9102 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009103 p = *optnext;
9104 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009105atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009106 p = NULL;
9107 done = 1;
9108 goto out;
9109 }
9110 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009111 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009112 goto atend;
9113 }
9114
9115 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009116 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009117 if (*q == '\0') {
9118 if (optstr[0] == ':') {
9119 s[0] = c;
9120 s[1] = '\0';
9121 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009122 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009123 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009124 (void) unsetvar("OPTARG");
9125 }
9126 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009127 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009128 }
9129 if (*++q == ':')
9130 q++;
9131 }
9132
9133 if (*++q == ':') {
9134 if (*p == '\0' && (p = *optnext) == NULL) {
9135 if (optstr[0] == ':') {
9136 s[0] = c;
9137 s[1] = '\0';
9138 err |= setvarsafe("OPTARG", s, 0);
9139 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009140 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009141 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009142 (void) unsetvar("OPTARG");
9143 c = '?';
9144 }
Eric Andersenc470f442003-07-28 09:56:35 +00009145 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009146 }
9147
9148 if (p == *optnext)
9149 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009150 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009151 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009152 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009153 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009154
Eric Andersenc470f442003-07-28 09:56:35 +00009155out:
Eric Andersencb57d552001-06-28 07:25:16 +00009156 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009157 *param_optind = optnext - optfirst + 1;
9158 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009159 err |= setvarsafe("OPTIND", s, VNOFUNC);
9160 s[0] = c;
9161 s[1] = '\0';
9162 err |= setvarsafe(optvar, s, 0);
9163 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009164 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009165 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009166 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009167 exraise(EXERROR);
9168 }
9169 return done;
9170}
Eric Andersenc470f442003-07-28 09:56:35 +00009171
9172/*
9173 * The getopts builtin. Shellparam.optnext points to the next argument
9174 * to be processed. Shellparam.optptr points to the next character to
9175 * be processed in the current argument. If shellparam.optnext is NULL,
9176 * then it's the first time getopts has been called.
9177 */
9178
9179int
9180getoptscmd(int argc, char **argv)
9181{
9182 char **optbase;
9183
9184 if (argc < 3)
9185 error("Usage: getopts optstring var [arg]");
9186 else if (argc == 3) {
9187 optbase = shellparam.p;
9188 if (shellparam.optind > shellparam.nparam + 1) {
9189 shellparam.optind = 1;
9190 shellparam.optoff = -1;
9191 }
9192 }
9193 else {
9194 optbase = &argv[3];
9195 if (shellparam.optind > argc - 2) {
9196 shellparam.optind = 1;
9197 shellparam.optoff = -1;
9198 }
9199 }
9200
9201 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9202 &shellparam.optoff);
9203}
9204#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009205
9206/*
9207 * XXX - should get rid of. have all builtins use getopt(3). the
9208 * library getopt must have the BSD extension static variable "optreset"
9209 * otherwise it can't be used within the shell safely.
9210 *
9211 * Standard option processing (a la getopt) for builtin routines. The
9212 * only argument that is passed to nextopt is the option string; the
9213 * other arguments are unnecessary. It return the character, or '\0' on
9214 * end of input.
9215 */
9216
Eric Andersenc470f442003-07-28 09:56:35 +00009217static int
9218nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009219{
Eric Andersencb57d552001-06-28 07:25:16 +00009220 char *p;
9221 const char *q;
9222 char c;
9223
9224 if ((p = optptr) == NULL || *p == '\0') {
9225 p = *argptr;
9226 if (p == NULL || *p != '-' || *++p == '\0')
9227 return '\0';
9228 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009229 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009230 return '\0';
9231 }
9232 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009233 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009234 if (*q == '\0')
9235 error("Illegal option -%c", c);
9236 if (*++q == ':')
9237 q++;
9238 }
9239 if (*++q == ':') {
9240 if (*p == '\0' && (p = *argptr++) == NULL)
9241 error("No arg for -%c option", c);
9242 optionarg = p;
9243 p = NULL;
9244 }
9245 optptr = p;
9246 return c;
9247}
9248
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009249
Eric Andersenc470f442003-07-28 09:56:35 +00009250/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9251
Eric Andersenc470f442003-07-28 09:56:35 +00009252void
9253outstr(const char *p, FILE *file)
9254{
9255 INTOFF;
9256 fputs(p, file);
9257 INTON;
9258}
9259
9260void
9261flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009262{
Eric Andersencb57d552001-06-28 07:25:16 +00009263 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009264 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009265 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009266 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009267}
9268
Eric Andersenc470f442003-07-28 09:56:35 +00009269void
Eric Andersen16767e22004-03-16 05:14:10 +00009270flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009271{
9272 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009273 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009274 INTON;
9275}
9276
9277static void
9278outcslow(int c, FILE *dest)
9279{
9280 INTOFF;
9281 putc(c, dest);
9282 fflush(dest);
9283 INTON;
9284}
9285
9286
9287static int
9288out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009289{
9290 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009291 int r;
9292
9293 INTOFF;
9294 va_start(ap, fmt);
9295 r = vprintf(fmt, ap);
9296 va_end(ap);
9297 INTON;
9298 return r;
9299}
9300
9301
9302int
9303fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9304{
9305 va_list ap;
9306 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009307
Eric Andersencb57d552001-06-28 07:25:16 +00009308 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009309 INTOFF;
9310 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009311 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009312 INTON;
9313 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009314}
9315
Eric Andersenc470f442003-07-28 09:56:35 +00009316
Eric Andersencb57d552001-06-28 07:25:16 +00009317
Eric Andersenc470f442003-07-28 09:56:35 +00009318/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9319
9320
Eric Andersencb57d552001-06-28 07:25:16 +00009321/*
9322 * Shell command parser.
9323 */
9324
9325#define EOFMARKLEN 79
9326
9327
Eric Andersencb57d552001-06-28 07:25:16 +00009328struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009329 struct heredoc *next; /* next here document in list */
9330 union node *here; /* redirection node */
9331 char *eofmark; /* string indicating end of input */
9332 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009333};
9334
9335
9336
Eric Andersenc470f442003-07-28 09:56:35 +00009337static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009338
9339
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009340static union node *list(int);
9341static union node *andor(void);
9342static union node *pipeline(void);
9343static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009344static union node *simplecmd(void);
9345static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009346static void parsefname(void);
9347static void parseheredoc(void);
9348static char peektoken(void);
9349static int readtoken(void);
9350static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009351static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009352static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009353static void synexpect(int) __attribute__((__noreturn__));
9354static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009355static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009356
9357
Eric Andersenc470f442003-07-28 09:56:35 +00009358
9359static inline int
9360isassignment(const char *p)
9361{
9362 const char *q = endofname(p);
9363 if (p == q)
9364 return 0;
9365 return *q == '=';
9366}
9367
9368
Eric Andersencb57d552001-06-28 07:25:16 +00009369/*
9370 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9371 * valid parse tree indicating a blank line.)
9372 */
9373
Eric Andersenc470f442003-07-28 09:56:35 +00009374union node *
9375parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009376{
9377 int t;
9378
9379 tokpushback = 0;
9380 doprompt = interact;
9381 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009382 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009383 needprompt = 0;
9384 t = readtoken();
9385 if (t == TEOF)
9386 return NEOF;
9387 if (t == TNL)
9388 return NULL;
9389 tokpushback++;
9390 return list(1);
9391}
9392
9393
Eric Andersenc470f442003-07-28 09:56:35 +00009394static union node *
9395list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009396{
9397 union node *n1, *n2, *n3;
9398 int tok;
9399
Eric Andersenc470f442003-07-28 09:56:35 +00009400 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9401 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009402 return NULL;
9403 n1 = NULL;
9404 for (;;) {
9405 n2 = andor();
9406 tok = readtoken();
9407 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009408 if (n2->type == NPIPE) {
9409 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009410 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009411 if (n2->type != NREDIR) {
9412 n3 = stalloc(sizeof(struct nredir));
9413 n3->nredir.n = n2;
9414 n3->nredir.redirect = NULL;
9415 n2 = n3;
9416 }
9417 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009418 }
9419 }
9420 if (n1 == NULL) {
9421 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009422 }
9423 else {
9424 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009425 n3->type = NSEMI;
9426 n3->nbinary.ch1 = n1;
9427 n3->nbinary.ch2 = n2;
9428 n1 = n3;
9429 }
9430 switch (tok) {
9431 case TBACKGND:
9432 case TSEMI:
9433 tok = readtoken();
9434 /* fall through */
9435 case TNL:
9436 if (tok == TNL) {
9437 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009438 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009439 return n1;
9440 } else {
9441 tokpushback++;
9442 }
Eric Andersenc470f442003-07-28 09:56:35 +00009443 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009444 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009445 return n1;
9446 break;
9447 case TEOF:
9448 if (heredoclist)
9449 parseheredoc();
9450 else
Eric Andersenc470f442003-07-28 09:56:35 +00009451 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009452 return n1;
9453 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009454 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009455 synexpect(-1);
9456 tokpushback++;
9457 return n1;
9458 }
9459 }
9460}
9461
9462
9463
Eric Andersenc470f442003-07-28 09:56:35 +00009464static union node *
9465andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009466{
Eric Andersencb57d552001-06-28 07:25:16 +00009467 union node *n1, *n2, *n3;
9468 int t;
9469
Eric Andersencb57d552001-06-28 07:25:16 +00009470 n1 = pipeline();
9471 for (;;) {
9472 if ((t = readtoken()) == TAND) {
9473 t = NAND;
9474 } else if (t == TOR) {
9475 t = NOR;
9476 } else {
9477 tokpushback++;
9478 return n1;
9479 }
Eric Andersenc470f442003-07-28 09:56:35 +00009480 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009481 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009482 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009483 n3->type = t;
9484 n3->nbinary.ch1 = n1;
9485 n3->nbinary.ch2 = n2;
9486 n1 = n3;
9487 }
9488}
9489
9490
9491
Eric Andersenc470f442003-07-28 09:56:35 +00009492static union node *
9493pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009494{
Eric Andersencb57d552001-06-28 07:25:16 +00009495 union node *n1, *n2, *pipenode;
9496 struct nodelist *lp, *prev;
9497 int negate;
9498
9499 negate = 0;
9500 TRACE(("pipeline: entered\n"));
9501 if (readtoken() == TNOT) {
9502 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009503 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009504 } else
9505 tokpushback++;
9506 n1 = command();
9507 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009508 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009509 pipenode->type = NPIPE;
9510 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009511 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009512 pipenode->npipe.cmdlist = lp;
9513 lp->n = n1;
9514 do {
9515 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009516 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9517 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009518 lp->n = command();
9519 prev->next = lp;
9520 } while (readtoken() == TPIPE);
9521 lp->next = NULL;
9522 n1 = pipenode;
9523 }
9524 tokpushback++;
9525 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009526 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009527 n2->type = NNOT;
9528 n2->nnot.com = n1;
9529 return n2;
9530 } else
9531 return n1;
9532}
9533
9534
9535
Eric Andersenc470f442003-07-28 09:56:35 +00009536static union node *
9537command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009538{
Eric Andersencb57d552001-06-28 07:25:16 +00009539 union node *n1, *n2;
9540 union node *ap, **app;
9541 union node *cp, **cpp;
9542 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009543 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009544 int t;
9545
9546 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009547 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009548
Eric Andersencb57d552001-06-28 07:25:16 +00009549 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009550 default:
9551 synexpect(-1);
9552 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009553 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009554 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009555 n1->type = NIF;
9556 n1->nif.test = list(0);
9557 if (readtoken() != TTHEN)
9558 synexpect(TTHEN);
9559 n1->nif.ifpart = list(0);
9560 n2 = n1;
9561 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009562 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009563 n2 = n2->nif.elsepart;
9564 n2->type = NIF;
9565 n2->nif.test = list(0);
9566 if (readtoken() != TTHEN)
9567 synexpect(TTHEN);
9568 n2->nif.ifpart = list(0);
9569 }
9570 if (lasttoken == TELSE)
9571 n2->nif.elsepart = list(0);
9572 else {
9573 n2->nif.elsepart = NULL;
9574 tokpushback++;
9575 }
Eric Andersenc470f442003-07-28 09:56:35 +00009576 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009577 break;
9578 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009579 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009580 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009581 n1 = (union node *)stalloc(sizeof (struct nbinary));
9582 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009583 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009584 if ((got=readtoken()) != TDO) {
9585TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009586 synexpect(TDO);
9587 }
9588 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009589 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009590 break;
9591 }
9592 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009593 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009594 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009595 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009596 n1->type = NFOR;
9597 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009598 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009599 if (readtoken() == TIN) {
9600 app = &ap;
9601 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009602 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009603 n2->type = NARG;
9604 n2->narg.text = wordtext;
9605 n2->narg.backquote = backquotelist;
9606 *app = n2;
9607 app = &n2->narg.next;
9608 }
9609 *app = NULL;
9610 n1->nfor.args = ap;
9611 if (lasttoken != TNL && lasttoken != TSEMI)
9612 synexpect(-1);
9613 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009614 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009615 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009616 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009617 n2->narg.backquote = NULL;
9618 n2->narg.next = NULL;
9619 n1->nfor.args = n2;
9620 /*
9621 * Newline or semicolon here is optional (but note
9622 * that the original Bourne shell only allowed NL).
9623 */
9624 if (lasttoken != TNL && lasttoken != TSEMI)
9625 tokpushback++;
9626 }
Eric Andersenc470f442003-07-28 09:56:35 +00009627 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009628 if (readtoken() != TDO)
9629 synexpect(TDO);
9630 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009631 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009632 break;
9633 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009634 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009635 n1->type = NCASE;
9636 if (readtoken() != TWORD)
9637 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009638 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009639 n2->type = NARG;
9640 n2->narg.text = wordtext;
9641 n2->narg.backquote = backquotelist;
9642 n2->narg.next = NULL;
9643 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009644 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009645 } while (readtoken() == TNL);
9646 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009647 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009648 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009649next_case:
9650 checkkwd = CHKNL | CHKKWD;
9651 t = readtoken();
9652 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009653 if (lasttoken == TLP)
9654 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009655 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009656 cp->type = NCLIST;
9657 app = &cp->nclist.pattern;
9658 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009659 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009660 ap->type = NARG;
9661 ap->narg.text = wordtext;
9662 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009663 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009664 break;
9665 app = &ap->narg.next;
9666 readtoken();
9667 }
9668 ap->narg.next = NULL;
9669 if (lasttoken != TRP)
9670 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009671 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009672
Eric Andersenc470f442003-07-28 09:56:35 +00009673 cpp = &cp->nclist.next;
9674
9675 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009676 if ((t = readtoken()) != TESAC) {
9677 if (t != TENDCASE)
9678 synexpect(TENDCASE);
9679 else
Eric Andersenc470f442003-07-28 09:56:35 +00009680 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009681 }
Eric Andersenc470f442003-07-28 09:56:35 +00009682 }
Eric Andersencb57d552001-06-28 07:25:16 +00009683 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009684 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009685 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009686 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009687 n1->type = NSUBSHELL;
9688 n1->nredir.n = list(0);
9689 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009690 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009691 break;
9692 case TBEGIN:
9693 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009694 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009695 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009696 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009697 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009698 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009699 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009700 }
9701
Eric Andersenc470f442003-07-28 09:56:35 +00009702 if (readtoken() != t)
9703 synexpect(t);
9704
9705redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009706 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009707 checkkwd = CHKKWD | CHKALIAS;
9708 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009709 while (readtoken() == TREDIR) {
9710 *rpp = n2 = redirnode;
9711 rpp = &n2->nfile.next;
9712 parsefname();
9713 }
9714 tokpushback++;
9715 *rpp = NULL;
9716 if (redir) {
9717 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009718 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009719 n2->type = NREDIR;
9720 n2->nredir.n = n1;
9721 n1 = n2;
9722 }
9723 n1->nredir.redirect = redir;
9724 }
9725
9726 return n1;
9727}
9728
9729
Eric Andersenc470f442003-07-28 09:56:35 +00009730static union node *
9731simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009732 union node *args, **app;
9733 union node *n = NULL;
9734 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009735 union node **rpp, *redir;
9736 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009737
9738 args = NULL;
9739 app = &args;
9740 vars = NULL;
9741 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009742 redir = NULL;
9743 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009744
Eric Andersenc470f442003-07-28 09:56:35 +00009745 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009746 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009747 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009748 switch (readtoken()) {
9749 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009750 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009751 n->type = NARG;
9752 n->narg.text = wordtext;
9753 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009754 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009755 *vpp = n;
9756 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009757 } else {
9758 *app = n;
9759 app = &n->narg.next;
9760 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009761 }
9762 break;
9763 case TREDIR:
9764 *rpp = n = redirnode;
9765 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009766 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009767 break;
9768 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009769 if (
9770 args && app == &args->narg.next &&
9771 !vars && !redir
9772 ) {
9773 struct builtincmd *bcmd;
9774 const char *name;
9775
Eric Andersencb57d552001-06-28 07:25:16 +00009776 /* We have a function */
9777 if (readtoken() != TRP)
9778 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009779 name = n->narg.text;
9780 if (
9781 !goodname(name) || (
9782 (bcmd = find_builtin(name)) &&
9783 IS_BUILTIN_SPECIAL(bcmd)
9784 )
9785 )
9786 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009787 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009788 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009789 n->narg.next = command();
9790 return n;
9791 }
9792 /* fall through */
9793 default:
9794 tokpushback++;
9795 goto out;
9796 }
9797 }
Eric Andersenc470f442003-07-28 09:56:35 +00009798out:
Eric Andersencb57d552001-06-28 07:25:16 +00009799 *app = NULL;
9800 *vpp = NULL;
9801 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009802 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009803 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009804 n->ncmd.args = args;
9805 n->ncmd.assign = vars;
9806 n->ncmd.redirect = redir;
9807 return n;
9808}
9809
Eric Andersenc470f442003-07-28 09:56:35 +00009810static union node *
9811makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009812{
Eric Andersencb57d552001-06-28 07:25:16 +00009813 union node *n;
9814
Eric Andersenc470f442003-07-28 09:56:35 +00009815 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009816 n->type = NARG;
9817 n->narg.next = NULL;
9818 n->narg.text = wordtext;
9819 n->narg.backquote = backquotelist;
9820 return n;
9821}
9822
Eric Andersenc470f442003-07-28 09:56:35 +00009823void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009824{
Eric Andersencb57d552001-06-28 07:25:16 +00009825 TRACE(("Fix redir %s %d\n", text, err));
9826 if (!err)
9827 n->ndup.vname = NULL;
9828
9829 if (is_digit(text[0]) && text[1] == '\0')
9830 n->ndup.dupfd = digit_val(text[0]);
9831 else if (text[0] == '-' && text[1] == '\0')
9832 n->ndup.dupfd = -1;
9833 else {
9834
9835 if (err)
9836 synerror("Bad fd number");
9837 else
9838 n->ndup.vname = makename();
9839 }
9840}
9841
9842
Eric Andersenc470f442003-07-28 09:56:35 +00009843static void
9844parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009845{
Eric Andersencb57d552001-06-28 07:25:16 +00009846 union node *n = redirnode;
9847
9848 if (readtoken() != TWORD)
9849 synexpect(-1);
9850 if (n->type == NHERE) {
9851 struct heredoc *here = heredoc;
9852 struct heredoc *p;
9853 int i;
9854
9855 if (quoteflag == 0)
9856 n->type = NXHERE;
9857 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009858 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009859 synerror("Illegal eof marker for << redirection");
9860 rmescapes(wordtext);
9861 here->eofmark = wordtext;
9862 here->next = NULL;
9863 if (heredoclist == NULL)
9864 heredoclist = here;
9865 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009866 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009867 p->next = here;
9868 }
9869 } else if (n->type == NTOFD || n->type == NFROMFD) {
9870 fixredir(n, wordtext, 0);
9871 } else {
9872 n->nfile.fname = makename();
9873 }
9874}
9875
9876
9877/*
9878 * Input any here documents.
9879 */
9880
Eric Andersenc470f442003-07-28 09:56:35 +00009881static void
9882parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009883{
Eric Andersencb57d552001-06-28 07:25:16 +00009884 struct heredoc *here;
9885 union node *n;
9886
Eric Andersenc470f442003-07-28 09:56:35 +00009887 here = heredoclist;
9888 heredoclist = 0;
9889
9890 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009891 if (needprompt) {
9892 setprompt(2);
9893 needprompt = 0;
9894 }
Eric Andersenc470f442003-07-28 09:56:35 +00009895 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9896 here->eofmark, here->striptabs);
9897 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009898 n->narg.type = NARG;
9899 n->narg.next = NULL;
9900 n->narg.text = wordtext;
9901 n->narg.backquote = backquotelist;
9902 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009903 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009904 }
9905}
9906
Eric Andersenc470f442003-07-28 09:56:35 +00009907static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009908{
Eric Andersencb57d552001-06-28 07:25:16 +00009909 int t;
9910
9911 t = readtoken();
9912 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009913 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009914}
9915
Eric Andersenc470f442003-07-28 09:56:35 +00009916static int
9917readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009918{
Eric Andersencb57d552001-06-28 07:25:16 +00009919 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009920#ifdef DEBUG
9921 int alreadyseen = tokpushback;
9922#endif
9923
Eric Andersend35c5df2002-01-09 15:37:36 +00009924#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009925top:
Eric Andersen2870d962001-07-02 17:27:21 +00009926#endif
9927
Eric Andersencb57d552001-06-28 07:25:16 +00009928 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009929
Eric Andersenc470f442003-07-28 09:56:35 +00009930 /*
9931 * eat newlines
9932 */
9933 if (checkkwd & CHKNL) {
9934 while (t == TNL) {
9935 parseheredoc();
9936 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009937 }
9938 }
9939
Eric Andersenc470f442003-07-28 09:56:35 +00009940 if (t != TWORD || quoteflag) {
9941 goto out;
9942 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009943
Eric Andersenc470f442003-07-28 09:56:35 +00009944 /*
9945 * check for keywords
9946 */
9947 if (checkkwd & CHKKWD) {
9948 const char *const *pp;
9949
9950 if ((pp = findkwd(wordtext))) {
9951 lasttoken = t = pp - tokname_array;
9952 TRACE(("keyword %s recognized\n", tokname(t)));
9953 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009954 }
Eric Andersenc470f442003-07-28 09:56:35 +00009955 }
9956
9957 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009958#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009959 struct alias *ap;
9960 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009961 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009962 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009963 }
Eric Andersencb57d552001-06-28 07:25:16 +00009964 goto top;
9965 }
Eric Andersen2870d962001-07-02 17:27:21 +00009966#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009967 }
Eric Andersenc470f442003-07-28 09:56:35 +00009968out:
9969 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009970#ifdef DEBUG
9971 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009972 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009973 else
Eric Andersenc470f442003-07-28 09:56:35 +00009974 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009975#endif
9976 return (t);
9977}
9978
9979
9980/*
9981 * Read the next input token.
9982 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009983 * backquotes. We set quoteflag to true if any part of the word was
9984 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009985 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009986 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009987 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009988 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009989 *
9990 * [Change comment: here documents and internal procedures]
9991 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9992 * word parsing code into a separate routine. In this case, readtoken
9993 * doesn't need to have any internal procedures, but parseword does.
9994 * We could also make parseoperator in essence the main routine, and
9995 * have parseword (readtoken1?) handle both words and redirection.]
9996 */
9997
Eric Andersen81fe1232003-07-29 06:38:40 +00009998#define NEW_xxreadtoken
9999#ifdef NEW_xxreadtoken
10000
10001/* singles must be first! */
10002static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10003
10004static const char xxreadtoken_tokens[] = {
10005 TNL, TLP, TRP, /* only single occurrence allowed */
10006 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10007 TEOF, /* corresponds to trailing nul */
10008 TAND, TOR, TENDCASE, /* if double occurrence */
10009};
10010
10011#define xxreadtoken_doubles \
10012 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10013#define xxreadtoken_singles \
10014 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10015
10016static int xxreadtoken()
10017{
10018 int c;
10019
10020 if (tokpushback) {
10021 tokpushback = 0;
10022 return lasttoken;
10023 }
10024 if (needprompt) {
10025 setprompt(2);
10026 needprompt = 0;
10027 }
10028 startlinno = plinno;
10029 for (;;) { /* until token or start of word found */
10030 c = pgetc_macro();
10031
10032 if ((c != ' ') && (c != '\t')
10033#ifdef CONFIG_ASH_ALIAS
10034 && (c != PEOA)
10035#endif
10036 ) {
10037 if (c == '#') {
10038 while ((c = pgetc()) != '\n' && c != PEOF);
10039 pungetc();
10040 } else if (c == '\\') {
10041 if (pgetc() != '\n') {
10042 pungetc();
10043 goto READTOKEN1;
10044 }
10045 startlinno = ++plinno;
10046 if (doprompt)
10047 setprompt(2);
10048 } else {
10049 const char *p
10050 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10051
10052 if (c != PEOF) {
10053 if (c == '\n') {
10054 plinno++;
10055 needprompt = doprompt;
10056 }
10057
10058 p = strchr(xxreadtoken_chars, c);
10059 if (p == NULL) {
10060 READTOKEN1:
10061 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10062 }
10063
10064 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10065 if (pgetc() == *p) { /* double occurrence? */
10066 p += xxreadtoken_doubles + 1;
10067 } else {
10068 pungetc();
10069 }
10070 }
10071 }
10072
10073 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10074 }
10075 }
10076 }
10077}
10078
10079
10080#else
Eric Andersen2870d962001-07-02 17:27:21 +000010081#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010082
Eric Andersenc470f442003-07-28 09:56:35 +000010083static int
10084xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010085{
Eric Andersencb57d552001-06-28 07:25:16 +000010086 int c;
10087
10088 if (tokpushback) {
10089 tokpushback = 0;
10090 return lasttoken;
10091 }
10092 if (needprompt) {
10093 setprompt(2);
10094 needprompt = 0;
10095 }
10096 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010097 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010098 c = pgetc_macro();
10099 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010100 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010101#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010102 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010103#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010104 continue;
10105 case '#':
10106 while ((c = pgetc()) != '\n' && c != PEOF);
10107 pungetc();
10108 continue;
10109 case '\\':
10110 if (pgetc() == '\n') {
10111 startlinno = ++plinno;
10112 if (doprompt)
10113 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010114 continue;
10115 }
10116 pungetc();
10117 goto breakloop;
10118 case '\n':
10119 plinno++;
10120 needprompt = doprompt;
10121 RETURN(TNL);
10122 case PEOF:
10123 RETURN(TEOF);
10124 case '&':
10125 if (pgetc() == '&')
10126 RETURN(TAND);
10127 pungetc();
10128 RETURN(TBACKGND);
10129 case '|':
10130 if (pgetc() == '|')
10131 RETURN(TOR);
10132 pungetc();
10133 RETURN(TPIPE);
10134 case ';':
10135 if (pgetc() == ';')
10136 RETURN(TENDCASE);
10137 pungetc();
10138 RETURN(TSEMI);
10139 case '(':
10140 RETURN(TLP);
10141 case ')':
10142 RETURN(TRP);
10143 default:
10144 goto breakloop;
10145 }
10146 }
Eric Andersenc470f442003-07-28 09:56:35 +000010147breakloop:
10148 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010149#undef RETURN
10150}
Eric Andersen81fe1232003-07-29 06:38:40 +000010151#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010152
Eric Andersencb57d552001-06-28 07:25:16 +000010153
Eric Andersencb57d552001-06-28 07:25:16 +000010154/*
10155 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10156 * is not NULL, read a here document. In the latter case, eofmark is the
10157 * word which marks the end of the document and striptabs is true if
10158 * leading tabs should be stripped from the document. The argument firstc
10159 * is the first character of the input token or document.
10160 *
10161 * Because C does not have internal subroutines, I have simulated them
10162 * using goto's to implement the subroutine linkage. The following macros
10163 * will run code that appears at the end of readtoken1.
10164 */
10165
Eric Andersen2870d962001-07-02 17:27:21 +000010166#define CHECKEND() {goto checkend; checkend_return:;}
10167#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10168#define PARSESUB() {goto parsesub; parsesub_return:;}
10169#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10170#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10171#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010172
10173static int
Eric Andersenc470f442003-07-28 09:56:35 +000010174readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010175{
Eric Andersencb57d552001-06-28 07:25:16 +000010176 int c = firstc;
10177 char *out;
10178 int len;
10179 char line[EOFMARKLEN + 1];
10180 struct nodelist *bqlist;
10181 int quotef;
10182 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010183 int varnest; /* levels of variables expansion */
10184 int arinest; /* levels of arithmetic expansion */
10185 int parenlevel; /* levels of parens in arithmetic */
10186 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010187 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010188 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010189#if __GNUC__
10190 /* Avoid longjmp clobbering */
10191 (void) &out;
10192 (void) &quotef;
10193 (void) &dblquote;
10194 (void) &varnest;
10195 (void) &arinest;
10196 (void) &parenlevel;
10197 (void) &dqvarnest;
10198 (void) &oldstyle;
10199 (void) &prevsyntax;
10200 (void) &syntax;
10201#endif
10202
10203 startlinno = plinno;
10204 dblquote = 0;
10205 if (syntax == DQSYNTAX)
10206 dblquote = 1;
10207 quotef = 0;
10208 bqlist = NULL;
10209 varnest = 0;
10210 arinest = 0;
10211 parenlevel = 0;
10212 dqvarnest = 0;
10213
10214 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010215 loop: { /* for each line, until end of word */
10216 CHECKEND(); /* set c to PEOF if at end of here document */
10217 for (;;) { /* until end of line or end of word */
10218 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10219 switch(SIT(c, syntax)) {
10220 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010221 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010222 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010223 USTPUTC(c, out);
10224 plinno++;
10225 if (doprompt)
10226 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010227 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010228 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010229 case CWORD:
10230 USTPUTC(c, out);
10231 break;
10232 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010233 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010234 USTPUTC(CTLESC, out);
10235 USTPUTC(c, out);
10236 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010237 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010238 c = pgetc2();
10239 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010240 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010241 USTPUTC('\\', out);
10242 pungetc();
10243 } else if (c == '\n') {
10244 if (doprompt)
10245 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010246 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010247 if (
10248 dblquote &&
10249 c != '\\' && c != '`' &&
10250 c != '$' && (
10251 c != '"' ||
10252 eofmark != NULL
10253 )
10254 ) {
10255 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010256 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010257 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010258 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010259 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010260 USTPUTC(c, out);
10261 quotef++;
10262 }
10263 break;
10264 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010265 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010266quotemark:
10267 if (eofmark == NULL) {
10268 USTPUTC(CTLQUOTEMARK, out);
10269 }
Eric Andersencb57d552001-06-28 07:25:16 +000010270 break;
10271 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010272 syntax = DQSYNTAX;
10273 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010274 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010275 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010276 if (eofmark != NULL && arinest == 0 &&
10277 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010278 USTPUTC(c, out);
10279 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010280 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010281 syntax = BASESYNTAX;
10282 dblquote = 0;
10283 }
10284 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010285 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010286 }
10287 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010288 case CVAR: /* '$' */
10289 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010290 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010291 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010292 if (varnest > 0) {
10293 varnest--;
10294 if (dqvarnest > 0) {
10295 dqvarnest--;
10296 }
10297 USTPUTC(CTLENDVAR, out);
10298 } else {
10299 USTPUTC(c, out);
10300 }
10301 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010302#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010303 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010304 parenlevel++;
10305 USTPUTC(c, out);
10306 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010307 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010308 if (parenlevel > 0) {
10309 USTPUTC(c, out);
10310 --parenlevel;
10311 } else {
10312 if (pgetc() == ')') {
10313 if (--arinest == 0) {
10314 USTPUTC(CTLENDARI, out);
10315 syntax = prevsyntax;
10316 if (syntax == DQSYNTAX)
10317 dblquote = 1;
10318 else
10319 dblquote = 0;
10320 } else
10321 USTPUTC(')', out);
10322 } else {
10323 /*
10324 * unbalanced parens
10325 * (don't 2nd guess - no error)
10326 */
10327 pungetc();
10328 USTPUTC(')', out);
10329 }
10330 }
10331 break;
10332#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010333 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010334 PARSEBACKQOLD();
10335 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010336 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010337 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010338 case CIGN:
10339 break;
10340 default:
10341 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010342 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010343#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010344 if (c != PEOA)
10345#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010346 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010347
Eric Andersencb57d552001-06-28 07:25:16 +000010348 }
10349 c = pgetc_macro();
10350 }
10351 }
Eric Andersenc470f442003-07-28 09:56:35 +000010352endword:
10353#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010354 if (syntax == ARISYNTAX)
10355 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010356#endif
10357 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010358 synerror("Unterminated quoted string");
10359 if (varnest != 0) {
10360 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010361 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010362 synerror("Missing '}'");
10363 }
10364 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010365 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010366 out = stackblock();
10367 if (eofmark == NULL) {
10368 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010369 && quotef == 0
10370 && len <= 2
10371 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010372 PARSEREDIR();
10373 return lasttoken = TREDIR;
10374 } else {
10375 pungetc();
10376 }
10377 }
10378 quoteflag = quotef;
10379 backquotelist = bqlist;
10380 grabstackblock(len);
10381 wordtext = out;
10382 return lasttoken = TWORD;
10383/* end of readtoken routine */
10384
10385
10386
10387/*
10388 * Check to see whether we are at the end of the here document. When this
10389 * is called, c is set to the first character of the next input line. If
10390 * we are at the end of the here document, this routine sets the c to PEOF.
10391 */
10392
Eric Andersenc470f442003-07-28 09:56:35 +000010393checkend: {
10394 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010395#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010396 if (c == PEOA) {
10397 c = pgetc2();
10398 }
10399#endif
10400 if (striptabs) {
10401 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010402 c = pgetc2();
10403 }
Eric Andersenc470f442003-07-28 09:56:35 +000010404 }
10405 if (c == *eofmark) {
10406 if (pfgets(line, sizeof line) != NULL) {
10407 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010408
Eric Andersenc470f442003-07-28 09:56:35 +000010409 p = line;
10410 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10411 if (*p == '\n' && *q == '\0') {
10412 c = PEOF;
10413 plinno++;
10414 needprompt = doprompt;
10415 } else {
10416 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010417 }
10418 }
10419 }
10420 }
Eric Andersenc470f442003-07-28 09:56:35 +000010421 goto checkend_return;
10422}
Eric Andersencb57d552001-06-28 07:25:16 +000010423
10424
10425/*
10426 * Parse a redirection operator. The variable "out" points to a string
10427 * specifying the fd to be redirected. The variable "c" contains the
10428 * first character of the redirection operator.
10429 */
10430
Eric Andersenc470f442003-07-28 09:56:35 +000010431parseredir: {
10432 char fd = *out;
10433 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010434
Eric Andersenc470f442003-07-28 09:56:35 +000010435 np = (union node *)stalloc(sizeof (struct nfile));
10436 if (c == '>') {
10437 np->nfile.fd = 1;
10438 c = pgetc();
10439 if (c == '>')
10440 np->type = NAPPEND;
10441 else if (c == '|')
10442 np->type = NCLOBBER;
10443 else if (c == '&')
10444 np->type = NTOFD;
10445 else {
10446 np->type = NTO;
10447 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010448 }
Eric Andersenc470f442003-07-28 09:56:35 +000010449 } else { /* c == '<' */
10450 np->nfile.fd = 0;
10451 switch (c = pgetc()) {
10452 case '<':
10453 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10454 np = (union node *)stalloc(sizeof (struct nhere));
10455 np->nfile.fd = 0;
10456 }
10457 np->type = NHERE;
10458 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10459 heredoc->here = np;
10460 if ((c = pgetc()) == '-') {
10461 heredoc->striptabs = 1;
10462 } else {
10463 heredoc->striptabs = 0;
10464 pungetc();
10465 }
10466 break;
10467
10468 case '&':
10469 np->type = NFROMFD;
10470 break;
10471
10472 case '>':
10473 np->type = NFROMTO;
10474 break;
10475
10476 default:
10477 np->type = NFROM;
10478 pungetc();
10479 break;
10480 }
Eric Andersencb57d552001-06-28 07:25:16 +000010481 }
Eric Andersenc470f442003-07-28 09:56:35 +000010482 if (fd != '\0')
10483 np->nfile.fd = digit_val(fd);
10484 redirnode = np;
10485 goto parseredir_return;
10486}
Eric Andersencb57d552001-06-28 07:25:16 +000010487
10488
10489/*
10490 * Parse a substitution. At this point, we have read the dollar sign
10491 * and nothing else.
10492 */
10493
Eric Andersenc470f442003-07-28 09:56:35 +000010494parsesub: {
10495 int subtype;
10496 int typeloc;
10497 int flags;
10498 char *p;
10499 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010500
Eric Andersenc470f442003-07-28 09:56:35 +000010501 c = pgetc();
10502 if (
10503 c <= PEOA_OR_PEOF ||
10504 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10505 ) {
10506 USTPUTC('$', out);
10507 pungetc();
10508 } else if (c == '(') { /* $(command) or $((arith)) */
10509 if (pgetc() == '(') {
10510#ifdef CONFIG_ASH_MATH_SUPPORT
10511 PARSEARITH();
10512#else
10513 synerror("We unsupport $((arith))");
10514#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010515 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010516 pungetc();
10517 PARSEBACKQNEW();
10518 }
10519 } else {
10520 USTPUTC(CTLVAR, out);
10521 typeloc = out - (char *)stackblock();
10522 USTPUTC(VSNORMAL, out);
10523 subtype = VSNORMAL;
10524 if (c == '{') {
10525 c = pgetc();
10526 if (c == '#') {
10527 if ((c = pgetc()) == '}')
10528 c = '#';
10529 else
10530 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010531 }
Eric Andersenc470f442003-07-28 09:56:35 +000010532 else
10533 subtype = 0;
10534 }
10535 if (c > PEOA_OR_PEOF && is_name(c)) {
10536 do {
10537 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010538 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010539 } while (c > PEOA_OR_PEOF && is_in_name(c));
10540 } else if (is_digit(c)) {
10541 do {
10542 STPUTC(c, out);
10543 c = pgetc();
10544 } while (is_digit(c));
10545 }
10546 else if (is_special(c)) {
10547 USTPUTC(c, out);
10548 c = pgetc();
10549 }
10550 else
10551badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010552
Eric Andersenc470f442003-07-28 09:56:35 +000010553 STPUTC('=', out);
10554 flags = 0;
10555 if (subtype == 0) {
10556 switch (c) {
10557 case ':':
10558 flags = VSNUL;
10559 c = pgetc();
10560 /*FALLTHROUGH*/
10561 default:
10562 p = strchr(types, c);
10563 if (p == NULL)
10564 goto badsub;
10565 subtype = p - types + VSNORMAL;
10566 break;
10567 case '%':
10568 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010569 {
10570 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010571 subtype = c == '#' ? VSTRIMLEFT :
10572 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010573 c = pgetc();
10574 if (c == cc)
10575 subtype++;
10576 else
10577 pungetc();
10578 break;
10579 }
10580 }
Eric Andersenc470f442003-07-28 09:56:35 +000010581 } else {
10582 pungetc();
10583 }
10584 if (dblquote || arinest)
10585 flags |= VSQUOTE;
10586 *((char *)stackblock() + typeloc) = subtype | flags;
10587 if (subtype != VSNORMAL) {
10588 varnest++;
10589 if (dblquote || arinest) {
10590 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010591 }
10592 }
10593 }
Eric Andersenc470f442003-07-28 09:56:35 +000010594 goto parsesub_return;
10595}
Eric Andersencb57d552001-06-28 07:25:16 +000010596
10597
10598/*
10599 * Called to parse command substitutions. Newstyle is set if the command
10600 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10601 * list of commands (passed by reference), and savelen is the number of
10602 * characters on the top of the stack which must be preserved.
10603 */
10604
Eric Andersenc470f442003-07-28 09:56:35 +000010605parsebackq: {
10606 struct nodelist **nlpp;
10607 int savepbq;
10608 union node *n;
10609 char *volatile str;
10610 struct jmploc jmploc;
10611 struct jmploc *volatile savehandler;
10612 size_t savelen;
10613 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010614#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010615 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010616#endif
10617
Eric Andersenc470f442003-07-28 09:56:35 +000010618 savepbq = parsebackquote;
10619 if (setjmp(jmploc.loc)) {
10620 if (str)
10621 ckfree(str);
10622 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010623 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010624 longjmp(handler->loc, 1);
10625 }
10626 INTOFF;
10627 str = NULL;
10628 savelen = out - (char *)stackblock();
10629 if (savelen > 0) {
10630 str = ckmalloc(savelen);
10631 memcpy(str, stackblock(), savelen);
10632 }
10633 savehandler = handler;
10634 handler = &jmploc;
10635 INTON;
10636 if (oldstyle) {
10637 /* We must read until the closing backquote, giving special
10638 treatment to some slashes, and then push the string and
10639 reread it as input, interpreting it normally. */
10640 char *pout;
10641 int pc;
10642 size_t psavelen;
10643 char *pstr;
10644
10645
10646 STARTSTACKSTR(pout);
10647 for (;;) {
10648 if (needprompt) {
10649 setprompt(2);
10650 needprompt = 0;
10651 }
10652 switch (pc = pgetc()) {
10653 case '`':
10654 goto done;
10655
10656 case '\\':
10657 if ((pc = pgetc()) == '\n') {
10658 plinno++;
10659 if (doprompt)
10660 setprompt(2);
10661 /*
10662 * If eating a newline, avoid putting
10663 * the newline into the new character
10664 * stream (via the STPUTC after the
10665 * switch).
10666 */
10667 continue;
10668 }
10669 if (pc != '\\' && pc != '`' && pc != '$'
10670 && (!dblquote || pc != '"'))
10671 STPUTC('\\', pout);
10672 if (pc > PEOA_OR_PEOF) {
10673 break;
10674 }
10675 /* fall through */
10676
10677 case PEOF:
10678#ifdef CONFIG_ASH_ALIAS
10679 case PEOA:
10680#endif
10681 startlinno = plinno;
10682 synerror("EOF in backquote substitution");
10683
10684 case '\n':
10685 plinno++;
10686 needprompt = doprompt;
10687 break;
10688
10689 default:
10690 break;
10691 }
10692 STPUTC(pc, pout);
10693 }
10694done:
10695 STPUTC('\0', pout);
10696 psavelen = pout - (char *)stackblock();
10697 if (psavelen > 0) {
10698 pstr = grabstackstr(pout);
10699 setinputstring(pstr);
10700 }
10701 }
10702 nlpp = &bqlist;
10703 while (*nlpp)
10704 nlpp = &(*nlpp)->next;
10705 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10706 (*nlpp)->next = NULL;
10707 parsebackquote = oldstyle;
10708
10709 if (oldstyle) {
10710 saveprompt = doprompt;
10711 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010712 }
10713
Eric Andersenc470f442003-07-28 09:56:35 +000010714 n = list(2);
10715
10716 if (oldstyle)
10717 doprompt = saveprompt;
10718 else {
10719 if (readtoken() != TRP)
10720 synexpect(TRP);
10721 }
10722
10723 (*nlpp)->n = n;
10724 if (oldstyle) {
10725 /*
10726 * Start reading from old file again, ignoring any pushed back
10727 * tokens left from the backquote parsing
10728 */
10729 popfile();
10730 tokpushback = 0;
10731 }
10732 while (stackblocksize() <= savelen)
10733 growstackblock();
10734 STARTSTACKSTR(out);
10735 if (str) {
10736 memcpy(out, str, savelen);
10737 STADJUST(savelen, out);
10738 INTOFF;
10739 ckfree(str);
10740 str = NULL;
10741 INTON;
10742 }
10743 parsebackquote = savepbq;
10744 handler = savehandler;
10745 if (arinest || dblquote)
10746 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10747 else
10748 USTPUTC(CTLBACKQ, out);
10749 if (oldstyle)
10750 goto parsebackq_oldreturn;
10751 else
10752 goto parsebackq_newreturn;
10753}
10754
10755#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010756/*
10757 * Parse an arithmetic expansion (indicate start of one and set state)
10758 */
Eric Andersenc470f442003-07-28 09:56:35 +000010759parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010760
Eric Andersenc470f442003-07-28 09:56:35 +000010761 if (++arinest == 1) {
10762 prevsyntax = syntax;
10763 syntax = ARISYNTAX;
10764 USTPUTC(CTLARI, out);
10765 if (dblquote)
10766 USTPUTC('"',out);
10767 else
10768 USTPUTC(' ',out);
10769 } else {
10770 /*
10771 * we collapse embedded arithmetic expansion to
10772 * parenthesis, which should be equivalent
10773 */
10774 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010775 }
Eric Andersenc470f442003-07-28 09:56:35 +000010776 goto parsearith_return;
10777}
10778#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010779
Eric Andersenc470f442003-07-28 09:56:35 +000010780} /* end of readtoken */
10781
Eric Andersencb57d552001-06-28 07:25:16 +000010782
10783
Eric Andersencb57d552001-06-28 07:25:16 +000010784/*
10785 * Returns true if the text contains nothing to expand (no dollar signs
10786 * or backquotes).
10787 */
10788
Eric Andersenc470f442003-07-28 09:56:35 +000010789static int
10790noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010791{
Eric Andersencb57d552001-06-28 07:25:16 +000010792 char *p;
10793 char c;
10794
10795 p = text;
10796 while ((c = *p++) != '\0') {
10797 if (c == CTLQUOTEMARK)
10798 continue;
10799 if (c == CTLESC)
10800 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010801 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010802 return 0;
10803 }
10804 return 1;
10805}
10806
10807
10808/*
Eric Andersenc470f442003-07-28 09:56:35 +000010809 * Return of a legal variable name (a letter or underscore followed by zero or
10810 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010811 */
10812
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010813static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010814endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010815{
Eric Andersenc470f442003-07-28 09:56:35 +000010816 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010817
Eric Andersenc470f442003-07-28 09:56:35 +000010818 p = (char *) name;
10819 if (! is_name(*p))
10820 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010821 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010822 if (! is_in_name(*p))
10823 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010824 }
Eric Andersenc470f442003-07-28 09:56:35 +000010825 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010826}
10827
10828
10829/*
10830 * Called when an unexpected token is read during the parse. The argument
10831 * is the token that is expected, or -1 if more than one type of token can
10832 * occur at this point.
10833 */
10834
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010835static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010836{
10837 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010838 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010839
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010840 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10841 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010842 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010843 synerror(msg);
10844 /* NOTREACHED */
10845}
10846
Eric Andersenc470f442003-07-28 09:56:35 +000010847static void
10848synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010849{
Eric Andersenc470f442003-07-28 09:56:35 +000010850 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010851 /* NOTREACHED */
10852}
10853
Eric Andersencb57d552001-06-28 07:25:16 +000010854
10855/*
10856 * called by editline -- any expansions to the prompt
10857 * should be added here.
10858 */
Eric Andersenc470f442003-07-28 09:56:35 +000010859
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010860static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010861{
Eric Andersenc470f442003-07-28 09:56:35 +000010862 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010863
10864 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010865 case 1:
10866 prompt = ps1val();
10867 break;
10868 case 2:
10869 prompt = ps2val();
10870 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010871 default: /* 0 */
10872 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010873 }
10874 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010875}
10876
Eric Andersencb57d552001-06-28 07:25:16 +000010877
Eric Andersenc470f442003-07-28 09:56:35 +000010878static const char *const *findkwd(const char *s)
10879{
10880 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010881 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010882 sizeof(const char *), pstrcmp);
10883}
10884
10885/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10886
Eric Andersencb57d552001-06-28 07:25:16 +000010887/*
10888 * Code for dealing with input/output redirection.
10889 */
10890
Eric Andersenc470f442003-07-28 09:56:35 +000010891#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010892#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010893# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010894#else
10895# define PIPESIZE PIPE_BUF
10896#endif
10897
Eric Andersen62483552001-07-10 06:09:16 +000010898/*
10899 * Open a file in noclobber mode.
10900 * The code was copied from bash.
10901 */
Eric Andersenc470f442003-07-28 09:56:35 +000010902static inline int
10903noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010904{
10905 int r, fd;
10906 struct stat finfo, finfo2;
10907
10908 /*
10909 * If the file exists and is a regular file, return an error
10910 * immediately.
10911 */
10912 r = stat(fname, &finfo);
10913 if (r == 0 && S_ISREG(finfo.st_mode)) {
10914 errno = EEXIST;
10915 return -1;
10916 }
10917
10918 /*
10919 * If the file was not present (r != 0), make sure we open it
10920 * exclusively so that if it is created before we open it, our open
10921 * will fail. Make sure that we do not truncate an existing file.
10922 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10923 * file was not a regular file, we leave O_EXCL off.
10924 */
10925 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010926 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10927 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010928
10929 /* If the open failed, return the file descriptor right away. */
10930 if (fd < 0)
10931 return fd;
10932
10933 /*
10934 * OK, the open succeeded, but the file may have been changed from a
10935 * non-regular file to a regular file between the stat and the open.
10936 * We are assuming that the O_EXCL open handles the case where FILENAME
10937 * did not exist and is symlinked to an existing file between the stat
10938 * and open.
10939 */
10940
10941 /*
10942 * If we can open it and fstat the file descriptor, and neither check
10943 * revealed that it was a regular file, and the file has not been
10944 * replaced, return the file descriptor.
10945 */
Eric Andersenc470f442003-07-28 09:56:35 +000010946 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10947 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010948 return fd;
10949
10950 /* The file has been replaced. badness. */
10951 close(fd);
10952 errno = EEXIST;
10953 return -1;
10954}
Eric Andersencb57d552001-06-28 07:25:16 +000010955
10956/*
Eric Andersen62483552001-07-10 06:09:16 +000010957 * Handle here documents. Normally we fork off a process to write the
10958 * data to a pipe. If the document is short, we can stuff the data in
10959 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010960 */
10961
Eric Andersenc470f442003-07-28 09:56:35 +000010962static inline int
10963openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010964{
10965 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010966 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010967
Eric Andersen62483552001-07-10 06:09:16 +000010968 if (pipe(pip) < 0)
10969 error("Pipe call failed");
10970 if (redir->type == NHERE) {
10971 len = strlen(redir->nhere.doc->narg.text);
10972 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010973 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010974 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010975 }
Eric Andersencb57d552001-06-28 07:25:16 +000010976 }
Eric Andersenc470f442003-07-28 09:56:35 +000010977 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010978 close(pip[0]);
10979 signal(SIGINT, SIG_IGN);
10980 signal(SIGQUIT, SIG_IGN);
10981 signal(SIGHUP, SIG_IGN);
10982#ifdef SIGTSTP
10983 signal(SIGTSTP, SIG_IGN);
10984#endif
10985 signal(SIGPIPE, SIG_DFL);
10986 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000010987 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010988 else
10989 expandhere(redir->nhere.doc, pip[1]);
10990 _exit(0);
10991 }
Eric Andersenc470f442003-07-28 09:56:35 +000010992out:
Eric Andersen62483552001-07-10 06:09:16 +000010993 close(pip[1]);
10994 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010995}
10996
Eric Andersenc470f442003-07-28 09:56:35 +000010997static int
10998openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010999{
Eric Andersencb57d552001-06-28 07:25:16 +000011000 char *fname;
11001 int f;
11002
11003 switch (redir->nfile.type) {
11004 case NFROM:
11005 fname = redir->nfile.expfname;
11006 if ((f = open(fname, O_RDONLY)) < 0)
11007 goto eopen;
11008 break;
11009 case NFROMTO:
11010 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011011 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011012 goto ecreate;
11013 break;
11014 case NTO:
11015 /* Take care of noclobber mode. */
11016 if (Cflag) {
11017 fname = redir->nfile.expfname;
11018 if ((f = noclobberopen(fname)) < 0)
11019 goto ecreate;
11020 break;
11021 }
Eric Andersenc470f442003-07-28 09:56:35 +000011022 /* FALLTHROUGH */
11023 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011024 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011025 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011026 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011027 break;
11028 case NAPPEND:
11029 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011030 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011031 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011032 break;
11033 default:
11034#ifdef DEBUG
11035 abort();
11036#endif
11037 /* Fall through to eliminate warning. */
11038 case NTOFD:
11039 case NFROMFD:
11040 f = -1;
11041 break;
11042 case NHERE:
11043 case NXHERE:
11044 f = openhere(redir);
11045 break;
11046 }
11047
11048 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011049ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011050 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011051eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011052 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11053}
11054
Eric Andersenc470f442003-07-28 09:56:35 +000011055static inline void
11056dupredirect(union node *redir, int f)
11057{
11058 int fd = redir->nfile.fd;
11059
11060 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11061 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11062 copyfd(redir->ndup.dupfd, fd);
11063 }
11064 return;
11065 }
11066
11067 if (f != fd) {
11068 copyfd(f, fd);
11069 close(f);
11070 }
11071 return;
11072}
Eric Andersencb57d552001-06-28 07:25:16 +000011073
Eric Andersen62483552001-07-10 06:09:16 +000011074/*
11075 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11076 * old file descriptors are stashed away so that the redirection can be
11077 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11078 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011079 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011080 */
11081
Eric Andersenc470f442003-07-28 09:56:35 +000011082static void
11083redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011084{
11085 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011086 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011087 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011088 int fd;
11089 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011090 int *p;
11091 nullredirs++;
11092 if (!redir) {
11093 return;
Eric Andersen62483552001-07-10 06:09:16 +000011094 }
Eric Andersenc470f442003-07-28 09:56:35 +000011095 sv = NULL;
11096 INTOFF;
11097 if (flags & REDIR_PUSH) {
11098 struct redirtab *q;
11099 q = ckmalloc(sizeof (struct redirtab));
11100 q->next = redirlist;
11101 redirlist = q;
11102 q->nullredirs = nullredirs - 1;
11103 for (i = 0 ; i < 10 ; i++)
11104 q->renamed[i] = EMPTY;
11105 nullredirs = 0;
11106 sv = q;
11107 }
11108 n = redir;
11109 do {
Eric Andersen62483552001-07-10 06:09:16 +000011110 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011111 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011112 n->ndup.dupfd == fd)
11113 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011114
Eric Andersen62483552001-07-10 06:09:16 +000011115 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011116 if (fd == newfd)
11117 continue;
11118 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11119 i = fcntl(fd, F_DUPFD, 10);
11120
11121 if (i == -1) {
11122 i = errno;
11123 if (i != EBADF) {
11124 close(newfd);
11125 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011126 error("%d: %m", fd);
11127 /* NOTREACHED */
11128 }
Eric Andersenc470f442003-07-28 09:56:35 +000011129 } else {
11130 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011131 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011132 }
Eric Andersenc470f442003-07-28 09:56:35 +000011133 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011134 close(fd);
11135 }
Eric Andersenc470f442003-07-28 09:56:35 +000011136 dupredirect(n, newfd);
11137 } while ((n = n->nfile.next));
11138 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011139 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11140 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011141}
11142
11143
Eric Andersencb57d552001-06-28 07:25:16 +000011144/*
11145 * Undo the effects of the last redirection.
11146 */
11147
Eric Andersenc470f442003-07-28 09:56:35 +000011148void
11149popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011150{
Eric Andersenc470f442003-07-28 09:56:35 +000011151 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011152 int i;
11153
Eric Andersenc470f442003-07-28 09:56:35 +000011154 if (--nullredirs >= 0)
11155 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011156 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011157 rp = redirlist;
11158 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011159 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011160 if (!drop) {
11161 close(i);
11162 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011163 }
Eric Andersenc470f442003-07-28 09:56:35 +000011164 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011165 }
11166 }
11167 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011168 nullredirs = rp->nullredirs;
11169 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011170 INTON;
11171}
11172
11173/*
Eric Andersenc470f442003-07-28 09:56:35 +000011174 * Undo all redirections. Called on error or interrupt.
11175 */
11176
11177/*
Eric Andersencb57d552001-06-28 07:25:16 +000011178 * Discard all saved file descriptors.
11179 */
11180
Eric Andersenc470f442003-07-28 09:56:35 +000011181void
11182clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011183{
Eric Andersenc470f442003-07-28 09:56:35 +000011184 for (;;) {
11185 nullredirs = 0;
11186 if (!redirlist)
11187 break;
11188 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011189 }
Eric Andersencb57d552001-06-28 07:25:16 +000011190}
11191
11192
Eric Andersencb57d552001-06-28 07:25:16 +000011193/*
11194 * Copy a file descriptor to be >= to. Returns -1
11195 * if the source file descriptor is closed, EMPTY if there are no unused
11196 * file descriptors left.
11197 */
11198
Eric Andersenc470f442003-07-28 09:56:35 +000011199int
11200copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011201{
11202 int newfd;
11203
11204 newfd = fcntl(from, F_DUPFD, to);
11205 if (newfd < 0) {
11206 if (errno == EMFILE)
11207 return EMPTY;
11208 else
Eric Andersen2870d962001-07-02 17:27:21 +000011209 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011210 }
11211 return newfd;
11212}
11213
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011214
Eric Andersenc470f442003-07-28 09:56:35 +000011215int
11216redirectsafe(union node *redir, int flags)
11217{
11218 int err;
11219 volatile int saveint;
11220 struct jmploc *volatile savehandler = handler;
11221 struct jmploc jmploc;
11222
11223 SAVEINT(saveint);
11224 if (!(err = setjmp(jmploc.loc) * 2)) {
11225 handler = &jmploc;
11226 redirect(redir, flags);
11227 }
11228 handler = savehandler;
11229 if (err && exception != EXERROR)
11230 longjmp(handler->loc, 1);
11231 RESTOREINT(saveint);
11232 return err;
11233}
11234
11235/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11236
11237#ifdef DEBUG
11238static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011239static void shcmd(union node *, FILE *);
11240static void sharg(union node *, FILE *);
11241static void indent(int, char *, FILE *);
11242static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011243
11244
Eric Andersenc470f442003-07-28 09:56:35 +000011245void
11246showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011247{
11248 trputs("showtree called\n");
11249 shtree(n, 1, NULL, stdout);
11250}
Eric Andersencb57d552001-06-28 07:25:16 +000011251
Eric Andersenc470f442003-07-28 09:56:35 +000011252
11253static void
11254shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011255{
11256 struct nodelist *lp;
11257 const char *s;
11258
11259 if (n == NULL)
11260 return;
11261
11262 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011263 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011264 case NSEMI:
11265 s = "; ";
11266 goto binop;
11267 case NAND:
11268 s = " && ";
11269 goto binop;
11270 case NOR:
11271 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011272binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011273 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011274 /* if (ind < 0) */
11275 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011276 shtree(n->nbinary.ch2, ind, NULL, fp);
11277 break;
11278 case NCMD:
11279 shcmd(n, fp);
11280 if (ind >= 0)
11281 putc('\n', fp);
11282 break;
11283 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011284 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011285 shcmd(lp->n, fp);
11286 if (lp->next)
11287 fputs(" | ", fp);
11288 }
11289 if (n->npipe.backgnd)
11290 fputs(" &", fp);
11291 if (ind >= 0)
11292 putc('\n', fp);
11293 break;
11294 default:
11295 fprintf(fp, "<node type %d>", n->type);
11296 if (ind >= 0)
11297 putc('\n', fp);
11298 break;
11299 }
11300}
11301
11302
Eric Andersenc470f442003-07-28 09:56:35 +000011303static void
11304shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011305{
11306 union node *np;
11307 int first;
11308 const char *s;
11309 int dftfd;
11310
11311 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011312 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11313 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011314 putchar(' ');
11315 sharg(np, fp);
11316 first = 0;
11317 }
Eric Andersenc470f442003-07-28 09:56:35 +000011318 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11319 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011320 putchar(' ');
11321 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011322 case NTO: s = ">"; dftfd = 1; break;
11323 case NCLOBBER: s = ">|"; dftfd = 1; break;
11324 case NAPPEND: s = ">>"; dftfd = 1; break;
11325 case NTOFD: s = ">&"; dftfd = 1; break;
11326 case NFROM: s = "<"; dftfd = 0; break;
11327 case NFROMFD: s = "<&"; dftfd = 0; break;
11328 case NFROMTO: s = "<>"; dftfd = 0; break;
11329 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011330 }
11331 if (np->nfile.fd != dftfd)
11332 fprintf(fp, "%d", np->nfile.fd);
11333 fputs(s, fp);
11334 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11335 fprintf(fp, "%d", np->ndup.dupfd);
11336 } else {
11337 sharg(np->nfile.fname, fp);
11338 }
11339 first = 0;
11340 }
11341}
11342
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011343
Eric Andersenc470f442003-07-28 09:56:35 +000011344
11345static void
11346sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011347{
Eric Andersencb57d552001-06-28 07:25:16 +000011348 char *p;
11349 struct nodelist *bqlist;
11350 int subtype;
11351
11352 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011353 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011354 abort();
11355 }
11356 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011357 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011358 switch (*p) {
11359 case CTLESC:
11360 putc(*++p, fp);
11361 break;
11362 case CTLVAR:
11363 putc('$', fp);
11364 putc('{', fp);
11365 subtype = *++p;
11366 if (subtype == VSLENGTH)
11367 putc('#', fp);
11368
11369 while (*p != '=')
11370 putc(*p++, fp);
11371
11372 if (subtype & VSNUL)
11373 putc(':', fp);
11374
11375 switch (subtype & VSTYPE) {
11376 case VSNORMAL:
11377 putc('}', fp);
11378 break;
11379 case VSMINUS:
11380 putc('-', fp);
11381 break;
11382 case VSPLUS:
11383 putc('+', fp);
11384 break;
11385 case VSQUESTION:
11386 putc('?', fp);
11387 break;
11388 case VSASSIGN:
11389 putc('=', fp);
11390 break;
11391 case VSTRIMLEFT:
11392 putc('#', fp);
11393 break;
11394 case VSTRIMLEFTMAX:
11395 putc('#', fp);
11396 putc('#', fp);
11397 break;
11398 case VSTRIMRIGHT:
11399 putc('%', fp);
11400 break;
11401 case VSTRIMRIGHTMAX:
11402 putc('%', fp);
11403 putc('%', fp);
11404 break;
11405 case VSLENGTH:
11406 break;
11407 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011408 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011409 }
11410 break;
11411 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011412 putc('}', fp);
11413 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011414 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011415 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011416 putc('$', fp);
11417 putc('(', fp);
11418 shtree(bqlist->n, -1, NULL, fp);
11419 putc(')', fp);
11420 break;
11421 default:
11422 putc(*p, fp);
11423 break;
11424 }
11425 }
11426}
11427
11428
Eric Andersenc470f442003-07-28 09:56:35 +000011429static void
11430indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011431{
11432 int i;
11433
Eric Andersenc470f442003-07-28 09:56:35 +000011434 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011435 if (pfx && i == amount - 1)
11436 fputs(pfx, fp);
11437 putc('\t', fp);
11438 }
11439}
Eric Andersencb57d552001-06-28 07:25:16 +000011440
Eric Andersenc470f442003-07-28 09:56:35 +000011441
11442
11443/*
11444 * Debugging stuff.
11445 */
11446
11447
Eric Andersencb57d552001-06-28 07:25:16 +000011448FILE *tracefile;
11449
Eric Andersencb57d552001-06-28 07:25:16 +000011450
Eric Andersenc470f442003-07-28 09:56:35 +000011451void
11452trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011453{
Eric Andersenc470f442003-07-28 09:56:35 +000011454 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011455 return;
11456 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011457}
11458
Eric Andersenc470f442003-07-28 09:56:35 +000011459void
11460trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011461{
11462 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011463
Eric Andersenc470f442003-07-28 09:56:35 +000011464 if (debug != 1)
11465 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011466 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011467 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011468 va_end(va);
11469}
11470
Eric Andersenc470f442003-07-28 09:56:35 +000011471void
11472tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011473{
Eric Andersenc470f442003-07-28 09:56:35 +000011474 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011475 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011476 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011477}
11478
11479
Eric Andersenc470f442003-07-28 09:56:35 +000011480void
11481trputs(const char *s)
11482{
11483 if (debug != 1)
11484 return;
11485 fputs(s, tracefile);
11486}
11487
11488
11489static void
11490trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011491{
11492 char *p;
11493 char c;
11494
Eric Andersenc470f442003-07-28 09:56:35 +000011495 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011496 return;
11497 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011498 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011499 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011500 case '\n': c = 'n'; goto backslash;
11501 case '\t': c = 't'; goto backslash;
11502 case '\r': c = 'r'; goto backslash;
11503 case '"': c = '"'; goto backslash;
11504 case '\\': c = '\\'; goto backslash;
11505 case CTLESC: c = 'e'; goto backslash;
11506 case CTLVAR: c = 'v'; goto backslash;
11507 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11508 case CTLBACKQ: c = 'q'; goto backslash;
11509 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11510backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011511 putc(c, tracefile);
11512 break;
11513 default:
11514 if (*p >= ' ' && *p <= '~')
11515 putc(*p, tracefile);
11516 else {
11517 putc('\\', tracefile);
11518 putc(*p >> 6 & 03, tracefile);
11519 putc(*p >> 3 & 07, tracefile);
11520 putc(*p & 07, tracefile);
11521 }
11522 break;
11523 }
11524 }
11525 putc('"', tracefile);
11526}
11527
11528
Eric Andersenc470f442003-07-28 09:56:35 +000011529void
11530trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011531{
Eric Andersenc470f442003-07-28 09:56:35 +000011532 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011533 return;
11534 while (*ap) {
11535 trstring(*ap++);
11536 if (*ap)
11537 putc(' ', tracefile);
11538 else
11539 putc('\n', tracefile);
11540 }
Eric Andersencb57d552001-06-28 07:25:16 +000011541}
11542
11543
Eric Andersenc470f442003-07-28 09:56:35 +000011544void
11545opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011546{
Eric Andersencb57d552001-06-28 07:25:16 +000011547 char s[100];
11548#ifdef O_APPEND
11549 int flags;
11550#endif
11551
Eric Andersenc470f442003-07-28 09:56:35 +000011552 if (debug != 1) {
11553 if (tracefile)
11554 fflush(tracefile);
11555 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011556 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011557 }
Eric Andersenc470f442003-07-28 09:56:35 +000011558 scopy("./trace", s);
11559 if (tracefile) {
11560 if (!freopen(s, "a", tracefile)) {
11561 fprintf(stderr, "Can't re-open %s\n", s);
11562 debug = 0;
11563 return;
11564 }
11565 } else {
11566 if ((tracefile = fopen(s, "a")) == NULL) {
11567 fprintf(stderr, "Can't open %s\n", s);
11568 debug = 0;
11569 return;
11570 }
11571 }
Eric Andersencb57d552001-06-28 07:25:16 +000011572#ifdef O_APPEND
11573 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11574 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11575#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011576 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011577 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011578}
Eric Andersenc470f442003-07-28 09:56:35 +000011579#endif /* DEBUG */
11580
11581
11582/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11583
11584/*
11585 * Sigmode records the current value of the signal handlers for the various
11586 * modes. A value of zero means that the current handler is not known.
11587 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11588 */
11589
11590#define S_DFL 1 /* default signal handling (SIG_DFL) */
11591#define S_CATCH 2 /* signal is caught */
11592#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11593#define S_HARD_IGN 4 /* signal is ignored permenantly */
11594#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11595
Eric Andersencb57d552001-06-28 07:25:16 +000011596
11597
11598/*
Eric Andersencb57d552001-06-28 07:25:16 +000011599 * The trap builtin.
11600 */
11601
Eric Andersenc470f442003-07-28 09:56:35 +000011602int
11603trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011604{
11605 char *action;
11606 char **ap;
11607 int signo;
11608
Eric Andersenc470f442003-07-28 09:56:35 +000011609 nextopt(nullstr);
11610 ap = argptr;
11611 if (!*ap) {
11612 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011613 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011614 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011615
Eric Andersenc470f442003-07-28 09:56:35 +000011616 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011617 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011618 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011619 out1fmt("trap -- %s %s\n",
11620 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011621 }
11622 }
11623 return 0;
11624 }
Eric Andersenc470f442003-07-28 09:56:35 +000011625 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011626 action = NULL;
11627 else
11628 action = *ap++;
11629 while (*ap) {
11630 if ((signo = decode_signal(*ap, 0)) < 0)
11631 error("%s: bad trap", *ap);
11632 INTOFF;
11633 if (action) {
11634 if (action[0] == '-' && action[1] == '\0')
11635 action = NULL;
11636 else
Eric Andersenc470f442003-07-28 09:56:35 +000011637 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011638 }
Eric Andersenc470f442003-07-28 09:56:35 +000011639 if (trap[signo])
11640 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011641 trap[signo] = action;
11642 if (signo != 0)
11643 setsignal(signo);
11644 INTON;
11645 ap++;
11646 }
11647 return 0;
11648}
11649
11650
Eric Andersenc470f442003-07-28 09:56:35 +000011651/*
11652 * Clear traps on a fork.
11653 */
11654
11655void
11656clear_traps(void)
11657{
11658 char **tp;
11659
11660 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11661 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11662 INTOFF;
11663 ckfree(*tp);
11664 *tp = NULL;
11665 if (tp != &trap[0])
11666 setsignal(tp - trap);
11667 INTON;
11668 }
11669 }
11670}
11671
11672
Eric Andersencb57d552001-06-28 07:25:16 +000011673/*
11674 * Set the signal handler for the specified signal. The routine figures
11675 * out what it should be set to.
11676 */
11677
Eric Andersenc470f442003-07-28 09:56:35 +000011678void
11679setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011680{
11681 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011682 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011683 struct sigaction act;
11684
11685 if ((t = trap[signo]) == NULL)
11686 action = S_DFL;
11687 else if (*t != '\0')
11688 action = S_CATCH;
11689 else
11690 action = S_IGN;
11691 if (rootshell && action == S_DFL) {
11692 switch (signo) {
11693 case SIGINT:
11694 if (iflag || minusc || sflag == 0)
11695 action = S_CATCH;
11696 break;
11697 case SIGQUIT:
11698#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011699 if (debug)
11700 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011701#endif
11702 /* FALLTHROUGH */
11703 case SIGTERM:
11704 if (iflag)
11705 action = S_IGN;
11706 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011707#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011708 case SIGTSTP:
11709 case SIGTTOU:
11710 if (mflag)
11711 action = S_IGN;
11712 break;
11713#endif
11714 }
11715 }
11716
11717 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011718 tsig = *t;
11719 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011720 /*
11721 * current setting unknown
11722 */
11723 if (sigaction(signo, 0, &act) == -1) {
11724 /*
11725 * Pretend it worked; maybe we should give a warning
11726 * here, but other shells don't. We don't alter
11727 * sigmode, so that we retry every time.
11728 */
11729 return;
11730 }
11731 if (act.sa_handler == SIG_IGN) {
11732 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011733 signo == SIGTTIN || signo == SIGTTOU)) {
11734 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011735 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011736 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011737 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011738 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011739 }
11740 }
Eric Andersenc470f442003-07-28 09:56:35 +000011741 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011742 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011743 switch (action) {
11744 case S_CATCH:
11745 act.sa_handler = onsig;
11746 break;
11747 case S_IGN:
11748 act.sa_handler = SIG_IGN;
11749 break;
11750 default:
11751 act.sa_handler = SIG_DFL;
11752 }
Eric Andersencb57d552001-06-28 07:25:16 +000011753 *t = action;
11754 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011755 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011756 sigaction(signo, &act, 0);
11757}
11758
11759/*
11760 * Ignore a signal.
11761 */
11762
Eric Andersenc470f442003-07-28 09:56:35 +000011763void
11764ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011765{
11766 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11767 signal(signo, SIG_IGN);
11768 }
11769 sigmode[signo - 1] = S_HARD_IGN;
11770}
11771
11772
Eric Andersencb57d552001-06-28 07:25:16 +000011773/*
11774 * Signal handler.
11775 */
11776
Eric Andersenc470f442003-07-28 09:56:35 +000011777void
11778onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011779{
Eric Andersencb57d552001-06-28 07:25:16 +000011780 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011781 pendingsigs = signo;
11782
11783 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11784 if (!suppressint)
11785 onint();
11786 intpending = 1;
11787 }
Eric Andersencb57d552001-06-28 07:25:16 +000011788}
11789
11790
Eric Andersencb57d552001-06-28 07:25:16 +000011791/*
11792 * Called to execute a trap. Perhaps we should avoid entering new trap
11793 * handlers while we are executing a trap handler.
11794 */
11795
Eric Andersenc470f442003-07-28 09:56:35 +000011796void
11797dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011798{
Eric Andersenc470f442003-07-28 09:56:35 +000011799 char *p;
11800 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011801 int savestatus;
11802
Eric Andersenc470f442003-07-28 09:56:35 +000011803 savestatus = exitstatus;
11804 q = gotsig;
11805 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11806 *p = 0;
11807 p = trap[p - q + 1];
11808 if (!p)
11809 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011810 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011811 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011812 }
Eric Andersencb57d552001-06-28 07:25:16 +000011813}
11814
Eric Andersenc470f442003-07-28 09:56:35 +000011815
Eric Andersenc470f442003-07-28 09:56:35 +000011816/*
11817 * Controls whether the shell is interactive or not.
11818 */
11819
Eric Andersenc470f442003-07-28 09:56:35 +000011820void
11821setinteractive(int on)
11822{
11823 static int is_interactive;
11824
11825 if (++on == is_interactive)
11826 return;
11827 is_interactive = on;
11828 setsignal(SIGINT);
11829 setsignal(SIGQUIT);
11830 setsignal(SIGTERM);
11831#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11832 if(is_interactive > 1) {
11833 /* Looks like they want an interactive shell */
11834 static int do_banner;
11835
11836 if(!do_banner) {
11837 out1fmt(
11838 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11839 "Enter 'help' for a list of built-in commands.\n\n");
11840 do_banner++;
11841 }
11842 }
11843#endif
11844}
11845
11846
11847#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11848/*** List the available builtins ***/
11849
11850static int helpcmd(int argc, char **argv)
11851{
11852 int col, i;
11853
11854 out1fmt("\nBuilt-in commands:\n-------------------\n");
11855 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11856 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11857 builtincmd[i].name + 1);
11858 if (col > 60) {
11859 out1fmt("\n");
11860 col = 0;
11861 }
11862 }
11863#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11864 {
11865 extern const struct BB_applet applets[];
11866 extern const size_t NUM_APPLETS;
11867
11868 for (i = 0; i < NUM_APPLETS; i++) {
11869
11870 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11871 if (col > 60) {
11872 out1fmt("\n");
11873 col = 0;
11874 }
11875 }
11876 }
11877#endif
11878 out1fmt("\n\n");
11879 return EXIT_SUCCESS;
11880}
11881#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11882
Eric Andersencb57d552001-06-28 07:25:16 +000011883/*
11884 * Called to exit the shell.
11885 */
11886
Eric Andersenc470f442003-07-28 09:56:35 +000011887void
11888exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011889{
Eric Andersenc470f442003-07-28 09:56:35 +000011890 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011891 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011892 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011893 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011894
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011895 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011896 status = exitstatus;
11897 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011898 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011899 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011900 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011901 if ((p = trap[0]) != NULL && *p != '\0') {
11902 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011903 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011904 }
Eric Andersencb57d552001-06-28 07:25:16 +000011905 flushall();
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011906#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11907 if (iflag && rootshell) {
11908 const char *hp = lookupvar("HISTFILE");
11909
11910 if(hp != NULL )
11911 save_history ( hp );
11912 }
11913#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011914out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011915 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011916 /* NOTREACHED */
11917}
11918
11919static int decode_signal(const char *string, int minsig)
11920{
11921 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011922 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011923
Eric Andersen34506362001-08-02 05:02:46 +000011924 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011925}
Eric Andersen34506362001-08-02 05:02:46 +000011926
Eric Andersenc470f442003-07-28 09:56:35 +000011927/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11928
11929static struct var *vartab[VTABSIZE];
11930
11931static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011932static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011933
11934/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011935 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011936 */
11937
Eric Andersenc470f442003-07-28 09:56:35 +000011938
11939#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011940/*
Eric Andersenc470f442003-07-28 09:56:35 +000011941 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011942 */
11943
Eric Andersenc470f442003-07-28 09:56:35 +000011944int
11945setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011946{
Eric Andersenc470f442003-07-28 09:56:35 +000011947 int err;
11948 volatile int saveint;
11949 struct jmploc *volatile savehandler = handler;
11950 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011951
Eric Andersenc470f442003-07-28 09:56:35 +000011952 SAVEINT(saveint);
11953 if (setjmp(jmploc.loc))
11954 err = 1;
11955 else {
11956 handler = &jmploc;
11957 setvar(name, val, flags);
11958 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011959 }
Eric Andersenc470f442003-07-28 09:56:35 +000011960 handler = savehandler;
11961 RESTOREINT(saveint);
11962 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011963}
Eric Andersenc470f442003-07-28 09:56:35 +000011964#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011965
11966/*
11967 * Set the value of a variable. The flags argument is ored with the
11968 * flags of the variable. If val is NULL, the variable is unset.
11969 */
11970
Eric Andersenc470f442003-07-28 09:56:35 +000011971static void
11972setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011973{
Eric Andersenc470f442003-07-28 09:56:35 +000011974 char *p, *q;
11975 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011976 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011977 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011978
Eric Andersenc470f442003-07-28 09:56:35 +000011979 q = endofname(name);
11980 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011981 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011982 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011983 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011984 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011985 if (val == NULL) {
11986 flags |= VUNSET;
11987 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011988 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011989 }
11990 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011991 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11992 *p++ = '\0';
11993 if (vallen) {
11994 p[-1] = '=';
11995 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011996 }
Eric Andersenc470f442003-07-28 09:56:35 +000011997 *p = '\0';
11998 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011999 INTON;
12000}
12001
12002
Eric Andersencb57d552001-06-28 07:25:16 +000012003/*
12004 * Same as setvar except that the variable and value are passed in
12005 * the first argument as name=value. Since the first argument will
12006 * be actually stored in the table, it should not be a string that
12007 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012008 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012009 */
12010
Eric Andersenc470f442003-07-28 09:56:35 +000012011void
12012setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012013{
12014 struct var *vp, **vpp;
12015
12016 vpp = hashvar(s);
12017 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012018 vp = *findvar(vpp, s);
12019 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012020 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12021 const char *n;
12022
Eric Andersenc470f442003-07-28 09:56:35 +000012023 if (flags & VNOSAVE)
12024 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012025 n = vp->text;
12026 error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012027 }
Eric Andersenc470f442003-07-28 09:56:35 +000012028
12029 if (flags & VNOSET)
12030 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012031
12032 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012033 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012034
Eric Andersenc470f442003-07-28 09:56:35 +000012035 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12036 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012037
Eric Andersenc470f442003-07-28 09:56:35 +000012038 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12039 } else {
12040 if (flags & VNOSET)
12041 return;
12042 /* not found */
12043 vp = ckmalloc(sizeof (*vp));
12044 vp->next = *vpp;
12045 vp->func = NULL;
12046 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012047 }
Eric Andersenc470f442003-07-28 09:56:35 +000012048 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12049 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012050 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012051 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012052}
12053
12054
Eric Andersencb57d552001-06-28 07:25:16 +000012055/*
12056 * Process a linked list of variable assignments.
12057 */
12058
Eric Andersenc470f442003-07-28 09:56:35 +000012059static void
12060listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012061{
Eric Andersenc470f442003-07-28 09:56:35 +000012062 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012063
Eric Andersenc470f442003-07-28 09:56:35 +000012064 if (!lp)
12065 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012066 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012067 do {
12068 setvareq(lp->text, flags);
12069 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012070 INTON;
12071}
12072
12073
Eric Andersencb57d552001-06-28 07:25:16 +000012074/*
12075 * Find the value of a variable. Returns NULL if not set.
12076 */
12077
Eric Andersenc470f442003-07-28 09:56:35 +000012078static char *
12079lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012080{
Eric Andersencb57d552001-06-28 07:25:16 +000012081 struct var *v;
12082
Eric Andersen16767e22004-03-16 05:14:10 +000012083 if ((v = *findvar(hashvar(name), name))) {
12084#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012085 /*
12086 * Dynamic variables are implemented roughly the same way they are
12087 * in bash. Namely, they're "special" so long as they aren't unset.
12088 * As soon as they're unset, they're no longer dynamic, and dynamic
12089 * lookup will no longer happen at that point. -- PFM.
12090 */
Eric Andersen16767e22004-03-16 05:14:10 +000012091 if((v->flags & VDYNAMIC))
12092 (*v->func)(NULL);
12093#endif
12094 if(!(v->flags & VUNSET))
12095 return strchrnul(v->text, '=') + 1;
12096 }
Eric Andersenef02f822004-03-11 13:34:24 +000012097
Eric Andersencb57d552001-06-28 07:25:16 +000012098 return NULL;
12099}
12100
12101
Eric Andersencb57d552001-06-28 07:25:16 +000012102/*
12103 * Search the environment of a builtin command.
12104 */
12105
Eric Andersenc470f442003-07-28 09:56:35 +000012106static char *
12107bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012108{
Eric Andersenc470f442003-07-28 09:56:35 +000012109 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012110
Eric Andersenc470f442003-07-28 09:56:35 +000012111 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012112 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012113 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012114 }
12115 return lookupvar(name);
12116}
12117
12118
Eric Andersencb57d552001-06-28 07:25:16 +000012119/*
Eric Andersenc470f442003-07-28 09:56:35 +000012120 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012121 */
12122
Eric Andersenc470f442003-07-28 09:56:35 +000012123static char **
12124listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012125{
Eric Andersencb57d552001-06-28 07:25:16 +000012126 struct var **vpp;
12127 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012128 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012129 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012130
Eric Andersenc470f442003-07-28 09:56:35 +000012131 STARTSTACKSTR(ep);
12132 vpp = vartab;
12133 mask = on | off;
12134 do {
12135 for (vp = *vpp ; vp ; vp = vp->next)
12136 if ((vp->flags & mask) == on) {
12137 if (ep == stackstrend())
12138 ep = growstackstr();
12139 *ep++ = (char *) vp->text;
12140 }
12141 } while (++vpp < vartab + VTABSIZE);
12142 if (ep == stackstrend())
12143 ep = growstackstr();
12144 if (end)
12145 *end = ep;
12146 *ep++ = NULL;
12147 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012148}
12149
12150
12151/*
Eric Andersenc470f442003-07-28 09:56:35 +000012152 * POSIX requires that 'set' (but not export or readonly) output the
12153 * variables in lexicographic order - by the locale's collating order (sigh).
12154 * Maybe we could keep them in an ordered balanced binary tree
12155 * instead of hashed lists.
12156 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012157 */
12158
Eric Andersenc470f442003-07-28 09:56:35 +000012159static int
12160showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012161{
Eric Andersenc470f442003-07-28 09:56:35 +000012162 const char *sep;
12163 char **ep, **epend;
12164
12165 ep = listvars(on, off, &epend);
12166 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12167
12168 sep = *sep_prefix ? spcstr : sep_prefix;
12169
12170 for (; ep < epend; ep++) {
12171 const char *p;
12172 const char *q;
12173
12174 p = strchrnul(*ep, '=');
12175 q = nullstr;
12176 if (*p)
12177 q = single_quote(++p);
12178
12179 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12180 }
12181
Eric Andersencb57d552001-06-28 07:25:16 +000012182 return 0;
12183}
12184
12185
12186
12187/*
12188 * The export and readonly commands.
12189 */
12190
Eric Andersenc470f442003-07-28 09:56:35 +000012191static int
12192exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012193{
12194 struct var *vp;
12195 char *name;
12196 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012197 char **aptr;
12198 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12199 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012200
Eric Andersenc470f442003-07-28 09:56:35 +000012201 notp = nextopt("p") - 'p';
12202 if (notp && ((name = *(aptr = argptr)))) {
12203 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012204 if ((p = strchr(name, '=')) != NULL) {
12205 p++;
12206 } else {
12207 if ((vp = *findvar(hashvar(name), name))) {
12208 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012209 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012210 }
12211 }
12212 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012213 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012214 } else {
12215 showvars(argv[0], flag, 0);
12216 }
12217 return 0;
12218}
12219
Eric Andersen34506362001-08-02 05:02:46 +000012220
Eric Andersencb57d552001-06-28 07:25:16 +000012221/*
Eric Andersencb57d552001-06-28 07:25:16 +000012222 * Make a variable a local variable. When a variable is made local, it's
12223 * value and flags are saved in a localvar structure. The saved values
12224 * will be restored when the shell function returns. We handle the name
12225 * "-" as a special case.
12226 */
12227
Eric Andersenc470f442003-07-28 09:56:35 +000012228static inline void
12229mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012230{
Eric Andersencb57d552001-06-28 07:25:16 +000012231 struct localvar *lvp;
12232 struct var **vpp;
12233 struct var *vp;
12234
12235 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012236 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012237 if (name[0] == '-' && name[1] == '\0') {
12238 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012239 p = ckmalloc(sizeof(optlist));
12240 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012241 vp = NULL;
12242 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012243 char *eq;
12244
Eric Andersencb57d552001-06-28 07:25:16 +000012245 vpp = hashvar(name);
12246 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012247 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012248 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012249 if (eq)
12250 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012251 else
12252 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012253 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012254 lvp->flags = VUNSET;
12255 } else {
12256 lvp->text = vp->text;
12257 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012258 vp->flags |= VSTRFIXED|VTEXTFIXED;
12259 if (eq)
12260 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012261 }
12262 }
12263 lvp->vp = vp;
12264 lvp->next = localvars;
12265 localvars = lvp;
12266 INTON;
12267}
12268
Eric Andersenc470f442003-07-28 09:56:35 +000012269/*
12270 * The "local" command.
12271 */
12272
12273static int
12274localcmd(int argc, char **argv)
12275{
12276 char *name;
12277
12278 argv = argptr;
12279 while ((name = *argv++) != NULL) {
12280 mklocal(name);
12281 }
12282 return 0;
12283}
12284
12285
Eric Andersencb57d552001-06-28 07:25:16 +000012286/*
12287 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012288 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012289 */
12290
Eric Andersenc470f442003-07-28 09:56:35 +000012291static void
12292poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012293{
Eric Andersencb57d552001-06-28 07:25:16 +000012294 struct localvar *lvp;
12295 struct var *vp;
12296
12297 while ((lvp = localvars) != NULL) {
12298 localvars = lvp->next;
12299 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012300 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12301 if (vp == NULL) { /* $- saved */
12302 memcpy(optlist, lvp->text, sizeof(optlist));
12303 ckfree(lvp->text);
12304 optschanged();
12305 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12306 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012307 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012308 if (vp->func)
12309 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12310 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12311 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012312 vp->flags = lvp->flags;
12313 vp->text = lvp->text;
12314 }
Eric Andersenc470f442003-07-28 09:56:35 +000012315 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012316 }
12317}
12318
12319
Eric Andersencb57d552001-06-28 07:25:16 +000012320/*
12321 * The unset builtin command. We unset the function before we unset the
12322 * variable to allow a function to be unset when there is a readonly variable
12323 * with the same name.
12324 */
12325
Eric Andersenc470f442003-07-28 09:56:35 +000012326int
12327unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012328{
12329 char **ap;
12330 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012331 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012332 int ret = 0;
12333
12334 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012335 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012336 }
Eric Andersencb57d552001-06-28 07:25:16 +000012337
Eric Andersenc470f442003-07-28 09:56:35 +000012338 for (ap = argptr; *ap ; ap++) {
12339 if (flag != 'f') {
12340 i = unsetvar(*ap);
12341 ret |= i;
12342 if (!(i & 2))
12343 continue;
12344 }
12345 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012346 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012347 }
Eric Andersenc470f442003-07-28 09:56:35 +000012348 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012349}
12350
12351
12352/*
12353 * Unset the specified variable.
12354 */
12355
Eric Andersenc470f442003-07-28 09:56:35 +000012356int
12357unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012358{
Eric Andersencb57d552001-06-28 07:25:16 +000012359 struct var **vpp;
12360 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012361 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012362
12363 vpp = findvar(hashvar(s), s);
12364 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012365 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012366 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012367 int flags = vp->flags;
12368
12369 retval = 1;
12370 if (flags & VREADONLY)
12371 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012372#ifdef DYNAMIC_VAR
12373 vp->flags &= ~VDYNAMIC;
12374#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012375 if (flags & VUNSET)
12376 goto ok;
12377 if ((flags & VSTRFIXED) == 0) {
12378 INTOFF;
12379 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12380 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012381 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012382 ckfree(vp);
12383 INTON;
12384 } else {
12385 setvar(s, 0, 0);
12386 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012387 }
Eric Andersenc470f442003-07-28 09:56:35 +000012388ok:
12389 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012390 }
12391
Eric Andersenc470f442003-07-28 09:56:35 +000012392out:
12393 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012394}
12395
12396
12397
12398/*
12399 * Find the appropriate entry in the hash table from the name.
12400 */
12401
Eric Andersenc470f442003-07-28 09:56:35 +000012402static struct var **
12403hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012404{
Eric Andersencb57d552001-06-28 07:25:16 +000012405 unsigned int hashval;
12406
12407 hashval = ((unsigned char) *p) << 4;
12408 while (*p && *p != '=')
12409 hashval += (unsigned char) *p++;
12410 return &vartab[hashval % VTABSIZE];
12411}
12412
12413
12414
12415/*
Eric Andersenc470f442003-07-28 09:56:35 +000012416 * Compares two strings up to the first = or '\0'. The first
12417 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012418 * either '=' or '\0'.
12419 */
12420
Eric Andersenc470f442003-07-28 09:56:35 +000012421int
12422varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012423{
Eric Andersenc470f442003-07-28 09:56:35 +000012424 int c, d;
12425
12426 while ((c = *p) == (d = *q)) {
12427 if (!c || c == '=')
12428 goto out;
12429 p++;
12430 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012431 }
Eric Andersenc470f442003-07-28 09:56:35 +000012432 if (c == '=')
12433 c = 0;
12434 if (d == '=')
12435 d = 0;
12436out:
12437 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012438}
12439
Eric Andersenc470f442003-07-28 09:56:35 +000012440static int
12441vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012442{
Eric Andersenc470f442003-07-28 09:56:35 +000012443 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012444}
12445
Eric Andersenc470f442003-07-28 09:56:35 +000012446static struct var **
12447findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012448{
12449 for (; *vpp; vpp = &(*vpp)->next) {
12450 if (varequal((*vpp)->text, name)) {
12451 break;
12452 }
12453 }
12454 return vpp;
12455}
Eric Andersenc470f442003-07-28 09:56:35 +000012456/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012457
Eric Andersenc470f442003-07-28 09:56:35 +000012458#include <sys/times.h>
12459
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012460static const unsigned char timescmd_str[] = {
12461 ' ', offsetof(struct tms, tms_utime),
12462 '\n', offsetof(struct tms, tms_stime),
12463 ' ', offsetof(struct tms, tms_cutime),
12464 '\n', offsetof(struct tms, tms_cstime),
12465 0
12466};
Eric Andersencb57d552001-06-28 07:25:16 +000012467
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012468static int timescmd(int ac, char **av)
12469{
12470 long int clk_tck, s, t;
12471 const unsigned char *p;
12472 struct tms buf;
12473
12474 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012475 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012476
12477 p = timescmd_str;
12478 do {
12479 t = *(clock_t *)(((char *) &buf) + p[1]);
12480 s = t / clk_tck;
12481 out1fmt("%ldm%ld.%.3lds%c",
12482 s/60, s%60,
12483 ((t - s * clk_tck) * 1000) / clk_tck,
12484 p[0]);
12485 } while (*(p += 2));
12486
Eric Andersencb57d552001-06-28 07:25:16 +000012487 return 0;
12488}
12489
Eric Andersend35c5df2002-01-09 15:37:36 +000012490#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen009617f2004-04-05 13:24:07 +000012491static long
Eric Andersenc470f442003-07-28 09:56:35 +000012492dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012493{
Eric Andersen90898442003-08-06 11:20:52 +000012494 long result;
Eric Andersenc470f442003-07-28 09:56:35 +000012495 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012496
Eric Andersenc470f442003-07-28 09:56:35 +000012497 INTOFF;
12498 result = arith(s, &errcode);
12499 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012500 if (errcode == -3)
12501 error("exponent less than 0");
12502 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012503 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012504 else if (errcode == -5)
12505 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012506 else
12507 synerror(s);
12508 }
12509 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012510
Eric Andersenc470f442003-07-28 09:56:35 +000012511 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012512}
Eric Andersenc470f442003-07-28 09:56:35 +000012513
12514
12515/*
Eric Andersen90898442003-08-06 11:20:52 +000012516 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12517 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12518 *
12519 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012520 */
Eric Andersen90898442003-08-06 11:20:52 +000012521
Eric Andersenc470f442003-07-28 09:56:35 +000012522static int
Eric Andersen90898442003-08-06 11:20:52 +000012523letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012524{
Eric Andersenc470f442003-07-28 09:56:35 +000012525 char **ap;
12526 long i;
12527
Eric Andersen90898442003-08-06 11:20:52 +000012528 ap = argv + 1;
12529 if(!*ap)
12530 error("expression expected");
12531 for (ap = argv + 1; *ap; ap++) {
12532 i = dash_arith(*ap);
12533 }
Eric Andersenc470f442003-07-28 09:56:35 +000012534
Eric Andersen90898442003-08-06 11:20:52 +000012535 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012536}
12537#endif /* CONFIG_ASH_MATH_SUPPORT */
12538
12539/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12540
12541/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012542 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012543 */
12544
12545#undef rflag
12546
12547#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012548#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012549typedef enum __rlimit_resource rlim_t;
12550#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012551#endif
12552
12553
Eric Andersenc470f442003-07-28 09:56:35 +000012554/*
12555 * The read builtin. The -e option causes backslashes to escape the
12556 * following character.
12557 *
12558 * This uses unbuffered input, which may be avoidable in some cases.
12559 */
12560
12561static int
12562readcmd(int argc, char **argv)
12563{
12564 char **ap;
12565 int backslash;
12566 char c;
12567 int rflag;
12568 char *prompt;
12569 const char *ifs;
12570 char *p;
12571 int startword;
12572 int status;
12573 int i;
12574
12575 rflag = 0;
12576 prompt = NULL;
12577 while ((i = nextopt("p:r")) != '\0') {
12578 if (i == 'p')
12579 prompt = optionarg;
12580 else
12581 rflag = 1;
12582 }
12583 if (prompt && isatty(0)) {
12584 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012585 }
12586 if (*(ap = argptr) == NULL)
12587 error("arg count");
12588 if ((ifs = bltinlookup("IFS")) == NULL)
12589 ifs = defifs;
12590 status = 0;
12591 startword = 1;
12592 backslash = 0;
12593 STARTSTACKSTR(p);
12594 for (;;) {
12595 if (read(0, &c, 1) != 1) {
12596 status = 1;
12597 break;
12598 }
12599 if (c == '\0')
12600 continue;
12601 if (backslash) {
12602 backslash = 0;
12603 if (c != '\n')
12604 goto put;
12605 continue;
12606 }
12607 if (!rflag && c == '\\') {
12608 backslash++;
12609 continue;
12610 }
12611 if (c == '\n')
12612 break;
12613 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12614 continue;
12615 }
12616 startword = 0;
12617 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12618 STACKSTRNUL(p);
12619 setvar(*ap, stackblock(), 0);
12620 ap++;
12621 startword = 1;
12622 STARTSTACKSTR(p);
12623 } else {
12624put:
12625 STPUTC(c, p);
12626 }
12627 }
12628 STACKSTRNUL(p);
12629 /* Remove trailing blanks */
12630 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12631 *p = '\0';
12632 setvar(*ap, stackblock(), 0);
12633 while (*++ap != NULL)
12634 setvar(*ap, nullstr, 0);
12635 return status;
12636}
12637
12638
12639static int umaskcmd(int argc, char **argv)
12640{
12641 static const char permuser[3] = "ugo";
12642 static const char permmode[3] = "rwx";
12643 static const short int permmask[] = {
12644 S_IRUSR, S_IWUSR, S_IXUSR,
12645 S_IRGRP, S_IWGRP, S_IXGRP,
12646 S_IROTH, S_IWOTH, S_IXOTH
12647 };
12648
12649 char *ap;
12650 mode_t mask;
12651 int i;
12652 int symbolic_mode = 0;
12653
12654 while (nextopt("S") != '\0') {
12655 symbolic_mode = 1;
12656 }
12657
12658 INTOFF;
12659 mask = umask(0);
12660 umask(mask);
12661 INTON;
12662
12663 if ((ap = *argptr) == NULL) {
12664 if (symbolic_mode) {
12665 char buf[18];
12666 char *p = buf;
12667
12668 for (i = 0; i < 3; i++) {
12669 int j;
12670
12671 *p++ = permuser[i];
12672 *p++ = '=';
12673 for (j = 0; j < 3; j++) {
12674 if ((mask & permmask[3 * i + j]) == 0) {
12675 *p++ = permmode[j];
12676 }
12677 }
12678 *p++ = ',';
12679 }
12680 *--p = 0;
12681 puts(buf);
12682 } else {
12683 out1fmt("%.4o\n", mask);
12684 }
12685 } else {
12686 if (is_digit((unsigned char) *ap)) {
12687 mask = 0;
12688 do {
12689 if (*ap >= '8' || *ap < '0')
12690 error(illnum, argv[1]);
12691 mask = (mask << 3) + (*ap - '0');
12692 } while (*++ap != '\0');
12693 umask(mask);
12694 } else {
12695 mask = ~mask & 0777;
12696 if (!bb_parse_mode(ap, &mask)) {
12697 error("Illegal mode: %s", ap);
12698 }
12699 umask(~mask & 0777);
12700 }
12701 }
12702 return 0;
12703}
12704
12705/*
12706 * ulimit builtin
12707 *
12708 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12709 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12710 * ash by J.T. Conklin.
12711 *
12712 * Public domain.
12713 */
12714
12715struct limits {
12716 const char *name;
12717 int cmd;
12718 int factor; /* multiply by to get rlim_{cur,max} values */
12719 char option;
12720};
12721
12722static const struct limits limits[] = {
12723#ifdef RLIMIT_CPU
12724 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12725#endif
12726#ifdef RLIMIT_FSIZE
12727 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12728#endif
12729#ifdef RLIMIT_DATA
12730 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12731#endif
12732#ifdef RLIMIT_STACK
12733 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12734#endif
12735#ifdef RLIMIT_CORE
12736 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12737#endif
12738#ifdef RLIMIT_RSS
12739 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12740#endif
12741#ifdef RLIMIT_MEMLOCK
12742 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12743#endif
12744#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012745 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012746#endif
12747#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012748 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012749#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012750#ifdef RLIMIT_AS
12751 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012752#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012753#ifdef RLIMIT_LOCKS
12754 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012755#endif
12756 { (char *) 0, 0, 0, '\0' }
12757};
12758
Glenn L McGrath76620622004-01-13 10:19:37 +000012759enum limtype { SOFT = 0x1, HARD = 0x2 };
12760
12761static void printlim(enum limtype how, const struct rlimit *limit,
12762 const struct limits *l)
12763{
12764 rlim_t val;
12765
12766 val = limit->rlim_max;
12767 if (how & SOFT)
12768 val = limit->rlim_cur;
12769
12770 if (val == RLIM_INFINITY)
12771 out1fmt("unlimited\n");
12772 else {
12773 val /= l->factor;
12774 out1fmt("%lld\n", (long long) val);
12775 }
12776}
12777
Eric Andersenc470f442003-07-28 09:56:35 +000012778int
12779ulimitcmd(int argc, char **argv)
12780{
12781 int c;
12782 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012783 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012784 const struct limits *l;
12785 int set, all = 0;
12786 int optc, what;
12787 struct rlimit limit;
12788
12789 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012790 while ((optc = nextopt("HSa"
12791#ifdef RLIMIT_CPU
12792 "t"
12793#endif
12794#ifdef RLIMIT_FSIZE
12795 "f"
12796#endif
12797#ifdef RLIMIT_DATA
12798 "d"
12799#endif
12800#ifdef RLIMIT_STACK
12801 "s"
12802#endif
12803#ifdef RLIMIT_CORE
12804 "c"
12805#endif
12806#ifdef RLIMIT_RSS
12807 "m"
12808#endif
12809#ifdef RLIMIT_MEMLOCK
12810 "l"
12811#endif
12812#ifdef RLIMIT_NPROC
12813 "p"
12814#endif
12815#ifdef RLIMIT_NOFILE
12816 "n"
12817#endif
12818#ifdef RLIMIT_AS
12819 "v"
12820#endif
12821#ifdef RLIMIT_LOCKS
12822 "w"
12823#endif
12824 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012825 switch (optc) {
12826 case 'H':
12827 how = HARD;
12828 break;
12829 case 'S':
12830 how = SOFT;
12831 break;
12832 case 'a':
12833 all = 1;
12834 break;
12835 default:
12836 what = optc;
12837 }
12838
Glenn L McGrath76620622004-01-13 10:19:37 +000012839 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012840 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012841
12842 set = *argptr ? 1 : 0;
12843 if (set) {
12844 char *p = *argptr;
12845
12846 if (all || argptr[1])
12847 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012848 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012849 val = RLIM_INFINITY;
12850 else {
12851 val = (rlim_t) 0;
12852
12853 while ((c = *p++) >= '0' && c <= '9')
12854 {
12855 val = (val * 10) + (long)(c - '0');
12856 if (val < (rlim_t) 0)
12857 break;
12858 }
12859 if (c)
12860 error("bad number");
12861 val *= l->factor;
12862 }
12863 }
12864 if (all) {
12865 for (l = limits; l->name; l++) {
12866 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012867 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012868 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012869 }
12870 return 0;
12871 }
12872
12873 getrlimit(l->cmd, &limit);
12874 if (set) {
12875 if (how & HARD)
12876 limit.rlim_max = val;
12877 if (how & SOFT)
12878 limit.rlim_cur = val;
12879 if (setrlimit(l->cmd, &limit) < 0)
12880 error("error setting limit (%m)");
12881 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012882 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012883 }
12884 return 0;
12885}
12886
Eric Andersen90898442003-08-06 11:20:52 +000012887
12888#ifdef CONFIG_ASH_MATH_SUPPORT
12889
12890/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12891
12892 Permission is hereby granted, free of charge, to any person obtaining
12893 a copy of this software and associated documentation files (the
12894 "Software"), to deal in the Software without restriction, including
12895 without limitation the rights to use, copy, modify, merge, publish,
12896 distribute, sublicense, and/or sell copies of the Software, and to
12897 permit persons to whom the Software is furnished to do so, subject to
12898 the following conditions:
12899
12900 The above copyright notice and this permission notice shall be
12901 included in all copies or substantial portions of the Software.
12902
12903 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12904 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12905 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12906 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12907 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12908 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12909 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12910*/
12911
12912/* This is my infix parser/evaluator. It is optimized for size, intended
12913 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000012914 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000012915 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000012916 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000012917 * be that which POSIX specifies for shells. */
12918
12919/* The code uses a simple two-stack algorithm. See
12920 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000012921 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000012922 * this is based (this code differs in that it applies operators immediately
12923 * to the stack instead of adding them to a queue to end up with an
12924 * expression). */
12925
12926/* To use the routine, call it with an expression string and error return
12927 * pointer */
12928
12929/*
12930 * Aug 24, 2001 Manuel Novoa III
12931 *
12932 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12933 *
12934 * 1) In arith_apply():
12935 * a) Cached values of *numptr and &(numptr[-1]).
12936 * b) Removed redundant test for zero denominator.
12937 *
12938 * 2) In arith():
12939 * a) Eliminated redundant code for processing operator tokens by moving
12940 * to a table-based implementation. Also folded handling of parens
12941 * into the table.
12942 * b) Combined all 3 loops which called arith_apply to reduce generated
12943 * code size at the cost of speed.
12944 *
12945 * 3) The following expressions were treated as valid by the original code:
12946 * 1() , 0! , 1 ( *3 ) .
12947 * These bugs have been fixed by internally enclosing the expression in
12948 * parens and then checking that all binary ops and right parens are
12949 * preceded by a valid expression (NUM_TOKEN).
12950 *
Eric Andersenaff114c2004-04-14 17:51:38 +000012951 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000012952 * ctype's isspace() if it is used by another busybox applet or if additional
12953 * whitespace chars should be considered. Look below the "#include"s for a
12954 * precompiler test.
12955 */
12956
12957/*
12958 * Aug 26, 2001 Manuel Novoa III
12959 *
12960 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12961 *
12962 * Merge in Aaron's comments previously posted to the busybox list,
12963 * modified slightly to take account of my changes to the code.
12964 *
12965 */
12966
12967/*
12968 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12969 *
12970 * - allow access to variable,
12971 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12972 * - realize assign syntax (VAR=expr, +=, *= etc)
12973 * - realize exponentiation (** operator)
12974 * - realize comma separated - expr, expr
12975 * - realise ++expr --expr expr++ expr--
12976 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000012977 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000012978 * - was restored loses XOR operator
12979 * - remove one goto label, added three ;-)
12980 * - protect $((num num)) as true zero expr (Manuel`s error)
12981 * - always use special isspace(), see comment from bash ;-)
12982 */
12983
12984
12985#define arith_isspace(arithval) \
12986 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12987
12988
12989typedef unsigned char operator;
12990
12991/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000012992 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000012993 * precedence. The ID portion is so that multiple operators can have the
12994 * same precedence, ensuring that the leftmost one is evaluated first.
12995 * Consider * and /. */
12996
12997#define tok_decl(prec,id) (((id)<<5)|(prec))
12998#define PREC(op) ((op) & 0x1F)
12999
13000#define TOK_LPAREN tok_decl(0,0)
13001
13002#define TOK_COMMA tok_decl(1,0)
13003
13004#define TOK_ASSIGN tok_decl(2,0)
13005#define TOK_AND_ASSIGN tok_decl(2,1)
13006#define TOK_OR_ASSIGN tok_decl(2,2)
13007#define TOK_XOR_ASSIGN tok_decl(2,3)
13008#define TOK_PLUS_ASSIGN tok_decl(2,4)
13009#define TOK_MINUS_ASSIGN tok_decl(2,5)
13010#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13011#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13012
13013#define TOK_MUL_ASSIGN tok_decl(3,0)
13014#define TOK_DIV_ASSIGN tok_decl(3,1)
13015#define TOK_REM_ASSIGN tok_decl(3,2)
13016
13017/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13018#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13019
13020/* conditional is right associativity too */
13021#define TOK_CONDITIONAL tok_decl(4,0)
13022#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13023
13024#define TOK_OR tok_decl(5,0)
13025
13026#define TOK_AND tok_decl(6,0)
13027
13028#define TOK_BOR tok_decl(7,0)
13029
13030#define TOK_BXOR tok_decl(8,0)
13031
13032#define TOK_BAND tok_decl(9,0)
13033
13034#define TOK_EQ tok_decl(10,0)
13035#define TOK_NE tok_decl(10,1)
13036
13037#define TOK_LT tok_decl(11,0)
13038#define TOK_GT tok_decl(11,1)
13039#define TOK_GE tok_decl(11,2)
13040#define TOK_LE tok_decl(11,3)
13041
13042#define TOK_LSHIFT tok_decl(12,0)
13043#define TOK_RSHIFT tok_decl(12,1)
13044
13045#define TOK_ADD tok_decl(13,0)
13046#define TOK_SUB tok_decl(13,1)
13047
13048#define TOK_MUL tok_decl(14,0)
13049#define TOK_DIV tok_decl(14,1)
13050#define TOK_REM tok_decl(14,2)
13051
13052/* exponent is right associativity */
13053#define TOK_EXPONENT tok_decl(15,1)
13054
13055/* For now unary operators. */
13056#define UNARYPREC 16
13057#define TOK_BNOT tok_decl(UNARYPREC,0)
13058#define TOK_NOT tok_decl(UNARYPREC,1)
13059
13060#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13061#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13062
13063#define PREC_PRE (UNARYPREC+2)
13064
13065#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13066#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13067
13068#define PREC_POST (UNARYPREC+3)
13069
13070#define TOK_POST_INC tok_decl(PREC_POST, 0)
13071#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13072
13073#define SPEC_PREC (UNARYPREC+4)
13074
13075#define TOK_NUM tok_decl(SPEC_PREC, 0)
13076#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13077
13078#define NUMPTR (*numstackptr)
13079
13080static inline int tok_have_assign(operator op)
13081{
13082 operator prec = PREC(op);
13083
13084 convert_prec_is_assing(prec);
13085 return (prec == PREC(TOK_ASSIGN) ||
13086 prec == PREC_PRE || prec == PREC_POST);
13087}
13088
13089static inline int is_right_associativity(operator prec)
13090{
13091 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13092 prec == PREC(TOK_CONDITIONAL));
13093}
13094
13095
13096typedef struct ARITCH_VAR_NUM {
13097 long val;
13098 long contidional_second_val;
13099 char contidional_second_val_initialized;
13100 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013101 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013102} v_n_t;
13103
13104
13105typedef struct CHK_VAR_RECURSIVE_LOOPED {
13106 const char *var;
13107 struct CHK_VAR_RECURSIVE_LOOPED *next;
13108} chk_var_recursive_looped_t;
13109
13110static chk_var_recursive_looped_t *prev_chk_var_recursive;
13111
13112
13113static int arith_lookup_val(v_n_t *t)
13114{
13115 if(t->var) {
13116 const char * p = lookupvar(t->var);
13117
13118 if(p) {
13119 int errcode;
13120
13121 /* recursive try as expression */
13122 chk_var_recursive_looped_t *cur;
13123 chk_var_recursive_looped_t cur_save;
13124
13125 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13126 if(strcmp(cur->var, t->var) == 0) {
13127 /* expression recursion loop detected */
13128 return -5;
13129 }
13130 }
13131 /* save current lookuped var name */
13132 cur = prev_chk_var_recursive;
13133 cur_save.var = t->var;
13134 cur_save.next = cur;
13135 prev_chk_var_recursive = &cur_save;
13136
13137 t->val = arith (p, &errcode);
13138 /* restore previous ptr after recursiving */
13139 prev_chk_var_recursive = cur;
13140 return errcode;
13141 } else {
13142 /* allow undefined var as 0 */
13143 t->val = 0;
13144 }
13145 }
13146 return 0;
13147}
13148
13149/* "applying" a token means performing it on the top elements on the integer
13150 * stack. For a unary operator it will only change the top element, but a
13151 * binary operator will pop two arguments and push a result */
13152static inline int
13153arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13154{
13155 long numptr_val;
13156 v_n_t *numptr_m1;
13157 long rez;
13158 int ret_arith_lookup_val;
13159
13160 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13161 without arguments */
13162 numptr_m1 = NUMPTR - 1;
13163
13164 /* check operand is var with noninteger value */
13165 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13166 if(ret_arith_lookup_val)
13167 return ret_arith_lookup_val;
13168
13169 rez = numptr_m1->val;
13170 if (op == TOK_UMINUS)
13171 rez *= -1;
13172 else if (op == TOK_NOT)
13173 rez = !rez;
13174 else if (op == TOK_BNOT)
13175 rez = ~rez;
13176 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13177 rez++;
13178 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13179 rez--;
13180 else if (op != TOK_UPLUS) {
13181 /* Binary operators */
13182
13183 /* check and binary operators need two arguments */
13184 if (numptr_m1 == numstack) goto err;
13185
13186 /* ... and they pop one */
13187 --NUMPTR;
13188 numptr_val = rez;
13189 if (op == TOK_CONDITIONAL) {
13190 if(! numptr_m1->contidional_second_val_initialized) {
13191 /* protect $((expr1 ? expr2)) without ": expr" */
13192 goto err;
13193 }
13194 rez = numptr_m1->contidional_second_val;
13195 } else if(numptr_m1->contidional_second_val_initialized) {
13196 /* protect $((expr1 : expr2)) without "expr ? " */
13197 goto err;
13198 }
13199 numptr_m1 = NUMPTR - 1;
13200 if(op != TOK_ASSIGN) {
13201 /* check operand is var with noninteger value for not '=' */
13202 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13203 if(ret_arith_lookup_val)
13204 return ret_arith_lookup_val;
13205 }
13206 if (op == TOK_CONDITIONAL) {
13207 numptr_m1->contidional_second_val = rez;
13208 }
13209 rez = numptr_m1->val;
13210 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13211 rez |= numptr_val;
13212 else if (op == TOK_OR)
13213 rez = numptr_val || rez;
13214 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13215 rez &= numptr_val;
13216 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13217 rez ^= numptr_val;
13218 else if (op == TOK_AND)
13219 rez = rez && numptr_val;
13220 else if (op == TOK_EQ)
13221 rez = (rez == numptr_val);
13222 else if (op == TOK_NE)
13223 rez = (rez != numptr_val);
13224 else if (op == TOK_GE)
13225 rez = (rez >= numptr_val);
13226 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13227 rez >>= numptr_val;
13228 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13229 rez <<= numptr_val;
13230 else if (op == TOK_GT)
13231 rez = (rez > numptr_val);
13232 else if (op == TOK_LT)
13233 rez = (rez < numptr_val);
13234 else if (op == TOK_LE)
13235 rez = (rez <= numptr_val);
13236 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13237 rez *= numptr_val;
13238 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13239 rez += numptr_val;
13240 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13241 rez -= numptr_val;
13242 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13243 rez = numptr_val;
13244 else if (op == TOK_CONDITIONAL_SEP) {
13245 if (numptr_m1 == numstack) {
13246 /* protect $((expr : expr)) without "expr ? " */
13247 goto err;
13248 }
13249 numptr_m1->contidional_second_val_initialized = op;
13250 numptr_m1->contidional_second_val = numptr_val;
13251 }
13252 else if (op == TOK_CONDITIONAL) {
13253 rez = rez ?
13254 numptr_val : numptr_m1->contidional_second_val;
13255 }
13256 else if(op == TOK_EXPONENT) {
13257 if(numptr_val < 0)
13258 return -3; /* exponent less than 0 */
13259 else {
13260 long c = 1;
13261
13262 if(numptr_val)
13263 while(numptr_val--)
13264 c *= rez;
13265 rez = c;
13266 }
13267 }
13268 else if(numptr_val==0) /* zero divisor check */
13269 return -2;
13270 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13271 rez /= numptr_val;
13272 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13273 rez %= numptr_val;
13274 }
13275 if(tok_have_assign(op)) {
13276 char buf[32];
13277
13278 if(numptr_m1->var == NULL) {
13279 /* Hmm, 1=2 ? */
13280 goto err;
13281 }
13282 /* save to shell variable */
13283 sprintf(buf, "%ld", rez);
13284 setvar(numptr_m1->var, buf, 0);
13285 /* after saving, make previous value for v++ or v-- */
13286 if(op == TOK_POST_INC)
13287 rez--;
13288 else if(op == TOK_POST_DEC)
13289 rez++;
13290 }
13291 numptr_m1->val = rez;
13292 /* protect geting var value, is number now */
13293 numptr_m1->var = NULL;
13294 return 0;
13295err: return(-1);
13296}
13297
13298/* longest must first */
13299static const char op_tokens[] = {
13300 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13301 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13302 '<','<', 0, TOK_LSHIFT,
13303 '>','>', 0, TOK_RSHIFT,
13304 '|','|', 0, TOK_OR,
13305 '&','&', 0, TOK_AND,
13306 '!','=', 0, TOK_NE,
13307 '<','=', 0, TOK_LE,
13308 '>','=', 0, TOK_GE,
13309 '=','=', 0, TOK_EQ,
13310 '|','=', 0, TOK_OR_ASSIGN,
13311 '&','=', 0, TOK_AND_ASSIGN,
13312 '*','=', 0, TOK_MUL_ASSIGN,
13313 '/','=', 0, TOK_DIV_ASSIGN,
13314 '%','=', 0, TOK_REM_ASSIGN,
13315 '+','=', 0, TOK_PLUS_ASSIGN,
13316 '-','=', 0, TOK_MINUS_ASSIGN,
13317 '-','-', 0, TOK_POST_DEC,
13318 '^','=', 0, TOK_XOR_ASSIGN,
13319 '+','+', 0, TOK_POST_INC,
13320 '*','*', 0, TOK_EXPONENT,
13321 '!', 0, TOK_NOT,
13322 '<', 0, TOK_LT,
13323 '>', 0, TOK_GT,
13324 '=', 0, TOK_ASSIGN,
13325 '|', 0, TOK_BOR,
13326 '&', 0, TOK_BAND,
13327 '*', 0, TOK_MUL,
13328 '/', 0, TOK_DIV,
13329 '%', 0, TOK_REM,
13330 '+', 0, TOK_ADD,
13331 '-', 0, TOK_SUB,
13332 '^', 0, TOK_BXOR,
13333 /* uniq */
13334 '~', 0, TOK_BNOT,
13335 ',', 0, TOK_COMMA,
13336 '?', 0, TOK_CONDITIONAL,
13337 ':', 0, TOK_CONDITIONAL_SEP,
13338 ')', 0, TOK_RPAREN,
13339 '(', 0, TOK_LPAREN,
13340 0
13341};
13342/* ptr to ")" */
13343#define endexpression &op_tokens[sizeof(op_tokens)-7]
13344
13345
13346extern long arith (const char *expr, int *perrcode)
13347{
13348 register char arithval; /* Current character under analysis */
13349 operator lasttok, op;
13350 operator prec;
13351
13352 const char *p = endexpression;
13353 int errcode;
13354
13355 size_t datasizes = strlen(expr) + 2;
13356
13357 /* Stack of integers */
13358 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013359 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013360 * the reader. */
13361 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13362 *numstackptr = numstack;
13363 /* Stack of operator tokens */
13364 operator *stack = alloca((datasizes) * sizeof(operator)),
13365 *stackptr = stack;
13366
13367 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13368 *perrcode = errcode = 0;
13369
13370 while(1) {
13371 if ((arithval = *expr) == 0) {
13372 if (p == endexpression) {
13373 /* Null expression. */
13374 return 0;
13375 }
13376
13377 /* This is only reached after all tokens have been extracted from the
13378 * input stream. If there are still tokens on the operator stack, they
13379 * are to be applied in order. At the end, there should be a final
13380 * result on the integer stack */
13381
13382 if (expr != endexpression + 1) {
13383 /* If we haven't done so already, */
13384 /* append a closing right paren */
13385 expr = endexpression;
13386 /* and let the loop process it. */
13387 continue;
13388 }
13389 /* At this point, we're done with the expression. */
13390 if (numstackptr != numstack+1) {
13391 /* ... but if there isn't, it's bad */
13392 err:
13393 return (*perrcode = -1);
13394 }
13395 if(numstack->var) {
13396 /* expression is $((var)) only, lookup now */
13397 errcode = arith_lookup_val(numstack);
13398 }
13399 ret:
13400 *perrcode = errcode;
13401 return numstack->val;
13402 } else {
13403 /* Continue processing the expression. */
13404 if (arith_isspace(arithval)) {
13405 /* Skip whitespace */
13406 goto prologue;
13407 }
13408 if((p = endofname(expr)) != expr) {
13409 int var_name_size = (p-expr) + 1; /* trailing zero */
13410
13411 numstackptr->var = alloca(var_name_size);
13412 safe_strncpy(numstackptr->var, expr, var_name_size);
13413 expr = p;
13414 num:
13415 numstackptr->contidional_second_val_initialized = 0;
13416 numstackptr++;
13417 lasttok = TOK_NUM;
13418 continue;
13419 } else if (is_digit(arithval)) {
13420 numstackptr->var = NULL;
13421 numstackptr->val = strtol(expr, (char **) &expr, 0);
13422 goto num;
13423 }
13424 for(p = op_tokens; ; p++) {
13425 const char *o;
13426
13427 if(*p == 0) {
13428 /* strange operator not found */
13429 goto err;
13430 }
13431 for(o = expr; *p && *o == *p; p++)
13432 o++;
13433 if(! *p) {
13434 /* found */
13435 expr = o - 1;
13436 break;
13437 }
13438 /* skip tail uncompared token */
13439 while(*p)
13440 p++;
13441 /* skip zero delim */
13442 p++;
13443 }
13444 op = p[1];
13445
13446 /* post grammar: a++ reduce to num */
13447 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13448 lasttok = TOK_NUM;
13449
13450 /* Plus and minus are binary (not unary) _only_ if the last
13451 * token was as number, or a right paren (which pretends to be
13452 * a number, since it evaluates to one). Think about it.
13453 * It makes sense. */
13454 if (lasttok != TOK_NUM) {
13455 switch(op) {
13456 case TOK_ADD:
13457 op = TOK_UPLUS;
13458 break;
13459 case TOK_SUB:
13460 op = TOK_UMINUS;
13461 break;
13462 case TOK_POST_INC:
13463 op = TOK_PRE_INC;
13464 break;
13465 case TOK_POST_DEC:
13466 op = TOK_PRE_DEC;
13467 break;
13468 }
13469 }
13470 /* We don't want a unary operator to cause recursive descent on the
13471 * stack, because there can be many in a row and it could cause an
13472 * operator to be evaluated before its argument is pushed onto the
13473 * integer stack. */
13474 /* But for binary operators, "apply" everything on the operator
13475 * stack until we find an operator with a lesser priority than the
13476 * one we have just extracted. */
13477 /* Left paren is given the lowest priority so it will never be
13478 * "applied" in this way.
13479 * if associativity is right and priority eq, applied also skip
13480 */
13481 prec = PREC(op);
13482 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13483 /* not left paren or unary */
13484 if (lasttok != TOK_NUM) {
13485 /* binary op must be preceded by a num */
13486 goto err;
13487 }
13488 while (stackptr != stack) {
13489 if (op == TOK_RPAREN) {
13490 /* The algorithm employed here is simple: while we don't
13491 * hit an open paren nor the bottom of the stack, pop
13492 * tokens and apply them */
13493 if (stackptr[-1] == TOK_LPAREN) {
13494 --stackptr;
13495 /* Any operator directly after a */
13496 lasttok = TOK_NUM;
13497 /* close paren should consider itself binary */
13498 goto prologue;
13499 }
13500 } else {
13501 operator prev_prec = PREC(stackptr[-1]);
13502
13503 convert_prec_is_assing(prec);
13504 convert_prec_is_assing(prev_prec);
13505 if (prev_prec < prec)
13506 break;
13507 /* check right assoc */
13508 if(prev_prec == prec && is_right_associativity(prec))
13509 break;
13510 }
13511 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13512 if(errcode) goto ret;
13513 }
13514 if (op == TOK_RPAREN) {
13515 goto err;
13516 }
13517 }
13518
13519 /* Push this operator to the stack and remember it. */
13520 *stackptr++ = lasttok = op;
13521
13522 prologue:
13523 ++expr;
13524 }
13525 }
13526}
13527#endif /* CONFIG_ASH_MATH_SUPPORT */
13528
13529
Eric Andersenc470f442003-07-28 09:56:35 +000013530#ifdef DEBUG
13531const char *bb_applet_name = "debug stuff usage";
13532int main(int argc, char **argv)
13533{
13534 return ash_main(argc, argv);
13535}
13536#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013537
Eric Andersendf82f612001-06-28 07:46:40 +000013538/*-
13539 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013540 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013541 *
13542 * This code is derived from software contributed to Berkeley by
13543 * Kenneth Almquist.
13544 *
13545 * Redistribution and use in source and binary forms, with or without
13546 * modification, are permitted provided that the following conditions
13547 * are met:
13548 * 1. Redistributions of source code must retain the above copyright
13549 * notice, this list of conditions and the following disclaimer.
13550 * 2. Redistributions in binary form must reproduce the above copyright
13551 * notice, this list of conditions and the following disclaimer in the
13552 * documentation and/or other materials provided with the distribution.
13553 *
Eric Andersen2870d962001-07-02 17:27:21 +000013554 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13555 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013556 *
13557 * 4. Neither the name of the University nor the names of its contributors
13558 * may be used to endorse or promote products derived from this software
13559 * without specific prior written permission.
13560 *
13561 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13562 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13563 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13564 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13565 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13566 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13567 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13568 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13569 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13570 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13571 * SUCH DAMAGE.
13572 */