blob: e27d2e088cdd891ad9a46dddc09f8df3b7671e16 [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 *
36 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2003 to be
37 * used in busybox and size optimizations,
38 * support locale, rewrited arith (see notes to this)
39 *
40 */
41
42
43/*
Eric Andersenc470f442003-07-28 09:56:35 +000044 * The follow should be set to reflect the type of system you have:
45 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
46 * define SYSV if you are running under System V.
47 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
48 * define DEBUG=2 to compile in and turn on debugging.
49 *
50 * When debugging is on, debugging info will be written to ./trace and
51 * a quit signal will generate a core dump.
52 */
Eric Andersen2870d962001-07-02 17:27:21 +000053
Eric Andersen2870d962001-07-02 17:27:21 +000054
Eric Andersenc470f442003-07-28 09:56:35 +000055
Eric Andersen5bb16772001-09-06 18:00:41 +000056#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000057
Eric Andersenc470f442003-07-28 09:56:35 +000058#define PROFILE 0
59
60#ifdef DEBUG
61#define _GNU_SOURCE
62#endif
63
64#include <sys/types.h>
65#include <sys/cdefs.h>
66#include <sys/ioctl.h>
67#include <sys/param.h>
68#include <sys/resource.h>
69#include <sys/stat.h>
70#include <sys/time.h>
71#include <sys/wait.h>
72
73#include <stdio.h>
74#include <stdlib.h>
75#include <string.h>
76#include <unistd.h>
77
78#include <stdarg.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000079#include <stddef.h>
Eric Andersenc470f442003-07-28 09:56:35 +000080#include <assert.h>
Eric Andersencb57d552001-06-28 07:25:16 +000081#include <ctype.h>
82#include <dirent.h>
83#include <errno.h>
84#include <fcntl.h>
85#include <limits.h>
86#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000087#include <setjmp.h>
88#include <signal.h>
Eric Andersenc470f442003-07-28 09:56:35 +000089#include <stdint.h>
Eric Andersencb57d552001-06-28 07:25:16 +000090#include <sysexits.h>
Eric Andersenc470f442003-07-28 09:56:35 +000091
92#include <fnmatch.h>
Eric Andersenc470f442003-07-28 09:56:35 +000093
94
Robert Grieblea1a63a2002-06-04 20:10:23 +000095#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +000096#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +000097
Eric Andersend35c5df2002-01-09 15:37:36 +000098#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000099#define JOBS 1
100#else
Eric Andersenca162042003-07-29 07:15:17 +0000101#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +0000102#endif
103
104#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000105#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000106#endif
107
Eric Andersen2870d962001-07-02 17:27:21 +0000108#include "cmdedit.h"
109
Eric Andersenc470f442003-07-28 09:56:35 +0000110#ifdef __GLIBC__
111/* glibc sucks */
112static int *dash_errno;
113#undef errno
114#define errno (*dash_errno)
115#endif
116
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000117#if defined(__uClinux__)
118#error "Do not even bother, ash will not run on uClinux"
119#endif
120
Eric Andersenc470f442003-07-28 09:56:35 +0000121#ifdef DEBUG
122#define _DIAGASSERT(assert_expr) assert(assert_expr)
123#else
124#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000125#endif
126
Eric Andersen2870d962001-07-02 17:27:21 +0000127
Eric Andersenc470f442003-07-28 09:56:35 +0000128#ifdef CONFIG_ASH_ALIAS
129/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
130
131#define ALIASINUSE 1
132#define ALIASDEAD 2
133
134struct alias {
135 struct alias *next;
136 char *name;
137 char *val;
138 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000139};
140
Eric Andersenc470f442003-07-28 09:56:35 +0000141static struct alias *lookupalias(const char *, int);
142static int aliascmd(int, char **);
143static int unaliascmd(int, char **);
144static void rmaliases(void);
145static int unalias(const char *);
146static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000147#endif
148
Eric Andersenc470f442003-07-28 09:56:35 +0000149/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
150
151
152static void setpwd(const char *, int);
153
154/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
155
156
157/*
158 * Types of operations (passed to the errmsg routine).
159 */
160
161
162static const char not_found_msg[] = "%s: not found";
163
164
165#define E_OPEN "No such file" /* opening a file */
166#define E_CREAT "Directory nonexistent" /* creating a file */
167#define E_EXEC not_found_msg+4 /* executing a program */
168
169/*
170 * We enclose jmp_buf in a structure so that we can declare pointers to
171 * jump locations. The global variable handler contains the location to
172 * jump to when an exception occurs, and the global variable exception
173 * contains a code identifying the exeception. To implement nested
174 * exception handlers, the user should save the value of handler on entry
175 * to an inner scope, set handler to point to a jmploc structure for the
176 * inner scope, and restore handler on exit from the scope.
177 */
178
179struct jmploc {
180 jmp_buf loc;
181};
182
183static struct jmploc *handler;
184static int exception;
185static volatile int suppressint;
186static volatile sig_atomic_t intpending;
187
188static int exerrno; /* Last exec error, error for EXEXEC */
189
190/* exceptions */
191#define EXINT 0 /* SIGINT received */
192#define EXERROR 1 /* a generic error */
193#define EXSHELLPROC 2 /* execute a shell procedure */
194#define EXEXEC 3 /* command execution failed */
195#define EXEXIT 4 /* exit the shell */
196#define EXSIG 5 /* trapped signal in wait(1) */
197
198
199/* do we generate EXSIG events */
200static int exsig;
201/* last pending signal */
202static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000203
204/*
205 * These macros allow the user to suspend the handling of interrupt signals
206 * over a period of time. This is similar to SIGHOLD to or sigblock, but
207 * much more efficient and portable. (But hacking the kernel is so much
208 * more fun than worrying about efficiency and portability. :-))
209 */
210
Eric Andersenc470f442003-07-28 09:56:35 +0000211#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
212#define INTOFF \
213 ({ \
214 suppressint++; \
215 barrier(); \
216 0; \
217 })
218#define SAVEINT(v) ((v) = suppressint)
219#define RESTOREINT(v) \
220 ({ \
221 barrier(); \
222 if ((suppressint = (v)) == 0 && intpending) onint(); \
223 0; \
224 })
225#define EXSIGON() \
226 ({ \
227 exsig++; \
228 barrier(); \
229 if (pendingsigs) \
230 exraise(EXSIG); \
231 0; \
232 })
233/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000234
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000235
Eric Andersenc470f442003-07-28 09:56:35 +0000236static void exraise(int) __attribute__((__noreturn__));
237static void onint(void) __attribute__((__noreturn__));
238
239static void error(const char *, ...) __attribute__((__noreturn__));
240static void exerror(int, const char *, ...) __attribute__((__noreturn__));
241
242static void sh_warnx(const char *, ...);
243
244#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
245static void
246inton(void) {
247 if (--suppressint == 0 && intpending) {
248 onint();
249 }
250}
251#define INTON inton()
252static void forceinton(void)
253{
254 suppressint = 0;
255 if (intpending)
256 onint();
257}
Eric Andersen3102ac42001-07-06 04:26:23 +0000258#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000259#else
Eric Andersenc470f442003-07-28 09:56:35 +0000260#define INTON \
261 ({ \
262 barrier(); \
263 if (--suppressint == 0 && intpending) onint(); \
264 0; \
265 })
266#define FORCEINTON \
267 ({ \
268 barrier(); \
269 suppressint = 0; \
270 if (intpending) onint(); \
271 0; \
272 })
273#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000274
275/*
Eric Andersenc470f442003-07-28 09:56:35 +0000276 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
277 * so we use _setjmp instead.
Eric Andersen2870d962001-07-02 17:27:21 +0000278 */
Eric Andersen2870d962001-07-02 17:27:21 +0000279
Eric Andersenc470f442003-07-28 09:56:35 +0000280#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
281#define setjmp(jmploc) _setjmp(jmploc)
282#define longjmp(jmploc, val) _longjmp(jmploc, val)
283#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000284
Eric Andersenc470f442003-07-28 09:56:35 +0000285/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000286
287struct strlist {
288 struct strlist *next;
289 char *text;
290};
291
292
293struct arglist {
294 struct strlist *list;
295 struct strlist **lastp;
296};
297
Eric Andersenc470f442003-07-28 09:56:35 +0000298/*
299 * expandarg() flags
300 */
301#define EXP_FULL 0x1 /* perform word splitting & file globbing */
302#define EXP_TILDE 0x2 /* do normal tilde expansion */
303#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
304#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
305#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
306#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
307#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
308#define EXP_WORD 0x80 /* expand word in parameter expansion */
309#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
310
311
312union node;
313static void expandarg(union node *, struct arglist *, int);
314#define rmescapes(p) _rmescapes((p), 0)
315static char *_rmescapes(char *, int);
316static int casematch(union node *, char *);
317
318#ifdef CONFIG_ASH_MATH_SUPPORT
319static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000320#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000321
Eric Andersenc470f442003-07-28 09:56:35 +0000322/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000323
Eric Andersenc470f442003-07-28 09:56:35 +0000324static char *commandname; /* currently executing command */
325static struct strlist *cmdenviron; /* environment for builtin command */
326static int exitstatus; /* exit status of last command */
327static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000328
Eric Andersenc470f442003-07-28 09:56:35 +0000329
330struct backcmd { /* result of evalbackcmd */
331 int fd; /* file descriptor to read from */
332 char *buf; /* buffer */
333 int nleft; /* number of chars in buffer */
334 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000335};
336
Eric Andersen62483552001-07-10 06:09:16 +0000337/*
Eric Andersenc470f442003-07-28 09:56:35 +0000338 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000339 */
Eric Andersenc470f442003-07-28 09:56:35 +0000340
341#define NCMD 0
342#define NPIPE 1
343#define NREDIR 2
344#define NBACKGND 3
345#define NSUBSHELL 4
346#define NAND 5
347#define NOR 6
348#define NSEMI 7
349#define NIF 8
350#define NWHILE 9
351#define NUNTIL 10
352#define NFOR 11
353#define NCASE 12
354#define NCLIST 13
355#define NDEFUN 14
356#define NARG 15
357#define NTO 16
358#define NCLOBBER 17
359#define NFROM 18
360#define NFROMTO 19
361#define NAPPEND 20
362#define NTOFD 21
363#define NFROMFD 22
364#define NHERE 23
365#define NXHERE 24
366#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000367
368
369
Eric Andersenc470f442003-07-28 09:56:35 +0000370struct ncmd {
371 int type;
372 union node *assign;
373 union node *args;
374 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000375};
376
377
Eric Andersenc470f442003-07-28 09:56:35 +0000378struct npipe {
379 int type;
380 int backgnd;
381 struct nodelist *cmdlist;
382};
Eric Andersen62483552001-07-10 06:09:16 +0000383
384
Eric Andersenc470f442003-07-28 09:56:35 +0000385struct nredir {
386 int type;
387 union node *n;
388 union node *redirect;
389};
Eric Andersen62483552001-07-10 06:09:16 +0000390
391
Eric Andersenc470f442003-07-28 09:56:35 +0000392struct nbinary {
393 int type;
394 union node *ch1;
395 union node *ch2;
396};
Eric Andersen2870d962001-07-02 17:27:21 +0000397
Eric Andersen2870d962001-07-02 17:27:21 +0000398
Eric Andersenc470f442003-07-28 09:56:35 +0000399struct nif {
400 int type;
401 union node *test;
402 union node *ifpart;
403 union node *elsepart;
404};
405
406
407struct nfor {
408 int type;
409 union node *args;
410 union node *body;
411 char *var;
412};
413
414
415struct ncase {
416 int type;
417 union node *expr;
418 union node *cases;
419};
420
421
422struct nclist {
423 int type;
424 union node *next;
425 union node *pattern;
426 union node *body;
427};
428
429
430struct narg {
431 int type;
432 union node *next;
433 char *text;
434 struct nodelist *backquote;
435};
436
437
438struct nfile {
439 int type;
440 union node *next;
441 int fd;
442 union node *fname;
443 char *expfname;
444};
445
446
447struct ndup {
448 int type;
449 union node *next;
450 int fd;
451 int dupfd;
452 union node *vname;
453};
454
455
456struct nhere {
457 int type;
458 union node *next;
459 int fd;
460 union node *doc;
461};
462
463
464struct nnot {
465 int type;
466 union node *com;
467};
468
469
470union node {
471 int type;
472 struct ncmd ncmd;
473 struct npipe npipe;
474 struct nredir nredir;
475 struct nbinary nbinary;
476 struct nif nif;
477 struct nfor nfor;
478 struct ncase ncase;
479 struct nclist nclist;
480 struct narg narg;
481 struct nfile nfile;
482 struct ndup ndup;
483 struct nhere nhere;
484 struct nnot nnot;
485};
486
487
488struct nodelist {
489 struct nodelist *next;
490 union node *n;
491};
492
493
494struct funcnode {
495 int count;
496 union node n;
497};
498
499
500static void freefunc(struct funcnode *);
501/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
502
503/* control characters in argument strings */
504#define CTL_FIRST '\201' /* first 'special' character */
505#define CTLESC '\201' /* escape next character */
506#define CTLVAR '\202' /* variable defn */
507#define CTLENDVAR '\203'
508#define CTLBACKQ '\204'
509#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
510/* CTLBACKQ | CTLQUOTE == '\205' */
511#define CTLARI '\206' /* arithmetic expression */
512#define CTLENDARI '\207'
513#define CTLQUOTEMARK '\210'
514#define CTL_LAST '\210' /* last 'special' character */
515
516/* variable substitution byte (follows CTLVAR) */
517#define VSTYPE 0x0f /* type of variable substitution */
518#define VSNUL 0x10 /* colon--treat the empty string as unset */
519#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
520
521/* values of VSTYPE field */
522#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
523#define VSMINUS 0x2 /* ${var-text} */
524#define VSPLUS 0x3 /* ${var+text} */
525#define VSQUESTION 0x4 /* ${var?message} */
526#define VSASSIGN 0x5 /* ${var=text} */
527#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
528#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
529#define VSTRIMLEFT 0x8 /* ${var#pattern} */
530#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
531#define VSLENGTH 0xa /* ${#var} */
532
533/* values of checkkwd variable */
534#define CHKALIAS 0x1
535#define CHKKWD 0x2
536#define CHKNL 0x4
537
538#define IBUFSIZ (BUFSIZ + 1)
539
540/*
541 * NEOF is returned by parsecmd when it encounters an end of file. It
542 * must be distinct from NULL, so we use the address of a variable that
543 * happens to be handy.
544 */
545static int plinno = 1; /* input line number */
546
547/* number of characters left in input buffer */
548static int parsenleft; /* copy of parsefile->nleft */
549static int parselleft; /* copy of parsefile->lleft */
550
551/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000552static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000553
554struct strpush {
555 struct strpush *prev; /* preceding string on stack */
556 char *prevstring;
557 int prevnleft;
558#ifdef CONFIG_ASH_ALIAS
559 struct alias *ap; /* if push was associated with an alias */
560#endif
561 char *string; /* remember the string since it may change */
562};
563
564struct parsefile {
565 struct parsefile *prev; /* preceding file on stack */
566 int linno; /* current line */
567 int fd; /* file descriptor (or -1 if string) */
568 int nleft; /* number of chars left in this line */
569 int lleft; /* number of chars left in this buffer */
570 char *nextc; /* next char in buffer */
571 char *buf; /* input buffer */
572 struct strpush *strpush; /* for pushing strings at this level */
573 struct strpush basestrpush; /* so pushing one is fast */
574};
575
Eric Andersenc470f442003-07-28 09:56:35 +0000576static struct parsefile basepf; /* top level input file */
577static char basebuf[IBUFSIZ]; /* buffer for top level input file */
578static struct parsefile *parsefile = &basepf; /* current input file */
579
580
581static int tokpushback; /* last token pushed back */
582#define NEOF ((union node *)&tokpushback)
583static int parsebackquote; /* nonzero if we are inside backquotes */
584static int doprompt; /* if set, prompt the user */
585static int needprompt; /* true if interactive and at start of line */
586static int lasttoken; /* last token read */
587static char *wordtext; /* text of last word returned by readtoken */
588static int checkkwd;
589static struct nodelist *backquotelist;
590static union node *redirnode;
591static struct heredoc *heredoc;
592static int quoteflag; /* set if (part of) last token was quoted */
593static int startlinno; /* line # where last token started */
594
595static union node *parsecmd(int);
596static void fixredir(union node *, const char *, int);
597static const char *const *findkwd(const char *);
598static char *endofname(const char *);
599
600/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
601
602typedef void *pointer;
603
604static char nullstr[1]; /* zero length string */
605static const char spcstr[] = " ";
606static const char snlfmt[] = "%s\n";
607static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
608static const char illnum[] = "Illegal number: %s";
609static const char homestr[] = "HOME";
610
611#ifdef DEBUG
612#define TRACE(param) trace param
613#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000614#else
Eric Andersenc470f442003-07-28 09:56:35 +0000615#define TRACE(param)
616#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000617#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000618
Eric Andersenc470f442003-07-28 09:56:35 +0000619#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
620#define __builtin_expect(x, expected_value) (x)
621#endif
622
623#define likely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000624
Eric Andersenc470f442003-07-28 09:56:35 +0000625
626#define TEOF 0
627#define TNL 1
628#define TREDIR 2
629#define TWORD 3
630#define TSEMI 4
631#define TBACKGND 5
632#define TAND 6
633#define TOR 7
634#define TPIPE 8
635#define TLP 9
636#define TRP 10
637#define TENDCASE 11
638#define TENDBQUOTE 12
639#define TNOT 13
640#define TCASE 14
641#define TDO 15
642#define TDONE 16
643#define TELIF 17
644#define TELSE 18
645#define TESAC 19
646#define TFI 20
647#define TFOR 21
648#define TIF 22
649#define TIN 23
650#define TTHEN 24
651#define TUNTIL 25
652#define TWHILE 26
653#define TBEGIN 27
654#define TEND 28
655
656/* first char is indicating which tokens mark the end of a list */
657static const char *const tokname_array[] = {
658 "\1end of file",
659 "\0newline",
660 "\0redirection",
661 "\0word",
662 "\0;",
663 "\0&",
664 "\0&&",
665 "\0||",
666 "\0|",
667 "\0(",
668 "\1)",
669 "\1;;",
670 "\1`",
671#define KWDOFFSET 13
672 /* the following are keywords */
673 "\0!",
674 "\0case",
675 "\1do",
676 "\1done",
677 "\1elif",
678 "\1else",
679 "\1esac",
680 "\1fi",
681 "\0for",
682 "\0if",
683 "\0in",
684 "\1then",
685 "\0until",
686 "\0while",
687 "\0{",
688 "\1}",
689};
690
691static const char *tokname(int tok)
692{
693 static char buf[16];
694
695 if (tok >= TSEMI)
696 buf[0] = '"';
697 sprintf(buf + (tok >= TSEMI), "%s%c",
698 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
699 return buf;
700}
701
702/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
703
704/*
705 * Most machines require the value returned from malloc to be aligned
706 * in some way. The following macro will get this right on many machines.
707 */
708
709#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
710/*
711 * It appears that grabstackstr() will barf with such alignments
712 * because stalloc() will return a string allocated in a new stackblock.
713 */
714#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
715
716/*
717 * This file was generated by the mksyntax program.
718 */
719
720
721/* Syntax classes */
722#define CWORD 0 /* character is nothing special */
723#define CNL 1 /* newline character */
724#define CBACK 2 /* a backslash character */
725#define CSQUOTE 3 /* single quote */
726#define CDQUOTE 4 /* double quote */
727#define CENDQUOTE 5 /* a terminating quote */
728#define CBQUOTE 6 /* backwards single quote */
729#define CVAR 7 /* a dollar sign */
730#define CENDVAR 8 /* a '}' character */
731#define CLP 9 /* a left paren in arithmetic */
732#define CRP 10 /* a right paren in arithmetic */
733#define CENDFILE 11 /* end of file */
734#define CCTL 12 /* like CWORD, except it must be escaped */
735#define CSPCL 13 /* these terminate a word */
736#define CIGN 14 /* character should be ignored */
737
738#ifdef CONFIG_ASH_ALIAS
739#define SYNBASE 130
740#define PEOF -130
741#define PEOA -129
742#define PEOA_OR_PEOF PEOA
743#else
744#define SYNBASE 129
745#define PEOF -129
746#define PEOA_OR_PEOF PEOF
747#endif
748
749#define is_digit(c) ((unsigned)((c) - '0') <= 9)
750#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
751#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
752
753/*
754 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
755 * (assuming ascii char codes, as the original implementation did)
756 */
757#define is_special(c) \
758 ( (((unsigned int)c) - 33 < 32) \
759 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
760
761#define digit_val(c) ((c) - '0')
762
763/*
764 * This file was generated by the mksyntax program.
765 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000766
Eric Andersend35c5df2002-01-09 15:37:36 +0000767#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000768#define USE_SIT_FUNCTION
769#endif
770
771/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000772#define BASESYNTAX 0 /* not in quotes */
773#define DQSYNTAX 1 /* in double quotes */
774#define SQSYNTAX 2 /* in single quotes */
775#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000776
Eric Andersenc470f442003-07-28 09:56:35 +0000777#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000778static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000779#ifdef CONFIG_ASH_ALIAS
780 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
781#endif
782 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
783 {CNL, CNL, CNL, CNL}, /* 2, \n */
784 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
785 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
786 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
787 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
788 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
789 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
790 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
791 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
792 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000793#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000794 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
795 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
796 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000797#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000798};
Eric Andersenc470f442003-07-28 09:56:35 +0000799#else
800static const char S_I_T[][3] = {
801#ifdef CONFIG_ASH_ALIAS
802 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
803#endif
804 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
805 {CNL, CNL, CNL}, /* 2, \n */
806 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
807 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
808 {CVAR, CVAR, CWORD}, /* 5, $ */
809 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
810 {CSPCL, CWORD, CWORD}, /* 7, ( */
811 {CSPCL, CWORD, CWORD}, /* 8, ) */
812 {CBACK, CBACK, CCTL}, /* 9, \ */
813 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
814 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
815#ifndef USE_SIT_FUNCTION
816 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
817 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
818 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
819#endif
820};
821#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000822
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000823#ifdef USE_SIT_FUNCTION
824
825#define U_C(c) ((unsigned char)(c))
826
827static int SIT(int c, int syntax)
828{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000829 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000830#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000831 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000832 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
833 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
834 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
835 11, 3 /* "}~" */
836 };
837#else
838 static const char syntax_index_table[] = {
839 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
840 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
841 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
842 10, 2 /* "}~" */
843 };
844#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000845 const char *s;
846 int indx;
847
Eric Andersenc470f442003-07-28 09:56:35 +0000848 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000849 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000850#ifdef CONFIG_ASH_ALIAS
851 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000852 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000853 else
854#endif
855 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
856 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000857 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000858 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000859 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000860 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000861 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000862 }
863 return S_I_T[indx][syntax];
864}
865
Eric Andersenc470f442003-07-28 09:56:35 +0000866#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000867
868#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
869
Eric Andersenc470f442003-07-28 09:56:35 +0000870#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000871#define CSPCL_CIGN_CIGN_CIGN 0
872#define CSPCL_CWORD_CWORD_CWORD 1
873#define CNL_CNL_CNL_CNL 2
874#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000875#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000876#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000877#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000878#define CSPCL_CWORD_CWORD_CLP 7
879#define CSPCL_CWORD_CWORD_CRP 8
880#define CBACK_CBACK_CCTL_CBACK 9
881#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
882#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
883#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
884#define CWORD_CWORD_CWORD_CWORD 13
885#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000886#else
887#define CSPCL_CWORD_CWORD_CWORD 0
888#define CNL_CNL_CNL_CNL 1
889#define CWORD_CCTL_CCTL_CWORD 2
890#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
891#define CVAR_CVAR_CWORD_CVAR 4
892#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
893#define CSPCL_CWORD_CWORD_CLP 6
894#define CSPCL_CWORD_CWORD_CRP 7
895#define CBACK_CBACK_CCTL_CBACK 8
896#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
897#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
898#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
899#define CWORD_CWORD_CWORD_CWORD 12
900#define CCTL_CCTL_CCTL_CCTL 13
901#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000902
903static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000904 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000905 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
906#ifdef CONFIG_ASH_ALIAS
907 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
908#endif
909 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
910 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
911 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
912 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
913 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
914 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
915 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
916 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
917 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000918 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
919 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
920 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
921 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
922 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
923 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
924 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
925 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
926 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
927 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
928 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
929 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
930 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
931 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
932 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
933 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
934 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
935 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
936 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
937 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
938 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
939 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
940 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
941 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
942 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
943 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
944 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
945 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
946 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
947 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
948 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
949 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
950 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
951 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
952 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
953 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
954 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
955 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
956 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
957 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
958 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
959 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
960 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
961 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
962 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
963 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
964 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
965 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
966 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
967 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
968 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
969 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
970 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
971 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
972 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
973 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
974 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
975 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
976 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
977 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
978 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
979 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
980 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
981 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
982 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
983 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
984 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
985 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
986 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
987 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
988 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
989 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
990 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
991 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
992 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
993 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
994 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
995 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
996 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
997 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
998 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
999 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1047 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1048 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1051 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1052 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1053 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1054 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1055 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1056 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1057 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1058 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1059 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1060 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1061 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1062 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1063 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1064 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1065 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1066 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1067 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1068 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1069 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1070 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001071 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001072 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1073 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1074 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1075 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001076 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001077 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1078 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1079 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1080 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1082 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1083 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1084 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1085 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1096 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1097 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1098 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1099 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1100 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1101 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1129 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1130 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1131 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1134 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1143 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1144 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1145 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1146 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1147 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1148 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1149 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1150 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1151 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1152 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1153 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1154 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1155 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1156 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1157 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1158 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1159 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1160 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1161 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1162 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1163 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1164 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001165};
1166
Eric Andersenc470f442003-07-28 09:56:35 +00001167#endif /* USE_SIT_FUNCTION */
1168
1169/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001170
Eric Andersen2870d962001-07-02 17:27:21 +00001171
Eric Andersenc470f442003-07-28 09:56:35 +00001172#define ATABSIZE 39
1173
1174static int funcblocksize; /* size of structures in function */
1175static int funcstringsize; /* size of strings in node */
1176static pointer funcblock; /* block to allocate function from */
1177static char *funcstring; /* block to allocate strings from */
1178
1179static const short nodesize[26] = {
1180 SHELL_ALIGN(sizeof (struct ncmd)),
1181 SHELL_ALIGN(sizeof (struct npipe)),
1182 SHELL_ALIGN(sizeof (struct nredir)),
1183 SHELL_ALIGN(sizeof (struct nredir)),
1184 SHELL_ALIGN(sizeof (struct nredir)),
1185 SHELL_ALIGN(sizeof (struct nbinary)),
1186 SHELL_ALIGN(sizeof (struct nbinary)),
1187 SHELL_ALIGN(sizeof (struct nbinary)),
1188 SHELL_ALIGN(sizeof (struct nif)),
1189 SHELL_ALIGN(sizeof (struct nbinary)),
1190 SHELL_ALIGN(sizeof (struct nbinary)),
1191 SHELL_ALIGN(sizeof (struct nfor)),
1192 SHELL_ALIGN(sizeof (struct ncase)),
1193 SHELL_ALIGN(sizeof (struct nclist)),
1194 SHELL_ALIGN(sizeof (struct narg)),
1195 SHELL_ALIGN(sizeof (struct narg)),
1196 SHELL_ALIGN(sizeof (struct nfile)),
1197 SHELL_ALIGN(sizeof (struct nfile)),
1198 SHELL_ALIGN(sizeof (struct nfile)),
1199 SHELL_ALIGN(sizeof (struct nfile)),
1200 SHELL_ALIGN(sizeof (struct nfile)),
1201 SHELL_ALIGN(sizeof (struct ndup)),
1202 SHELL_ALIGN(sizeof (struct ndup)),
1203 SHELL_ALIGN(sizeof (struct nhere)),
1204 SHELL_ALIGN(sizeof (struct nhere)),
1205 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001206};
1207
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001208
Eric Andersenc470f442003-07-28 09:56:35 +00001209static void calcsize(union node *);
1210static void sizenodelist(struct nodelist *);
1211static union node *copynode(union node *);
1212static struct nodelist *copynodelist(struct nodelist *);
1213static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001214
1215
Eric Andersen2870d962001-07-02 17:27:21 +00001216
Glenn L McGrath76620622004-01-13 10:19:37 +00001217static void evalstring(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001218union node; /* BLETCH for ansi C */
1219static void evaltree(union node *, int);
1220static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001221
Eric Andersenc470f442003-07-28 09:56:35 +00001222/* in_function returns nonzero if we are currently evaluating a function */
1223#define in_function() funcnest
1224static int evalskip; /* set if we are skipping commands */
1225static int skipcount; /* number of levels to skip */
1226static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001227
1228/* reasons for skipping commands (see comment on breakcmd routine) */
1229#define SKIPBREAK 1
1230#define SKIPCONT 2
1231#define SKIPFUNC 3
1232#define SKIPFILE 4
1233
Eric Andersenc470f442003-07-28 09:56:35 +00001234/*
1235 * This file was generated by the mkbuiltins program.
1236 */
Eric Andersen2870d962001-07-02 17:27:21 +00001237
Eric Andersenc470f442003-07-28 09:56:35 +00001238#ifdef JOBS
1239static int bgcmd(int, char **);
1240#endif
1241static int breakcmd(int, char **);
1242static int cdcmd(int, char **);
1243#ifdef CONFIG_ASH_CMDCMD
1244static int commandcmd(int, char **);
1245#endif
1246static int dotcmd(int, char **);
1247static int evalcmd(int, char **);
1248static int execcmd(int, char **);
1249static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001250static int exportcmd(int, char **);
1251static int falsecmd(int, char **);
1252#ifdef JOBS
1253static int fgcmd(int, char **);
1254#endif
1255#ifdef CONFIG_ASH_GETOPTS
1256static int getoptscmd(int, char **);
1257#endif
1258static int hashcmd(int, char **);
1259#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1260static int helpcmd(int argc, char **argv);
1261#endif
1262#ifdef JOBS
1263static int jobscmd(int, char **);
1264#endif
Eric Andersen90898442003-08-06 11:20:52 +00001265#ifdef CONFIG_ASH_MATH_SUPPORT
1266static int letcmd(int, char **);
1267#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001268static int localcmd(int, char **);
1269static int pwdcmd(int, char **);
1270static int readcmd(int, char **);
1271static int returncmd(int, char **);
1272static int setcmd(int, char **);
1273static int shiftcmd(int, char **);
1274static int timescmd(int, char **);
1275static int trapcmd(int, char **);
1276static int truecmd(int, char **);
1277static int typecmd(int, char **);
1278static int umaskcmd(int, char **);
1279static int unsetcmd(int, char **);
1280static int waitcmd(int, char **);
1281static int ulimitcmd(int, char **);
1282#ifdef JOBS
1283static int killcmd(int, char **);
1284#endif
1285
1286/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1287
1288#ifdef CONFIG_ASH_MAIL
1289static void chkmail(void);
1290static void changemail(const char *);
1291#endif
1292
1293/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1294
1295/* values of cmdtype */
1296#define CMDUNKNOWN -1 /* no entry in table for command */
1297#define CMDNORMAL 0 /* command is an executable program */
1298#define CMDFUNCTION 1 /* command is a shell function */
1299#define CMDBUILTIN 2 /* command is a shell builtin */
1300
1301struct builtincmd {
1302 const char *name;
1303 int (*builtin)(int, char **);
1304 /* unsigned flags; */
1305};
1306
1307#ifdef CONFIG_ASH_CMDCMD
1308# ifdef JOBS
1309# ifdef CONFIG_ASH_ALIAS
1310# define COMMANDCMD (builtincmd + 7)
1311# define EXECCMD (builtincmd + 10)
1312# else
1313# define COMMANDCMD (builtincmd + 6)
1314# define EXECCMD (builtincmd + 9)
1315# endif
1316# else /* ! JOBS */
1317# ifdef CONFIG_ASH_ALIAS
1318# define COMMANDCMD (builtincmd + 6)
1319# define EXECCMD (builtincmd + 9)
1320# else
1321# define COMMANDCMD (builtincmd + 5)
1322# define EXECCMD (builtincmd + 8)
1323# endif
1324# endif /* JOBS */
1325#else /* ! CONFIG_ASH_CMDCMD */
1326# ifdef JOBS
1327# ifdef CONFIG_ASH_ALIAS
1328# define EXECCMD (builtincmd + 9)
1329# else
1330# define EXECCMD (builtincmd + 8)
1331# endif
1332# else /* ! JOBS */
1333# ifdef CONFIG_ASH_ALIAS
1334# define EXECCMD (builtincmd + 8)
1335# else
1336# define EXECCMD (builtincmd + 7)
1337# endif
1338# endif /* JOBS */
1339#endif /* CONFIG_ASH_CMDCMD */
1340
1341#define BUILTIN_NOSPEC "0"
1342#define BUILTIN_SPECIAL "1"
1343#define BUILTIN_REGULAR "2"
1344#define BUILTIN_SPEC_REG "3"
1345#define BUILTIN_ASSIGN "4"
1346#define BUILTIN_SPEC_ASSG "5"
1347#define BUILTIN_REG_ASSG "6"
1348#define BUILTIN_SPEC_REG_ASSG "7"
1349
1350#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1351#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1352
1353static const struct builtincmd builtincmd[] = {
1354 { BUILTIN_SPEC_REG ".", dotcmd },
1355 { BUILTIN_SPEC_REG ":", truecmd },
1356#ifdef CONFIG_ASH_ALIAS
1357 { BUILTIN_REG_ASSG "alias", aliascmd },
1358#endif
1359#ifdef JOBS
1360 { BUILTIN_REGULAR "bg", bgcmd },
1361#endif
1362 { BUILTIN_SPEC_REG "break", breakcmd },
1363 { BUILTIN_REGULAR "cd", cdcmd },
1364 { BUILTIN_NOSPEC "chdir", cdcmd },
1365#ifdef CONFIG_ASH_CMDCMD
1366 { BUILTIN_REGULAR "command", commandcmd },
1367#endif
1368 { BUILTIN_SPEC_REG "continue", breakcmd },
1369 { BUILTIN_SPEC_REG "eval", evalcmd },
1370 { BUILTIN_SPEC_REG "exec", execcmd },
1371 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001372 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1373 { BUILTIN_REGULAR "false", falsecmd },
1374#ifdef JOBS
1375 { BUILTIN_REGULAR "fg", fgcmd },
1376#endif
1377#ifdef CONFIG_ASH_GETOPTS
1378 { BUILTIN_REGULAR "getopts", getoptscmd },
1379#endif
1380 { BUILTIN_NOSPEC "hash", hashcmd },
1381#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1382 { BUILTIN_NOSPEC "help", helpcmd },
1383#endif
1384#ifdef JOBS
1385 { BUILTIN_REGULAR "jobs", jobscmd },
1386 { BUILTIN_REGULAR "kill", killcmd },
1387#endif
1388#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001389 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001390#endif
1391 { BUILTIN_ASSIGN "local", localcmd },
1392 { BUILTIN_NOSPEC "pwd", pwdcmd },
1393 { BUILTIN_REGULAR "read", readcmd },
1394 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1395 { BUILTIN_SPEC_REG "return", returncmd },
1396 { BUILTIN_SPEC_REG "set", setcmd },
1397 { BUILTIN_SPEC_REG "shift", shiftcmd },
1398 { BUILTIN_SPEC_REG "times", timescmd },
1399 { BUILTIN_SPEC_REG "trap", trapcmd },
1400 { BUILTIN_REGULAR "true", truecmd },
1401 { BUILTIN_NOSPEC "type", typecmd },
1402 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1403 { BUILTIN_REGULAR "umask", umaskcmd },
1404#ifdef CONFIG_ASH_ALIAS
1405 { BUILTIN_REGULAR "unalias", unaliascmd },
1406#endif
1407 { BUILTIN_SPEC_REG "unset", unsetcmd },
1408 { BUILTIN_REGULAR "wait", waitcmd },
1409};
1410
1411#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1412
1413
1414
1415struct cmdentry {
1416 int cmdtype;
1417 union param {
1418 int index;
1419 const struct builtincmd *cmd;
1420 struct funcnode *func;
1421 } u;
1422};
1423
1424
1425/* action to find_command() */
1426#define DO_ERR 0x01 /* prints errors */
1427#define DO_ABS 0x02 /* checks absolute paths */
1428#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1429#define DO_ALTPATH 0x08 /* using alternate path */
1430#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1431
1432static const char *pathopt; /* set by padvance */
1433
1434static void shellexec(char **, const char *, int)
1435 __attribute__((__noreturn__));
1436static char *padvance(const char **, const char *);
1437static void find_command(char *, struct cmdentry *, int, const char *);
1438static struct builtincmd *find_builtin(const char *);
1439static void hashcd(void);
1440static void changepath(const char *);
1441static void defun(char *, union node *);
1442static void unsetfunc(const char *);
1443
1444#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001445static int dash_arith(const char *);
1446#endif
1447
1448/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1449
1450static void reset(void);
1451
1452/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001453
1454/*
1455 * Shell variables.
1456 */
1457
1458/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001459#define VEXPORT 0x01 /* variable is exported */
1460#define VREADONLY 0x02 /* variable cannot be modified */
1461#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1462#define VTEXTFIXED 0x08 /* text is statically allocated */
1463#define VSTACK 0x10 /* text is allocated on the stack */
1464#define VUNSET 0x20 /* the variable is not set */
1465#define VNOFUNC 0x40 /* don't call the callback function */
1466#define VNOSET 0x80 /* do not set variable - just readonly test */
1467#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen2870d962001-07-02 17:27:21 +00001468
1469
1470struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001471 struct var *next; /* next entry in hash list */
1472 int flags; /* flags are defined above */
1473 const char *text; /* name=value */
1474 void (*func)(const char *);
1475 /* function to be called when */
1476 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001477};
1478
1479struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001480 struct localvar *next; /* next local variable in list */
1481 struct var *vp; /* the variable that was made local */
1482 int flags; /* saved flags */
1483 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001484};
1485
1486
Eric Andersen2870d962001-07-02 17:27:21 +00001487static struct localvar *localvars;
1488
Eric Andersenc470f442003-07-28 09:56:35 +00001489/*
1490 * Shell variables.
1491 */
1492
1493#ifdef CONFIG_ASH_GETOPTS
1494static void getoptsreset(const char *);
1495#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001496
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001497#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001498#include <locale.h>
1499static void change_lc_all(const char *value);
1500static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001501#endif
1502
Eric Andersen2870d962001-07-02 17:27:21 +00001503#define VTABSIZE 39
1504
Eric Andersen90898442003-08-06 11:20:52 +00001505static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001506#ifdef IFS_BROKEN
1507static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001508#define defifs (defifsvar + 4)
1509#else
Eric Andersenc470f442003-07-28 09:56:35 +00001510static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001511#endif
1512
Eric Andersenc470f442003-07-28 09:56:35 +00001513
1514static struct var varinit[] = {
1515#ifdef IFS_BROKEN
1516 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1517#else
1518 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1519#endif
1520
1521#ifdef CONFIG_ASH_MAIL
1522 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1523 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1524#endif
1525
1526 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1527 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1528 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1529 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1530#ifdef CONFIG_ASH_GETOPTS
1531 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1532#endif
1533#ifdef CONFIG_LOCALE_SUPPORT
1534 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
1535 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
1536#endif
1537#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1538 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
1539#endif
1540};
1541
1542#define vifs varinit[0]
1543#ifdef CONFIG_ASH_MAIL
1544#define vmail (&vifs)[1]
1545#define vmpath (&vmail)[1]
1546#else
1547#define vmpath vifs
1548#endif
1549#define vpath (&vmpath)[1]
1550#define vps1 (&vpath)[1]
1551#define vps2 (&vps1)[1]
1552#define vps4 (&vps2)[1]
1553#define voptind (&vps4)[1]
1554
1555#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001556
1557/*
1558 * The following macros access the values of the above variables.
1559 * They have to skip over the name. They return the null string
1560 * for unset variables.
1561 */
1562
1563#define ifsval() (vifs.text + 4)
1564#define ifsset() ((vifs.flags & VUNSET) == 0)
1565#define mailval() (vmail.text + 5)
1566#define mpathval() (vmpath.text + 9)
1567#define pathval() (vpath.text + 5)
1568#define ps1val() (vps1.text + 4)
1569#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001570#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001571#define optindval() (voptind.text + 7)
1572
1573#define mpathset() ((vmpath.flags & VUNSET) == 0)
1574
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001575static void setvar(const char *, const char *, int);
1576static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001577static void listsetvar(struct strlist *, int);
1578static char *lookupvar(const char *);
1579static char *bltinlookup(const char *);
1580static char **listvars(int, int, char ***);
1581#define environment() listvars(VEXPORT, VUNSET, 0)
1582static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001583static void poplocalvars(void);
1584static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001585#ifdef CONFIG_ASH_GETOPTS
1586static int setvarsafe(const char *, const char *, int);
1587#endif
1588static int varcmp(const char *, const char *);
1589static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001590
1591
Eric Andersenc470f442003-07-28 09:56:35 +00001592static inline int varequal(const char *a, const char *b) {
1593 return !varcmp(a, b);
1594}
Eric Andersen2870d962001-07-02 17:27:21 +00001595
1596
Eric Andersenc470f442003-07-28 09:56:35 +00001597static int loopnest; /* current loop nesting level */
1598
Eric Andersenc470f442003-07-28 09:56:35 +00001599/*
1600 * The parsefile structure pointed to by the global variable parsefile
1601 * contains information about the current file being read.
1602 */
1603
1604
1605struct redirtab {
1606 struct redirtab *next;
1607 int renamed[10];
1608 int nullredirs;
1609};
1610
1611static struct redirtab *redirlist;
1612static int nullredirs;
1613
1614extern char **environ;
1615
1616/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1617
1618
1619static void outstr(const char *, FILE *);
1620static void outcslow(int, FILE *);
1621static void flushall(void);
1622static void flushout(FILE *);
1623static int out1fmt(const char *, ...)
1624 __attribute__((__format__(__printf__,1,2)));
1625static int fmtstr(char *, size_t, const char *, ...)
1626 __attribute__((__format__(__printf__,3,4)));
1627static void xwrite(int, const void *, size_t);
1628
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001629static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001630
Eric Andersenc470f442003-07-28 09:56:35 +00001631
1632static void out1str(const char *p)
1633{
1634 outstr(p, stdout);
1635}
1636
1637static void out2str(const char *p)
1638{
1639 outstr(p, stderr);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001640 flushout(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001641}
1642
1643/*
1644 * Initialization code.
1645 */
1646
1647/*
1648 * This routine initializes the builtin variables.
1649 */
1650
1651static inline void
1652initvar(void)
1653{
1654 struct var *vp;
1655 struct var *end;
1656 struct var **vpp;
1657
1658 /*
1659 * PS1 depends on uid
1660 */
1661#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1662 vps1.text = "PS1=\\w \\$ ";
1663#else
1664 if (!geteuid())
1665 vps1.text = "PS1=# ";
1666#endif
1667 vp = varinit;
1668 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1669 do {
1670 vpp = hashvar(vp->text);
1671 vp->next = *vpp;
1672 *vpp = vp;
1673 } while (++vp < end);
1674}
1675
1676static inline void
1677init(void)
1678{
1679
1680 /* from input.c: */
1681 {
1682 basepf.nextc = basepf.buf = basebuf;
1683 }
1684
1685 /* from trap.c: */
1686 {
1687 signal(SIGCHLD, SIG_DFL);
1688 }
1689
1690 /* from var.c: */
1691 {
1692 char **envp;
1693 char ppid[32];
1694
1695 initvar();
1696 for (envp = environ ; *envp ; envp++) {
1697 if (strchr(*envp, '=')) {
1698 setvareq(*envp, VEXPORT|VTEXTFIXED);
1699 }
1700 }
1701
1702 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1703 setvar("PPID", ppid, 0);
1704 setpwd(0, 0);
1705 }
1706}
1707
1708/* PEOF (the end of file marker) */
1709
1710/*
1711 * The input line number. Input.c just defines this variable, and saves
1712 * and restores it when files are pushed and popped. The user of this
1713 * package must set its value.
1714 */
1715
1716static int pgetc(void);
1717static int pgetc2(void);
1718static int preadbuffer(void);
1719static void pungetc(void);
1720static void pushstring(char *, void *);
1721static void popstring(void);
1722static void setinputfile(const char *, int);
1723static void setinputfd(int, int);
1724static void setinputstring(char *);
1725static void popfile(void);
1726static void popallfiles(void);
1727static void closescript(void);
1728
1729
1730/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1731
1732
1733/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1734#define FORK_FG 0
1735#define FORK_BG 1
1736#define FORK_NOJOB 2
1737
1738/* mode flags for showjob(s) */
1739#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1740#define SHOW_PID 0x04 /* include process pid */
1741#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1742
1743
1744/*
1745 * A job structure contains information about a job. A job is either a
1746 * single process or a set of processes contained in a pipeline. In the
1747 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1748 * array of pids.
1749 */
1750
1751struct procstat {
1752 pid_t pid; /* process id */
1753 int status; /* last process status from wait() */
1754 char *cmd; /* text of command being run */
1755};
1756
1757struct job {
1758 struct procstat ps0; /* status of process */
1759 struct procstat *ps; /* status or processes when more than one */
1760#if JOBS
1761 int stopstatus; /* status of a stopped job */
1762#endif
1763 uint32_t
1764 nprocs: 16, /* number of processes */
1765 state: 8,
1766#define JOBRUNNING 0 /* at least one proc running */
1767#define JOBSTOPPED 1 /* all procs are stopped */
1768#define JOBDONE 2 /* all procs are completed */
1769#if JOBS
1770 sigint: 1, /* job was killed by SIGINT */
1771 jobctl: 1, /* job running under job control */
1772#endif
1773 waited: 1, /* true if this entry has been waited for */
1774 used: 1, /* true if this entry is in used */
1775 changed: 1; /* true if status has changed */
1776 struct job *prev_job; /* previous job */
1777};
1778
1779static pid_t backgndpid; /* pid of last background process */
1780static int job_warning; /* user was warned about stopped jobs */
1781#if JOBS
1782static int jobctl; /* true if doing job control */
1783#endif
1784
1785static struct job *makejob(union node *, int);
1786static int forkshell(struct job *, union node *, int);
1787static int waitforjob(struct job *);
1788static int stoppedjobs(void);
1789
1790#if ! JOBS
1791#define setjobctl(on) /* do nothing */
1792#else
1793static void setjobctl(int);
1794static void showjobs(FILE *, int);
1795#endif
1796
1797/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1798
1799
1800/* pid of main shell */
1801static int rootpid;
1802/* true if we aren't a child of the main shell */
1803static int rootshell;
1804
1805static void readcmdfile(char *);
1806static void cmdloop(int);
1807
1808/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1809
1810
1811struct stackmark {
1812 struct stack_block *stackp;
1813 char *stacknxt;
1814 size_t stacknleft;
1815 struct stackmark *marknext;
1816};
1817
1818/* minimum size of a block */
1819#define MINSIZE SHELL_ALIGN(504)
1820
1821struct stack_block {
1822 struct stack_block *prev;
1823 char space[MINSIZE];
1824};
1825
1826static struct stack_block stackbase;
1827static struct stack_block *stackp = &stackbase;
1828static struct stackmark *markp;
1829static char *stacknxt = stackbase.space;
1830static size_t stacknleft = MINSIZE;
1831static char *sstrend = stackbase.space + MINSIZE;
1832static int herefd = -1;
1833
1834
1835static pointer ckmalloc(size_t);
1836static pointer ckrealloc(pointer, size_t);
1837static char *savestr(const char *);
1838static pointer stalloc(size_t);
1839static void stunalloc(pointer);
1840static void setstackmark(struct stackmark *);
1841static void popstackmark(struct stackmark *);
1842static void growstackblock(void);
1843static void *growstackstr(void);
1844static char *makestrspace(size_t, char *);
1845static char *stnputs(const char *, size_t, char *);
1846static char *stputs(const char *, char *);
1847
1848
1849static inline char *_STPUTC(char c, char *p) {
1850 if (p == sstrend)
1851 p = growstackstr();
1852 *p++ = c;
1853 return p;
1854}
1855
1856#define stackblock() ((void *)stacknxt)
1857#define stackblocksize() stacknleft
1858#define STARTSTACKSTR(p) ((p) = stackblock())
1859#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1860#define CHECKSTRSPACE(n, p) \
1861 ({ \
1862 char *q = (p); \
1863 size_t l = (n); \
1864 size_t m = sstrend - q; \
1865 if (l > m) \
1866 (p) = makestrspace(l, q); \
1867 0; \
1868 })
1869#define USTPUTC(c, p) (*p++ = (c))
1870#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1871#define STUNPUTC(p) (--p)
1872#define STTOPC(p) p[-1]
1873#define STADJUST(amount, p) (p += (amount))
1874
1875#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1876#define ungrabstackstr(s, p) stunalloc((s))
1877#define stackstrend() ((void *)sstrend)
1878
1879#define ckfree(p) free((pointer)(p))
1880
1881/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1882
1883
1884#define DOLATSTRLEN 4
1885
1886static char *prefix(const char *, const char *);
1887static int number(const char *);
1888static int is_number(const char *);
1889static char *single_quote(const char *);
1890static char *sstrdup(const char *);
1891
1892#define equal(s1, s2) (strcmp(s1, s2) == 0)
1893#define scopy(s1, s2) ((void)strcpy(s2, s1))
1894
1895/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1896
1897struct shparam {
1898 int nparam; /* # of positional parameters (without $0) */
1899 unsigned char malloc; /* if parameter list dynamically allocated */
1900 char **p; /* parameter list */
1901#ifdef CONFIG_ASH_GETOPTS
1902 int optind; /* next parameter to be processed by getopts */
1903 int optoff; /* used by getopts */
1904#endif
1905};
1906
1907
1908#define eflag optlist[0]
1909#define fflag optlist[1]
1910#define Iflag optlist[2]
1911#define iflag optlist[3]
1912#define mflag optlist[4]
1913#define nflag optlist[5]
1914#define sflag optlist[6]
1915#define xflag optlist[7]
1916#define vflag optlist[8]
1917#define Cflag optlist[9]
1918#define aflag optlist[10]
1919#define bflag optlist[11]
1920#define uflag optlist[12]
1921#define qflag optlist[13]
1922
1923#ifdef DEBUG
1924#define nolog optlist[14]
1925#define debug optlist[15]
1926#define NOPTS 16
1927#else
1928#define NOPTS 14
1929#endif
1930
1931/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1932
1933
1934static const char *const optletters_optnames[NOPTS] = {
1935 "e" "errexit",
1936 "f" "noglob",
1937 "I" "ignoreeof",
1938 "i" "interactive",
1939 "m" "monitor",
1940 "n" "noexec",
1941 "s" "stdin",
1942 "x" "xtrace",
1943 "v" "verbose",
1944 "C" "noclobber",
1945 "a" "allexport",
1946 "b" "notify",
1947 "u" "nounset",
1948 "q" "quietprofile",
1949#ifdef DEBUG
1950 "\0" "nolog",
1951 "\0" "debug",
1952#endif
1953};
1954
1955#define optletters(n) optletters_optnames[(n)][0]
1956#define optnames(n) (&optletters_optnames[(n)][1])
1957
1958
1959static char optlist[NOPTS];
1960
1961
1962static char *arg0; /* value of $0 */
1963static struct shparam shellparam; /* $@ current positional parameters */
1964static char **argptr; /* argument list for builtin commands */
1965static char *optionarg; /* set by nextopt (like getopt) */
1966static char *optptr; /* used by nextopt */
1967
1968static char *minusc; /* argument to -c option */
1969
1970
1971static void procargs(int, char **);
1972static void optschanged(void);
1973static void setparam(char **);
1974static void freeparam(volatile struct shparam *);
1975static int shiftcmd(int, char **);
1976static int setcmd(int, char **);
1977static int nextopt(const char *);
1978
1979/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1980
1981/* flags passed to redirect */
1982#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001983#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00001984
1985union node;
1986static void redirect(union node *, int);
1987static void popredir(int);
1988static void clearredir(int);
1989static int copyfd(int, int);
1990static int redirectsafe(union node *, int);
1991
1992/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
1993
1994
1995#ifdef DEBUG
1996static void showtree(union node *);
1997static void trace(const char *, ...);
1998static void tracev(const char *, va_list);
1999static void trargs(char **);
2000static void trputc(int);
2001static void trputs(const char *);
2002static void opentrace(void);
2003#endif
2004
2005/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2006
2007
2008/* trap handler commands */
2009static char *trap[NSIG];
2010/* current value of signal */
2011static char sigmode[NSIG - 1];
2012/* indicates specified signal received */
2013static char gotsig[NSIG - 1];
2014
2015static void clear_traps(void);
2016static void setsignal(int);
2017static void ignoresig(int);
2018static void onsig(int);
2019static void dotrap(void);
2020static void setinteractive(int);
2021static void exitshell(void) __attribute__((__noreturn__));
2022static int decode_signal(const char *, int);
2023
2024/*
2025 * This routine is called when an error or an interrupt occurs in an
2026 * interactive shell and control is returned to the main command loop.
2027 */
2028
2029static void
2030reset(void)
2031{
2032 /* from eval.c: */
2033 {
2034 evalskip = 0;
2035 loopnest = 0;
2036 funcnest = 0;
2037 }
2038
2039 /* from input.c: */
2040 {
2041 parselleft = parsenleft = 0; /* clear input buffer */
2042 popallfiles();
2043 }
2044
2045 /* from parser.c: */
2046 {
2047 tokpushback = 0;
2048 checkkwd = 0;
2049 }
2050
2051 /* from redir.c: */
2052 {
2053 clearredir(0);
2054 }
2055
2056}
2057
2058#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002059static struct alias *atab[ATABSIZE];
2060
Eric Andersenc470f442003-07-28 09:56:35 +00002061static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002062static struct alias *freealias(struct alias *);
2063static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002064
Eric Andersenc470f442003-07-28 09:56:35 +00002065static void
2066setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002067{
2068 struct alias *ap, **app;
2069
2070 app = __lookupalias(name);
2071 ap = *app;
2072 INTOFF;
2073 if (ap) {
2074 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002075 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002076 }
Eric Andersenc470f442003-07-28 09:56:35 +00002077 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002078 ap->flag &= ~ALIASDEAD;
2079 } else {
2080 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002081 ap = ckmalloc(sizeof (struct alias));
2082 ap->name = savestr(name);
2083 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002084 ap->flag = 0;
2085 ap->next = 0;
2086 *app = ap;
2087 }
2088 INTON;
2089}
2090
Eric Andersenc470f442003-07-28 09:56:35 +00002091static int
2092unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002093{
Eric Andersencb57d552001-06-28 07:25:16 +00002094 struct alias **app;
2095
2096 app = __lookupalias(name);
2097
2098 if (*app) {
2099 INTOFF;
2100 *app = freealias(*app);
2101 INTON;
2102 return (0);
2103 }
2104
2105 return (1);
2106}
2107
Eric Andersenc470f442003-07-28 09:56:35 +00002108static void
2109rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002110{
Eric Andersencb57d552001-06-28 07:25:16 +00002111 struct alias *ap, **app;
2112 int i;
2113
2114 INTOFF;
2115 for (i = 0; i < ATABSIZE; i++) {
2116 app = &atab[i];
2117 for (ap = *app; ap; ap = *app) {
2118 *app = freealias(*app);
2119 if (ap == *app) {
2120 app = &ap->next;
2121 }
2122 }
2123 }
2124 INTON;
2125}
2126
Eric Andersenc470f442003-07-28 09:56:35 +00002127static struct alias *
2128lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002129{
Eric Andersenc470f442003-07-28 09:56:35 +00002130 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002131
Eric Andersenc470f442003-07-28 09:56:35 +00002132 if (check && ap && (ap->flag & ALIASINUSE))
2133 return (NULL);
2134 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002135}
2136
Eric Andersencb57d552001-06-28 07:25:16 +00002137/*
2138 * TODO - sort output
2139 */
Eric Andersenc470f442003-07-28 09:56:35 +00002140static int
2141aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002142{
2143 char *n, *v;
2144 int ret = 0;
2145 struct alias *ap;
2146
2147 if (argc == 1) {
2148 int i;
2149
2150 for (i = 0; i < ATABSIZE; i++)
2151 for (ap = atab[i]; ap; ap = ap->next) {
2152 printalias(ap);
2153 }
2154 return (0);
2155 }
2156 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002157 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002158 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002159 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002160 ret = 1;
2161 } else
2162 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002163 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002164 *v++ = '\0';
2165 setalias(n, v);
2166 }
2167 }
2168
2169 return (ret);
2170}
2171
Eric Andersenc470f442003-07-28 09:56:35 +00002172static int
2173unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002174{
2175 int i;
2176
2177 while ((i = nextopt("a")) != '\0') {
2178 if (i == 'a') {
2179 rmaliases();
2180 return (0);
2181 }
2182 }
2183 for (i = 0; *argptr; argptr++) {
2184 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002185 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002186 i = 1;
2187 }
2188 }
2189
2190 return (i);
2191}
2192
Eric Andersenc470f442003-07-28 09:56:35 +00002193static struct alias *
2194freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002195 struct alias *next;
2196
2197 if (ap->flag & ALIASINUSE) {
2198 ap->flag |= ALIASDEAD;
2199 return ap;
2200 }
2201
2202 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002203 ckfree(ap->name);
2204 ckfree(ap->val);
2205 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002206 return next;
2207}
2208
Eric Andersenc470f442003-07-28 09:56:35 +00002209static void
2210printalias(const struct alias *ap) {
2211 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2212}
Eric Andersencb57d552001-06-28 07:25:16 +00002213
Eric Andersenc470f442003-07-28 09:56:35 +00002214static struct alias **
2215__lookupalias(const char *name) {
2216 unsigned int hashval;
2217 struct alias **app;
2218 const char *p;
2219 unsigned int ch;
2220
2221 p = name;
2222
2223 ch = (unsigned char)*p;
2224 hashval = ch << 4;
2225 while (ch) {
2226 hashval += ch;
2227 ch = (unsigned char)*++p;
2228 }
2229 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002230
2231 for (; *app; app = &(*app)->next) {
2232 if (equal(name, (*app)->name)) {
2233 break;
2234 }
2235 }
2236
2237 return app;
2238}
Eric Andersenc470f442003-07-28 09:56:35 +00002239#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002240
Eric Andersencb57d552001-06-28 07:25:16 +00002241
Eric Andersenc470f442003-07-28 09:56:35 +00002242/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00002243
Eric Andersencb57d552001-06-28 07:25:16 +00002244/*
Eric Andersenc470f442003-07-28 09:56:35 +00002245 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002246 */
2247
Eric Andersenc470f442003-07-28 09:56:35 +00002248#define CD_PHYSICAL 1
2249#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002250
Eric Andersenc470f442003-07-28 09:56:35 +00002251static int docd(const char *, int);
2252static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002253
Eric Andersenc470f442003-07-28 09:56:35 +00002254static char *curdir = nullstr; /* current working directory */
2255static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002256
Eric Andersenc470f442003-07-28 09:56:35 +00002257static int
2258cdopt(void)
2259{
2260 int flags = 0;
2261 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002262
Eric Andersenc470f442003-07-28 09:56:35 +00002263 j = 'L';
2264 while ((i = nextopt("LP"))) {
2265 if (i != j) {
2266 flags ^= CD_PHYSICAL;
2267 j = i;
2268 }
2269 }
Eric Andersencb57d552001-06-28 07:25:16 +00002270
Eric Andersenc470f442003-07-28 09:56:35 +00002271 return flags;
2272}
Eric Andersen2870d962001-07-02 17:27:21 +00002273
Eric Andersenc470f442003-07-28 09:56:35 +00002274static int
2275cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002276{
2277 const char *dest;
2278 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002279 const char *p;
2280 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002281 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002282 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002283
Eric Andersenc470f442003-07-28 09:56:35 +00002284 flags = cdopt();
2285 dest = *argptr;
2286 if (!dest)
2287 dest = bltinlookup(homestr);
2288 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002289 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002290 flags |= CD_PRINT;
2291 goto step7;
Eric Andersencb57d552001-06-28 07:25:16 +00002292 }
Eric Andersenc470f442003-07-28 09:56:35 +00002293 if (!dest)
2294 dest = nullstr;
2295 if (*dest == '/')
2296 goto step7;
2297 if (*dest == '.') {
2298 c = dest[1];
2299dotdot:
2300 switch (c) {
2301 case '\0':
2302 case '/':
2303 goto step6;
2304 case '.':
2305 c = dest[2];
2306 if (c != '.')
2307 goto dotdot;
2308 }
2309 }
2310 if (!*dest)
2311 dest = ".";
2312 if (!(path = bltinlookup("CDPATH"))) {
2313step6:
2314step7:
2315 p = dest;
2316 goto docd;
2317 }
2318 do {
2319 c = *path;
2320 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002321 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002322 if (c && c != ':')
2323 flags |= CD_PRINT;
2324docd:
2325 if (!docd(p, flags))
2326 goto out;
2327 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002328 }
Eric Andersenc470f442003-07-28 09:56:35 +00002329 } while (path);
Eric Andersencb57d552001-06-28 07:25:16 +00002330 error("can't cd to %s", dest);
2331 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002332out:
2333 if (flags & CD_PRINT)
2334 out1fmt(snlfmt, curdir);
2335 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002336}
2337
2338
2339/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002340 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002341 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002342 */
2343
Eric Andersenc470f442003-07-28 09:56:35 +00002344static inline const char *
2345updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002346{
Eric Andersenc470f442003-07-28 09:56:35 +00002347 char *new;
2348 char *p;
2349 char *cdcomppath;
2350 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002351
Eric Andersenc470f442003-07-28 09:56:35 +00002352 cdcomppath = sstrdup(dir);
2353 STARTSTACKSTR(new);
2354 if (*dir != '/') {
2355 if (curdir == nullstr)
2356 return 0;
2357 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002358 }
Eric Andersenc470f442003-07-28 09:56:35 +00002359 new = makestrspace(strlen(dir) + 2, new);
2360 lim = stackblock() + 1;
2361 if (*dir != '/') {
2362 if (new[-1] != '/')
2363 USTPUTC('/', new);
2364 if (new > lim && *lim == '/')
2365 lim++;
2366 } else {
2367 USTPUTC('/', new);
2368 cdcomppath++;
2369 if (dir[1] == '/' && dir[2] != '/') {
2370 USTPUTC('/', new);
2371 cdcomppath++;
2372 lim++;
2373 }
2374 }
2375 p = strtok(cdcomppath, "/");
2376 while (p) {
2377 switch(*p) {
2378 case '.':
2379 if (p[1] == '.' && p[2] == '\0') {
2380 while (new > lim) {
2381 STUNPUTC(new);
2382 if (new[-1] == '/')
2383 break;
2384 }
2385 break;
2386 } else if (p[1] == '\0')
2387 break;
2388 /* fall through */
2389 default:
2390 new = stputs(p, new);
2391 USTPUTC('/', new);
2392 }
2393 p = strtok(0, "/");
2394 }
2395 if (new > lim)
2396 STUNPUTC(new);
2397 *new = 0;
2398 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002399}
2400
2401/*
Eric Andersenc470f442003-07-28 09:56:35 +00002402 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2403 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002404 */
2405
Eric Andersenc470f442003-07-28 09:56:35 +00002406static int
2407docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002408{
Eric Andersenc470f442003-07-28 09:56:35 +00002409 const char *dir = 0;
2410 int err;
2411
2412 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2413
Eric Andersencb57d552001-06-28 07:25:16 +00002414 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002415 if (!(flags & CD_PHYSICAL)) {
2416 dir = updatepwd(dest);
2417 if (dir)
2418 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002419 }
Eric Andersenc470f442003-07-28 09:56:35 +00002420 err = chdir(dest);
2421 if (err)
2422 goto out;
2423 setpwd(dir, 1);
2424 hashcd();
2425out:
Eric Andersencb57d552001-06-28 07:25:16 +00002426 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002427 return err;
2428}
2429
2430/*
2431 * Find out what the current directory is. If we already know the current
2432 * directory, this routine returns immediately.
2433 */
2434static inline char *
2435getpwd(void)
2436{
2437 char *dir = getcwd(0, 0);
2438 return dir ? dir : nullstr;
2439}
2440
2441static int
2442pwdcmd(int argc, char **argv)
2443{
2444 int flags;
2445 const char *dir = curdir;
2446
2447 flags = cdopt();
2448 if (flags) {
2449 if (physdir == nullstr)
2450 setpwd(dir, 0);
2451 dir = physdir;
2452 }
2453 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002454 return 0;
2455}
2456
Eric Andersenc470f442003-07-28 09:56:35 +00002457static void
2458setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002459{
Eric Andersenc470f442003-07-28 09:56:35 +00002460 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002461
Eric Andersenc470f442003-07-28 09:56:35 +00002462 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002463
Eric Andersencb57d552001-06-28 07:25:16 +00002464 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002465 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002466 }
2467 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002468 if (physdir != nullstr) {
2469 if (physdir != oldcur)
2470 free(physdir);
2471 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002472 }
Eric Andersenc470f442003-07-28 09:56:35 +00002473 if (oldcur == val || !val) {
2474 char *s = getpwd();
2475 physdir = s;
2476 if (!val)
2477 dir = s;
2478 } else
2479 dir = savestr(val);
2480 if (oldcur != dir && oldcur != nullstr) {
2481 free(oldcur);
2482 }
2483 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002484 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002485 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002486}
2487
Eric Andersenc470f442003-07-28 09:56:35 +00002488/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2489
Eric Andersencb57d552001-06-28 07:25:16 +00002490/*
2491 * Errors and exceptions.
2492 */
2493
2494/*
2495 * Code to handle exceptions in C.
2496 */
2497
Eric Andersen2870d962001-07-02 17:27:21 +00002498
Eric Andersencb57d552001-06-28 07:25:16 +00002499
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002500static void exverror(int, const char *, va_list)
Eric Andersenc470f442003-07-28 09:56:35 +00002501 __attribute__((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00002502
2503/*
2504 * Called to raise an exception. Since C doesn't include exceptions, we
2505 * just do a longjmp to the exception handler. The type of exception is
2506 * stored in the global variable "exception".
2507 */
2508
Eric Andersenc470f442003-07-28 09:56:35 +00002509static void
2510exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002511{
2512#ifdef DEBUG
2513 if (handler == NULL)
2514 abort();
2515#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002516 INTOFF;
2517
Eric Andersencb57d552001-06-28 07:25:16 +00002518 exception = e;
2519 longjmp(handler->loc, 1);
2520}
2521
2522
2523/*
2524 * Called from trap.c when a SIGINT is received. (If the user specifies
2525 * that SIGINT is to be trapped or ignored using the trap builtin, then
2526 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002527 * are held using the INTOFF macro. (The test for iflag is just
2528 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002529 */
2530
Eric Andersenc470f442003-07-28 09:56:35 +00002531static void
2532onint(void) {
2533 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002534
Eric Andersencb57d552001-06-28 07:25:16 +00002535 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002536 sigsetmask(0);
2537 i = EXSIG;
2538 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2539 if (!(rootshell && iflag)) {
2540 signal(SIGINT, SIG_DFL);
2541 raise(SIGINT);
2542 }
2543 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002544 }
Eric Andersenc470f442003-07-28 09:56:35 +00002545 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002546 /* NOTREACHED */
2547}
2548
Eric Andersenc470f442003-07-28 09:56:35 +00002549static void
2550exvwarning(const char *msg, va_list ap)
2551{
2552 FILE *errs;
2553 const char *name;
2554 const char *fmt;
Eric Andersencb57d552001-06-28 07:25:16 +00002555
Eric Andersenc470f442003-07-28 09:56:35 +00002556 errs = stderr;
2557 name = arg0;
2558 fmt = "%s: ";
2559 if (commandname) {
2560 name = commandname;
2561 fmt = "%s: %d: ";
2562 }
2563 fprintf(errs, fmt, name, startlinno);
2564 vfprintf(errs, msg, ap);
2565 outcslow('\n', errs);
2566}
Eric Andersen2870d962001-07-02 17:27:21 +00002567
Eric Andersencb57d552001-06-28 07:25:16 +00002568/*
Eric Andersenc470f442003-07-28 09:56:35 +00002569 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002570 * is not NULL then error prints an error message using printf style
2571 * formatting. It then raises the error exception.
2572 */
Eric Andersenc470f442003-07-28 09:56:35 +00002573static void
2574exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002575{
Eric Andersencb57d552001-06-28 07:25:16 +00002576#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002577 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002578 TRACE(("exverror(%d, \"", cond));
2579 TRACEV((msg, ap));
2580 TRACE(("\") pid=%d\n", getpid()));
2581 } else
2582 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2583 if (msg)
2584#endif
2585 exvwarning(msg, ap);
2586
2587 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002588 exraise(cond);
2589 /* NOTREACHED */
2590}
2591
2592
Eric Andersenc470f442003-07-28 09:56:35 +00002593static void
2594error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002595{
Eric Andersencb57d552001-06-28 07:25:16 +00002596 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002597
Eric Andersencb57d552001-06-28 07:25:16 +00002598 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002599 exverror(EXERROR, msg, ap);
2600 /* NOTREACHED */
2601 va_end(ap);
2602}
2603
2604
Eric Andersenc470f442003-07-28 09:56:35 +00002605static void
2606exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002607{
Eric Andersencb57d552001-06-28 07:25:16 +00002608 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002609
Eric Andersencb57d552001-06-28 07:25:16 +00002610 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002611 exverror(cond, msg, ap);
2612 /* NOTREACHED */
2613 va_end(ap);
2614}
2615
Eric Andersencb57d552001-06-28 07:25:16 +00002616/*
Eric Andersenc470f442003-07-28 09:56:35 +00002617 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002618 */
2619
Eric Andersenc470f442003-07-28 09:56:35 +00002620static void
2621sh_warnx(const char *fmt, ...)
2622{
2623 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002624
Eric Andersenc470f442003-07-28 09:56:35 +00002625 va_start(ap, fmt);
2626 exvwarning(fmt, ap);
2627 va_end(ap);
2628}
Eric Andersen2870d962001-07-02 17:27:21 +00002629
Eric Andersencb57d552001-06-28 07:25:16 +00002630
2631/*
2632 * Return a string describing an error. The returned string may be a
2633 * pointer to a static buffer that will be overwritten on the next call.
2634 * Action describes the operation that got the error.
2635 */
2636
Eric Andersenc470f442003-07-28 09:56:35 +00002637static const char *
2638errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002639{
Eric Andersenc470f442003-07-28 09:56:35 +00002640 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002641
Eric Andersenc470f442003-07-28 09:56:35 +00002642 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002643 }
Eric Andersenc470f442003-07-28 09:56:35 +00002644 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002645}
2646
2647
Eric Andersenc470f442003-07-28 09:56:35 +00002648/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2649
2650/*
2651 * Evaluate a command.
2652 */
Eric Andersencb57d552001-06-28 07:25:16 +00002653
2654/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002655#define EV_EXIT 01 /* exit after evaluating tree */
2656#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2657#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002658
2659
Eric Andersenc470f442003-07-28 09:56:35 +00002660static void evalloop(union node *, int);
2661static void evalfor(union node *, int);
2662static void evalcase(union node *, int);
2663static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002664static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002665static void evalpipe(union node *, int);
2666static void evalcommand(union node *, int);
2667static int evalbltin(const struct builtincmd *, int, char **);
2668static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002669static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002670static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002671
Eric Andersenc470f442003-07-28 09:56:35 +00002672
2673static const struct builtincmd bltin = {
2674 "\0\0", bltincmd
2675};
2676
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002677
Eric Andersencb57d552001-06-28 07:25:16 +00002678/*
2679 * Called to reset things after an exception.
2680 */
2681
Eric Andersencb57d552001-06-28 07:25:16 +00002682/*
2683 * The eval commmand.
2684 */
2685
Eric Andersenc470f442003-07-28 09:56:35 +00002686static int
2687evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002688{
Eric Andersen2870d962001-07-02 17:27:21 +00002689 char *p;
2690 char *concat;
2691 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002692
Eric Andersen2870d962001-07-02 17:27:21 +00002693 if (argc > 1) {
2694 p = argv[1];
2695 if (argc > 2) {
2696 STARTSTACKSTR(concat);
2697 ap = argv + 2;
2698 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002699 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002700 if ((p = *ap++) == NULL)
2701 break;
2702 STPUTC(' ', concat);
2703 }
2704 STPUTC('\0', concat);
2705 p = grabstackstr(concat);
2706 }
Glenn L McGrath76620622004-01-13 10:19:37 +00002707 evalstring(p);
Eric Andersen2870d962001-07-02 17:27:21 +00002708 }
2709 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002710}
2711
Eric Andersenc470f442003-07-28 09:56:35 +00002712
Eric Andersencb57d552001-06-28 07:25:16 +00002713/*
2714 * Execute a command or commands contained in a string.
2715 */
2716
Eric Andersenc470f442003-07-28 09:56:35 +00002717static void
Glenn L McGrath76620622004-01-13 10:19:37 +00002718evalstring(char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00002719{
Eric Andersencb57d552001-06-28 07:25:16 +00002720 union node *n;
2721 struct stackmark smark;
2722
2723 setstackmark(&smark);
2724 setinputstring(s);
Eric Andersenc470f442003-07-28 09:56:35 +00002725
Eric Andersencb57d552001-06-28 07:25:16 +00002726 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002727 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002728 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002729 if (evalskip)
2730 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002731 }
2732 popfile();
2733 popstackmark(&smark);
2734}
2735
Eric Andersenc470f442003-07-28 09:56:35 +00002736
Eric Andersen62483552001-07-10 06:09:16 +00002737
2738/*
Eric Andersenc470f442003-07-28 09:56:35 +00002739 * Evaluate a parse tree. The value is left in the global variable
2740 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002741 */
2742
Eric Andersenc470f442003-07-28 09:56:35 +00002743static void
2744evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002745{
Eric Andersenc470f442003-07-28 09:56:35 +00002746 int checkexit = 0;
2747 void (*evalfn)(union node *, int);
2748 unsigned isor;
2749 int status;
2750 if (n == NULL) {
2751 TRACE(("evaltree(NULL) called\n"));
2752 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002753 }
Eric Andersenc470f442003-07-28 09:56:35 +00002754 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2755 getpid(), n, n->type, flags));
2756 switch (n->type) {
2757 default:
2758#ifdef DEBUG
2759 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002760 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002761 break;
2762#endif
2763 case NNOT:
2764 evaltree(n->nnot.com, EV_TESTED);
2765 status = !exitstatus;
2766 goto setstatus;
2767 case NREDIR:
2768 expredir(n->nredir.redirect);
2769 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2770 if (!status) {
2771 evaltree(n->nredir.n, flags & EV_TESTED);
2772 status = exitstatus;
2773 }
2774 popredir(0);
2775 goto setstatus;
2776 case NCMD:
2777 evalfn = evalcommand;
2778checkexit:
2779 if (eflag && !(flags & EV_TESTED))
2780 checkexit = ~0;
2781 goto calleval;
2782 case NFOR:
2783 evalfn = evalfor;
2784 goto calleval;
2785 case NWHILE:
2786 case NUNTIL:
2787 evalfn = evalloop;
2788 goto calleval;
2789 case NSUBSHELL:
2790 case NBACKGND:
2791 evalfn = evalsubshell;
2792 goto calleval;
2793 case NPIPE:
2794 evalfn = evalpipe;
2795 goto checkexit;
2796 case NCASE:
2797 evalfn = evalcase;
2798 goto calleval;
2799 case NAND:
2800 case NOR:
2801 case NSEMI:
2802#if NAND + 1 != NOR
2803#error NAND + 1 != NOR
2804#endif
2805#if NOR + 1 != NSEMI
2806#error NOR + 1 != NSEMI
2807#endif
2808 isor = n->type - NAND;
2809 evaltree(
2810 n->nbinary.ch1,
2811 (flags | ((isor >> 1) - 1)) & EV_TESTED
2812 );
2813 if (!exitstatus == isor)
2814 break;
2815 if (!evalskip) {
2816 n = n->nbinary.ch2;
2817evaln:
2818 evalfn = evaltree;
2819calleval:
2820 evalfn(n, flags);
2821 break;
2822 }
2823 break;
2824 case NIF:
2825 evaltree(n->nif.test, EV_TESTED);
2826 if (evalskip)
2827 break;
2828 if (exitstatus == 0) {
2829 n = n->nif.ifpart;
2830 goto evaln;
2831 } else if (n->nif.elsepart) {
2832 n = n->nif.elsepart;
2833 goto evaln;
2834 }
2835 goto success;
2836 case NDEFUN:
2837 defun(n->narg.text, n->narg.next);
2838success:
2839 status = 0;
2840setstatus:
2841 exitstatus = status;
2842 break;
2843 }
2844out:
2845 if (pendingsigs)
2846 dotrap();
2847 if (flags & EV_EXIT || checkexit & exitstatus)
2848 exraise(EXEXIT);
Eric Andersen62483552001-07-10 06:09:16 +00002849}
2850
Eric Andersenc470f442003-07-28 09:56:35 +00002851
2852#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2853static
2854#endif
2855void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2856
2857
2858static void
2859evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002860{
2861 int status;
2862
2863 loopnest++;
2864 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002865 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002866 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002867 int i;
2868
Eric Andersencb57d552001-06-28 07:25:16 +00002869 evaltree(n->nbinary.ch1, EV_TESTED);
2870 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002871skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002872 evalskip = 0;
2873 continue;
2874 }
2875 if (evalskip == SKIPBREAK && --skipcount <= 0)
2876 evalskip = 0;
2877 break;
2878 }
Eric Andersenc470f442003-07-28 09:56:35 +00002879 i = exitstatus;
2880 if (n->type != NWHILE)
2881 i = !i;
2882 if (i != 0)
2883 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002884 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002885 status = exitstatus;
2886 if (evalskip)
2887 goto skipping;
2888 }
2889 loopnest--;
2890 exitstatus = status;
2891}
2892
Eric Andersenc470f442003-07-28 09:56:35 +00002893
2894
2895static void
2896evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002897{
2898 struct arglist arglist;
2899 union node *argp;
2900 struct strlist *sp;
2901 struct stackmark smark;
2902
2903 setstackmark(&smark);
2904 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002905 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002906 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002907 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002908 if (evalskip)
2909 goto out;
2910 }
2911 *arglist.lastp = NULL;
2912
2913 exitstatus = 0;
2914 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002915 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002916 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002917 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002918 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002919 if (evalskip) {
2920 if (evalskip == SKIPCONT && --skipcount <= 0) {
2921 evalskip = 0;
2922 continue;
2923 }
2924 if (evalskip == SKIPBREAK && --skipcount <= 0)
2925 evalskip = 0;
2926 break;
2927 }
2928 }
2929 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002930out:
Eric Andersencb57d552001-06-28 07:25:16 +00002931 popstackmark(&smark);
2932}
2933
Eric Andersenc470f442003-07-28 09:56:35 +00002934
2935
2936static void
2937evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002938{
2939 union node *cp;
2940 union node *patp;
2941 struct arglist arglist;
2942 struct stackmark smark;
2943
2944 setstackmark(&smark);
2945 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002946 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002947 exitstatus = 0;
2948 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2949 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002950 if (casematch(patp, arglist.list->text)) {
2951 if (evalskip == 0) {
2952 evaltree(cp->nclist.body, flags);
2953 }
2954 goto out;
2955 }
2956 }
2957 }
Eric Andersenc470f442003-07-28 09:56:35 +00002958out:
Eric Andersencb57d552001-06-28 07:25:16 +00002959 popstackmark(&smark);
2960}
2961
Eric Andersenc470f442003-07-28 09:56:35 +00002962
2963
2964/*
2965 * Kick off a subshell to evaluate a tree.
2966 */
2967
2968static void
2969evalsubshell(union node *n, int flags)
2970{
2971 struct job *jp;
2972 int backgnd = (n->type == NBACKGND);
2973 int status;
2974
2975 expredir(n->nredir.redirect);
2976 if (!backgnd && flags & EV_EXIT && !trap[0])
2977 goto nofork;
2978 INTOFF;
2979 jp = makejob(n, 1);
2980 if (forkshell(jp, n, backgnd) == 0) {
2981 INTON;
2982 flags |= EV_EXIT;
2983 if (backgnd)
2984 flags &=~ EV_TESTED;
2985nofork:
2986 redirect(n->nredir.redirect, 0);
2987 evaltreenr(n->nredir.n, flags);
2988 /* never returns */
2989 }
2990 status = 0;
2991 if (! backgnd)
2992 status = waitforjob(jp);
2993 exitstatus = status;
2994 INTON;
2995}
2996
2997
2998
2999/*
3000 * Compute the names of the files in a redirection list.
3001 */
3002
3003static void
3004expredir(union node *n)
3005{
3006 union node *redir;
3007
3008 for (redir = n ; redir ; redir = redir->nfile.next) {
3009 struct arglist fn;
3010 fn.lastp = &fn.list;
3011 switch (redir->type) {
3012 case NFROMTO:
3013 case NFROM:
3014 case NTO:
3015 case NCLOBBER:
3016 case NAPPEND:
3017 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3018 redir->nfile.expfname = fn.list->text;
3019 break;
3020 case NFROMFD:
3021 case NTOFD:
3022 if (redir->ndup.vname) {
3023 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3024 fixredir(redir, fn.list->text, 1);
3025 }
3026 break;
3027 }
3028 }
3029}
3030
3031
3032
Eric Andersencb57d552001-06-28 07:25:16 +00003033/*
Eric Andersencb57d552001-06-28 07:25:16 +00003034 * Evaluate a pipeline. All the processes in the pipeline are children
3035 * of the process creating the pipeline. (This differs from some versions
3036 * of the shell, which make the last process in a pipeline the parent
3037 * of all the rest.)
3038 */
3039
Eric Andersenc470f442003-07-28 09:56:35 +00003040static void
3041evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003042{
3043 struct job *jp;
3044 struct nodelist *lp;
3045 int pipelen;
3046 int prevfd;
3047 int pip[2];
3048
Eric Andersenc470f442003-07-28 09:56:35 +00003049 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003050 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003051 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003052 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003053 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003054 INTOFF;
3055 jp = makejob(n, pipelen);
3056 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003057 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003058 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003059 pip[1] = -1;
3060 if (lp->next) {
3061 if (pipe(pip) < 0) {
3062 close(prevfd);
3063 error("Pipe call failed");
3064 }
3065 }
3066 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3067 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003068 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003069 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003070 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003071 if (prevfd > 0) {
3072 dup2(prevfd, 0);
3073 close(prevfd);
3074 }
3075 if (pip[1] > 1) {
3076 dup2(pip[1], 1);
3077 close(pip[1]);
3078 }
Eric Andersenc470f442003-07-28 09:56:35 +00003079 evaltreenr(lp->n, flags);
3080 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003081 }
3082 if (prevfd >= 0)
3083 close(prevfd);
3084 prevfd = pip[0];
3085 close(pip[1]);
3086 }
Eric Andersencb57d552001-06-28 07:25:16 +00003087 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003088 exitstatus = waitforjob(jp);
3089 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003090 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003091 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003092}
3093
Eric Andersen62483552001-07-10 06:09:16 +00003094
3095
3096/*
3097 * Execute a command inside back quotes. If it's a builtin command, we
3098 * want to save its output in a block obtained from malloc. Otherwise
3099 * we fork off a subprocess and get the output of the command via a pipe.
3100 * Should be called with interrupts off.
3101 */
3102
Eric Andersenc470f442003-07-28 09:56:35 +00003103static void
3104evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003105{
Eric Andersenc470f442003-07-28 09:56:35 +00003106 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003107
Eric Andersen62483552001-07-10 06:09:16 +00003108 result->fd = -1;
3109 result->buf = NULL;
3110 result->nleft = 0;
3111 result->jp = NULL;
3112 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003113 goto out;
3114 }
Eric Andersenc470f442003-07-28 09:56:35 +00003115
3116 saveherefd = herefd;
3117 herefd = -1;
3118
3119 {
3120 int pip[2];
3121 struct job *jp;
3122
3123 if (pipe(pip) < 0)
3124 error("Pipe call failed");
3125 jp = makejob(n, 1);
3126 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3127 FORCEINTON;
3128 close(pip[0]);
3129 if (pip[1] != 1) {
3130 close(1);
3131 copyfd(pip[1], 1);
3132 close(pip[1]);
3133 }
3134 eflag = 0;
3135 evaltreenr(n, EV_EXIT);
3136 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003137 }
Eric Andersenc470f442003-07-28 09:56:35 +00003138 close(pip[1]);
3139 result->fd = pip[0];
3140 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003141 }
Eric Andersenc470f442003-07-28 09:56:35 +00003142 herefd = saveherefd;
3143out:
Eric Andersen62483552001-07-10 06:09:16 +00003144 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003145 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003146}
3147
Eric Andersenc470f442003-07-28 09:56:35 +00003148#ifdef CONFIG_ASH_CMDCMD
3149static inline char **
3150parse_command_args(char **argv, const char **path)
3151{
3152 char *cp, c;
3153
3154 for (;;) {
3155 cp = *++argv;
3156 if (!cp)
3157 return 0;
3158 if (*cp++ != '-')
3159 break;
3160 if (!(c = *cp++))
3161 break;
3162 if (c == '-' && !*cp) {
3163 argv++;
3164 break;
3165 }
3166 do {
3167 switch (c) {
3168 case 'p':
3169 *path = defpath;
3170 break;
3171 default:
3172 /* run 'typecmd' for other options */
3173 return 0;
3174 }
3175 } while ((c = *cp++));
3176 }
3177 return argv;
3178}
3179#endif
3180
3181
Eric Andersen62483552001-07-10 06:09:16 +00003182
3183/*
3184 * Execute a simple command.
3185 */
Eric Andersencb57d552001-06-28 07:25:16 +00003186
Eric Andersenc470f442003-07-28 09:56:35 +00003187static void
3188evalcommand(union node *cmd, int flags)
3189{
3190 struct stackmark smark;
3191 union node *argp;
3192 struct arglist arglist;
3193 struct arglist varlist;
3194 char **argv;
3195 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003196 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003197 struct cmdentry cmdentry;
3198 struct job *jp;
3199 char *lastarg;
3200 const char *path;
3201 int spclbltin;
3202 int cmd_is_exec;
3203 int status;
3204 char **nargv;
3205
3206 /* First expand the arguments. */
3207 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3208 setstackmark(&smark);
3209 back_exitstatus = 0;
3210
3211 cmdentry.cmdtype = CMDBUILTIN;
3212 cmdentry.u.cmd = &bltin;
3213 varlist.lastp = &varlist.list;
3214 *varlist.lastp = NULL;
3215 arglist.lastp = &arglist.list;
3216 *arglist.lastp = NULL;
3217
3218 argc = 0;
3219 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3220 struct strlist **spp;
3221
3222 spp = arglist.lastp;
3223 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3224 for (sp = *spp; sp; sp = sp->next)
3225 argc++;
3226 }
3227
3228 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3229 for (sp = arglist.list ; sp ; sp = sp->next) {
3230 TRACE(("evalcommand arg: %s\n", sp->text));
3231 *nargv++ = sp->text;
3232 }
3233 *nargv = NULL;
3234
3235 lastarg = NULL;
3236 if (iflag && funcnest == 0 && argc > 0)
3237 lastarg = nargv[-1];
3238
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003239 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003240 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003241 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003242
3243 path = vpath.text;
3244 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3245 struct strlist **spp;
3246 char *p;
3247
3248 spp = varlist.lastp;
3249 expandarg(argp, &varlist, EXP_VARTILDE);
3250
3251 /*
3252 * Modify the command lookup path, if a PATH= assignment
3253 * is present
3254 */
3255 p = (*spp)->text;
3256 if (varequal(p, path))
3257 path = p;
3258 }
3259
3260 /* Print the command if xflag is set. */
3261 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003262 int n;
3263 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003264
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003265 p++;
3266 dprintf(preverrout_fd, p, ps4val());
3267
3268 sp = varlist.list;
3269 for(n = 0; n < 2; n++) {
3270 while (sp) {
3271 dprintf(preverrout_fd, p, sp->text);
3272 sp = sp->next;
3273 if(*p == '%') {
3274 p--;
3275 }
3276 }
3277 sp = arglist.list;
3278 }
3279 xwrite(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003280 }
3281
3282 cmd_is_exec = 0;
3283 spclbltin = -1;
3284
3285 /* Now locate the command. */
3286 if (argc) {
3287 const char *oldpath;
3288 int cmd_flag = DO_ERR;
3289
3290 path += 5;
3291 oldpath = path;
3292 for (;;) {
3293 find_command(argv[0], &cmdentry, cmd_flag, path);
3294 if (cmdentry.cmdtype == CMDUNKNOWN) {
3295 status = 127;
3296 flushout(stderr);
3297 goto bail;
3298 }
3299
3300 /* implement bltin and command here */
3301 if (cmdentry.cmdtype != CMDBUILTIN)
3302 break;
3303 if (spclbltin < 0)
3304 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3305 if (cmdentry.u.cmd == EXECCMD)
3306 cmd_is_exec++;
3307#ifdef CONFIG_ASH_CMDCMD
3308 if (cmdentry.u.cmd == COMMANDCMD) {
3309
3310 path = oldpath;
3311 nargv = parse_command_args(argv, &path);
3312 if (!nargv)
3313 break;
3314 argc -= nargv - argv;
3315 argv = nargv;
3316 cmd_flag |= DO_NOFUNC;
3317 } else
3318#endif
3319 break;
3320 }
3321 }
3322
3323 if (status) {
3324 /* We have a redirection error. */
3325 if (spclbltin > 0)
3326 exraise(EXERROR);
3327bail:
3328 exitstatus = status;
3329 goto out;
3330 }
3331
3332 /* Execute the command. */
3333 switch (cmdentry.cmdtype) {
3334 default:
3335 /* Fork off a child process if necessary. */
3336 if (!(flags & EV_EXIT) || trap[0]) {
3337 INTOFF;
3338 jp = makejob(cmd, 1);
3339 if (forkshell(jp, cmd, FORK_FG) != 0) {
3340 exitstatus = waitforjob(jp);
3341 INTON;
3342 break;
3343 }
3344 FORCEINTON;
3345 }
3346 listsetvar(varlist.list, VEXPORT|VSTACK);
3347 shellexec(argv, path, cmdentry.u.index);
3348 /* NOTREACHED */
3349
3350 case CMDBUILTIN:
3351 cmdenviron = varlist.list;
3352 if (cmdenviron) {
3353 struct strlist *list = cmdenviron;
3354 int i = VNOSET;
3355 if (spclbltin > 0 || argc == 0) {
3356 i = 0;
3357 if (cmd_is_exec && argc > 1)
3358 i = VEXPORT;
3359 }
3360 listsetvar(list, i);
3361 }
3362 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3363 int exit_status;
3364 int i, j;
3365
3366 i = exception;
3367 if (i == EXEXIT)
3368 goto raise;
3369
3370 exit_status = 2;
3371 j = 0;
3372 if (i == EXINT)
3373 j = SIGINT;
3374 if (i == EXSIG)
3375 j = pendingsigs;
3376 if (j)
3377 exit_status = j + 128;
3378 exitstatus = exit_status;
3379
3380 if (i == EXINT || spclbltin > 0) {
3381raise:
3382 longjmp(handler->loc, 1);
3383 }
3384 FORCEINTON;
3385 }
3386 break;
3387
3388 case CMDFUNCTION:
3389 listsetvar(varlist.list, 0);
3390 if (evalfun(cmdentry.u.func, argc, argv, flags))
3391 goto raise;
3392 break;
3393 }
3394
3395out:
3396 popredir(cmd_is_exec);
3397 if (lastarg)
3398 /* dsl: I think this is intended to be used to support
3399 * '_' in 'vi' command mode during line editing...
3400 * However I implemented that within libedit itself.
3401 */
3402 setvar("_", lastarg, 0);
3403 popstackmark(&smark);
3404}
3405
3406static int
3407evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3408 char *volatile savecmdname;
3409 struct jmploc *volatile savehandler;
3410 struct jmploc jmploc;
3411 int i;
3412
3413 savecmdname = commandname;
3414 if ((i = setjmp(jmploc.loc)))
3415 goto cmddone;
3416 savehandler = handler;
3417 handler = &jmploc;
3418 commandname = argv[0];
3419 argptr = argv + 1;
3420 optptr = NULL; /* initialize nextopt */
3421 exitstatus = (*cmd->builtin)(argc, argv);
3422 flushall();
3423cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003424 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003425 commandname = savecmdname;
3426 exsig = 0;
3427 handler = savehandler;
3428
3429 return i;
3430}
3431
3432static int
3433evalfun(struct funcnode *func, int argc, char **argv, int flags)
3434{
3435 volatile struct shparam saveparam;
3436 struct localvar *volatile savelocalvars;
3437 struct jmploc *volatile savehandler;
3438 struct jmploc jmploc;
3439 int e;
3440
3441 saveparam = shellparam;
3442 savelocalvars = localvars;
3443 if ((e = setjmp(jmploc.loc))) {
3444 goto funcdone;
3445 }
3446 INTOFF;
3447 savehandler = handler;
3448 handler = &jmploc;
3449 localvars = NULL;
3450 shellparam.malloc = 0;
3451 func->count++;
3452 INTON;
3453 shellparam.nparam = argc - 1;
3454 shellparam.p = argv + 1;
3455#ifdef CONFIG_ASH_GETOPTS
3456 shellparam.optind = 1;
3457 shellparam.optoff = -1;
3458#endif
3459 funcnest++;
3460 evaltree(&func->n, flags & EV_TESTED);
3461 funcnest--;
3462funcdone:
3463 INTOFF;
3464 freefunc(func);
3465 poplocalvars();
3466 localvars = savelocalvars;
3467 freeparam(&shellparam);
3468 shellparam = saveparam;
3469 handler = savehandler;
3470 INTON;
3471 if (evalskip == SKIPFUNC) {
3472 evalskip = 0;
3473 skipcount = 0;
3474 }
3475 return e;
3476}
3477
3478
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003479static inline int
3480goodname(const char *p)
3481{
3482 return !*endofname(p);
3483}
3484
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003485/*
3486 * Search for a command. This is called before we fork so that the
3487 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003488 * the child. The check for "goodname" is an overly conservative
3489 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003490 */
3491
Eric Andersenc470f442003-07-28 09:56:35 +00003492static void
3493prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003494{
3495 struct cmdentry entry;
3496
3497 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003498 if (goodname(n->ncmd.args->narg.text))
3499 find_command(n->ncmd.args->narg.text, &entry, 0,
3500 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003501}
3502
Eric Andersencb57d552001-06-28 07:25:16 +00003503
Eric Andersenc470f442003-07-28 09:56:35 +00003504
Eric Andersencb57d552001-06-28 07:25:16 +00003505/*
3506 * Builtin commands. Builtin commands whose functions are closely
3507 * tied to evaluation are implemented here.
3508 */
3509
3510/*
Eric Andersenc470f442003-07-28 09:56:35 +00003511 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003512 */
3513
Eric Andersenc470f442003-07-28 09:56:35 +00003514static int
3515bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003516{
3517 /*
3518 * Preserve exitstatus of a previous possible redirection
3519 * as POSIX mandates
3520 */
Eric Andersenc470f442003-07-28 09:56:35 +00003521 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003522}
3523
3524
3525/*
3526 * Handle break and continue commands. Break, continue, and return are
3527 * all handled by setting the evalskip flag. The evaluation routines
3528 * above all check this flag, and if it is set they start skipping
3529 * commands rather than executing them. The variable skipcount is
3530 * the number of loops to break/continue, or the number of function
3531 * levels to return. (The latter is always 1.) It should probably
3532 * be an error to break out of more loops than exist, but it isn't
3533 * in the standard shell so we don't make it one here.
3534 */
3535
Eric Andersenc470f442003-07-28 09:56:35 +00003536static int
3537breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003538{
3539 int n = argc > 1 ? number(argv[1]) : 1;
3540
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003541 if (n <= 0)
Eric Andersenc470f442003-07-28 09:56:35 +00003542 error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003543 if (n > loopnest)
3544 n = loopnest;
3545 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003546 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003547 skipcount = n;
3548 }
3549 return 0;
3550}
3551
3552
3553/*
3554 * The return command.
3555 */
3556
Eric Andersenc470f442003-07-28 09:56:35 +00003557static int
3558returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003559{
Eric Andersenc470f442003-07-28 09:56:35 +00003560 int ret = argc > 1 ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003561
3562 if (funcnest) {
3563 evalskip = SKIPFUNC;
3564 skipcount = 1;
3565 return ret;
Eric Andersenc470f442003-07-28 09:56:35 +00003566 }
3567 else {
Eric Andersencb57d552001-06-28 07:25:16 +00003568 /* Do what ksh does; skip the rest of the file */
3569 evalskip = SKIPFILE;
3570 skipcount = 1;
3571 return ret;
3572 }
3573}
3574
3575
Eric Andersenc470f442003-07-28 09:56:35 +00003576static int
3577falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003578{
3579 return 1;
3580}
3581
Eric Andersenc470f442003-07-28 09:56:35 +00003582
3583static int
3584truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003585{
3586 return 0;
3587}
Eric Andersen2870d962001-07-02 17:27:21 +00003588
Eric Andersencb57d552001-06-28 07:25:16 +00003589
Eric Andersenc470f442003-07-28 09:56:35 +00003590static int
3591execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003592{
3593 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003594 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003595 mflag = 0;
3596 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003597 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003598 }
3599 return 0;
3600}
3601
Eric Andersenc470f442003-07-28 09:56:35 +00003602
Eric Andersenc470f442003-07-28 09:56:35 +00003603/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3604
3605/*
3606 * When commands are first encountered, they are entered in a hash table.
3607 * This ensures that a full path search will not have to be done for them
3608 * on each invocation.
3609 *
3610 * We should investigate converting to a linear search, even though that
3611 * would make the command name "hash" a misnomer.
3612 */
3613
3614#define CMDTABLESIZE 31 /* should be prime */
3615#define ARB 1 /* actual size determined at run time */
3616
3617
3618
3619struct tblentry {
3620 struct tblentry *next; /* next entry in hash chain */
3621 union param param; /* definition of builtin function */
3622 short cmdtype; /* index identifying command */
3623 char rehash; /* if set, cd done since entry created */
3624 char cmdname[ARB]; /* name of command */
3625};
3626
3627
3628static struct tblentry *cmdtable[CMDTABLESIZE];
3629static int builtinloc = -1; /* index in path of %builtin, or -1 */
3630
3631
3632static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003633static void clearcmdentry(int);
3634static struct tblentry *cmdlookup(const char *, int);
3635static void delete_cmd_entry(void);
3636
Eric Andersencb57d552001-06-28 07:25:16 +00003637
3638/*
3639 * Exec a program. Never returns. If you change this routine, you may
3640 * have to change the find_command routine as well.
3641 */
3642
Eric Andersenc470f442003-07-28 09:56:35 +00003643static void
3644shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003645{
3646 char *cmdname;
3647 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003648 char **envp;
Eric Andersencb57d552001-06-28 07:25:16 +00003649
Eric Andersenc470f442003-07-28 09:56:35 +00003650 clearredir(1);
3651 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003652 if (strchr(argv[0], '/') != NULL
3653#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3654 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003655#endif
3656 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003657 tryexec(argv[0], argv, envp);
3658 e = errno;
3659 } else {
3660 e = ENOENT;
3661 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3662 if (--idx < 0 && pathopt == NULL) {
3663 tryexec(cmdname, argv, envp);
3664 if (errno != ENOENT && errno != ENOTDIR)
3665 e = errno;
3666 }
3667 stunalloc(cmdname);
3668 }
3669 }
3670
3671 /* Map to POSIX errors */
3672 switch (e) {
3673 case EACCES:
3674 exerrno = 126;
3675 break;
3676 case ENOENT:
3677 exerrno = 127;
3678 break;
3679 default:
3680 exerrno = 2;
3681 break;
3682 }
Eric Andersenc470f442003-07-28 09:56:35 +00003683 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3684 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003685 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3686 /* NOTREACHED */
3687}
3688
Eric Andersen2870d962001-07-02 17:27:21 +00003689
Eric Andersenc470f442003-07-28 09:56:35 +00003690static void
3691tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003692{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003693 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003694#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003695 int flg_bb = 0;
Eric Andersen3102ac42001-07-06 04:26:23 +00003696 char *name = cmd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003697
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003698#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Manuel Novoa III cad53642003-03-19 09:13:01 +00003699 name = bb_get_last_path_component(name);
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003700 if(find_applet_by_name(name) != NULL)
3701 flg_bb = 1;
3702#else
3703 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3704 flg_bb = 1;
3705 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003706#endif
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003707 if(flg_bb) {
3708 char **ap;
3709 char **new;
3710
3711 *argv = name;
3712 if(strcmp(name, "busybox")) {
3713 for (ap = argv; *ap; ap++);
3714 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3715 *ap++ = cmd = "/bin/busybox";
3716 while ((*ap++ = *argv++));
3717 argv = new;
3718 repeated++;
3719 } else {
3720 cmd = "/bin/busybox";
3721 }
3722 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003723#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003724
3725repeat:
3726#ifdef SYSV
3727 do {
3728 execve(cmd, argv, envp);
3729 } while (errno == EINTR);
3730#else
Eric Andersencb57d552001-06-28 07:25:16 +00003731 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003732#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003733 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003734 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003735 } else if (errno == ENOEXEC) {
3736 char **ap;
3737 char **new;
3738
Eric Andersenc470f442003-07-28 09:56:35 +00003739 for (ap = argv; *ap; ap++)
3740 ;
3741 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003742 ap[1] = cmd;
3743 *ap = cmd = (char *)DEFAULT_SHELL;
3744 ap += 2;
3745 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003746 while ((*ap++ = *argv++))
3747 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003748 argv = new;
3749 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003750 }
Eric Andersencb57d552001-06-28 07:25:16 +00003751}
3752
Eric Andersenc470f442003-07-28 09:56:35 +00003753
Eric Andersencb57d552001-06-28 07:25:16 +00003754
3755/*
3756 * Do a path search. The variable path (passed by reference) should be
3757 * set to the start of the path before the first call; padvance will update
3758 * this value as it proceeds. Successive calls to padvance will return
3759 * the possible path expansions in sequence. If an option (indicated by
3760 * a percent sign) appears in the path entry then the global variable
3761 * pathopt will be set to point to it; otherwise pathopt will be set to
3762 * NULL.
3763 */
3764
Eric Andersenc470f442003-07-28 09:56:35 +00003765static char *
3766padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003767{
Eric Andersencb57d552001-06-28 07:25:16 +00003768 const char *p;
3769 char *q;
3770 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003771 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003772
3773 if (*path == NULL)
3774 return NULL;
3775 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003776 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3777 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003778 while (stackblocksize() < len)
3779 growstackblock();
3780 q = stackblock();
3781 if (p != start) {
3782 memcpy(q, start, p - start);
3783 q += p - start;
3784 *q++ = '/';
3785 }
3786 strcpy(q, name);
3787 pathopt = NULL;
3788 if (*p == '%') {
3789 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003790 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003791 }
3792 if (*p == ':')
3793 *path = p + 1;
3794 else
3795 *path = NULL;
3796 return stalloc(len);
3797}
3798
3799
Eric Andersencb57d552001-06-28 07:25:16 +00003800/*** Command hashing code ***/
3801
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003802static void
3803printentry(struct tblentry *cmdp)
3804{
3805 int idx;
3806 const char *path;
3807 char *name;
3808
3809 idx = cmdp->param.index;
3810 path = pathval();
3811 do {
3812 name = padvance(&path, cmdp->cmdname);
3813 stunalloc(name);
3814 } while (--idx >= 0);
3815 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3816}
3817
Eric Andersenc470f442003-07-28 09:56:35 +00003818
3819static int
3820hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003821{
3822 struct tblentry **pp;
3823 struct tblentry *cmdp;
3824 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003825 struct cmdentry entry;
3826 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003827
Eric Andersenc470f442003-07-28 09:56:35 +00003828 while ((c = nextopt("r")) != '\0') {
3829 clearcmdentry(0);
3830 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003831 }
3832 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003833 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3834 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3835 if (cmdp->cmdtype == CMDNORMAL)
3836 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003837 }
3838 }
3839 return 0;
3840 }
3841 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003842 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003843 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003844 && (cmdp->cmdtype == CMDNORMAL
3845 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003846 delete_cmd_entry();
3847 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003848 if (entry.cmdtype == CMDUNKNOWN)
3849 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003850 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003851 }
3852 return c;
3853}
3854
Eric Andersenc470f442003-07-28 09:56:35 +00003855
Eric Andersencb57d552001-06-28 07:25:16 +00003856/*
3857 * Resolve a command name. If you change this routine, you may have to
3858 * change the shellexec routine as well.
3859 */
3860
3861static void
Eric Andersenc470f442003-07-28 09:56:35 +00003862find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003863{
3864 struct tblentry *cmdp;
3865 int idx;
3866 int prev;
3867 char *fullname;
3868 struct stat statb;
3869 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003870 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003871 struct builtincmd *bcmd;
3872
Eric Andersenc470f442003-07-28 09:56:35 +00003873 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003874 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003875 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003876 if (act & DO_ABS) {
3877 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003878#ifdef SYSV
3879 if (errno == EINTR)
3880 continue;
3881#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003882 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003883 return;
3884 }
Eric Andersencb57d552001-06-28 07:25:16 +00003885 }
3886 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003887 return;
3888 }
3889
Eric Andersenbf8bf102002-09-17 08:41:08 +00003890#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3891 if (find_applet_by_name(name)) {
3892 entry->cmdtype = CMDNORMAL;
3893 entry->u.index = -1;
3894 return;
3895 }
3896#endif
3897
Eric Andersenc470f442003-07-28 09:56:35 +00003898 updatetbl = (path == pathval());
3899 if (!updatetbl) {
3900 act |= DO_ALTPATH;
3901 if (strstr(path, "%builtin") != NULL)
3902 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003903 }
3904
Eric Andersenc470f442003-07-28 09:56:35 +00003905 /* If name is in the table, check answer will be ok */
3906 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3907 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003908
Eric Andersenc470f442003-07-28 09:56:35 +00003909 switch (cmdp->cmdtype) {
3910 default:
3911#if DEBUG
3912 abort();
3913#endif
3914 case CMDNORMAL:
3915 bit = DO_ALTPATH;
3916 break;
3917 case CMDFUNCTION:
3918 bit = DO_NOFUNC;
3919 break;
3920 case CMDBUILTIN:
3921 bit = DO_ALTBLTIN;
3922 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003923 }
Eric Andersenc470f442003-07-28 09:56:35 +00003924 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003925 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003926 cmdp = NULL;
3927 } else if (cmdp->rehash == 0)
3928 /* if not invalidated by cd, we're done */
3929 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003930 }
3931
3932 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003933 bcmd = find_builtin(name);
3934 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3935 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3936 )))
3937 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003938
3939 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003940 prev = -1; /* where to start */
3941 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003942 if (cmdp->cmdtype == CMDBUILTIN)
3943 prev = builtinloc;
3944 else
3945 prev = cmdp->param.index;
3946 }
3947
3948 e = ENOENT;
3949 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003950loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003951 while ((fullname = padvance(&path, name)) != NULL) {
3952 stunalloc(fullname);
3953 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003954 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003955 if (prefix(pathopt, "builtin")) {
3956 if (bcmd)
3957 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003958 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003959 } else if (!(act & DO_NOFUNC) &&
3960 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003961 /* handled below */
3962 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003963 /* ignore unimplemented options */
3964 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003965 }
3966 }
3967 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003968 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003969 if (idx < prev)
3970 continue;
3971 TRACE(("searchexec \"%s\": no change\n", name));
3972 goto success;
3973 }
3974 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003975#ifdef SYSV
3976 if (errno == EINTR)
3977 continue;
3978#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003979 if (errno != ENOENT && errno != ENOTDIR)
3980 e = errno;
3981 goto loop;
3982 }
Eric Andersenc470f442003-07-28 09:56:35 +00003983 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003984 if (!S_ISREG(statb.st_mode))
3985 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003986 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003987 stalloc(strlen(fullname) + 1);
3988 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00003989 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3990 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00003991 error("%s not defined in %s", name, fullname);
3992 stunalloc(fullname);
3993 goto success;
3994 }
Eric Andersencb57d552001-06-28 07:25:16 +00003995 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00003996 if (!updatetbl) {
3997 entry->cmdtype = CMDNORMAL;
3998 entry->u.index = idx;
3999 return;
4000 }
4001 INTOFF;
4002 cmdp = cmdlookup(name, 1);
4003 cmdp->cmdtype = CMDNORMAL;
4004 cmdp->param.index = idx;
4005 INTON;
4006 goto success;
4007 }
4008
4009 /* We failed. If there was an entry for this command, delete it */
4010 if (cmdp && updatetbl)
4011 delete_cmd_entry();
4012 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004013 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004014 entry->cmdtype = CMDUNKNOWN;
4015 return;
4016
Eric Andersenc470f442003-07-28 09:56:35 +00004017builtin_success:
4018 if (!updatetbl) {
4019 entry->cmdtype = CMDBUILTIN;
4020 entry->u.cmd = bcmd;
4021 return;
4022 }
4023 INTOFF;
4024 cmdp = cmdlookup(name, 1);
4025 cmdp->cmdtype = CMDBUILTIN;
4026 cmdp->param.cmd = bcmd;
4027 INTON;
4028success:
Eric Andersencb57d552001-06-28 07:25:16 +00004029 cmdp->rehash = 0;
4030 entry->cmdtype = cmdp->cmdtype;
4031 entry->u = cmdp->param;
4032}
4033
4034
Eric Andersenc470f442003-07-28 09:56:35 +00004035/*
4036 * Wrapper around strcmp for qsort/bsearch/...
4037 */
4038static int pstrcmp(const void *a, const void *b)
4039{
4040 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4041}
Eric Andersencb57d552001-06-28 07:25:16 +00004042
4043/*
4044 * Search the table of builtin commands.
4045 */
4046
Eric Andersenc470f442003-07-28 09:56:35 +00004047static struct builtincmd *
4048find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004049{
4050 struct builtincmd *bp;
4051
Eric Andersenc470f442003-07-28 09:56:35 +00004052 bp = bsearch(
4053 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4054 pstrcmp
4055 );
Eric Andersencb57d552001-06-28 07:25:16 +00004056 return bp;
4057}
4058
4059
Eric Andersenc470f442003-07-28 09:56:35 +00004060
Eric Andersencb57d552001-06-28 07:25:16 +00004061/*
4062 * Called when a cd is done. Marks all commands so the next time they
4063 * are executed they will be rehashed.
4064 */
4065
Eric Andersenc470f442003-07-28 09:56:35 +00004066static void
4067hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004068{
Eric Andersencb57d552001-06-28 07:25:16 +00004069 struct tblentry **pp;
4070 struct tblentry *cmdp;
4071
Eric Andersenc470f442003-07-28 09:56:35 +00004072 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4073 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4074 if (cmdp->cmdtype == CMDNORMAL || (
4075 cmdp->cmdtype == CMDBUILTIN &&
4076 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4077 builtinloc > 0
4078 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004079 cmdp->rehash = 1;
4080 }
4081 }
4082}
4083
4084
4085
4086/*
Eric Andersenc470f442003-07-28 09:56:35 +00004087 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004088 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004089 * pathval() still returns the old value at this point.
4090 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004091 */
4092
Eric Andersenc470f442003-07-28 09:56:35 +00004093static void
4094changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004095{
Eric Andersenc470f442003-07-28 09:56:35 +00004096 const char *old, *new;
4097 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004098 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004099 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004100
Eric Andersenc470f442003-07-28 09:56:35 +00004101 old = pathval();
4102 new = newval;
4103 firstchange = 9999; /* assume no change */
4104 idx = 0;
4105 idx_bltin = -1;
4106 for (;;) {
4107 if (*old != *new) {
4108 firstchange = idx;
4109 if ((*old == '\0' && *new == ':')
4110 || (*old == ':' && *new == '\0'))
4111 firstchange++;
4112 old = new; /* ignore subsequent differences */
4113 }
4114 if (*new == '\0')
4115 break;
4116 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4117 idx_bltin = idx;
4118 if (*new == ':') {
4119 idx++;
4120 }
4121 new++, old++;
4122 }
4123 if (builtinloc < 0 && idx_bltin >= 0)
4124 builtinloc = idx_bltin; /* zap builtins */
4125 if (builtinloc >= 0 && idx_bltin < 0)
4126 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004127 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004128 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004129}
4130
4131
4132/*
4133 * Clear out command entries. The argument specifies the first entry in
4134 * PATH which has changed.
4135 */
4136
Eric Andersenc470f442003-07-28 09:56:35 +00004137static void
4138clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004139{
4140 struct tblentry **tblp;
4141 struct tblentry **pp;
4142 struct tblentry *cmdp;
4143
4144 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004145 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004146 pp = tblp;
4147 while ((cmdp = *pp) != NULL) {
4148 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004149 cmdp->param.index >= firstchange)
4150 || (cmdp->cmdtype == CMDBUILTIN &&
4151 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004152 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004153 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004154 } else {
4155 pp = &cmdp->next;
4156 }
4157 }
4158 }
4159 INTON;
4160}
4161
4162
Eric Andersenc470f442003-07-28 09:56:35 +00004163
Eric Andersencb57d552001-06-28 07:25:16 +00004164/*
Eric Andersencb57d552001-06-28 07:25:16 +00004165 * Locate a command in the command hash table. If "add" is nonzero,
4166 * add the command to the table if it is not already present. The
4167 * variable "lastcmdentry" is set to point to the address of the link
4168 * pointing to the entry, so that delete_cmd_entry can delete the
4169 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004170 *
4171 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004172 */
4173
Eric Andersen2870d962001-07-02 17:27:21 +00004174static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004175
Eric Andersenc470f442003-07-28 09:56:35 +00004176
4177static struct tblentry *
4178cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004179{
Eric Andersenc470f442003-07-28 09:56:35 +00004180 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004181 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004182 struct tblentry *cmdp;
4183 struct tblentry **pp;
4184
4185 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004186 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004187 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004188 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004189 hashval &= 0x7FFF;
4190 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004191 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004192 if (equal(cmdp->cmdname, name))
4193 break;
4194 pp = &cmdp->next;
4195 }
4196 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004197 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4198 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004199 cmdp->next = NULL;
4200 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004201 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004202 }
4203 lastcmdentry = pp;
4204 return cmdp;
4205}
4206
4207/*
4208 * Delete the command entry returned on the last lookup.
4209 */
4210
Eric Andersenc470f442003-07-28 09:56:35 +00004211static void
4212delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004213{
Eric Andersencb57d552001-06-28 07:25:16 +00004214 struct tblentry *cmdp;
4215
4216 INTOFF;
4217 cmdp = *lastcmdentry;
4218 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004219 if (cmdp->cmdtype == CMDFUNCTION)
4220 freefunc(cmdp->param.func);
4221 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004222 INTON;
4223}
4224
4225
Eric Andersenc470f442003-07-28 09:56:35 +00004226/*
4227 * Add a new command entry, replacing any existing command entry for
4228 * the same name - except special builtins.
4229 */
Eric Andersencb57d552001-06-28 07:25:16 +00004230
Eric Andersenc470f442003-07-28 09:56:35 +00004231static inline void
4232addcmdentry(char *name, struct cmdentry *entry)
4233{
4234 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004235
Eric Andersenc470f442003-07-28 09:56:35 +00004236 cmdp = cmdlookup(name, 1);
4237 if (cmdp->cmdtype == CMDFUNCTION) {
4238 freefunc(cmdp->param.func);
4239 }
4240 cmdp->cmdtype = entry->cmdtype;
4241 cmdp->param = entry->u;
4242 cmdp->rehash = 0;
4243}
Eric Andersencb57d552001-06-28 07:25:16 +00004244
Eric Andersenc470f442003-07-28 09:56:35 +00004245/*
4246 * Make a copy of a parse tree.
4247 */
Eric Andersencb57d552001-06-28 07:25:16 +00004248
Eric Andersenc470f442003-07-28 09:56:35 +00004249static inline struct funcnode *
4250copyfunc(union node *n)
4251{
4252 struct funcnode *f;
4253 size_t blocksize;
4254
4255 funcblocksize = offsetof(struct funcnode, n);
4256 funcstringsize = 0;
4257 calcsize(n);
4258 blocksize = funcblocksize;
4259 f = ckmalloc(blocksize + funcstringsize);
4260 funcblock = (char *) f + offsetof(struct funcnode, n);
4261 funcstring = (char *) f + blocksize;
4262 copynode(n);
4263 f->count = 0;
4264 return f;
4265}
4266
4267/*
4268 * Define a shell function.
4269 */
4270
4271static void
4272defun(char *name, union node *func)
4273{
4274 struct cmdentry entry;
4275
4276 INTOFF;
4277 entry.cmdtype = CMDFUNCTION;
4278 entry.u.func = copyfunc(func);
4279 addcmdentry(name, &entry);
4280 INTON;
4281}
Eric Andersencb57d552001-06-28 07:25:16 +00004282
4283
4284/*
4285 * Delete a function if it exists.
4286 */
4287
Eric Andersenc470f442003-07-28 09:56:35 +00004288static void
4289unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004290{
Eric Andersencb57d552001-06-28 07:25:16 +00004291 struct tblentry *cmdp;
4292
Eric Andersenc470f442003-07-28 09:56:35 +00004293 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4294 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004295 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004296}
4297
Eric Andersen2870d962001-07-02 17:27:21 +00004298/*
Eric Andersencb57d552001-06-28 07:25:16 +00004299 * Locate and print what a word is...
4300 */
4301
Eric Andersenc470f442003-07-28 09:56:35 +00004302
4303#ifdef CONFIG_ASH_CMDCMD
4304static int
4305describe_command(char *command, int describe_command_verbose)
4306#else
4307#define describe_command_verbose 1
4308static int
4309describe_command(char *command)
4310#endif
4311{
4312 struct cmdentry entry;
4313 struct tblentry *cmdp;
4314#ifdef CONFIG_ASH_ALIAS
4315 const struct alias *ap;
4316#endif
4317 const char *path = pathval();
4318
4319 if (describe_command_verbose) {
4320 out1str(command);
4321 }
4322
4323 /* First look at the keywords */
4324 if (findkwd(command)) {
4325 out1str(describe_command_verbose ? " is a shell keyword" : command);
4326 goto out;
4327 }
4328
4329#ifdef CONFIG_ASH_ALIAS
4330 /* Then look at the aliases */
4331 if ((ap = lookupalias(command, 0)) != NULL) {
4332 if (describe_command_verbose) {
4333 out1fmt(" is an alias for %s", ap->val);
4334 } else {
4335 out1str("alias ");
4336 printalias(ap);
4337 return 0;
4338 }
4339 goto out;
4340 }
4341#endif
4342 /* Then check if it is a tracked alias */
4343 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4344 entry.cmdtype = cmdp->cmdtype;
4345 entry.u = cmdp->param;
4346 } else {
4347 /* Finally use brute force */
4348 find_command(command, &entry, DO_ABS, path);
4349 }
4350
4351 switch (entry.cmdtype) {
4352 case CMDNORMAL: {
4353 int j = entry.u.index;
4354 char *p;
4355 if (j == -1) {
4356 p = command;
4357 } else {
4358 do {
4359 p = padvance(&path, command);
4360 stunalloc(p);
4361 } while (--j >= 0);
4362 }
4363 if (describe_command_verbose) {
4364 out1fmt(" is%s %s",
4365 (cmdp ? " a tracked alias for" : nullstr), p
4366 );
4367 } else {
4368 out1str(p);
4369 }
4370 break;
4371 }
4372
4373 case CMDFUNCTION:
4374 if (describe_command_verbose) {
4375 out1str(" is a shell function");
4376 } else {
4377 out1str(command);
4378 }
4379 break;
4380
4381 case CMDBUILTIN:
4382 if (describe_command_verbose) {
4383 out1fmt(" is a %sshell builtin",
4384 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4385 "special " : nullstr
4386 );
4387 } else {
4388 out1str(command);
4389 }
4390 break;
4391
4392 default:
4393 if (describe_command_verbose) {
4394 out1str(": not found\n");
4395 }
4396 return 127;
4397 }
4398
4399out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004400 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004401 return 0;
4402}
4403
4404static int
4405typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004406{
4407 int i;
4408 int err = 0;
4409
4410 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004411#ifdef CONFIG_ASH_CMDCMD
4412 err |= describe_command(argv[i], 1);
4413#else
4414 err |= describe_command(argv[i]);
4415#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004416 }
4417 return err;
4418}
4419
Eric Andersend35c5df2002-01-09 15:37:36 +00004420#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004421static int
4422commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004423{
4424 int c;
4425 int default_path = 0;
4426 int verify_only = 0;
4427 int verbose_verify_only = 0;
4428
4429 while ((c = nextopt("pvV")) != '\0')
4430 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004431 default:
4432#ifdef DEBUG
4433 fprintf(stderr,
4434"command: nextopt returned character code 0%o\n", c);
4435 return EX_SOFTWARE;
4436#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004437 case 'p':
4438 default_path = 1;
4439 break;
4440 case 'v':
4441 verify_only = 1;
4442 break;
4443 case 'V':
4444 verbose_verify_only = 1;
4445 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004446 }
4447
Eric Andersenc470f442003-07-28 09:56:35 +00004448 if (default_path + verify_only + verbose_verify_only > 1 ||
4449 !*argptr) {
4450 fprintf(stderr,
4451 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004452 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004453 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004454 }
4455
Eric Andersencb57d552001-06-28 07:25:16 +00004456 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004457 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004458 }
Eric Andersencb57d552001-06-28 07:25:16 +00004459
4460 return 0;
4461}
Eric Andersen2870d962001-07-02 17:27:21 +00004462#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004463
Eric Andersenc470f442003-07-28 09:56:35 +00004464/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004465
Eric Andersencb57d552001-06-28 07:25:16 +00004466/*
4467 * Routines to expand arguments to commands. We have to deal with
4468 * backquotes, shell variables, and file metacharacters.
4469 */
Eric Andersenc470f442003-07-28 09:56:35 +00004470
Eric Andersencb57d552001-06-28 07:25:16 +00004471/*
4472 * _rmescape() flags
4473 */
Eric Andersenc470f442003-07-28 09:56:35 +00004474#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4475#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4476#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4477#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4478#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004479
4480/*
4481 * Structure specifying which parts of the string should be searched
4482 * for IFS characters.
4483 */
4484
4485struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004486 struct ifsregion *next; /* next region in list */
4487 int begoff; /* offset of start of region */
4488 int endoff; /* offset of end of region */
4489 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004490};
4491
Eric Andersenc470f442003-07-28 09:56:35 +00004492/* output of current string */
4493static char *expdest;
4494/* list of back quote expressions */
4495static struct nodelist *argbackq;
4496/* first struct in list of ifs regions */
4497static struct ifsregion ifsfirst;
4498/* last struct in list */
4499static struct ifsregion *ifslastp;
4500/* holds expanded arg list */
4501static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004502
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004503static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004504static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004505static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004506static const char *subevalvar(char *, char *, int, int, int, int, int);
4507static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004508static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004509static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004510static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004511static void recordregion(int, int, int);
4512static void removerecordregions(int);
4513static void ifsbreakup(char *, struct arglist *);
4514static void ifsfree(void);
4515static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004516static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004517
Eric Andersenc470f442003-07-28 09:56:35 +00004518static int cvtnum(long);
4519static size_t esclen(const char *, const char *);
4520static char *scanleft(char *, char *, char *, char *, int, int);
4521static char *scanright(char *, char *, char *, char *, int, int);
4522static void varunset(const char *, const char *, const char *, int)
4523 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004524
Eric Andersenc470f442003-07-28 09:56:35 +00004525
4526#define pmatch(a, b) !fnmatch((a), (b), 0)
4527/*
Eric Andersen90898442003-08-06 11:20:52 +00004528 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004529 *
4530 * Returns an stalloced string.
4531 */
4532
4533static inline char *
4534preglob(const char *pattern, int quoted, int flag) {
4535 flag |= RMESCAPE_GLOB;
4536 if (quoted) {
4537 flag |= RMESCAPE_QUOTED;
4538 }
4539 return _rmescapes((char *)pattern, flag);
4540}
4541
4542
4543static size_t
4544esclen(const char *start, const char *p) {
4545 size_t esc = 0;
4546
4547 while (p > start && *--p == CTLESC) {
4548 esc++;
4549 }
4550 return esc;
4551}
4552
Eric Andersencb57d552001-06-28 07:25:16 +00004553
4554/*
4555 * Expand shell variables and backquotes inside a here document.
4556 */
4557
Eric Andersenc470f442003-07-28 09:56:35 +00004558static inline void
4559expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004560{
Eric Andersencb57d552001-06-28 07:25:16 +00004561 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004562 expandarg(arg, (struct arglist *)NULL, 0);
4563 xwrite(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004564}
4565
4566
4567/*
4568 * Perform variable substitution and command substitution on an argument,
4569 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4570 * perform splitting and file name expansion. When arglist is NULL, perform
4571 * here document expansion.
4572 */
4573
Eric Andersenc470f442003-07-28 09:56:35 +00004574void
4575expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004576{
4577 struct strlist *sp;
4578 char *p;
4579
4580 argbackq = arg->narg.backquote;
4581 STARTSTACKSTR(expdest);
4582 ifsfirst.next = NULL;
4583 ifslastp = NULL;
4584 argstr(arg->narg.text, flag);
4585 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004586 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004587 }
4588 STPUTC('\0', expdest);
4589 p = grabstackstr(expdest);
4590 exparg.lastp = &exparg.list;
4591 /*
4592 * TODO - EXP_REDIR
4593 */
4594 if (flag & EXP_FULL) {
4595 ifsbreakup(p, &exparg);
4596 *exparg.lastp = NULL;
4597 exparg.lastp = &exparg.list;
4598 expandmeta(exparg.list, flag);
4599 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004600 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004601 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004602 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004603 sp->text = p;
4604 *exparg.lastp = sp;
4605 exparg.lastp = &sp->next;
4606 }
Eric Andersenc470f442003-07-28 09:56:35 +00004607 if (ifsfirst.next)
4608 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004609 *exparg.lastp = NULL;
4610 if (exparg.list) {
4611 *arglist->lastp = exparg.list;
4612 arglist->lastp = exparg.lastp;
4613 }
4614}
4615
4616
Eric Andersenc470f442003-07-28 09:56:35 +00004617/*
4618 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4619 * characters to allow for further processing. Otherwise treat
4620 * $@ like $* since no splitting will be performed.
4621 */
4622
4623static void
4624argstr(char *p, int flag)
4625{
4626 static const char spclchars[] = {
4627 '=',
4628 ':',
4629 CTLQUOTEMARK,
4630 CTLENDVAR,
4631 CTLESC,
4632 CTLVAR,
4633 CTLBACKQ,
4634 CTLBACKQ | CTLQUOTE,
4635#ifdef CONFIG_ASH_MATH_SUPPORT
4636 CTLENDARI,
4637#endif
4638 0
4639 };
4640 const char *reject = spclchars;
4641 int c;
4642 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4643 int breakall = flag & EXP_WORD;
4644 int inquotes;
4645 size_t length;
4646 int startloc;
4647
4648 if (!(flag & EXP_VARTILDE)) {
4649 reject += 2;
4650 } else if (flag & EXP_VARTILDE2) {
4651 reject++;
4652 }
4653 inquotes = 0;
4654 length = 0;
4655 if (flag & EXP_TILDE) {
4656 char *q;
4657
4658 flag &= ~EXP_TILDE;
4659tilde:
4660 q = p;
4661 if (*q == CTLESC && (flag & EXP_QWORD))
4662 q++;
4663 if (*q == '~')
4664 p = exptilde(p, q, flag);
4665 }
4666start:
4667 startloc = expdest - (char *)stackblock();
4668 for (;;) {
4669 length += strcspn(p + length, reject);
4670 c = p[length];
4671 if (c && (!(c & 0x80)
4672#ifdef CONFIG_ASH_MATH_SUPPORT
4673 || c == CTLENDARI
4674#endif
4675 )) {
4676 /* c == '=' || c == ':' || c == CTLENDARI */
4677 length++;
4678 }
4679 if (length > 0) {
4680 int newloc;
4681 expdest = stnputs(p, length, expdest);
4682 newloc = expdest - (char *)stackblock();
4683 if (breakall && !inquotes && newloc > startloc) {
4684 recordregion(startloc, newloc, 0);
4685 }
4686 startloc = newloc;
4687 }
4688 p += length + 1;
4689 length = 0;
4690
4691 switch (c) {
4692 case '\0':
4693 goto breakloop;
4694 case '=':
4695 if (flag & EXP_VARTILDE2) {
4696 p--;
4697 continue;
4698 }
4699 flag |= EXP_VARTILDE2;
4700 reject++;
4701 /* fall through */
4702 case ':':
4703 /*
4704 * sort of a hack - expand tildes in variable
4705 * assignments (after the first '=' and after ':'s).
4706 */
4707 if (*--p == '~') {
4708 goto tilde;
4709 }
4710 continue;
4711 }
4712
4713 switch (c) {
4714 case CTLENDVAR: /* ??? */
4715 goto breakloop;
4716 case CTLQUOTEMARK:
4717 /* "$@" syntax adherence hack */
4718 if (
4719 !inquotes &&
4720 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4721 (p[4] == CTLQUOTEMARK || (
4722 p[4] == CTLENDVAR &&
4723 p[5] == CTLQUOTEMARK
4724 ))
4725 ) {
4726 p = evalvar(p + 1, flag) + 1;
4727 goto start;
4728 }
4729 inquotes = !inquotes;
4730addquote:
4731 if (quotes) {
4732 p--;
4733 length++;
4734 startloc++;
4735 }
4736 break;
4737 case CTLESC:
4738 startloc++;
4739 length++;
4740 goto addquote;
4741 case CTLVAR:
4742 p = evalvar(p, flag);
4743 goto start;
4744 case CTLBACKQ:
4745 c = 0;
4746 case CTLBACKQ|CTLQUOTE:
4747 expbackq(argbackq->n, c, quotes);
4748 argbackq = argbackq->next;
4749 goto start;
4750#ifdef CONFIG_ASH_MATH_SUPPORT
4751 case CTLENDARI:
4752 p--;
4753 expari(quotes);
4754 goto start;
4755#endif
4756 }
4757 }
4758breakloop:
4759 ;
4760}
4761
4762static char *
4763exptilde(char *startp, char *p, int flag)
4764{
4765 char c;
4766 char *name;
4767 struct passwd *pw;
4768 const char *home;
4769 int quotes = flag & (EXP_FULL | EXP_CASE);
4770 int startloc;
4771
4772 name = p + 1;
4773
4774 while ((c = *++p) != '\0') {
4775 switch(c) {
4776 case CTLESC:
4777 return (startp);
4778 case CTLQUOTEMARK:
4779 return (startp);
4780 case ':':
4781 if (flag & EXP_VARTILDE)
4782 goto done;
4783 break;
4784 case '/':
4785 case CTLENDVAR:
4786 goto done;
4787 }
4788 }
4789done:
4790 *p = '\0';
4791 if (*name == '\0') {
4792 if ((home = lookupvar(homestr)) == NULL)
4793 goto lose;
4794 } else {
4795 if ((pw = getpwnam(name)) == NULL)
4796 goto lose;
4797 home = pw->pw_dir;
4798 }
4799 if (*home == '\0')
4800 goto lose;
4801 *p = c;
4802 startloc = expdest - (char *)stackblock();
4803 strtodest(home, SQSYNTAX, quotes);
4804 recordregion(startloc, expdest - (char *)stackblock(), 0);
4805 return (p);
4806lose:
4807 *p = c;
4808 return (startp);
4809}
4810
4811
4812static void
4813removerecordregions(int endoff)
4814{
4815 if (ifslastp == NULL)
4816 return;
4817
4818 if (ifsfirst.endoff > endoff) {
4819 while (ifsfirst.next != NULL) {
4820 struct ifsregion *ifsp;
4821 INTOFF;
4822 ifsp = ifsfirst.next->next;
4823 ckfree(ifsfirst.next);
4824 ifsfirst.next = ifsp;
4825 INTON;
4826 }
4827 if (ifsfirst.begoff > endoff)
4828 ifslastp = NULL;
4829 else {
4830 ifslastp = &ifsfirst;
4831 ifsfirst.endoff = endoff;
4832 }
4833 return;
4834 }
4835
4836 ifslastp = &ifsfirst;
4837 while (ifslastp->next && ifslastp->next->begoff < endoff)
4838 ifslastp=ifslastp->next;
4839 while (ifslastp->next != NULL) {
4840 struct ifsregion *ifsp;
4841 INTOFF;
4842 ifsp = ifslastp->next->next;
4843 ckfree(ifslastp->next);
4844 ifslastp->next = ifsp;
4845 INTON;
4846 }
4847 if (ifslastp->endoff > endoff)
4848 ifslastp->endoff = endoff;
4849}
4850
4851
4852#ifdef CONFIG_ASH_MATH_SUPPORT
4853/*
4854 * Expand arithmetic expression. Backup to start of expression,
4855 * evaluate, place result in (backed up) result, adjust string position.
4856 */
4857void
4858expari(int quotes)
4859{
4860 char *p, *start;
4861 int begoff;
4862 int flag;
4863 int len;
4864
4865 /* ifsfree(); */
4866
4867 /*
4868 * This routine is slightly over-complicated for
4869 * efficiency. Next we scan backwards looking for the
4870 * start of arithmetic.
4871 */
4872 start = stackblock();
4873 p = expdest - 1;
4874 *p = '\0';
4875 p--;
4876 do {
4877 int esc;
4878
4879 while (*p != CTLARI) {
4880 p--;
4881#ifdef DEBUG
4882 if (p < start) {
4883 error("missing CTLARI (shouldn't happen)");
4884 }
4885#endif
4886 }
4887
4888 esc = esclen(start, p);
4889 if (!(esc % 2)) {
4890 break;
4891 }
4892
4893 p -= esc + 1;
4894 } while (1);
4895
4896 begoff = p - start;
4897
4898 removerecordregions(begoff);
4899
4900 flag = p[1];
4901
4902 expdest = p;
4903
4904 if (quotes)
4905 rmescapes(p + 2);
4906
4907 len = cvtnum(dash_arith(p + 2));
4908
4909 if (flag != '"')
4910 recordregion(begoff, begoff + len, 0);
4911}
4912#endif
4913
4914/*
4915 * Expand stuff in backwards quotes.
4916 */
4917
4918static void
4919expbackq(union node *cmd, int quoted, int quotes)
4920{
4921 struct backcmd in;
4922 int i;
4923 char buf[128];
4924 char *p;
4925 char *dest;
4926 int startloc;
4927 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4928 struct stackmark smark;
4929
4930 INTOFF;
4931 setstackmark(&smark);
4932 dest = expdest;
4933 startloc = dest - (char *)stackblock();
4934 grabstackstr(dest);
4935 evalbackcmd(cmd, (struct backcmd *) &in);
4936 popstackmark(&smark);
4937
4938 p = in.buf;
4939 i = in.nleft;
4940 if (i == 0)
4941 goto read;
4942 for (;;) {
4943 memtodest(p, i, syntax, quotes);
4944read:
4945 if (in.fd < 0)
4946 break;
4947 i = safe_read(in.fd, buf, sizeof buf);
4948 TRACE(("expbackq: read returns %d\n", i));
4949 if (i <= 0)
4950 break;
4951 p = buf;
4952 }
4953
4954 if (in.buf)
4955 ckfree(in.buf);
4956 if (in.fd >= 0) {
4957 close(in.fd);
4958 back_exitstatus = waitforjob(in.jp);
4959 }
4960 INTON;
4961
4962 /* Eat all trailing newlines */
4963 dest = expdest;
4964 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4965 STUNPUTC(dest);
4966 expdest = dest;
4967
4968 if (quoted == 0)
4969 recordregion(startloc, dest - (char *)stackblock(), 0);
4970 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4971 (dest - (char *)stackblock()) - startloc,
4972 (dest - (char *)stackblock()) - startloc,
4973 stackblock() + startloc));
4974}
4975
4976
4977static char *
Eric Andersen90898442003-08-06 11:20:52 +00004978scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4979 int zero)
4980{
Eric Andersenc470f442003-07-28 09:56:35 +00004981 char *loc;
4982 char *loc2;
4983 char c;
4984
4985 loc = startp;
4986 loc2 = rmesc;
4987 do {
4988 int match;
4989 const char *s = loc2;
4990 c = *loc2;
4991 if (zero) {
4992 *loc2 = '\0';
4993 s = rmesc;
4994 }
4995 match = pmatch(str, s);
4996 *loc2 = c;
4997 if (match)
4998 return loc;
4999 if (quotes && *loc == CTLESC)
5000 loc++;
5001 loc++;
5002 loc2++;
5003 } while (c);
5004 return 0;
5005}
5006
5007
5008static char *
Eric Andersen90898442003-08-06 11:20:52 +00005009scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5010 int zero)
5011{
Eric Andersenc470f442003-07-28 09:56:35 +00005012 int esc = 0;
5013 char *loc;
5014 char *loc2;
5015
5016 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5017 int match;
5018 char c = *loc2;
5019 const char *s = loc2;
5020 if (zero) {
5021 *loc2 = '\0';
5022 s = rmesc;
5023 }
5024 match = pmatch(str, s);
5025 *loc2 = c;
5026 if (match)
5027 return loc;
5028 loc--;
5029 if (quotes) {
5030 if (--esc < 0) {
5031 esc = esclen(startp, loc);
5032 }
5033 if (esc % 2) {
5034 esc--;
5035 loc--;
5036 }
5037 }
5038 }
5039 return 0;
5040}
5041
5042static const char *
5043subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5044{
5045 char *startp;
5046 char *loc;
5047 int saveherefd = herefd;
5048 struct nodelist *saveargbackq = argbackq;
5049 int amount;
5050 char *rmesc, *rmescend;
5051 int zero;
5052 char *(*scan)(char *, char *, char *, char *, int , int);
5053
5054 herefd = -1;
5055 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5056 STPUTC('\0', expdest);
5057 herefd = saveherefd;
5058 argbackq = saveargbackq;
5059 startp = stackblock() + startloc;
5060
5061 switch (subtype) {
5062 case VSASSIGN:
5063 setvar(str, startp, 0);
5064 amount = startp - expdest;
5065 STADJUST(amount, expdest);
5066 return startp;
5067
5068 case VSQUESTION:
5069 varunset(p, str, startp, varflags);
5070 /* NOTREACHED */
5071 }
5072
5073 subtype -= VSTRIMRIGHT;
5074#ifdef DEBUG
5075 if (subtype < 0 || subtype > 3)
5076 abort();
5077#endif
5078
5079 rmesc = startp;
5080 rmescend = stackblock() + strloc;
5081 if (quotes) {
5082 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5083 if (rmesc != startp) {
5084 rmescend = expdest;
5085 startp = stackblock() + startloc;
5086 }
5087 }
5088 rmescend--;
5089 str = stackblock() + strloc;
5090 preglob(str, varflags & VSQUOTE, 0);
5091
5092 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5093 zero = subtype >> 1;
5094 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5095 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5096
5097 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5098 if (loc) {
5099 if (zero) {
5100 memmove(startp, loc, str - loc);
5101 loc = startp + (str - loc) - 1;
5102 }
5103 *loc = '\0';
5104 amount = loc - expdest;
5105 STADJUST(amount, expdest);
5106 }
5107 return loc;
5108}
5109
5110
Eric Andersen62483552001-07-10 06:09:16 +00005111/*
5112 * Expand a variable, and return a pointer to the next character in the
5113 * input string.
5114 */
Eric Andersenc470f442003-07-28 09:56:35 +00005115static char *
5116evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005117{
5118 int subtype;
5119 int varflags;
5120 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005121 int patloc;
5122 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005123 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005124 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005125 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005126 int quotes;
5127 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005128
Eric Andersenc470f442003-07-28 09:56:35 +00005129 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005130 varflags = *p++;
5131 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005132 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005133 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005134 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005135 startloc = expdest - (char *)stackblock();
5136 p = strchr(p, '=') + 1;
5137
Eric Andersenc470f442003-07-28 09:56:35 +00005138again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005139 varlen = varvalue(var, varflags, flag);
5140 if (varflags & VSNUL)
5141 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005142
Glenn L McGrath76620622004-01-13 10:19:37 +00005143 if (subtype == VSPLUS) {
5144 varlen = -1 - varlen;
5145 goto vsplus;
5146 }
Eric Andersen62483552001-07-10 06:09:16 +00005147
Eric Andersenc470f442003-07-28 09:56:35 +00005148 if (subtype == VSMINUS) {
5149vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005150 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005151 argstr(
5152 p, flag | EXP_TILDE |
5153 (quoted ? EXP_QWORD : EXP_WORD)
5154 );
5155 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005156 }
5157 if (easy)
5158 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005159 goto end;
5160 }
Eric Andersen62483552001-07-10 06:09:16 +00005161
Eric Andersenc470f442003-07-28 09:56:35 +00005162 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005163 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005164 if (subevalvar(p, var, 0, subtype, startloc,
5165 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005166 varflags &= ~VSNUL;
5167 /*
5168 * Remove any recorded regions beyond
5169 * start of variable
5170 */
5171 removerecordregions(startloc);
5172 goto again;
5173 }
Eric Andersenc470f442003-07-28 09:56:35 +00005174 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005175 }
5176 if (easy)
5177 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005178 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005179 }
5180
Glenn L McGrath76620622004-01-13 10:19:37 +00005181 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005182 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005183
Eric Andersenc470f442003-07-28 09:56:35 +00005184 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005185 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005186 goto record;
5187 }
5188
5189 if (subtype == VSNORMAL) {
5190 if (!easy)
5191 goto end;
5192record:
5193 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5194 goto end;
5195 }
5196
5197#ifdef DEBUG
5198 switch (subtype) {
5199 case VSTRIMLEFT:
5200 case VSTRIMLEFTMAX:
5201 case VSTRIMRIGHT:
5202 case VSTRIMRIGHTMAX:
5203 break;
5204 default:
5205 abort();
5206 }
5207#endif
5208
Glenn L McGrath76620622004-01-13 10:19:37 +00005209 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005210 /*
5211 * Terminate the string and start recording the pattern
5212 * right after it
5213 */
5214 STPUTC('\0', expdest);
5215 patloc = expdest - (char *)stackblock();
5216 if (subevalvar(p, NULL, patloc, subtype,
5217 startloc, varflags, quotes) == 0) {
5218 int amount = expdest - (
5219 (char *)stackblock() + patloc - 1
5220 );
5221 STADJUST(-amount, expdest);
5222 }
5223 /* Remove any recorded regions beyond start of variable */
5224 removerecordregions(startloc);
5225 goto record;
5226 }
5227
5228end:
5229 if (subtype != VSNORMAL) { /* skip to end of alternative */
5230 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005231 for (;;) {
5232 if ((c = *p++) == CTLESC)
5233 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005234 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005235 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005236 argbackq = argbackq->next;
5237 } else if (c == CTLVAR) {
5238 if ((*p++ & VSTYPE) != VSNORMAL)
5239 nesting++;
5240 } else if (c == CTLENDVAR) {
5241 if (--nesting == 0)
5242 break;
5243 }
5244 }
5245 }
5246 return p;
5247}
5248
Eric Andersencb57d552001-06-28 07:25:16 +00005249
Eric Andersencb57d552001-06-28 07:25:16 +00005250/*
5251 * Put a string on the stack.
5252 */
5253
Eric Andersenc470f442003-07-28 09:56:35 +00005254static void
5255memtodest(const char *p, size_t len, int syntax, int quotes) {
5256 char *q = expdest;
5257
5258 q = makestrspace(len * 2, q);
5259
5260 while (len--) {
5261 int c = *p++;
5262 if (!c)
5263 continue;
5264 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5265 USTPUTC(CTLESC, q);
5266 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005267 }
Eric Andersenc470f442003-07-28 09:56:35 +00005268
5269 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005270}
5271
Eric Andersenc470f442003-07-28 09:56:35 +00005272
5273static void
5274strtodest(const char *p, int syntax, int quotes)
5275{
5276 memtodest(p, strlen(p), syntax, quotes);
5277}
5278
5279
Eric Andersencb57d552001-06-28 07:25:16 +00005280/*
5281 * Add the value of a specialized variable to the stack string.
5282 */
5283
Glenn L McGrath76620622004-01-13 10:19:37 +00005284static ssize_t
5285varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005286{
5287 int num;
5288 char *p;
5289 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005290 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005291 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005292 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005293 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005294 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005295 int quoted = varflags & VSQUOTE;
5296 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005297 int quotes = flags & (EXP_FULL | EXP_CASE);
5298
Glenn L McGrath76620622004-01-13 10:19:37 +00005299 if (quoted && (flags & EXP_FULL))
5300 sep = 1 << CHAR_BIT;
5301
Eric Andersencb57d552001-06-28 07:25:16 +00005302 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5303 switch (*name) {
5304 case '$':
5305 num = rootpid;
5306 goto numvar;
5307 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005308 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005309 goto numvar;
5310 case '#':
5311 num = shellparam.nparam;
5312 goto numvar;
5313 case '!':
5314 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005315 if (num == 0)
5316 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005317numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005318 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005319 break;
5320 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005321 p = makestrspace(NOPTS, expdest);
5322 for (i = NOPTS - 1; i >= 0; i--) {
5323 if (optlist[i]) {
5324 USTPUTC(optletters(i), p);
5325 len++;
5326 }
Eric Andersencb57d552001-06-28 07:25:16 +00005327 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005328 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005329 break;
5330 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005331 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005332 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005333 /* fall through */
5334 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005335 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005336 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5337 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005338param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005339 if (!(ap = shellparam.p))
5340 return -1;
5341 while ((p = *ap++)) {
5342 size_t partlen;
5343
5344 partlen = strlen(p);
5345
5346 len += partlen;
5347 if (len > partlen && sep) {
5348 char *q;
5349
5350 len++;
5351 if (subtype == VSPLUS || subtype == VSLENGTH) {
5352 continue;
5353 }
5354 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005355 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005356 STPUTC(CTLESC, q);
5357 STPUTC(sep, q);
5358 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005359 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005360
5361 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5362 memtodest(p, partlen, syntax, quotes);
Eric Andersencb57d552001-06-28 07:25:16 +00005363 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005364 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005365 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005366 case '1':
5367 case '2':
5368 case '3':
5369 case '4':
5370 case '5':
5371 case '6':
5372 case '7':
5373 case '8':
5374 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005375 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005376 if (num < 0 || num > shellparam.nparam)
5377 return -1;
5378 p = num ? shellparam.p[num - 1] : arg0;
5379 goto value;
5380 default:
5381 p = lookupvar(name);
5382value:
5383 if (!p)
5384 return -1;
5385
5386 len = strlen(p);
5387 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5388 memtodest(p, len, syntax, quotes);
5389 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005390 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005391
5392 if (subtype == VSPLUS || subtype == VSLENGTH)
5393 STADJUST(-len, expdest);
5394 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005395}
5396
5397
Eric Andersencb57d552001-06-28 07:25:16 +00005398/*
5399 * Record the fact that we have to scan this region of the
5400 * string for IFS characters.
5401 */
5402
Eric Andersenc470f442003-07-28 09:56:35 +00005403static void
5404recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005405{
5406 struct ifsregion *ifsp;
5407
5408 if (ifslastp == NULL) {
5409 ifsp = &ifsfirst;
5410 } else {
5411 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005412 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005413 ifsp->next = NULL;
5414 ifslastp->next = ifsp;
5415 INTON;
5416 }
5417 ifslastp = ifsp;
5418 ifslastp->begoff = start;
5419 ifslastp->endoff = end;
5420 ifslastp->nulonly = nulonly;
5421}
5422
5423
Eric Andersencb57d552001-06-28 07:25:16 +00005424/*
5425 * Break the argument string into pieces based upon IFS and add the
5426 * strings to the argument list. The regions of the string to be
5427 * searched for IFS characters have been stored by recordregion.
5428 */
Eric Andersenc470f442003-07-28 09:56:35 +00005429static void
5430ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005431{
Eric Andersencb57d552001-06-28 07:25:16 +00005432 struct ifsregion *ifsp;
5433 struct strlist *sp;
5434 char *start;
5435 char *p;
5436 char *q;
5437 const char *ifs, *realifs;
5438 int ifsspc;
5439 int nulonly;
5440
5441
5442 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005443 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005444 ifsspc = 0;
5445 nulonly = 0;
5446 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005447 ifsp = &ifsfirst;
5448 do {
5449 p = string + ifsp->begoff;
5450 nulonly = ifsp->nulonly;
5451 ifs = nulonly ? nullstr : realifs;
5452 ifsspc = 0;
5453 while (p < string + ifsp->endoff) {
5454 q = p;
5455 if (*p == CTLESC)
5456 p++;
5457 if (strchr(ifs, *p)) {
5458 if (!nulonly)
5459 ifsspc = (strchr(defifs, *p) != NULL);
5460 /* Ignore IFS whitespace at start */
5461 if (q == start && ifsspc) {
5462 p++;
5463 start = p;
5464 continue;
5465 }
5466 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005467 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005468 sp->text = start;
5469 *arglist->lastp = sp;
5470 arglist->lastp = &sp->next;
5471 p++;
5472 if (!nulonly) {
5473 for (;;) {
5474 if (p >= string + ifsp->endoff) {
5475 break;
5476 }
5477 q = p;
5478 if (*p == CTLESC)
5479 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005480 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005481 p = q;
5482 break;
5483 } else if (strchr(defifs, *p) == NULL) {
5484 if (ifsspc) {
5485 p++;
5486 ifsspc = 0;
5487 } else {
5488 p = q;
5489 break;
5490 }
5491 } else
5492 p++;
5493 }
5494 }
5495 start = p;
5496 } else
5497 p++;
5498 }
5499 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005500 if (nulonly)
5501 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005502 }
5503
Eric Andersenc470f442003-07-28 09:56:35 +00005504 if (!*start)
5505 return;
5506
5507add:
5508 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005509 sp->text = start;
5510 *arglist->lastp = sp;
5511 arglist->lastp = &sp->next;
5512}
5513
Eric Andersenc470f442003-07-28 09:56:35 +00005514static void
5515ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005516{
Eric Andersenc470f442003-07-28 09:56:35 +00005517 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005518
Eric Andersenc470f442003-07-28 09:56:35 +00005519 INTOFF;
5520 p = ifsfirst.next;
5521 do {
5522 struct ifsregion *ifsp;
5523 ifsp = p->next;
5524 ckfree(p);
5525 p = ifsp;
5526 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005527 ifslastp = NULL;
5528 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005529 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005530}
5531
Eric Andersen90898442003-08-06 11:20:52 +00005532static void expmeta(char *, char *);
5533static struct strlist *expsort(struct strlist *);
5534static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005535
Eric Andersen90898442003-08-06 11:20:52 +00005536static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005537
Eric Andersencb57d552001-06-28 07:25:16 +00005538
Eric Andersenc470f442003-07-28 09:56:35 +00005539static void
Eric Andersen90898442003-08-06 11:20:52 +00005540expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005541{
Eric Andersen90898442003-08-06 11:20:52 +00005542 static const char metachars[] = {
5543 '*', '?', '[', 0
5544 };
Eric Andersencb57d552001-06-28 07:25:16 +00005545 /* TODO - EXP_REDIR */
5546
5547 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005548 struct strlist **savelastp;
5549 struct strlist *sp;
5550 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005551
Eric Andersencb57d552001-06-28 07:25:16 +00005552 if (fflag)
5553 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005554 if (!strpbrk(str->text, metachars))
5555 goto nometa;
5556 savelastp = exparg.lastp;
5557
Eric Andersencb57d552001-06-28 07:25:16 +00005558 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005559 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005560 {
5561 int i = strlen(str->text);
5562 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5563 }
5564
5565 expmeta(expdir, p);
5566 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005567 if (p != str->text)
5568 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005569 INTON;
5570 if (exparg.lastp == savelastp) {
5571 /*
5572 * no matches
5573 */
Eric Andersenc470f442003-07-28 09:56:35 +00005574nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005575 *exparg.lastp = str;
5576 rmescapes(str->text);
5577 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005578 } else {
5579 *exparg.lastp = NULL;
5580 *savelastp = sp = expsort(*savelastp);
5581 while (sp->next != NULL)
5582 sp = sp->next;
5583 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005584 }
5585 str = str->next;
5586 }
5587}
5588
Eric Andersencb57d552001-06-28 07:25:16 +00005589/*
Eric Andersenc470f442003-07-28 09:56:35 +00005590 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005591 */
5592
Eric Andersenc470f442003-07-28 09:56:35 +00005593static void
Eric Andersen90898442003-08-06 11:20:52 +00005594addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005595{
Eric Andersencb57d552001-06-28 07:25:16 +00005596 struct strlist *sp;
5597
Eric Andersenc470f442003-07-28 09:56:35 +00005598 sp = (struct strlist *)stalloc(sizeof *sp);
5599 sp->text = sstrdup(name);
5600 *exparg.lastp = sp;
5601 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005602}
5603
5604
Eric Andersencb57d552001-06-28 07:25:16 +00005605/*
Eric Andersen90898442003-08-06 11:20:52 +00005606 * Do metacharacter (i.e. *, ?, [...]) expansion.
5607 */
5608
5609static void
5610expmeta(char *enddir, char *name)
5611{
5612 char *p;
5613 const char *cp;
5614 char *start;
5615 char *endname;
5616 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005617 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005618 DIR *dirp;
5619 struct dirent *dp;
5620 int atend;
5621 int matchdot;
5622
5623 metaflag = 0;
5624 start = name;
5625 for (p = name; *p; p++) {
5626 if (*p == '*' || *p == '?')
5627 metaflag = 1;
5628 else if (*p == '[') {
5629 char *q = p + 1;
5630 if (*q == '!')
5631 q++;
5632 for (;;) {
5633 if (*q == '\\')
5634 q++;
5635 if (*q == '/' || *q == '\0')
5636 break;
5637 if (*++q == ']') {
5638 metaflag = 1;
5639 break;
5640 }
5641 }
5642 } else if (*p == '\\')
5643 p++;
5644 else if (*p == '/') {
5645 if (metaflag)
5646 goto out;
5647 start = p + 1;
5648 }
5649 }
5650out:
5651 if (metaflag == 0) { /* we've reached the end of the file name */
5652 if (enddir != expdir)
5653 metaflag++;
5654 p = name;
5655 do {
5656 if (*p == '\\')
5657 p++;
5658 *enddir++ = *p;
5659 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005660 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005661 addfname(expdir);
5662 return;
5663 }
5664 endname = p;
5665 if (name < start) {
5666 p = name;
5667 do {
5668 if (*p == '\\')
5669 p++;
5670 *enddir++ = *p++;
5671 } while (p < start);
5672 }
5673 if (enddir == expdir) {
5674 cp = ".";
5675 } else if (enddir == expdir + 1 && *expdir == '/') {
5676 cp = "/";
5677 } else {
5678 cp = expdir;
5679 enddir[-1] = '\0';
5680 }
5681 if ((dirp = opendir(cp)) == NULL)
5682 return;
5683 if (enddir != expdir)
5684 enddir[-1] = '/';
5685 if (*endname == 0) {
5686 atend = 1;
5687 } else {
5688 atend = 0;
5689 *endname++ = '\0';
5690 }
5691 matchdot = 0;
5692 p = start;
5693 if (*p == '\\')
5694 p++;
5695 if (*p == '.')
5696 matchdot++;
5697 while (! intpending && (dp = readdir(dirp)) != NULL) {
5698 if (dp->d_name[0] == '.' && ! matchdot)
5699 continue;
5700 if (pmatch(start, dp->d_name)) {
5701 if (atend) {
5702 scopy(dp->d_name, enddir);
5703 addfname(expdir);
5704 } else {
5705 for (p = enddir, cp = dp->d_name;
5706 (*p++ = *cp++) != '\0';)
5707 continue;
5708 p[-1] = '/';
5709 expmeta(p, endname);
5710 }
5711 }
5712 }
5713 closedir(dirp);
5714 if (! atend)
5715 endname[-1] = '/';
5716}
5717
5718/*
5719 * Sort the results of file name expansion. It calculates the number of
5720 * strings to sort and then calls msort (short for merge sort) to do the
5721 * work.
5722 */
5723
5724static struct strlist *
5725expsort(struct strlist *str)
5726{
5727 int len;
5728 struct strlist *sp;
5729
5730 len = 0;
5731 for (sp = str ; sp ; sp = sp->next)
5732 len++;
5733 return msort(str, len);
5734}
5735
5736
5737static struct strlist *
5738msort(struct strlist *list, int len)
5739{
5740 struct strlist *p, *q = NULL;
5741 struct strlist **lpp;
5742 int half;
5743 int n;
5744
5745 if (len <= 1)
5746 return list;
5747 half = len >> 1;
5748 p = list;
5749 for (n = half ; --n >= 0 ; ) {
5750 q = p;
5751 p = p->next;
5752 }
5753 q->next = NULL; /* terminate first half of list */
5754 q = msort(list, half); /* sort first half of list */
5755 p = msort(p, len - half); /* sort second half */
5756 lpp = &list;
5757 for (;;) {
5758#ifdef CONFIG_LOCALE_SUPPORT
5759 if (strcoll(p->text, q->text) < 0)
5760#else
5761 if (strcmp(p->text, q->text) < 0)
5762#endif
5763 {
5764 *lpp = p;
5765 lpp = &p->next;
5766 if ((p = *lpp) == NULL) {
5767 *lpp = q;
5768 break;
5769 }
5770 } else {
5771 *lpp = q;
5772 lpp = &q->next;
5773 if ((q = *lpp) == NULL) {
5774 *lpp = p;
5775 break;
5776 }
5777 }
5778 }
5779 return list;
5780}
5781
5782
5783/*
Eric Andersencb57d552001-06-28 07:25:16 +00005784 * Returns true if the pattern matches the string.
5785 */
5786
Eric Andersenc470f442003-07-28 09:56:35 +00005787static inline int
5788patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005789{
Eric Andersenc470f442003-07-28 09:56:35 +00005790 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005791}
5792
5793
Eric Andersencb57d552001-06-28 07:25:16 +00005794/*
5795 * Remove any CTLESC characters from a string.
5796 */
5797
Eric Andersenc470f442003-07-28 09:56:35 +00005798static char *
5799_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005800{
5801 char *p, *q, *r;
5802 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005803 unsigned inquotes;
5804 int notescaped;
5805 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005806
5807 p = strpbrk(str, qchars);
5808 if (!p) {
5809 return str;
5810 }
5811 q = p;
5812 r = str;
5813 if (flag & RMESCAPE_ALLOC) {
5814 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005815 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005816
Eric Andersenc470f442003-07-28 09:56:35 +00005817 if (flag & RMESCAPE_GROW) {
5818 r = makestrspace(fulllen, expdest);
5819 } else if (flag & RMESCAPE_HEAP) {
5820 r = ckmalloc(fulllen);
5821 } else {
5822 r = stalloc(fulllen);
5823 }
5824 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005825 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005826 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005827 }
5828 }
Eric Andersenc470f442003-07-28 09:56:35 +00005829 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5830 globbing = flag & RMESCAPE_GLOB;
5831 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005832 while (*p) {
5833 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005834 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005835 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005836 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005837 continue;
5838 }
Eric Andersenc470f442003-07-28 09:56:35 +00005839 if (*p == '\\') {
5840 /* naked back slash */
5841 notescaped = 0;
5842 goto copy;
5843 }
Eric Andersencb57d552001-06-28 07:25:16 +00005844 if (*p == CTLESC) {
5845 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005846 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005847 *q++ = '\\';
5848 }
5849 }
Eric Andersenc470f442003-07-28 09:56:35 +00005850 notescaped = globbing;
5851copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005852 *q++ = *p++;
5853 }
5854 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005855 if (flag & RMESCAPE_GROW) {
5856 expdest = r;
5857 STADJUST(q - r + 1, expdest);
5858 }
Eric Andersencb57d552001-06-28 07:25:16 +00005859 return r;
5860}
Eric Andersencb57d552001-06-28 07:25:16 +00005861
5862
Eric Andersencb57d552001-06-28 07:25:16 +00005863/*
5864 * See if a pattern matches in a case statement.
5865 */
5866
Eric Andersenc470f442003-07-28 09:56:35 +00005867int
5868casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005869{
Eric Andersencb57d552001-06-28 07:25:16 +00005870 struct stackmark smark;
5871 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005872
5873 setstackmark(&smark);
5874 argbackq = pattern->narg.backquote;
5875 STARTSTACKSTR(expdest);
5876 ifslastp = NULL;
5877 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005878 STACKSTRNUL(expdest);
5879 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005880 popstackmark(&smark);
5881 return result;
5882}
5883
5884/*
5885 * Our own itoa().
5886 */
5887
Eric Andersenc470f442003-07-28 09:56:35 +00005888static int
5889cvtnum(long num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005890{
Eric Andersencb57d552001-06-28 07:25:16 +00005891 int len;
5892
Eric Andersenc470f442003-07-28 09:56:35 +00005893 expdest = makestrspace(32, expdest);
5894 len = fmtstr(expdest, 32, "%ld", num);
5895 STADJUST(len, expdest);
5896 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005897}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005898
Eric Andersenc470f442003-07-28 09:56:35 +00005899static void
5900varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005901{
Eric Andersenc470f442003-07-28 09:56:35 +00005902 const char *msg;
5903 const char *tail;
5904
5905 tail = nullstr;
5906 msg = "parameter not set";
5907 if (umsg) {
5908 if (*end == CTLENDVAR) {
5909 if (varflags & VSNUL)
5910 tail = " or null";
5911 } else
5912 msg = umsg;
5913 }
5914 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005915}
Eric Andersen90898442003-08-06 11:20:52 +00005916
5917
Eric Andersenc470f442003-07-28 09:56:35 +00005918/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005919
Eric Andersencb57d552001-06-28 07:25:16 +00005920/*
Eric Andersen90898442003-08-06 11:20:52 +00005921 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005922 */
5923
Eric Andersenc470f442003-07-28 09:56:35 +00005924#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5925#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005926
Eric Andersenc470f442003-07-28 09:56:35 +00005927static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005928
Eric Andersencb57d552001-06-28 07:25:16 +00005929/*
5930 * Read a line from the script.
5931 */
5932
Eric Andersenc470f442003-07-28 09:56:35 +00005933static inline char *
5934pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005935{
5936 char *p = line;
5937 int nleft = len;
5938 int c;
5939
5940 while (--nleft > 0) {
5941 c = pgetc2();
5942 if (c == PEOF) {
5943 if (p == line)
5944 return NULL;
5945 break;
5946 }
5947 *p++ = c;
5948 if (c == '\n')
5949 break;
5950 }
5951 *p = '\0';
5952 return line;
5953}
5954
Eric Andersenc470f442003-07-28 09:56:35 +00005955
5956/*
5957 * Read a character from the script, returning PEOF on end of file.
5958 * Nul characters in the input are silently discarded.
5959 */
5960
5961#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5962
5963#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5964#define pgetc_macro() pgetc()
5965static int
5966pgetc(void)
5967{
5968 return pgetc_as_macro();
5969}
5970#else
5971#define pgetc_macro() pgetc_as_macro()
5972static int
5973pgetc(void)
5974{
5975 return pgetc_macro();
5976}
5977#endif
5978
5979
5980/*
5981 * Same as pgetc(), but ignores PEOA.
5982 */
5983#ifdef CONFIG_ASH_ALIAS
5984static int pgetc2(void)
5985{
5986 int c;
5987
5988 do {
5989 c = pgetc_macro();
5990 } while (c == PEOA);
5991 return c;
5992}
5993#else
5994static inline int pgetc2(void)
5995{
5996 return pgetc_macro();
5997}
5998#endif
5999
6000
6001#ifdef CONFIG_FEATURE_COMMAND_EDITING
6002static const char *cmdedit_prompt;
6003static inline void putprompt(const char *s)
6004{
6005 cmdedit_prompt = s;
6006}
6007#else
6008static inline void putprompt(const char *s)
6009{
6010 out2str(s);
6011}
6012#endif
6013
6014static inline int
6015preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006016{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006017 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006018 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006019 parsenextc = buf;
6020
Eric Andersenc470f442003-07-28 09:56:35 +00006021retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006022#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006023 if (!iflag || parsefile->fd)
6024 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6025 else {
Eric Andersenfa06a772004-02-06 10:33:19 +00006026 cmdedit_path_lookup = pathval();
Eric Andersenc470f442003-07-28 09:56:35 +00006027 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6028 if(nr == 0) {
6029 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006030 if(trap[SIGINT]) {
6031 buf[0] = '\n';
6032 buf[1] = 0;
6033 raise(SIGINT);
6034 return 1;
6035 }
Eric Andersenc470f442003-07-28 09:56:35 +00006036 goto retry;
6037 }
6038 if(nr < 0) {
6039 /* Ctrl+D presend */
6040 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006041 }
Eric Andersencb57d552001-06-28 07:25:16 +00006042 }
6043#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006044 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006045#endif
6046
6047 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006048 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6049 int flags = fcntl(0, F_GETFL, 0);
6050 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006051 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006052 if (fcntl(0, F_SETFL, flags) >= 0) {
6053 out2str("sh: turning off NDELAY mode\n");
6054 goto retry;
6055 }
6056 }
6057 }
6058 }
6059 return nr;
6060}
6061
6062/*
6063 * Refill the input buffer and return the next input character:
6064 *
6065 * 1) If a string was pushed back on the input, pop it;
6066 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6067 * from a string so we can't refill the buffer, return EOF.
6068 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6069 * 4) Process input up to the next newline, deleting nul characters.
6070 */
6071
Eric Andersenc470f442003-07-28 09:56:35 +00006072int
6073preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006074{
6075 char *p, *q;
6076 int more;
6077 char savec;
6078
6079 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006080#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006081 if (parsenleft == -1 && parsefile->strpush->ap &&
6082 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006083 return PEOA;
6084 }
Eric Andersen2870d962001-07-02 17:27:21 +00006085#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006086 popstring();
6087 if (--parsenleft >= 0)
6088 return (*parsenextc++);
6089 }
6090 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6091 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006092 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006093
Eric Andersenc470f442003-07-28 09:56:35 +00006094again:
Eric Andersencb57d552001-06-28 07:25:16 +00006095 if (parselleft <= 0) {
6096 if ((parselleft = preadfd()) <= 0) {
6097 parselleft = parsenleft = EOF_NLEFT;
6098 return PEOF;
6099 }
6100 }
6101
6102 q = p = parsenextc;
6103
6104 /* delete nul characters */
6105 for (more = 1; more;) {
6106 switch (*p) {
6107 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006108 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006109 goto check;
6110
Eric Andersencb57d552001-06-28 07:25:16 +00006111 case '\n':
6112 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006113 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006114 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006115
Eric Andersencb57d552001-06-28 07:25:16 +00006116 }
6117
6118 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006119check:
Eric Andersencb57d552001-06-28 07:25:16 +00006120 if (--parselleft <= 0 && more) {
6121 parsenleft = q - parsenextc - 1;
6122 if (parsenleft < 0)
6123 goto again;
6124 more = 0;
6125 }
6126 }
6127
6128 savec = *q;
6129 *q = '\0';
6130
6131 if (vflag) {
6132 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006133 }
6134
6135 *q = savec;
6136
6137 return *parsenextc++;
6138}
6139
Eric Andersenc470f442003-07-28 09:56:35 +00006140/*
6141 * Undo the last call to pgetc. Only one character may be pushed back.
6142 * PEOF may be pushed back.
6143 */
6144
6145void
6146pungetc(void)
6147{
6148 parsenleft++;
6149 parsenextc--;
6150}
Eric Andersencb57d552001-06-28 07:25:16 +00006151
6152/*
6153 * Push a string back onto the input at this current parsefile level.
6154 * We handle aliases this way.
6155 */
Eric Andersenc470f442003-07-28 09:56:35 +00006156void
6157pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006158{
Eric Andersencb57d552001-06-28 07:25:16 +00006159 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006160 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006161
Eric Andersenc470f442003-07-28 09:56:35 +00006162 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006163 INTOFF;
6164/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6165 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006166 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006167 sp->prev = parsefile->strpush;
6168 parsefile->strpush = sp;
6169 } else
6170 sp = parsefile->strpush = &(parsefile->basestrpush);
6171 sp->prevstring = parsenextc;
6172 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006173#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006174 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006175 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006176 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006177 sp->string = s;
6178 }
Eric Andersen2870d962001-07-02 17:27:21 +00006179#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006180 parsenextc = s;
6181 parsenleft = len;
6182 INTON;
6183}
6184
Eric Andersenc470f442003-07-28 09:56:35 +00006185void
6186popstring(void)
6187{
6188 struct strpush *sp = parsefile->strpush;
6189
6190 INTOFF;
6191#ifdef CONFIG_ASH_ALIAS
6192 if (sp->ap) {
6193 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6194 checkkwd |= CHKALIAS;
6195 }
6196 if (sp->string != sp->ap->val) {
6197 ckfree(sp->string);
6198 }
6199 sp->ap->flag &= ~ALIASINUSE;
6200 if (sp->ap->flag & ALIASDEAD) {
6201 unalias(sp->ap->name);
6202 }
6203 }
6204#endif
6205 parsenextc = sp->prevstring;
6206 parsenleft = sp->prevnleft;
6207/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6208 parsefile->strpush = sp->prev;
6209 if (sp != &(parsefile->basestrpush))
6210 ckfree(sp);
6211 INTON;
6212}
6213
6214/*
6215 * Set the input to take input from a file. If push is set, push the
6216 * old input onto the stack first.
6217 */
6218
6219void
6220setinputfile(const char *fname, int push)
6221{
6222 int fd;
6223 int fd2;
6224
6225 INTOFF;
6226 if ((fd = open(fname, O_RDONLY)) < 0)
6227 error("Can't open %s", fname);
6228 if (fd < 10) {
6229 fd2 = copyfd(fd, 10);
6230 close(fd);
6231 if (fd2 < 0)
6232 error("Out of file descriptors");
6233 fd = fd2;
6234 }
6235 setinputfd(fd, push);
6236 INTON;
6237}
6238
6239
6240/*
6241 * Like setinputfile, but takes an open file descriptor. Call this with
6242 * interrupts off.
6243 */
6244
6245static void
6246setinputfd(int fd, int push)
6247{
6248 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6249 if (push) {
6250 pushfile();
6251 parsefile->buf = 0;
6252 }
6253 parsefile->fd = fd;
6254 if (parsefile->buf == NULL)
6255 parsefile->buf = ckmalloc(IBUFSIZ);
6256 parselleft = parsenleft = 0;
6257 plinno = 1;
6258}
6259
Eric Andersencb57d552001-06-28 07:25:16 +00006260
Eric Andersencb57d552001-06-28 07:25:16 +00006261/*
6262 * Like setinputfile, but takes input from a string.
6263 */
6264
Eric Andersenc470f442003-07-28 09:56:35 +00006265static void
6266setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006267{
Eric Andersencb57d552001-06-28 07:25:16 +00006268 INTOFF;
6269 pushfile();
6270 parsenextc = string;
6271 parsenleft = strlen(string);
6272 parsefile->buf = NULL;
6273 plinno = 1;
6274 INTON;
6275}
6276
6277
Eric Andersencb57d552001-06-28 07:25:16 +00006278/*
6279 * To handle the "." command, a stack of input files is used. Pushfile
6280 * adds a new entry to the stack and popfile restores the previous level.
6281 */
6282
Eric Andersenc470f442003-07-28 09:56:35 +00006283static void
6284pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006285{
Eric Andersencb57d552001-06-28 07:25:16 +00006286 struct parsefile *pf;
6287
6288 parsefile->nleft = parsenleft;
6289 parsefile->lleft = parselleft;
6290 parsefile->nextc = parsenextc;
6291 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006292 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006293 pf->prev = parsefile;
6294 pf->fd = -1;
6295 pf->strpush = NULL;
6296 pf->basestrpush.prev = NULL;
6297 parsefile = pf;
6298}
6299
Eric Andersenc470f442003-07-28 09:56:35 +00006300
6301static void
6302popfile(void)
6303{
6304 struct parsefile *pf = parsefile;
6305
6306 INTOFF;
6307 if (pf->fd >= 0)
6308 close(pf->fd);
6309 if (pf->buf)
6310 ckfree(pf->buf);
6311 while (pf->strpush)
6312 popstring();
6313 parsefile = pf->prev;
6314 ckfree(pf);
6315 parsenleft = parsefile->nleft;
6316 parselleft = parsefile->lleft;
6317 parsenextc = parsefile->nextc;
6318 plinno = parsefile->linno;
6319 INTON;
6320}
Eric Andersencb57d552001-06-28 07:25:16 +00006321
6322
Eric Andersen2870d962001-07-02 17:27:21 +00006323/*
Eric Andersenc470f442003-07-28 09:56:35 +00006324 * Return to top level.
6325 */
Eric Andersen2870d962001-07-02 17:27:21 +00006326
Eric Andersenc470f442003-07-28 09:56:35 +00006327static void
6328popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006329{
Eric Andersenc470f442003-07-28 09:56:35 +00006330 while (parsefile != &basepf)
6331 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006332}
6333
Eric Andersen2870d962001-07-02 17:27:21 +00006334
Eric Andersenc470f442003-07-28 09:56:35 +00006335/*
6336 * Close the file(s) that the shell is reading commands from. Called
6337 * after a fork is done.
6338 */
6339
6340static void
6341closescript(void)
6342{
6343 popallfiles();
6344 if (parsefile->fd > 0) {
6345 close(parsefile->fd);
6346 parsefile->fd = 0;
6347 }
6348}
Eric Andersenc470f442003-07-28 09:56:35 +00006349
Eric Andersen90898442003-08-06 11:20:52 +00006350/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006351
6352/* mode flags for set_curjob */
6353#define CUR_DELETE 2
6354#define CUR_RUNNING 1
6355#define CUR_STOPPED 0
6356
6357/* mode flags for dowait */
6358#define DOWAIT_NORMAL 0
6359#define DOWAIT_BLOCK 1
6360
6361/* array of jobs */
6362static struct job *jobtab;
6363/* size of array */
6364static unsigned njobs;
6365#if JOBS
6366/* pgrp of shell on invocation */
6367static int initialpgrp;
6368static int ttyfd = -1;
6369#endif
6370/* current job */
6371static struct job *curjob;
6372/* number of presumed living untracked jobs */
6373static int jobless;
6374
6375static void set_curjob(struct job *, unsigned);
6376#if JOBS
6377static int restartjob(struct job *, int);
6378static void xtcsetpgrp(int, pid_t);
6379static char *commandtext(union node *);
6380static void cmdlist(union node *, int);
6381static void cmdtxt(union node *);
6382static void cmdputs(const char *);
6383static void showpipe(struct job *, FILE *);
6384#endif
6385static int sprint_status(char *, int, int);
6386static void freejob(struct job *);
6387static struct job *getjob(const char *, int);
6388static struct job *growjobtab(void);
6389static void forkchild(struct job *, union node *, int);
6390static void forkparent(struct job *, union node *, int, pid_t);
6391static int dowait(int, struct job *);
6392static int getstatus(struct job *);
6393
6394static void
6395set_curjob(struct job *jp, unsigned mode)
6396{
6397 struct job *jp1;
6398 struct job **jpp, **curp;
6399
6400 /* first remove from list */
6401 jpp = curp = &curjob;
6402 do {
6403 jp1 = *jpp;
6404 if (jp1 == jp)
6405 break;
6406 jpp = &jp1->prev_job;
6407 } while (1);
6408 *jpp = jp1->prev_job;
6409
6410 /* Then re-insert in correct position */
6411 jpp = curp;
6412 switch (mode) {
6413 default:
6414#ifdef DEBUG
6415 abort();
6416#endif
6417 case CUR_DELETE:
6418 /* job being deleted */
6419 break;
6420 case CUR_RUNNING:
6421 /* newly created job or backgrounded job,
6422 put after all stopped jobs. */
6423 do {
6424 jp1 = *jpp;
6425#ifdef JOBS
6426 if (!jp1 || jp1->state != JOBSTOPPED)
6427#endif
6428 break;
6429 jpp = &jp1->prev_job;
6430 } while (1);
6431 /* FALLTHROUGH */
6432#ifdef JOBS
6433 case CUR_STOPPED:
6434#endif
6435 /* newly stopped job - becomes curjob */
6436 jp->prev_job = *jpp;
6437 *jpp = jp;
6438 break;
6439 }
6440}
6441
6442#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006443/*
6444 * Turn job control on and off.
6445 *
6446 * Note: This code assumes that the third arg to ioctl is a character
6447 * pointer, which is true on Berkeley systems but not System V. Since
6448 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006449 *
6450 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006451 */
6452
Eric Andersenc470f442003-07-28 09:56:35 +00006453void
6454setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006455{
Eric Andersenc470f442003-07-28 09:56:35 +00006456 int fd;
6457 int pgrp;
6458
6459 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006460 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006461 if (on) {
6462 int ofd;
6463 ofd = fd = open(_PATH_TTY, O_RDWR);
6464 if (fd < 0) {
6465 fd += 3;
6466 while (!isatty(fd) && --fd >= 0)
6467 ;
6468 }
6469 fd = fcntl(fd, F_DUPFD, 10);
6470 close(ofd);
6471 if (fd < 0)
6472 goto out;
6473 fcntl(fd, F_SETFD, FD_CLOEXEC);
6474 do { /* while we are in the background */
6475 if ((pgrp = tcgetpgrp(fd)) < 0) {
6476out:
6477 sh_warnx("can't access tty; job control turned off");
6478 mflag = on = 0;
6479 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006480 }
Eric Andersenc470f442003-07-28 09:56:35 +00006481 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006482 break;
6483 killpg(0, SIGTTIN);
6484 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006485 initialpgrp = pgrp;
6486
Eric Andersencb57d552001-06-28 07:25:16 +00006487 setsignal(SIGTSTP);
6488 setsignal(SIGTTOU);
6489 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006490 pgrp = rootpid;
6491 setpgid(0, pgrp);
6492 xtcsetpgrp(fd, pgrp);
6493 } else {
6494 /* turning job control off */
6495 fd = ttyfd;
6496 pgrp = initialpgrp;
6497 xtcsetpgrp(fd, pgrp);
6498 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006499 setsignal(SIGTSTP);
6500 setsignal(SIGTTOU);
6501 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006502close:
6503 close(fd);
6504 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006505 }
Eric Andersenc470f442003-07-28 09:56:35 +00006506 ttyfd = fd;
6507 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006508}
Eric Andersencb57d552001-06-28 07:25:16 +00006509
Eric Andersenc470f442003-07-28 09:56:35 +00006510static int
Eric Andersen90898442003-08-06 11:20:52 +00006511killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006512{
6513 int signo = -1;
6514 int list = 0;
6515 int i;
6516 pid_t pid;
6517 struct job *jp;
6518
6519 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006520usage:
6521 error(
6522"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6523"kill -l [exitstatus]"
6524 );
Eric Andersencb57d552001-06-28 07:25:16 +00006525 }
6526
Eric Andersenc470f442003-07-28 09:56:35 +00006527 if (**++argv == '-') {
6528 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006529 if (signo < 0) {
6530 int c;
6531
6532 while ((c = nextopt("ls:")) != '\0')
6533 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006534 default:
6535#ifdef DEBUG
6536 abort();
6537#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006538 case 'l':
6539 list = 1;
6540 break;
6541 case 's':
6542 signo = decode_signal(optionarg, 1);
6543 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006544 error(
6545 "invalid signal number or name: %s",
6546 optionarg
6547 );
Eric Andersencb57d552001-06-28 07:25:16 +00006548 }
Eric Andersen2870d962001-07-02 17:27:21 +00006549 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006550 }
Eric Andersenc470f442003-07-28 09:56:35 +00006551 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006552 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006553 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006554 }
6555
6556 if (!list && signo < 0)
6557 signo = SIGTERM;
6558
Eric Andersenc470f442003-07-28 09:56:35 +00006559 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006560 goto usage;
6561 }
6562
6563 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006564 const char *name;
6565
Eric Andersenc470f442003-07-28 09:56:35 +00006566 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006567 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006568 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006569 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006570 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006571 }
6572 return 0;
6573 }
Eric Andersen34506362001-08-02 05:02:46 +00006574 name = u_signal_names(*argptr, &signo, -1);
6575 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006576 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006577 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006578 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006579 return 0;
6580 }
6581
Eric Andersenc470f442003-07-28 09:56:35 +00006582 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006583 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006584 if (**argv == '%') {
6585 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006586 pid = -jp->ps[0].pid;
6587 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006588 pid = number(*argv);
6589 if (kill(pid, signo) != 0) {
6590 sh_warnx("%m\n");
6591 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006592 }
Eric Andersenc470f442003-07-28 09:56:35 +00006593 } while (*++argv);
6594
6595 return i;
6596}
6597#endif /* JOBS */
6598
6599#if defined(JOBS) || defined(DEBUG)
6600static int
6601jobno(const struct job *jp)
6602{
6603 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006604}
6605#endif
6606
Eric Andersenc470f442003-07-28 09:56:35 +00006607#ifdef JOBS
6608static int
6609fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006610{
Eric Andersenc470f442003-07-28 09:56:35 +00006611 struct job *jp;
6612 FILE *out;
6613 int mode;
6614 int retval;
6615
6616 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6617 nextopt(nullstr);
6618 argv = argptr;
6619 out = stdout;
6620 do {
6621 jp = getjob(*argv, 1);
6622 if (mode == FORK_BG) {
6623 set_curjob(jp, CUR_RUNNING);
6624 fprintf(out, "[%d] ", jobno(jp));
6625 }
6626 outstr(jp->ps->cmd, out);
6627 showpipe(jp, out);
6628 retval = restartjob(jp, mode);
6629 } while (*argv && *++argv);
6630 return retval;
6631}
6632
6633static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6634
6635
6636static int
6637restartjob(struct job *jp, int mode)
6638{
6639 struct procstat *ps;
6640 int i;
6641 int status;
6642 pid_t pgid;
6643
6644 INTOFF;
6645 if (jp->state == JOBDONE)
6646 goto out;
6647 jp->state = JOBRUNNING;
6648 pgid = jp->ps->pid;
6649 if (mode == FORK_FG)
6650 xtcsetpgrp(ttyfd, pgid);
6651 killpg(pgid, SIGCONT);
6652 ps = jp->ps;
6653 i = jp->nprocs;
6654 do {
6655 if (WIFSTOPPED(ps->status)) {
6656 ps->status = -1;
6657 }
6658 } while (ps++, --i);
6659out:
6660 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6661 INTON;
6662 return status;
6663}
6664#endif
6665
6666static int
6667sprint_status(char *s, int status, int sigonly)
6668{
6669 int col;
6670 int st;
6671
6672 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006673 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006674#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006675 if (WIFSTOPPED(status))
6676 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006677 else
Eric Andersenc470f442003-07-28 09:56:35 +00006678#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006679 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006680 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006681 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006682 goto out;
6683#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006684 if (WIFSTOPPED(status))
6685 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006686#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006687 }
6688 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006689 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006690 if (WCOREDUMP(status)) {
6691 col += fmtstr(s + col, 16, " (core dumped)");
6692 }
6693 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006694 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006695 if (st)
6696 col = fmtstr(s, 16, "Done(%d)", st);
6697 else
6698 col = fmtstr(s, 16, "Done");
6699 }
6700
6701out:
6702 return col;
6703}
6704
6705#if JOBS
6706static void
6707showjob(FILE *out, struct job *jp, int mode)
6708{
6709 struct procstat *ps;
6710 struct procstat *psend;
6711 int col;
6712 int indent;
6713 char s[80];
6714
6715 ps = jp->ps;
6716
6717 if (mode & SHOW_PGID) {
6718 /* just output process (group) id of pipeline */
6719 fprintf(out, "%d\n", ps->pid);
6720 return;
6721 }
6722
6723 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6724 indent = col;
6725
6726 if (jp == curjob)
6727 s[col - 2] = '+';
6728 else if (curjob && jp == curjob->prev_job)
6729 s[col - 2] = '-';
6730
6731 if (mode & SHOW_PID)
6732 col += fmtstr(s + col, 16, "%d ", ps->pid);
6733
6734 psend = ps + jp->nprocs;
6735
6736 if (jp->state == JOBRUNNING) {
6737 scopy("Running", s + col);
6738 col += strlen("Running");
6739 } else {
6740 int status = psend[-1].status;
6741#if JOBS
6742 if (jp->state == JOBSTOPPED)
6743 status = jp->stopstatus;
6744#endif
6745 col += sprint_status(s + col, status, 0);
6746 }
6747
6748 goto start;
6749
6750 do {
6751 /* for each process */
6752 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6753
6754start:
Eric Andersen90898442003-08-06 11:20:52 +00006755 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006756 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6757 );
6758 if (!(mode & SHOW_PID)) {
6759 showpipe(jp, out);
6760 break;
6761 }
6762 if (++ps == psend) {
6763 outcslow('\n', out);
6764 break;
6765 }
6766 } while (1);
6767
6768 jp->changed = 0;
6769
6770 if (jp->state == JOBDONE) {
6771 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6772 freejob(jp);
6773 }
6774}
6775
6776
6777static int
6778jobscmd(int argc, char **argv)
6779{
6780 int mode, m;
6781 FILE *out;
6782
6783 mode = 0;
6784 while ((m = nextopt("lp")))
6785 if (m == 'l')
6786 mode = SHOW_PID;
6787 else
6788 mode = SHOW_PGID;
6789
6790 out = stdout;
6791 argv = argptr;
6792 if (*argv)
6793 do
6794 showjob(out, getjob(*argv,0), mode);
6795 while (*++argv);
6796 else
6797 showjobs(out, mode);
6798
Eric Andersencb57d552001-06-28 07:25:16 +00006799 return 0;
6800}
6801
6802
6803/*
6804 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6805 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006806 */
6807
Eric Andersenc470f442003-07-28 09:56:35 +00006808static void
6809showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006810{
Eric Andersencb57d552001-06-28 07:25:16 +00006811 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006812
Eric Andersenc470f442003-07-28 09:56:35 +00006813 TRACE(("showjobs(%x) called\n", mode));
6814
6815 /* If not even one one job changed, there is nothing to do */
6816 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6817 continue;
6818
6819 for (jp = curjob; jp; jp = jp->prev_job) {
6820 if (!(mode & SHOW_CHANGED) || jp->changed)
6821 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006822 }
6823}
Eric Andersenc470f442003-07-28 09:56:35 +00006824#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006825
6826/*
6827 * Mark a job structure as unused.
6828 */
6829
Eric Andersenc470f442003-07-28 09:56:35 +00006830static void
6831freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006832{
Eric Andersenc470f442003-07-28 09:56:35 +00006833 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006834 int i;
6835
6836 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006837 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006838 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006839 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006840 }
6841 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006842 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006843 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006844 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006845 INTON;
6846}
6847
6848
Eric Andersenc470f442003-07-28 09:56:35 +00006849static int
6850waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006851{
6852 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006853 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006854 struct job *jp;
6855
Eric Andersenc470f442003-07-28 09:56:35 +00006856 EXSIGON();
6857
6858 nextopt(nullstr);
6859 retval = 0;
6860
6861 argv = argptr;
6862 if (!*argv) {
6863 /* wait for all jobs */
6864 for (;;) {
6865 jp = curjob;
6866 while (1) {
6867 if (!jp) {
6868 /* no running procs */
6869 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006870 }
Eric Andersenc470f442003-07-28 09:56:35 +00006871 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006872 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006873 jp->waited = 1;
6874 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006875 }
Eric Andersenc470f442003-07-28 09:56:35 +00006876 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006877 }
6878 }
Eric Andersenc470f442003-07-28 09:56:35 +00006879
6880 retval = 127;
6881 do {
6882 if (**argv != '%') {
6883 pid_t pid = number(*argv);
6884 job = curjob;
6885 goto start;
6886 do {
6887 if (job->ps[job->nprocs - 1].pid == pid)
6888 break;
6889 job = job->prev_job;
6890start:
6891 if (!job)
6892 goto repeat;
6893 } while (1);
6894 } else
6895 job = getjob(*argv, 0);
6896 /* loop until process terminated or stopped */
6897 while (job->state == JOBRUNNING)
6898 dowait(DOWAIT_BLOCK, 0);
6899 job->waited = 1;
6900 retval = getstatus(job);
6901repeat:
6902 ;
6903 } while (*++argv);
6904
6905out:
6906 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006907}
6908
6909
Eric Andersencb57d552001-06-28 07:25:16 +00006910/*
6911 * Convert a job name to a job structure.
6912 */
6913
Eric Andersenc470f442003-07-28 09:56:35 +00006914static struct job *
6915getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006916{
Eric Andersencb57d552001-06-28 07:25:16 +00006917 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006918 struct job *found;
6919 const char *err_msg = "No such job: %s";
6920 unsigned num;
6921 int c;
6922 const char *p;
6923 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006924
Eric Andersenc470f442003-07-28 09:56:35 +00006925 jp = curjob;
6926 p = name;
6927 if (!p)
6928 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006929
Eric Andersenc470f442003-07-28 09:56:35 +00006930 if (*p != '%')
6931 goto err;
6932
6933 c = *++p;
6934 if (!c)
6935 goto currentjob;
6936
6937 if (!p[1]) {
6938 if (c == '+' || c == '%') {
6939currentjob:
6940 err_msg = "No current job";
6941 goto check;
6942 } else if (c == '-') {
6943 if (jp)
6944 jp = jp->prev_job;
6945 err_msg = "No previous job";
6946check:
6947 if (!jp)
6948 goto err;
6949 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006950 }
6951 }
Eric Andersenc470f442003-07-28 09:56:35 +00006952
6953 if (is_number(p)) {
6954 num = atoi(p);
6955 if (num < njobs) {
6956 jp = jobtab + num - 1;
6957 if (jp->used)
6958 goto gotit;
6959 goto err;
6960 }
6961 }
6962
6963 match = prefix;
6964 if (*p == '?') {
6965 match = strstr;
6966 p++;
6967 }
6968
6969 found = 0;
6970 while (1) {
6971 if (!jp)
6972 goto err;
6973 if (match(jp->ps[0].cmd, p)) {
6974 if (found)
6975 goto err;
6976 found = jp;
6977 err_msg = "%s: ambiguous";
6978 }
6979 jp = jp->prev_job;
6980 }
6981
6982gotit:
6983#if JOBS
6984 err_msg = "job %s not created under job control";
6985 if (getctl && jp->jobctl == 0)
6986 goto err;
6987#endif
6988 return jp;
6989err:
6990 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006991}
6992
6993
Eric Andersencb57d552001-06-28 07:25:16 +00006994/*
Eric Andersenc470f442003-07-28 09:56:35 +00006995 * Return a new job structure.
6996 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006997 */
6998
Eric Andersenc470f442003-07-28 09:56:35 +00006999static struct job *
7000makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007001{
7002 int i;
7003 struct job *jp;
7004
Eric Andersenc470f442003-07-28 09:56:35 +00007005 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007006 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007007 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007008 break;
7009 }
7010 if (jp->used == 0)
7011 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007012 if (jp->state != JOBDONE || !jp->waited)
7013 continue;
7014#if JOBS
7015 if (jobctl)
7016 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007017#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007018 freejob(jp);
7019 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007020 }
Eric Andersenc470f442003-07-28 09:56:35 +00007021 memset(jp, 0, sizeof(*jp));
7022#if JOBS
7023 if (jobctl)
7024 jp->jobctl = 1;
7025#endif
7026 jp->prev_job = curjob;
7027 curjob = jp;
7028 jp->used = 1;
7029 jp->ps = &jp->ps0;
7030 if (nprocs > 1) {
7031 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7032 }
7033 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7034 jobno(jp)));
7035 return jp;
7036}
7037
7038static struct job *
7039growjobtab(void)
7040{
7041 size_t len;
7042 ptrdiff_t offset;
7043 struct job *jp, *jq;
7044
7045 len = njobs * sizeof(*jp);
7046 jq = jobtab;
7047 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7048
7049 offset = (char *)jp - (char *)jq;
7050 if (offset) {
7051 /* Relocate pointers */
7052 size_t l = len;
7053
7054 jq = (struct job *)((char *)jq + l);
7055 while (l) {
7056 l -= sizeof(*jp);
7057 jq--;
7058#define joff(p) ((struct job *)((char *)(p) + l))
7059#define jmove(p) (p) = (void *)((char *)(p) + offset)
7060 if (likely(joff(jp)->ps == &jq->ps0))
7061 jmove(joff(jp)->ps);
7062 if (joff(jp)->prev_job)
7063 jmove(joff(jp)->prev_job);
7064 }
7065 if (curjob)
7066 jmove(curjob);
7067#undef joff
7068#undef jmove
7069 }
7070
7071 njobs += 4;
7072 jobtab = jp;
7073 jp = (struct job *)((char *)jp + len);
7074 jq = jp + 3;
7075 do {
7076 jq->used = 0;
7077 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007078 return jp;
7079}
7080
7081
7082/*
Eric Andersenc470f442003-07-28 09:56:35 +00007083 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007084 * own process group. Jp is a job structure that the job is to be added to.
7085 * N is the command that will be evaluated by the child. Both jp and n may
7086 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007087 * FORK_FG - Fork off a foreground process.
7088 * FORK_BG - Fork off a background process.
7089 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7090 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007091 *
7092 * When job control is turned off, background processes have their standard
7093 * input redirected to /dev/null (except for the second and later processes
7094 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007095 *
7096 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007097 */
7098
Eric Andersenc470f442003-07-28 09:56:35 +00007099static inline void
7100forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007101{
Eric Andersenc470f442003-07-28 09:56:35 +00007102 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007103
Eric Andersenc470f442003-07-28 09:56:35 +00007104 TRACE(("Child shell %d\n", getpid()));
7105 wasroot = rootshell;
7106 rootshell = 0;
7107
7108 closescript();
7109 clear_traps();
7110#if JOBS
7111 /* do job control only in root shell */
7112 jobctl = 0;
7113 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7114 pid_t pgrp;
7115
7116 if (jp->nprocs == 0)
7117 pgrp = getpid();
7118 else
7119 pgrp = jp->ps[0].pid;
7120 /* This can fail because we are doing it in the parent also */
7121 (void)setpgid(0, pgrp);
7122 if (mode == FORK_FG)
7123 xtcsetpgrp(ttyfd, pgrp);
7124 setsignal(SIGTSTP);
7125 setsignal(SIGTTOU);
7126 } else
Eric Andersen62483552001-07-10 06:09:16 +00007127#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007128 if (mode == FORK_BG) {
7129 ignoresig(SIGINT);
7130 ignoresig(SIGQUIT);
7131 if (jp->nprocs == 0) {
7132 close(0);
7133 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7134 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007135 }
Eric Andersencb57d552001-06-28 07:25:16 +00007136 }
Eric Andersenc470f442003-07-28 09:56:35 +00007137 if (wasroot && iflag) {
7138 setsignal(SIGINT);
7139 setsignal(SIGQUIT);
7140 setsignal(SIGTERM);
7141 }
7142 for (jp = curjob; jp; jp = jp->prev_job)
7143 freejob(jp);
7144 jobless = 0;
7145}
7146
7147static inline void
7148forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7149{
7150 TRACE(("In parent shell: child = %d\n", pid));
7151 if (!jp) {
7152 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7153 jobless++;
7154 return;
7155 }
7156#if JOBS
7157 if (mode != FORK_NOJOB && jp->jobctl) {
7158 int pgrp;
7159
7160 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007161 pgrp = pid;
7162 else
7163 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007164 /* This can fail because we are doing it in the child also */
7165 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007166 }
Eric Andersen62483552001-07-10 06:09:16 +00007167#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007168 if (mode == FORK_BG) {
7169 backgndpid = pid; /* set $! */
7170 set_curjob(jp, CUR_RUNNING);
7171 }
Eric Andersencb57d552001-06-28 07:25:16 +00007172 if (jp) {
7173 struct procstat *ps = &jp->ps[jp->nprocs++];
7174 ps->pid = pid;
7175 ps->status = -1;
7176 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007177#if JOBS
7178 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007179 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007180#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007181 }
Eric Andersencb57d552001-06-28 07:25:16 +00007182}
7183
Eric Andersenc470f442003-07-28 09:56:35 +00007184static int
7185forkshell(struct job *jp, union node *n, int mode)
7186{
7187 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007188
Eric Andersenc470f442003-07-28 09:56:35 +00007189 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7190 pid = fork();
7191 if (pid < 0) {
7192 TRACE(("Fork failed, errno=%d", errno));
7193 if (jp)
7194 freejob(jp);
7195 error("Cannot fork");
7196 }
7197 if (pid == 0)
7198 forkchild(jp, n, mode);
7199 else
7200 forkparent(jp, n, mode, pid);
7201 return pid;
7202}
Eric Andersencb57d552001-06-28 07:25:16 +00007203
7204/*
7205 * Wait for job to finish.
7206 *
7207 * Under job control we have the problem that while a child process is
7208 * running interrupts generated by the user are sent to the child but not
7209 * to the shell. This means that an infinite loop started by an inter-
7210 * active user may be hard to kill. With job control turned off, an
7211 * interactive user may place an interactive program inside a loop. If
7212 * the interactive program catches interrupts, the user doesn't want
7213 * these interrupts to also abort the loop. The approach we take here
7214 * is to have the shell ignore interrupt signals while waiting for a
7215 * forground process to terminate, and then send itself an interrupt
7216 * signal if the child process was terminated by an interrupt signal.
7217 * Unfortunately, some programs want to do a bit of cleanup and then
7218 * exit on interrupt; unless these processes terminate themselves by
7219 * sending a signal to themselves (instead of calling exit) they will
7220 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007221 *
7222 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007223 */
7224
Eric Andersenc470f442003-07-28 09:56:35 +00007225int
7226waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007227{
Eric Andersencb57d552001-06-28 07:25:16 +00007228 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007229
Eric Andersenc470f442003-07-28 09:56:35 +00007230 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7231 while (jp->state == JOBRUNNING) {
7232 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007233 }
Eric Andersenc470f442003-07-28 09:56:35 +00007234 st = getstatus(jp);
7235#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007236 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007237 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007238 /*
7239 * This is truly gross.
7240 * If we're doing job control, then we did a TIOCSPGRP which
7241 * caused us (the shell) to no longer be in the controlling
7242 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7243 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007244 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007245 */
Eric Andersenc470f442003-07-28 09:56:35 +00007246 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007247 raise(SIGINT);
7248 }
Eric Andersen2870d962001-07-02 17:27:21 +00007249 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007250#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007251 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007252 return st;
7253}
7254
7255
Eric Andersen62483552001-07-10 06:09:16 +00007256/*
7257 * Do a wait system call. If job control is compiled in, we accept
7258 * stopped processes. If block is zero, we return a value of zero
7259 * rather than blocking.
7260 *
7261 * System V doesn't have a non-blocking wait system call. It does
7262 * have a SIGCLD signal that is sent to a process when one of it's
7263 * children dies. The obvious way to use SIGCLD would be to install
7264 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7265 * was received, and have waitproc bump another counter when it got
7266 * the status of a process. Waitproc would then know that a wait
7267 * system call would not block if the two counters were different.
7268 * This approach doesn't work because if a process has children that
7269 * have not been waited for, System V will send it a SIGCLD when it
7270 * installs a signal handler for SIGCLD. What this means is that when
7271 * a child exits, the shell will be sent SIGCLD signals continuously
7272 * until is runs out of stack space, unless it does a wait call before
7273 * restoring the signal handler. The code below takes advantage of
7274 * this (mis)feature by installing a signal handler for SIGCLD and
7275 * then checking to see whether it was called. If there are any
7276 * children to be waited for, it will be.
7277 *
Eric Andersenc470f442003-07-28 09:56:35 +00007278 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7279 * waits at all. In this case, the user will not be informed when
7280 * a background process until the next time she runs a real program
7281 * (as opposed to running a builtin command or just typing return),
7282 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007283 */
7284
Eric Andersenc470f442003-07-28 09:56:35 +00007285static inline int
7286waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007287{
Eric Andersenc470f442003-07-28 09:56:35 +00007288 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007289
Eric Andersenc470f442003-07-28 09:56:35 +00007290#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007291 if (jobctl)
7292 flags |= WUNTRACED;
7293#endif
7294 if (block == 0)
7295 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007296 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007297}
7298
Eric Andersenc470f442003-07-28 09:56:35 +00007299/*
7300 * Wait for a process to terminate.
7301 */
7302
7303static int
7304dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007305{
7306 int pid;
7307 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007308 struct job *jp;
7309 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007310 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007311
7312 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007313 pid = waitproc(block, &status);
7314 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007315 if (pid <= 0)
7316 return pid;
7317 INTOFF;
7318 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007319 for (jp = curjob; jp; jp = jp->prev_job) {
7320 struct procstat *sp;
7321 struct procstat *spend;
7322 if (jp->state == JOBDONE)
7323 continue;
7324 state = JOBDONE;
7325 spend = jp->ps + jp->nprocs;
7326 sp = jp->ps;
7327 do {
7328 if (sp->pid == pid) {
7329 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7330 sp->status = status;
7331 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007332 }
Eric Andersenc470f442003-07-28 09:56:35 +00007333 if (sp->status == -1)
7334 state = JOBRUNNING;
7335#ifdef JOBS
7336 if (state == JOBRUNNING)
7337 continue;
7338 if (WIFSTOPPED(sp->status)) {
7339 jp->stopstatus = sp->status;
7340 state = JOBSTOPPED;
7341 }
Eric Andersencb57d552001-06-28 07:25:16 +00007342#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007343 } while (++sp < spend);
7344 if (thisjob)
7345 goto gotjob;
7346 }
7347#ifdef JOBS
7348 if (!WIFSTOPPED(status))
7349#endif
7350
7351 jobless--;
7352 goto out;
7353
7354gotjob:
7355 if (state != JOBRUNNING) {
7356 thisjob->changed = 1;
7357
7358 if (thisjob->state != state) {
7359 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7360 thisjob->state = state;
7361#ifdef JOBS
7362 if (state == JOBSTOPPED) {
7363 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007364 }
Eric Andersenc470f442003-07-28 09:56:35 +00007365#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007366 }
7367 }
Eric Andersencb57d552001-06-28 07:25:16 +00007368
Eric Andersenc470f442003-07-28 09:56:35 +00007369out:
7370 INTON;
7371
7372 if (thisjob && thisjob == job) {
7373 char s[48 + 1];
7374 int len;
7375
7376 len = sprint_status(s, status, 1);
7377 if (len) {
7378 s[len] = '\n';
7379 s[len + 1] = 0;
7380 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007381 }
Eric Andersencb57d552001-06-28 07:25:16 +00007382 }
7383 return pid;
7384}
7385
7386
Eric Andersencb57d552001-06-28 07:25:16 +00007387/*
7388 * return 1 if there are stopped jobs, otherwise 0
7389 */
Eric Andersen90898442003-08-06 11:20:52 +00007390
Eric Andersenc470f442003-07-28 09:56:35 +00007391int
7392stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007393{
Eric Andersencb57d552001-06-28 07:25:16 +00007394 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007395 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007396
Eric Andersenc470f442003-07-28 09:56:35 +00007397 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007398 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007399 goto out;
7400 jp = curjob;
7401 if (jp && jp->state == JOBSTOPPED) {
7402 out2str("You have stopped jobs.\n");
7403 job_warning = 2;
7404 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007405 }
7406
Eric Andersenc470f442003-07-28 09:56:35 +00007407out:
7408 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007409}
7410
7411/*
7412 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007413 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007414 */
7415
Eric Andersenc470f442003-07-28 09:56:35 +00007416#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007417static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007418
Eric Andersenc470f442003-07-28 09:56:35 +00007419static char *
7420commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007421{
Eric Andersenc470f442003-07-28 09:56:35 +00007422 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007423
Eric Andersenc470f442003-07-28 09:56:35 +00007424 STARTSTACKSTR(cmdnextc);
7425 cmdtxt(n);
7426 name = stackblock();
7427 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7428 name, cmdnextc, cmdnextc));
7429 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007430}
7431
Eric Andersenc470f442003-07-28 09:56:35 +00007432static void
7433cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007434{
Eric Andersencb57d552001-06-28 07:25:16 +00007435 union node *np;
7436 struct nodelist *lp;
7437 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007438 char s[2];
7439
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007440 if (!n)
7441 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007442 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007443 default:
7444#if DEBUG
7445 abort();
7446#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007447 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007448 lp = n->npipe.cmdlist;
7449 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007450 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007451 lp = lp->next;
7452 if (!lp)
7453 break;
7454 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007455 }
7456 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007457 case NSEMI:
7458 p = "; ";
7459 goto binop;
7460 case NAND:
7461 p = " && ";
7462 goto binop;
7463 case NOR:
7464 p = " || ";
7465binop:
7466 cmdtxt(n->nbinary.ch1);
7467 cmdputs(p);
7468 n = n->nbinary.ch2;
7469 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007470 case NREDIR:
7471 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007472 n = n->nredir.n;
7473 goto donode;
7474 case NNOT:
7475 cmdputs("!");
7476 n = n->nnot.com;
7477donode:
7478 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007479 break;
7480 case NIF:
7481 cmdputs("if ");
7482 cmdtxt(n->nif.test);
7483 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007484 n = n->nif.ifpart;
7485 if (n->nif.elsepart) {
7486 cmdtxt(n);
7487 cmdputs("; else ");
7488 n = n->nif.elsepart;
7489 }
7490 p = "; fi";
7491 goto dotail;
7492 case NSUBSHELL:
7493 cmdputs("(");
7494 n = n->nredir.n;
7495 p = ")";
7496 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007497 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007498 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007499 goto until;
7500 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007501 p = "until ";
7502until:
7503 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007504 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007505 n = n->nbinary.ch2;
7506 p = "; done";
7507dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007508 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007509dotail:
7510 cmdtxt(n);
7511 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007512 case NFOR:
7513 cmdputs("for ");
7514 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007515 cmdputs(" in ");
7516 cmdlist(n->nfor.args, 1);
7517 n = n->nfor.body;
7518 p = "; done";
7519 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007520 case NDEFUN:
7521 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007522 p = "() { ... }";
7523 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007524 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007525 cmdlist(n->ncmd.args, 1);
7526 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007527 break;
7528 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007529 p = n->narg.text;
7530dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007531 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007532 break;
7533 case NHERE:
7534 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007535 p = "<<...";
7536 goto dotail2;
7537 case NCASE:
7538 cmdputs("case ");
7539 cmdputs(n->ncase.expr->narg.text);
7540 cmdputs(" in ");
7541 for (np = n->ncase.cases; np; np = np->nclist.next) {
7542 cmdtxt(np->nclist.pattern);
7543 cmdputs(") ");
7544 cmdtxt(np->nclist.body);
7545 cmdputs(";; ");
7546 }
7547 p = "esac";
7548 goto dotail2;
7549 case NTO:
7550 p = ">";
7551 goto redir;
7552 case NCLOBBER:
7553 p = ">|";
7554 goto redir;
7555 case NAPPEND:
7556 p = ">>";
7557 goto redir;
7558 case NTOFD:
7559 p = ">&";
7560 goto redir;
7561 case NFROM:
7562 p = "<";
7563 goto redir;
7564 case NFROMFD:
7565 p = "<&";
7566 goto redir;
7567 case NFROMTO:
7568 p = "<>";
7569redir:
7570 s[0] = n->nfile.fd + '0';
7571 s[1] = '\0';
7572 cmdputs(s);
7573 cmdputs(p);
7574 if (n->type == NTOFD || n->type == NFROMFD) {
7575 s[0] = n->ndup.dupfd + '0';
7576 p = s;
7577 goto dotail2;
7578 } else {
7579 n = n->nfile.fname;
7580 goto donode;
7581 }
Eric Andersencb57d552001-06-28 07:25:16 +00007582 }
7583}
Eric Andersencb57d552001-06-28 07:25:16 +00007584
Eric Andersenc470f442003-07-28 09:56:35 +00007585static void
7586cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007587{
Eric Andersenc470f442003-07-28 09:56:35 +00007588 for (; np; np = np->narg.next) {
7589 if (!sep)
7590 cmdputs(spcstr);
7591 cmdtxt(np);
7592 if (sep && np->narg.next)
7593 cmdputs(spcstr);
7594 }
Eric Andersencb57d552001-06-28 07:25:16 +00007595}
7596
Eric Andersenc470f442003-07-28 09:56:35 +00007597static void
7598cmdputs(const char *s)
7599{
7600 const char *p, *str;
7601 char c, cc[2] = " ";
7602 char *nextc;
7603 int subtype = 0;
7604 int quoted = 0;
7605 static const char *const vstype[16] = {
7606 nullstr, "}", "-", "+", "?", "=",
7607 "#", "##", "%", "%%"
7608 };
7609
7610 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7611 p = s;
7612 while ((c = *p++) != 0) {
7613 str = 0;
7614 switch (c) {
7615 case CTLESC:
7616 c = *p++;
7617 break;
7618 case CTLVAR:
7619 subtype = *p++;
7620 if ((subtype & VSTYPE) == VSLENGTH)
7621 str = "${#";
7622 else
7623 str = "${";
7624 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7625 quoted ^= 1;
7626 c = '"';
7627 } else
7628 goto dostr;
7629 break;
7630 case CTLENDVAR:
7631 quoted >>= 1;
7632 subtype = 0;
7633 if (quoted & 1) {
7634 str = "\"}";
7635 goto dostr;
7636 }
7637 c = '}';
7638 break;
7639 case CTLBACKQ:
7640 str = "$(...)";
7641 goto dostr;
7642 case CTLBACKQ+CTLQUOTE:
7643 str = "\"$(...)\"";
7644 goto dostr;
7645#ifdef CONFIG_ASH_MATH_SUPPORT
7646 case CTLARI:
7647 str = "$((";
7648 goto dostr;
7649 case CTLENDARI:
7650 str = "))";
7651 goto dostr;
7652#endif
7653 case CTLQUOTEMARK:
7654 quoted ^= 1;
7655 c = '"';
7656 break;
7657 case '=':
7658 if (subtype == 0)
7659 break;
7660 str = vstype[subtype & VSTYPE];
7661 if (subtype & VSNUL)
7662 c = ':';
7663 else
7664 c = *str++;
7665 if (c != '}')
7666 quoted <<= 1;
7667 break;
7668 case '\'':
7669 case '\\':
7670 case '"':
7671 case '$':
7672 /* These can only happen inside quotes */
7673 cc[0] = c;
7674 str = cc;
7675 c = '\\';
7676 break;
7677 default:
7678 break;
7679 }
7680 USTPUTC(c, nextc);
7681 if (!str)
7682 continue;
7683dostr:
7684 while ((c = *str++)) {
7685 USTPUTC(c, nextc);
7686 }
7687 }
7688 if (quoted & 1) {
7689 USTPUTC('"', nextc);
7690 }
7691 *nextc = 0;
7692 cmdnextc = nextc;
7693}
7694
7695
7696static void
7697showpipe(struct job *jp, FILE *out)
7698{
7699 struct procstat *sp;
7700 struct procstat *spend;
7701
7702 spend = jp->ps + jp->nprocs;
7703 for (sp = jp->ps + 1; sp < spend; sp++)
7704 fprintf(out, " | %s", sp->cmd);
7705 outcslow('\n', out);
7706 flushall();
7707}
7708
7709static void
7710xtcsetpgrp(int fd, pid_t pgrp)
7711{
7712 if (tcsetpgrp(fd, pgrp))
7713 error("Cannot set tty process group (%m)");
7714}
7715#endif /* JOBS */
7716
7717static int
7718getstatus(struct job *job) {
7719 int status;
7720 int retval;
7721
7722 status = job->ps[job->nprocs - 1].status;
7723 retval = WEXITSTATUS(status);
7724 if (!WIFEXITED(status)) {
7725#if JOBS
7726 retval = WSTOPSIG(status);
7727 if (!WIFSTOPPED(status))
7728#endif
7729 {
7730 /* XXX: limits number of signals */
7731 retval = WTERMSIG(status);
7732#if JOBS
7733 if (retval == SIGINT)
7734 job->sigint = 1;
7735#endif
7736 }
7737 retval += 128;
7738 }
7739 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7740 jobno(job), job->nprocs, status, retval));
7741 return retval;
7742}
7743
Eric Andersend35c5df2002-01-09 15:37:36 +00007744#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007745/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007746
Eric Andersencb57d552001-06-28 07:25:16 +00007747/*
Eric Andersenc470f442003-07-28 09:56:35 +00007748 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007749 */
7750
Eric Andersencb57d552001-06-28 07:25:16 +00007751#define MAXMBOXES 10
7752
Eric Andersenc470f442003-07-28 09:56:35 +00007753/* times of mailboxes */
7754static time_t mailtime[MAXMBOXES];
7755/* Set if MAIL or MAILPATH is changed. */
7756static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007757
7758
7759
7760/*
Eric Andersenc470f442003-07-28 09:56:35 +00007761 * Print appropriate message(s) if mail has arrived.
7762 * If mail_var_path_changed is set,
7763 * then the value of MAIL has mail_var_path_changed,
7764 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007765 */
7766
Eric Andersenc470f442003-07-28 09:56:35 +00007767static void
7768chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007769{
Eric Andersencb57d552001-06-28 07:25:16 +00007770 const char *mpath;
7771 char *p;
7772 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007773 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007774 struct stackmark smark;
7775 struct stat statb;
7776
Eric Andersencb57d552001-06-28 07:25:16 +00007777 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007778 mpath = mpathset() ? mpathval() : mailval();
7779 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007780 p = padvance(&mpath, nullstr);
7781 if (p == NULL)
7782 break;
7783 if (*p == '\0')
7784 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007785 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007786#ifdef DEBUG
7787 if (q[-1] != '/')
7788 abort();
7789#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007790 q[-1] = '\0'; /* delete trailing '/' */
7791 if (stat(p, &statb) < 0) {
7792 *mtp = 0;
7793 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007794 }
Eric Andersenc470f442003-07-28 09:56:35 +00007795 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7796 fprintf(
7797 stderr, snlfmt,
7798 pathopt ? pathopt : "you have mail"
7799 );
7800 }
7801 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007802 }
Eric Andersenc470f442003-07-28 09:56:35 +00007803 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007804 popstackmark(&smark);
7805}
Eric Andersencb57d552001-06-28 07:25:16 +00007806
Eric Andersenec074692001-10-31 11:05:49 +00007807
Eric Andersenc470f442003-07-28 09:56:35 +00007808static void
7809changemail(const char *val)
7810{
7811 mail_var_path_changed++;
7812}
7813
7814#endif /* CONFIG_ASH_MAIL */
7815
7816/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7817
Eric Andersencb57d552001-06-28 07:25:16 +00007818
Eric Andersencb57d552001-06-28 07:25:16 +00007819#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007820static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007821extern int etext();
7822#endif
7823
Eric Andersenc470f442003-07-28 09:56:35 +00007824static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007825
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007826static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007827
Eric Andersencb57d552001-06-28 07:25:16 +00007828/*
7829 * Main routine. We initialize things, parse the arguments, execute
7830 * profiles if we're a login shell, and then call cmdloop to execute
7831 * commands. The setjmp call sets up the location to jump to when an
7832 * exception occurs. When an exception occurs the variable "state"
7833 * is used to figure out how far we had gotten.
7834 */
7835
Eric Andersenc470f442003-07-28 09:56:35 +00007836int
7837ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007838{
Eric Andersenc470f442003-07-28 09:56:35 +00007839 char *shinit;
7840 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007841 struct jmploc jmploc;
7842 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007843
Eric Andersenc470f442003-07-28 09:56:35 +00007844#ifdef __GLIBC__
7845 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007846#endif
7847
Eric Andersencb57d552001-06-28 07:25:16 +00007848#if PROFILE
7849 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7850#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007851 state = 0;
7852 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007853 int status;
7854 int e;
7855
Eric Andersencb57d552001-06-28 07:25:16 +00007856 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007857
7858 e = exception;
7859 switch (exception) {
7860 case EXEXEC:
7861 status = exerrno;
7862 break;
7863
7864 case EXERROR:
7865 status = 2;
7866 break;
7867
7868 default:
7869 status = exitstatus;
7870 break;
7871 }
7872 exitstatus = status;
7873
7874 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7875 exitshell();
7876
Eric Andersen90898442003-08-06 11:20:52 +00007877 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007878 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007879 }
7880 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007881 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007882 if (state == 1)
7883 goto state1;
7884 else if (state == 2)
7885 goto state2;
7886 else if (state == 3)
7887 goto state3;
7888 else
7889 goto state4;
7890 }
7891 handler = &jmploc;
7892#ifdef DEBUG
7893 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007894 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007895#endif
7896 rootpid = getpid();
7897 rootshell = 1;
7898 init();
7899 setstackmark(&smark);
7900 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007901#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7902 if ( iflag ) {
7903 const char *hp = lookupvar("HISTFILE");
7904
7905 if(hp == NULL ) {
7906 hp = lookupvar("HOME");
7907 if(hp != NULL) {
7908 char *defhp = concat_path_file(hp, ".ash_history");
7909 setvar("HISTFILE", defhp, 0);
7910 free(defhp);
7911 }
7912 }
7913 }
7914#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007915 if (argv[0] && argv[0][0] == '-')
7916 isloginsh = 1;
7917 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007918 state = 1;
7919 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007920state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007921 state = 2;
7922 read_profile(".profile");
7923 }
Eric Andersenc470f442003-07-28 09:56:35 +00007924state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007925 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007926 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007927#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007928 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007929#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007930 iflag
7931 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007932 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007933 read_profile(shinit);
7934 }
Eric Andersencb57d552001-06-28 07:25:16 +00007935 }
Eric Andersenc470f442003-07-28 09:56:35 +00007936state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007937 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007938 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007939 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007940
7941 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007942#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007943 if ( iflag ) {
7944 const char *hp = lookupvar("HISTFILE");
7945
7946 if(hp != NULL )
7947 load_history ( hp );
7948 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007949#endif
Eric Andersen90898442003-08-06 11:20:52 +00007950state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007951 cmdloop(1);
7952 }
7953#if PROFILE
7954 monitor(0);
7955#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007956#if GPROF
7957 {
7958 extern void _mcleanup(void);
7959 _mcleanup();
7960 }
7961#endif
7962 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007963 /* NOTREACHED */
7964}
7965
7966
7967/*
7968 * Read and execute commands. "Top" is nonzero for the top level command
7969 * loop; it turns on prompting if the shell is interactive.
7970 */
7971
Eric Andersenc470f442003-07-28 09:56:35 +00007972static void
7973cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007974{
7975 union node *n;
7976 struct stackmark smark;
7977 int inter;
7978 int numeof = 0;
7979
7980 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00007981 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00007982 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00007983 if (pendingsigs)
7984 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00007985#if JOBS
7986 if (jobctl)
7987 showjobs(stderr, SHOW_CHANGED);
7988#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007989 inter = 0;
7990 if (iflag && top) {
7991 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00007992#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007993 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00007994#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007995 }
7996 n = parsecmd(inter);
7997 /* showtree(n); DEBUG */
7998 if (n == NEOF) {
7999 if (!top || numeof >= 50)
8000 break;
8001 if (!stoppedjobs()) {
8002 if (!Iflag)
8003 break;
8004 out2str("\nUse \"exit\" to leave shell.\n");
8005 }
8006 numeof++;
8007 } else if (n != NULL && nflag == 0) {
8008 job_warning = (job_warning == 2) ? 1 : 0;
8009 numeof = 0;
8010 evaltree(n, 0);
8011 }
8012 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008013 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008014 evalskip = 0;
8015 break;
8016 }
8017 }
Eric Andersencb57d552001-06-28 07:25:16 +00008018}
8019
8020
Eric Andersencb57d552001-06-28 07:25:16 +00008021/*
8022 * Read /etc/profile or .profile. Return on error.
8023 */
8024
Eric Andersenc470f442003-07-28 09:56:35 +00008025static void
8026read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008027{
8028 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008029 int xflag_set = 0;
8030 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008031
8032 INTOFF;
8033 if ((fd = open(name, O_RDONLY)) >= 0)
8034 setinputfd(fd, 1);
8035 INTON;
8036 if (fd < 0)
8037 return;
8038 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008039 if (qflag) {
8040 if (xflag)
8041 xflag = 0, xflag_set = 1;
8042 if (vflag)
8043 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008044 }
8045 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008046 if (qflag) {
8047 if (xflag_set)
8048 xflag = 1;
8049 if (vflag_set)
8050 vflag = 1;
8051 }
Eric Andersencb57d552001-06-28 07:25:16 +00008052 popfile();
8053}
8054
8055
Eric Andersencb57d552001-06-28 07:25:16 +00008056/*
8057 * Read a file containing shell functions.
8058 */
8059
Eric Andersenc470f442003-07-28 09:56:35 +00008060static void
8061readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008062{
8063 int fd;
8064
8065 INTOFF;
8066 if ((fd = open(name, O_RDONLY)) >= 0)
8067 setinputfd(fd, 1);
8068 else
8069 error("Can't open %s", name);
8070 INTON;
8071 cmdloop(0);
8072 popfile();
8073}
8074
8075
Eric Andersencb57d552001-06-28 07:25:16 +00008076/*
Eric Andersenc470f442003-07-28 09:56:35 +00008077 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008078 * search for the file, which is necessary to find sub-commands.
8079 */
8080
Eric Andersenc470f442003-07-28 09:56:35 +00008081static inline char *
8082find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008083{
8084 char *fullname;
8085 const char *path = pathval();
8086 struct stat statb;
8087
8088 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008089 if (strchr(name, '/'))
8090 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008091
Eric Andersenc470f442003-07-28 09:56:35 +00008092 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008093 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8094 /*
8095 * Don't bother freeing here, since it will
8096 * be freed by the caller.
8097 */
8098 return fullname;
8099 }
8100 stunalloc(fullname);
8101 }
8102
8103 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008104 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008105 /* NOTREACHED */
8106}
8107
Eric Andersenc470f442003-07-28 09:56:35 +00008108int
8109dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008110{
Eric Andersencb57d552001-06-28 07:25:16 +00008111 exitstatus = 0;
8112
Eric Andersenc470f442003-07-28 09:56:35 +00008113 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008114 char *fullname;
8115 struct stackmark smark;
8116
8117 setstackmark(&smark);
8118 fullname = find_dot_file(argv[1]);
8119 setinputfile(fullname, 1);
8120 commandname = fullname;
8121 cmdloop(0);
8122 popfile();
8123 popstackmark(&smark);
8124 }
8125 return exitstatus;
8126}
8127
8128
Eric Andersenc470f442003-07-28 09:56:35 +00008129static int
8130exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008131{
8132 if (stoppedjobs())
8133 return 0;
8134 if (argc > 1)
8135 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008136 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008137 /* NOTREACHED */
8138}
Eric Andersen62483552001-07-10 06:09:16 +00008139
Eric Andersenc470f442003-07-28 09:56:35 +00008140/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8141
8142/*
Eric Andersen90898442003-08-06 11:20:52 +00008143 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008144 */
8145
8146static pointer
8147ckrealloc(pointer p, size_t nbytes)
8148{
8149 p = realloc(p, nbytes);
8150 if (p == NULL)
8151 error(bb_msg_memory_exhausted);
8152 return p;
8153}
8154
Eric Andersen90898442003-08-06 11:20:52 +00008155static pointer
8156ckmalloc(size_t nbytes)
8157{
8158 return ckrealloc(NULL, nbytes);
8159}
Eric Andersenc470f442003-07-28 09:56:35 +00008160
8161/*
8162 * Make a copy of a string in safe storage.
8163 */
8164
8165static char *
8166savestr(const char *s)
8167{
8168 char *p = strdup(s);
8169 if (!p)
8170 error(bb_msg_memory_exhausted);
8171 return p;
8172}
8173
8174
8175/*
8176 * Parse trees for commands are allocated in lifo order, so we use a stack
8177 * to make this more efficient, and also to avoid all sorts of exception
8178 * handling code to handle interrupts in the middle of a parse.
8179 *
8180 * The size 504 was chosen because the Ultrix malloc handles that size
8181 * well.
8182 */
8183
8184
8185static pointer
8186stalloc(size_t nbytes)
8187{
8188 char *p;
8189 size_t aligned;
8190
8191 aligned = SHELL_ALIGN(nbytes);
8192 if (aligned > stacknleft) {
8193 size_t len;
8194 size_t blocksize;
8195 struct stack_block *sp;
8196
8197 blocksize = aligned;
8198 if (blocksize < MINSIZE)
8199 blocksize = MINSIZE;
8200 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8201 if (len < blocksize)
8202 error(bb_msg_memory_exhausted);
8203 INTOFF;
8204 sp = ckmalloc(len);
8205 sp->prev = stackp;
8206 stacknxt = sp->space;
8207 stacknleft = blocksize;
8208 sstrend = stacknxt + blocksize;
8209 stackp = sp;
8210 INTON;
8211 }
8212 p = stacknxt;
8213 stacknxt += aligned;
8214 stacknleft -= aligned;
8215 return p;
8216}
8217
8218
8219void
8220stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008221{
Eric Andersencb57d552001-06-28 07:25:16 +00008222#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008223 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008224 write(2, "stunalloc\n", 10);
8225 abort();
8226 }
8227#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008228 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008229 stacknxt = p;
8230}
8231
8232
Eric Andersenc470f442003-07-28 09:56:35 +00008233void
8234setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008235{
Eric Andersencb57d552001-06-28 07:25:16 +00008236 mark->stackp = stackp;
8237 mark->stacknxt = stacknxt;
8238 mark->stacknleft = stacknleft;
8239 mark->marknext = markp;
8240 markp = mark;
8241}
8242
8243
Eric Andersenc470f442003-07-28 09:56:35 +00008244void
8245popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008246{
Eric Andersencb57d552001-06-28 07:25:16 +00008247 struct stack_block *sp;
8248
8249 INTOFF;
8250 markp = mark->marknext;
8251 while (stackp != mark->stackp) {
8252 sp = stackp;
8253 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008254 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008255 }
8256 stacknxt = mark->stacknxt;
8257 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008258 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008259 INTON;
8260}
8261
8262
8263/*
8264 * When the parser reads in a string, it wants to stick the string on the
8265 * stack and only adjust the stack pointer when it knows how big the
8266 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8267 * of space on top of the stack and stackblocklen returns the length of
8268 * this block. Growstackblock will grow this space by at least one byte,
8269 * possibly moving it (like realloc). Grabstackblock actually allocates the
8270 * part of the block that has been used.
8271 */
8272
Eric Andersenc470f442003-07-28 09:56:35 +00008273void
8274growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008275{
Eric Andersenc470f442003-07-28 09:56:35 +00008276 size_t newlen;
8277
8278 newlen = stacknleft * 2;
8279 if (newlen < stacknleft)
8280 error(bb_msg_memory_exhausted);
8281 if (newlen < 128)
8282 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008283
8284 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008285 struct stack_block *oldstackp;
8286 struct stackmark *xmark;
8287 struct stack_block *sp;
8288 struct stack_block *prevstackp;
8289 size_t grosslen;
8290
Eric Andersencb57d552001-06-28 07:25:16 +00008291 INTOFF;
8292 oldstackp = stackp;
8293 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008294 prevstackp = sp->prev;
8295 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8296 sp = ckrealloc((pointer)sp, grosslen);
8297 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008298 stackp = sp;
8299 stacknxt = sp->space;
8300 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008301 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008302
Eric Andersenc470f442003-07-28 09:56:35 +00008303 /*
8304 * Stack marks pointing to the start of the old block
8305 * must be relocated to point to the new block
8306 */
8307 xmark = markp;
8308 while (xmark != NULL && xmark->stackp == oldstackp) {
8309 xmark->stackp = stackp;
8310 xmark->stacknxt = stacknxt;
8311 xmark->stacknleft = stacknleft;
8312 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008313 }
8314 INTON;
8315 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008316 char *oldspace = stacknxt;
8317 int oldlen = stacknleft;
8318 char *p = stalloc(newlen);
8319
8320 /* free the space we just allocated */
8321 stacknxt = memcpy(p, oldspace, oldlen);
8322 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008323 }
8324}
8325
Eric Andersenc470f442003-07-28 09:56:35 +00008326static inline void
8327grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008328{
Eric Andersenc470f442003-07-28 09:56:35 +00008329 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008330 stacknxt += len;
8331 stacknleft -= len;
8332}
8333
Eric Andersencb57d552001-06-28 07:25:16 +00008334/*
Eric Andersenc470f442003-07-28 09:56:35 +00008335 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008336 * The user declares a variable of type STACKSTR, which may be declared
8337 * to be a register. The macro STARTSTACKSTR initializes things. Then
8338 * the user uses the macro STPUTC to add characters to the string. In
8339 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8340 * grown as necessary. When the user is done, she can just leave the
8341 * string there and refer to it using stackblock(). Or she can allocate
8342 * the space for it using grabstackstr(). If it is necessary to allow
8343 * someone else to use the stack temporarily and then continue to grow
8344 * the string, the user should use grabstack to allocate the space, and
8345 * then call ungrabstr(p) to return to the previous mode of operation.
8346 *
8347 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8348 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8349 * is space for at least one character.
8350 */
8351
Eric Andersenc470f442003-07-28 09:56:35 +00008352void *
8353growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008354{
Eric Andersenc470f442003-07-28 09:56:35 +00008355 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008356 if (herefd >= 0 && len >= 1024) {
8357 xwrite(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008358 return stackblock();
8359 }
8360 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008361 return stackblock() + len;
8362}
8363
Eric Andersencb57d552001-06-28 07:25:16 +00008364/*
8365 * Called from CHECKSTRSPACE.
8366 */
8367
Eric Andersenc470f442003-07-28 09:56:35 +00008368char *
8369makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008370{
Eric Andersenc470f442003-07-28 09:56:35 +00008371 size_t len = p - stacknxt;
8372 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008373
Eric Andersenc470f442003-07-28 09:56:35 +00008374 for (;;) {
8375 size_t nleft;
8376
8377 size = stackblocksize();
8378 nleft = size - len;
8379 if (nleft >= newlen)
8380 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008381 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008382 }
Eric Andersencb57d552001-06-28 07:25:16 +00008383 return stackblock() + len;
8384}
8385
Eric Andersenc470f442003-07-28 09:56:35 +00008386char *
8387stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008388{
Eric Andersenc470f442003-07-28 09:56:35 +00008389 p = makestrspace(n, p);
8390 p = mempcpy(p, s, n);
8391 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008392}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008393
Eric Andersenc470f442003-07-28 09:56:35 +00008394char *
8395stputs(const char *s, char *p)
8396{
8397 return stnputs(s, strlen(s), p);
8398}
8399
8400/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8401
Eric Andersencb57d552001-06-28 07:25:16 +00008402/*
Eric Andersenc470f442003-07-28 09:56:35 +00008403 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008404 *
Eric Andersenc470f442003-07-28 09:56:35 +00008405 * number(s) Convert a string of digits to an integer.
8406 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008407 */
8408
Eric Andersencb57d552001-06-28 07:25:16 +00008409/*
8410 * prefix -- see if pfx is a prefix of string.
8411 */
8412
Eric Andersenc470f442003-07-28 09:56:35 +00008413char *
8414prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008415{
Eric Andersencb57d552001-06-28 07:25:16 +00008416 while (*pfx) {
8417 if (*pfx++ != *string++)
8418 return 0;
8419 }
Eric Andersenc470f442003-07-28 09:56:35 +00008420 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008421}
8422
8423
8424/*
8425 * Convert a string of digits to an integer, printing an error message on
8426 * failure.
8427 */
8428
Eric Andersenc470f442003-07-28 09:56:35 +00008429int
8430number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008431{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008432
Eric Andersenc470f442003-07-28 09:56:35 +00008433 if (! is_number(s))
8434 error(illnum, s);
8435 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008436}
8437
Eric Andersenc470f442003-07-28 09:56:35 +00008438
Eric Andersenc470f442003-07-28 09:56:35 +00008439/*
8440 * Check for a valid number. This should be elsewhere.
8441 */
8442
8443int
8444is_number(const char *p)
8445{
8446 do {
8447 if (! is_digit(*p))
8448 return 0;
8449 } while (*++p != '\0');
8450 return 1;
8451}
8452
8453
Eric Andersencb57d552001-06-28 07:25:16 +00008454/*
8455 * Produce a possibly single quoted string suitable as input to the shell.
8456 * The return string is allocated on the stack.
8457 */
8458
Eric Andersenc470f442003-07-28 09:56:35 +00008459char *
8460single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008461 char *p;
8462
8463 STARTSTACKSTR(p);
8464
8465 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008466 char *q;
8467 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008468
Eric Andersenc470f442003-07-28 09:56:35 +00008469 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008470
Eric Andersenc470f442003-07-28 09:56:35 +00008471 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008472
Eric Andersenc470f442003-07-28 09:56:35 +00008473 *q++ = '\'';
8474 q = mempcpy(q, s, len);
8475 *q++ = '\'';
8476 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008477
Eric Andersenc470f442003-07-28 09:56:35 +00008478 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008479
Eric Andersenc470f442003-07-28 09:56:35 +00008480 len = strspn(s, "'");
8481 if (!len)
8482 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008483
Eric Andersenc470f442003-07-28 09:56:35 +00008484 q = p = makestrspace(len + 3, p);
8485
8486 *q++ = '"';
8487 q = mempcpy(q, s, len);
8488 *q++ = '"';
8489 s += len;
8490
8491 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008492 } while (*s);
8493
8494 USTPUTC(0, p);
8495
Eric Andersenc470f442003-07-28 09:56:35 +00008496 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008497}
8498
8499/*
Eric Andersenc470f442003-07-28 09:56:35 +00008500 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008501 */
8502
Eric Andersenc470f442003-07-28 09:56:35 +00008503char *
8504sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008505{
Eric Andersenc470f442003-07-28 09:56:35 +00008506 size_t len = strlen(p) + 1;
8507 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008508}
Eric Andersenc470f442003-07-28 09:56:35 +00008509
8510
8511static void
8512calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008513{
Eric Andersenc470f442003-07-28 09:56:35 +00008514 if (n == NULL)
8515 return;
8516 funcblocksize += nodesize[n->type];
8517 switch (n->type) {
8518 case NCMD:
8519 calcsize(n->ncmd.redirect);
8520 calcsize(n->ncmd.args);
8521 calcsize(n->ncmd.assign);
8522 break;
8523 case NPIPE:
8524 sizenodelist(n->npipe.cmdlist);
8525 break;
8526 case NREDIR:
8527 case NBACKGND:
8528 case NSUBSHELL:
8529 calcsize(n->nredir.redirect);
8530 calcsize(n->nredir.n);
8531 break;
8532 case NAND:
8533 case NOR:
8534 case NSEMI:
8535 case NWHILE:
8536 case NUNTIL:
8537 calcsize(n->nbinary.ch2);
8538 calcsize(n->nbinary.ch1);
8539 break;
8540 case NIF:
8541 calcsize(n->nif.elsepart);
8542 calcsize(n->nif.ifpart);
8543 calcsize(n->nif.test);
8544 break;
8545 case NFOR:
8546 funcstringsize += strlen(n->nfor.var) + 1;
8547 calcsize(n->nfor.body);
8548 calcsize(n->nfor.args);
8549 break;
8550 case NCASE:
8551 calcsize(n->ncase.cases);
8552 calcsize(n->ncase.expr);
8553 break;
8554 case NCLIST:
8555 calcsize(n->nclist.body);
8556 calcsize(n->nclist.pattern);
8557 calcsize(n->nclist.next);
8558 break;
8559 case NDEFUN:
8560 case NARG:
8561 sizenodelist(n->narg.backquote);
8562 funcstringsize += strlen(n->narg.text) + 1;
8563 calcsize(n->narg.next);
8564 break;
8565 case NTO:
8566 case NCLOBBER:
8567 case NFROM:
8568 case NFROMTO:
8569 case NAPPEND:
8570 calcsize(n->nfile.fname);
8571 calcsize(n->nfile.next);
8572 break;
8573 case NTOFD:
8574 case NFROMFD:
8575 calcsize(n->ndup.vname);
8576 calcsize(n->ndup.next);
8577 break;
8578 case NHERE:
8579 case NXHERE:
8580 calcsize(n->nhere.doc);
8581 calcsize(n->nhere.next);
8582 break;
8583 case NNOT:
8584 calcsize(n->nnot.com);
8585 break;
8586 };
Eric Andersencb57d552001-06-28 07:25:16 +00008587}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008588
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008589
Eric Andersenc470f442003-07-28 09:56:35 +00008590static void
8591sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008592{
8593 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008594 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008595 calcsize(lp->n);
8596 lp = lp->next;
8597 }
8598}
Eric Andersencb57d552001-06-28 07:25:16 +00008599
8600
Eric Andersenc470f442003-07-28 09:56:35 +00008601static union node *
8602copynode(union node *n)
8603{
8604 union node *new;
8605
8606 if (n == NULL)
8607 return NULL;
8608 new = funcblock;
8609 funcblock = (char *) funcblock + nodesize[n->type];
8610 switch (n->type) {
8611 case NCMD:
8612 new->ncmd.redirect = copynode(n->ncmd.redirect);
8613 new->ncmd.args = copynode(n->ncmd.args);
8614 new->ncmd.assign = copynode(n->ncmd.assign);
8615 break;
8616 case NPIPE:
8617 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8618 new->npipe.backgnd = n->npipe.backgnd;
8619 break;
8620 case NREDIR:
8621 case NBACKGND:
8622 case NSUBSHELL:
8623 new->nredir.redirect = copynode(n->nredir.redirect);
8624 new->nredir.n = copynode(n->nredir.n);
8625 break;
8626 case NAND:
8627 case NOR:
8628 case NSEMI:
8629 case NWHILE:
8630 case NUNTIL:
8631 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8632 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8633 break;
8634 case NIF:
8635 new->nif.elsepart = copynode(n->nif.elsepart);
8636 new->nif.ifpart = copynode(n->nif.ifpart);
8637 new->nif.test = copynode(n->nif.test);
8638 break;
8639 case NFOR:
8640 new->nfor.var = nodesavestr(n->nfor.var);
8641 new->nfor.body = copynode(n->nfor.body);
8642 new->nfor.args = copynode(n->nfor.args);
8643 break;
8644 case NCASE:
8645 new->ncase.cases = copynode(n->ncase.cases);
8646 new->ncase.expr = copynode(n->ncase.expr);
8647 break;
8648 case NCLIST:
8649 new->nclist.body = copynode(n->nclist.body);
8650 new->nclist.pattern = copynode(n->nclist.pattern);
8651 new->nclist.next = copynode(n->nclist.next);
8652 break;
8653 case NDEFUN:
8654 case NARG:
8655 new->narg.backquote = copynodelist(n->narg.backquote);
8656 new->narg.text = nodesavestr(n->narg.text);
8657 new->narg.next = copynode(n->narg.next);
8658 break;
8659 case NTO:
8660 case NCLOBBER:
8661 case NFROM:
8662 case NFROMTO:
8663 case NAPPEND:
8664 new->nfile.fname = copynode(n->nfile.fname);
8665 new->nfile.fd = n->nfile.fd;
8666 new->nfile.next = copynode(n->nfile.next);
8667 break;
8668 case NTOFD:
8669 case NFROMFD:
8670 new->ndup.vname = copynode(n->ndup.vname);
8671 new->ndup.dupfd = n->ndup.dupfd;
8672 new->ndup.fd = n->ndup.fd;
8673 new->ndup.next = copynode(n->ndup.next);
8674 break;
8675 case NHERE:
8676 case NXHERE:
8677 new->nhere.doc = copynode(n->nhere.doc);
8678 new->nhere.fd = n->nhere.fd;
8679 new->nhere.next = copynode(n->nhere.next);
8680 break;
8681 case NNOT:
8682 new->nnot.com = copynode(n->nnot.com);
8683 break;
8684 };
8685 new->type = n->type;
8686 return new;
8687}
8688
8689
8690static struct nodelist *
8691copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008692{
8693 struct nodelist *start;
8694 struct nodelist **lpp;
8695
8696 lpp = &start;
8697 while (lp) {
8698 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008699 funcblock = (char *) funcblock +
8700 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008701 (*lpp)->n = copynode(lp->n);
8702 lp = lp->next;
8703 lpp = &(*lpp)->next;
8704 }
8705 *lpp = NULL;
8706 return start;
8707}
8708
8709
Eric Andersenc470f442003-07-28 09:56:35 +00008710static char *
8711nodesavestr(char *s)
8712{
8713 char *rtn = funcstring;
8714
8715 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008716 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008717}
8718
Eric Andersenc470f442003-07-28 09:56:35 +00008719
Eric Andersenc470f442003-07-28 09:56:35 +00008720/*
8721 * Free a parse tree.
8722 */
8723
8724static void
8725freefunc(struct funcnode *f)
8726{
8727 if (f && --f->count < 0)
8728 ckfree(f);
8729}
8730
8731
8732static void options(int);
8733static void setoption(int, int);
8734
Eric Andersencb57d552001-06-28 07:25:16 +00008735
Eric Andersencb57d552001-06-28 07:25:16 +00008736/*
8737 * Process the shell command line arguments.
8738 */
8739
Eric Andersenc470f442003-07-28 09:56:35 +00008740void
8741procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008742{
8743 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008744 const char *xminusc;
8745 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008746
Eric Andersenc470f442003-07-28 09:56:35 +00008747 xargv = argv;
8748 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008749 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008750 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008751 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008752 optlist[i] = 2;
8753 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008754 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008755 xargv = argptr;
8756 xminusc = minusc;
8757 if (*xargv == NULL) {
8758 if (xminusc)
8759 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008760 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008761 }
Eric Andersencb57d552001-06-28 07:25:16 +00008762 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8763 iflag = 1;
8764 if (mflag == 2)
8765 mflag = iflag;
8766 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008767 if (optlist[i] == 2)
8768 optlist[i] = 0;
8769#if DEBUG == 2
8770 debug = 1;
8771#endif
8772 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8773 if (xminusc) {
8774 minusc = *xargv++;
8775 if (*xargv)
8776 goto setarg0;
8777 } else if (!sflag) {
8778 setinputfile(*xargv, 0);
8779setarg0:
8780 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008781 commandname = arg0;
8782 }
Eric Andersencb57d552001-06-28 07:25:16 +00008783
Eric Andersenc470f442003-07-28 09:56:35 +00008784 shellparam.p = xargv;
8785#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008786 shellparam.optind = 1;
8787 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008788#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008789 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008790 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008791 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008792 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008793 }
8794 optschanged();
8795}
8796
8797
Eric Andersenc470f442003-07-28 09:56:35 +00008798void
8799optschanged(void)
8800{
8801#ifdef DEBUG
8802 opentrace();
8803#endif
8804 setinteractive(iflag);
8805 setjobctl(mflag);
8806}
Eric Andersencb57d552001-06-28 07:25:16 +00008807
Eric Andersenc470f442003-07-28 09:56:35 +00008808static inline void
8809minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008810{
8811 int i;
8812
8813 if (name == NULL) {
8814 out1str("Current option settings\n");
8815 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008816 out1fmt("%-16s%s\n", optnames(i),
8817 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008818 } else {
8819 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008820 if (equal(name, optnames(i))) {
8821 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008822 return;
8823 }
8824 error("Illegal option -o %s", name);
8825 }
8826}
8827
Eric Andersenc470f442003-07-28 09:56:35 +00008828/*
8829 * Process shell options. The global variable argptr contains a pointer
8830 * to the argument list; we advance it past the options.
8831 */
Eric Andersen62483552001-07-10 06:09:16 +00008832
Eric Andersenc470f442003-07-28 09:56:35 +00008833static void
8834options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008835{
8836 char *p;
8837 int val;
8838 int c;
8839
8840 if (cmdline)
8841 minusc = NULL;
8842 while ((p = *argptr) != NULL) {
8843 argptr++;
8844 if ((c = *p++) == '-') {
8845 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008846 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8847 if (!cmdline) {
8848 /* "-" means turn off -x and -v */
8849 if (p[0] == '\0')
8850 xflag = vflag = 0;
8851 /* "--" means reset params */
8852 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008853 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008854 }
Eric Andersenc470f442003-07-28 09:56:35 +00008855 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008856 }
8857 } else if (c == '+') {
8858 val = 0;
8859 } else {
8860 argptr--;
8861 break;
8862 }
8863 while ((c = *p++) != '\0') {
8864 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008865 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008866 } else if (c == 'o') {
8867 minus_o(*argptr, val);
8868 if (*argptr)
8869 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008870 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008871 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008872 isloginsh = 1;
8873 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008874 } else {
8875 setoption(c, val);
8876 }
8877 }
8878 }
8879}
8880
Eric Andersencb57d552001-06-28 07:25:16 +00008881
Eric Andersenc470f442003-07-28 09:56:35 +00008882static void
8883setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008884{
Eric Andersencb57d552001-06-28 07:25:16 +00008885 int i;
8886
8887 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008888 if (optletters(i) == flag) {
8889 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008890 return;
8891 }
8892 error("Illegal option -%c", flag);
8893 /* NOTREACHED */
8894}
8895
8896
8897
Eric Andersencb57d552001-06-28 07:25:16 +00008898/*
8899 * Set the shell parameters.
8900 */
8901
Eric Andersenc470f442003-07-28 09:56:35 +00008902void
8903setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008904{
Eric Andersencb57d552001-06-28 07:25:16 +00008905 char **newparam;
8906 char **ap;
8907 int nparam;
8908
Eric Andersenc470f442003-07-28 09:56:35 +00008909 for (nparam = 0 ; argv[nparam] ; nparam++);
8910 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008911 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008912 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008913 }
8914 *ap = NULL;
8915 freeparam(&shellparam);
8916 shellparam.malloc = 1;
8917 shellparam.nparam = nparam;
8918 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008919#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008920 shellparam.optind = 1;
8921 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008922#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008923}
8924
8925
8926/*
8927 * Free the list of positional parameters.
8928 */
8929
Eric Andersenc470f442003-07-28 09:56:35 +00008930void
8931freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008932{
Eric Andersencb57d552001-06-28 07:25:16 +00008933 char **ap;
8934
8935 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008936 for (ap = param->p ; *ap ; ap++)
8937 ckfree(*ap);
8938 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008939 }
8940}
8941
8942
8943
8944/*
8945 * The shift builtin command.
8946 */
8947
Eric Andersenc470f442003-07-28 09:56:35 +00008948int
8949shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008950{
8951 int n;
8952 char **ap1, **ap2;
8953
8954 n = 1;
8955 if (argc > 1)
8956 n = number(argv[1]);
8957 if (n > shellparam.nparam)
8958 error("can't shift that many");
8959 INTOFF;
8960 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008961 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008962 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008963 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008964 }
8965 ap2 = shellparam.p;
8966 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008967#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008968 shellparam.optind = 1;
8969 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008970#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008971 INTON;
8972 return 0;
8973}
8974
8975
8976
8977/*
8978 * The set command builtin.
8979 */
8980
Eric Andersenc470f442003-07-28 09:56:35 +00008981int
8982setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008983{
8984 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00008985 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00008986 INTOFF;
8987 options(0);
8988 optschanged();
8989 if (*argptr != NULL) {
8990 setparam(argptr);
8991 }
8992 INTON;
8993 return 0;
8994}
8995
8996
Eric Andersenc470f442003-07-28 09:56:35 +00008997#ifdef CONFIG_ASH_GETOPTS
8998static void
8999getoptsreset(value)
9000 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009001{
9002 shellparam.optind = number(value);
9003 shellparam.optoff = -1;
9004}
Eric Andersenc470f442003-07-28 09:56:35 +00009005#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009006
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009007#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009008static void change_lc_all(const char *value)
9009{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009010 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009011 setlocale(LC_ALL, value);
9012}
9013
9014static void change_lc_ctype(const char *value)
9015{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009016 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009017 setlocale(LC_CTYPE, value);
9018}
9019
9020#endif
9021
Eric Andersend35c5df2002-01-09 15:37:36 +00009022#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009023static int
Eric Andersenc470f442003-07-28 09:56:35 +00009024getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009025{
9026 char *p, *q;
9027 char c = '?';
9028 int done = 0;
9029 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009030 char s[12];
9031 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009032
Eric Andersena48b0a32003-10-22 10:56:47 +00009033 if(*param_optind < 1)
9034 return 1;
9035 optnext = optfirst + *param_optind - 1;
9036
9037 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009038 p = NULL;
9039 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009040 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009041 if (p == NULL || *p == '\0') {
9042 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009043 p = *optnext;
9044 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009045atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009046 p = NULL;
9047 done = 1;
9048 goto out;
9049 }
9050 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009051 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009052 goto atend;
9053 }
9054
9055 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009056 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009057 if (*q == '\0') {
9058 if (optstr[0] == ':') {
9059 s[0] = c;
9060 s[1] = '\0';
9061 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009062 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009063 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009064 (void) unsetvar("OPTARG");
9065 }
9066 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009067 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009068 }
9069 if (*++q == ':')
9070 q++;
9071 }
9072
9073 if (*++q == ':') {
9074 if (*p == '\0' && (p = *optnext) == NULL) {
9075 if (optstr[0] == ':') {
9076 s[0] = c;
9077 s[1] = '\0';
9078 err |= setvarsafe("OPTARG", s, 0);
9079 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009080 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009081 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009082 (void) unsetvar("OPTARG");
9083 c = '?';
9084 }
Eric Andersenc470f442003-07-28 09:56:35 +00009085 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009086 }
9087
9088 if (p == *optnext)
9089 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009090 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009091 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009092 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009093 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009094
Eric Andersenc470f442003-07-28 09:56:35 +00009095out:
Eric Andersencb57d552001-06-28 07:25:16 +00009096 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009097 *param_optind = optnext - optfirst + 1;
9098 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009099 err |= setvarsafe("OPTIND", s, VNOFUNC);
9100 s[0] = c;
9101 s[1] = '\0';
9102 err |= setvarsafe(optvar, s, 0);
9103 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009104 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009105 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009106 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009107 exraise(EXERROR);
9108 }
9109 return done;
9110}
Eric Andersenc470f442003-07-28 09:56:35 +00009111
9112/*
9113 * The getopts builtin. Shellparam.optnext points to the next argument
9114 * to be processed. Shellparam.optptr points to the next character to
9115 * be processed in the current argument. If shellparam.optnext is NULL,
9116 * then it's the first time getopts has been called.
9117 */
9118
9119int
9120getoptscmd(int argc, char **argv)
9121{
9122 char **optbase;
9123
9124 if (argc < 3)
9125 error("Usage: getopts optstring var [arg]");
9126 else if (argc == 3) {
9127 optbase = shellparam.p;
9128 if (shellparam.optind > shellparam.nparam + 1) {
9129 shellparam.optind = 1;
9130 shellparam.optoff = -1;
9131 }
9132 }
9133 else {
9134 optbase = &argv[3];
9135 if (shellparam.optind > argc - 2) {
9136 shellparam.optind = 1;
9137 shellparam.optoff = -1;
9138 }
9139 }
9140
9141 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9142 &shellparam.optoff);
9143}
9144#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009145
9146/*
9147 * XXX - should get rid of. have all builtins use getopt(3). the
9148 * library getopt must have the BSD extension static variable "optreset"
9149 * otherwise it can't be used within the shell safely.
9150 *
9151 * Standard option processing (a la getopt) for builtin routines. The
9152 * only argument that is passed to nextopt is the option string; the
9153 * other arguments are unnecessary. It return the character, or '\0' on
9154 * end of input.
9155 */
9156
Eric Andersenc470f442003-07-28 09:56:35 +00009157static int
9158nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009159{
Eric Andersencb57d552001-06-28 07:25:16 +00009160 char *p;
9161 const char *q;
9162 char c;
9163
9164 if ((p = optptr) == NULL || *p == '\0') {
9165 p = *argptr;
9166 if (p == NULL || *p != '-' || *++p == '\0')
9167 return '\0';
9168 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009169 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009170 return '\0';
9171 }
9172 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009173 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009174 if (*q == '\0')
9175 error("Illegal option -%c", c);
9176 if (*++q == ':')
9177 q++;
9178 }
9179 if (*++q == ':') {
9180 if (*p == '\0' && (p = *argptr++) == NULL)
9181 error("No arg for -%c option", c);
9182 optionarg = p;
9183 p = NULL;
9184 }
9185 optptr = p;
9186 return c;
9187}
9188
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009189
Eric Andersenc470f442003-07-28 09:56:35 +00009190/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9191
Eric Andersenc470f442003-07-28 09:56:35 +00009192void
9193outstr(const char *p, FILE *file)
9194{
9195 INTOFF;
9196 fputs(p, file);
9197 INTON;
9198}
9199
9200void
9201flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009202{
Eric Andersencb57d552001-06-28 07:25:16 +00009203 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009204 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009205 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009206 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009207}
9208
Eric Andersenc470f442003-07-28 09:56:35 +00009209void
9210flushout(FILE *dest)
9211{
9212 INTOFF;
9213 fflush(dest);
9214 INTON;
9215}
9216
9217static void
9218outcslow(int c, FILE *dest)
9219{
9220 INTOFF;
9221 putc(c, dest);
9222 fflush(dest);
9223 INTON;
9224}
9225
9226
9227static int
9228out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009229{
9230 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009231 int r;
9232
9233 INTOFF;
9234 va_start(ap, fmt);
9235 r = vprintf(fmt, ap);
9236 va_end(ap);
9237 INTON;
9238 return r;
9239}
9240
9241
9242int
9243fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9244{
9245 va_list ap;
9246 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009247
Eric Andersencb57d552001-06-28 07:25:16 +00009248 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009249 INTOFF;
9250 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009251 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009252 INTON;
9253 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009254}
9255
Eric Andersenc470f442003-07-28 09:56:35 +00009256
Eric Andersencb57d552001-06-28 07:25:16 +00009257/*
9258 * Version of write which resumes after a signal is caught.
9259 */
9260
Eric Andersenc470f442003-07-28 09:56:35 +00009261static void
9262xwrite(int fd, const void *p, size_t n)
Eric Andersen2870d962001-07-02 17:27:21 +00009263{
Eric Andersenc470f442003-07-28 09:56:35 +00009264 ssize_t i;
Eric Andersencb57d552001-06-28 07:25:16 +00009265
Eric Andersenc470f442003-07-28 09:56:35 +00009266 do {
9267 i = bb_full_write(fd, p, n);
9268 } while (i < 0 && errno == EINTR);
Eric Andersencb57d552001-06-28 07:25:16 +00009269}
9270
9271
Eric Andersenc470f442003-07-28 09:56:35 +00009272/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9273
9274
Eric Andersencb57d552001-06-28 07:25:16 +00009275/*
9276 * Shell command parser.
9277 */
9278
9279#define EOFMARKLEN 79
9280
9281
Eric Andersencb57d552001-06-28 07:25:16 +00009282struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009283 struct heredoc *next; /* next here document in list */
9284 union node *here; /* redirection node */
9285 char *eofmark; /* string indicating end of input */
9286 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009287};
9288
9289
9290
Eric Andersenc470f442003-07-28 09:56:35 +00009291static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009292
9293
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009294static union node *list(int);
9295static union node *andor(void);
9296static union node *pipeline(void);
9297static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009298static union node *simplecmd(void);
9299static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009300static void parsefname(void);
9301static void parseheredoc(void);
9302static char peektoken(void);
9303static int readtoken(void);
9304static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009305static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009306static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009307static void synexpect(int) __attribute__((__noreturn__));
9308static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009309static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009310
9311
Eric Andersenc470f442003-07-28 09:56:35 +00009312
9313static inline int
9314isassignment(const char *p)
9315{
9316 const char *q = endofname(p);
9317 if (p == q)
9318 return 0;
9319 return *q == '=';
9320}
9321
9322
Eric Andersencb57d552001-06-28 07:25:16 +00009323/*
9324 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9325 * valid parse tree indicating a blank line.)
9326 */
9327
Eric Andersenc470f442003-07-28 09:56:35 +00009328union node *
9329parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009330{
9331 int t;
9332
9333 tokpushback = 0;
9334 doprompt = interact;
9335 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009336 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009337 needprompt = 0;
9338 t = readtoken();
9339 if (t == TEOF)
9340 return NEOF;
9341 if (t == TNL)
9342 return NULL;
9343 tokpushback++;
9344 return list(1);
9345}
9346
9347
Eric Andersenc470f442003-07-28 09:56:35 +00009348static union node *
9349list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009350{
9351 union node *n1, *n2, *n3;
9352 int tok;
9353
Eric Andersenc470f442003-07-28 09:56:35 +00009354 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9355 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009356 return NULL;
9357 n1 = NULL;
9358 for (;;) {
9359 n2 = andor();
9360 tok = readtoken();
9361 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009362 if (n2->type == NPIPE) {
9363 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009364 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009365 if (n2->type != NREDIR) {
9366 n3 = stalloc(sizeof(struct nredir));
9367 n3->nredir.n = n2;
9368 n3->nredir.redirect = NULL;
9369 n2 = n3;
9370 }
9371 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009372 }
9373 }
9374 if (n1 == NULL) {
9375 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009376 }
9377 else {
9378 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009379 n3->type = NSEMI;
9380 n3->nbinary.ch1 = n1;
9381 n3->nbinary.ch2 = n2;
9382 n1 = n3;
9383 }
9384 switch (tok) {
9385 case TBACKGND:
9386 case TSEMI:
9387 tok = readtoken();
9388 /* fall through */
9389 case TNL:
9390 if (tok == TNL) {
9391 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009392 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009393 return n1;
9394 } else {
9395 tokpushback++;
9396 }
Eric Andersenc470f442003-07-28 09:56:35 +00009397 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009398 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009399 return n1;
9400 break;
9401 case TEOF:
9402 if (heredoclist)
9403 parseheredoc();
9404 else
Eric Andersenc470f442003-07-28 09:56:35 +00009405 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009406 return n1;
9407 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009408 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009409 synexpect(-1);
9410 tokpushback++;
9411 return n1;
9412 }
9413 }
9414}
9415
9416
9417
Eric Andersenc470f442003-07-28 09:56:35 +00009418static union node *
9419andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009420{
Eric Andersencb57d552001-06-28 07:25:16 +00009421 union node *n1, *n2, *n3;
9422 int t;
9423
Eric Andersencb57d552001-06-28 07:25:16 +00009424 n1 = pipeline();
9425 for (;;) {
9426 if ((t = readtoken()) == TAND) {
9427 t = NAND;
9428 } else if (t == TOR) {
9429 t = NOR;
9430 } else {
9431 tokpushback++;
9432 return n1;
9433 }
Eric Andersenc470f442003-07-28 09:56:35 +00009434 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009435 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009436 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009437 n3->type = t;
9438 n3->nbinary.ch1 = n1;
9439 n3->nbinary.ch2 = n2;
9440 n1 = n3;
9441 }
9442}
9443
9444
9445
Eric Andersenc470f442003-07-28 09:56:35 +00009446static union node *
9447pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009448{
Eric Andersencb57d552001-06-28 07:25:16 +00009449 union node *n1, *n2, *pipenode;
9450 struct nodelist *lp, *prev;
9451 int negate;
9452
9453 negate = 0;
9454 TRACE(("pipeline: entered\n"));
9455 if (readtoken() == TNOT) {
9456 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009457 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009458 } else
9459 tokpushback++;
9460 n1 = command();
9461 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009462 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009463 pipenode->type = NPIPE;
9464 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009465 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009466 pipenode->npipe.cmdlist = lp;
9467 lp->n = n1;
9468 do {
9469 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009470 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9471 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009472 lp->n = command();
9473 prev->next = lp;
9474 } while (readtoken() == TPIPE);
9475 lp->next = NULL;
9476 n1 = pipenode;
9477 }
9478 tokpushback++;
9479 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009480 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009481 n2->type = NNOT;
9482 n2->nnot.com = n1;
9483 return n2;
9484 } else
9485 return n1;
9486}
9487
9488
9489
Eric Andersenc470f442003-07-28 09:56:35 +00009490static union node *
9491command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009492{
Eric Andersencb57d552001-06-28 07:25:16 +00009493 union node *n1, *n2;
9494 union node *ap, **app;
9495 union node *cp, **cpp;
9496 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009497 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009498 int t;
9499
9500 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009501 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009502
Eric Andersencb57d552001-06-28 07:25:16 +00009503 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009504 default:
9505 synexpect(-1);
9506 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009507 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009508 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009509 n1->type = NIF;
9510 n1->nif.test = list(0);
9511 if (readtoken() != TTHEN)
9512 synexpect(TTHEN);
9513 n1->nif.ifpart = list(0);
9514 n2 = n1;
9515 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009516 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009517 n2 = n2->nif.elsepart;
9518 n2->type = NIF;
9519 n2->nif.test = list(0);
9520 if (readtoken() != TTHEN)
9521 synexpect(TTHEN);
9522 n2->nif.ifpart = list(0);
9523 }
9524 if (lasttoken == TELSE)
9525 n2->nif.elsepart = list(0);
9526 else {
9527 n2->nif.elsepart = NULL;
9528 tokpushback++;
9529 }
Eric Andersenc470f442003-07-28 09:56:35 +00009530 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009531 break;
9532 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009533 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009534 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009535 n1 = (union node *)stalloc(sizeof (struct nbinary));
9536 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009537 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009538 if ((got=readtoken()) != TDO) {
9539TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009540 synexpect(TDO);
9541 }
9542 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009543 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009544 break;
9545 }
9546 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009547 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009548 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009549 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009550 n1->type = NFOR;
9551 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009552 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009553 if (readtoken() == TIN) {
9554 app = &ap;
9555 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009556 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009557 n2->type = NARG;
9558 n2->narg.text = wordtext;
9559 n2->narg.backquote = backquotelist;
9560 *app = n2;
9561 app = &n2->narg.next;
9562 }
9563 *app = NULL;
9564 n1->nfor.args = ap;
9565 if (lasttoken != TNL && lasttoken != TSEMI)
9566 synexpect(-1);
9567 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009568 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009569 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009570 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009571 n2->narg.backquote = NULL;
9572 n2->narg.next = NULL;
9573 n1->nfor.args = n2;
9574 /*
9575 * Newline or semicolon here is optional (but note
9576 * that the original Bourne shell only allowed NL).
9577 */
9578 if (lasttoken != TNL && lasttoken != TSEMI)
9579 tokpushback++;
9580 }
Eric Andersenc470f442003-07-28 09:56:35 +00009581 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009582 if (readtoken() != TDO)
9583 synexpect(TDO);
9584 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009585 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009586 break;
9587 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009588 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009589 n1->type = NCASE;
9590 if (readtoken() != TWORD)
9591 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009592 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009593 n2->type = NARG;
9594 n2->narg.text = wordtext;
9595 n2->narg.backquote = backquotelist;
9596 n2->narg.next = NULL;
9597 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009598 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009599 } while (readtoken() == TNL);
9600 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009601 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009602 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009603next_case:
9604 checkkwd = CHKNL | CHKKWD;
9605 t = readtoken();
9606 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009607 if (lasttoken == TLP)
9608 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009609 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009610 cp->type = NCLIST;
9611 app = &cp->nclist.pattern;
9612 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009613 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009614 ap->type = NARG;
9615 ap->narg.text = wordtext;
9616 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009617 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009618 break;
9619 app = &ap->narg.next;
9620 readtoken();
9621 }
9622 ap->narg.next = NULL;
9623 if (lasttoken != TRP)
9624 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009625 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009626
Eric Andersenc470f442003-07-28 09:56:35 +00009627 cpp = &cp->nclist.next;
9628
9629 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009630 if ((t = readtoken()) != TESAC) {
9631 if (t != TENDCASE)
9632 synexpect(TENDCASE);
9633 else
Eric Andersenc470f442003-07-28 09:56:35 +00009634 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009635 }
Eric Andersenc470f442003-07-28 09:56:35 +00009636 }
Eric Andersencb57d552001-06-28 07:25:16 +00009637 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009638 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009639 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009640 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009641 n1->type = NSUBSHELL;
9642 n1->nredir.n = list(0);
9643 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009644 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009645 break;
9646 case TBEGIN:
9647 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009648 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009649 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009650 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009651 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009652 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009653 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009654 }
9655
Eric Andersenc470f442003-07-28 09:56:35 +00009656 if (readtoken() != t)
9657 synexpect(t);
9658
9659redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009660 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009661 checkkwd = CHKKWD | CHKALIAS;
9662 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009663 while (readtoken() == TREDIR) {
9664 *rpp = n2 = redirnode;
9665 rpp = &n2->nfile.next;
9666 parsefname();
9667 }
9668 tokpushback++;
9669 *rpp = NULL;
9670 if (redir) {
9671 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009672 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009673 n2->type = NREDIR;
9674 n2->nredir.n = n1;
9675 n1 = n2;
9676 }
9677 n1->nredir.redirect = redir;
9678 }
9679
9680 return n1;
9681}
9682
9683
Eric Andersenc470f442003-07-28 09:56:35 +00009684static union node *
9685simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009686 union node *args, **app;
9687 union node *n = NULL;
9688 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009689 union node **rpp, *redir;
9690 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009691
9692 args = NULL;
9693 app = &args;
9694 vars = NULL;
9695 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009696 redir = NULL;
9697 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009698
Eric Andersenc470f442003-07-28 09:56:35 +00009699 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009700 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009701 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009702 switch (readtoken()) {
9703 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009704 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009705 n->type = NARG;
9706 n->narg.text = wordtext;
9707 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009708 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009709 *vpp = n;
9710 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009711 } else {
9712 *app = n;
9713 app = &n->narg.next;
9714 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009715 }
9716 break;
9717 case TREDIR:
9718 *rpp = n = redirnode;
9719 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009720 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009721 break;
9722 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009723 if (
9724 args && app == &args->narg.next &&
9725 !vars && !redir
9726 ) {
9727 struct builtincmd *bcmd;
9728 const char *name;
9729
Eric Andersencb57d552001-06-28 07:25:16 +00009730 /* We have a function */
9731 if (readtoken() != TRP)
9732 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009733 name = n->narg.text;
9734 if (
9735 !goodname(name) || (
9736 (bcmd = find_builtin(name)) &&
9737 IS_BUILTIN_SPECIAL(bcmd)
9738 )
9739 )
9740 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009741 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009742 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009743 n->narg.next = command();
9744 return n;
9745 }
9746 /* fall through */
9747 default:
9748 tokpushback++;
9749 goto out;
9750 }
9751 }
Eric Andersenc470f442003-07-28 09:56:35 +00009752out:
Eric Andersencb57d552001-06-28 07:25:16 +00009753 *app = NULL;
9754 *vpp = NULL;
9755 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009756 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009757 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009758 n->ncmd.args = args;
9759 n->ncmd.assign = vars;
9760 n->ncmd.redirect = redir;
9761 return n;
9762}
9763
Eric Andersenc470f442003-07-28 09:56:35 +00009764static union node *
9765makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009766{
Eric Andersencb57d552001-06-28 07:25:16 +00009767 union node *n;
9768
Eric Andersenc470f442003-07-28 09:56:35 +00009769 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009770 n->type = NARG;
9771 n->narg.next = NULL;
9772 n->narg.text = wordtext;
9773 n->narg.backquote = backquotelist;
9774 return n;
9775}
9776
Eric Andersenc470f442003-07-28 09:56:35 +00009777void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009778{
Eric Andersencb57d552001-06-28 07:25:16 +00009779 TRACE(("Fix redir %s %d\n", text, err));
9780 if (!err)
9781 n->ndup.vname = NULL;
9782
9783 if (is_digit(text[0]) && text[1] == '\0')
9784 n->ndup.dupfd = digit_val(text[0]);
9785 else if (text[0] == '-' && text[1] == '\0')
9786 n->ndup.dupfd = -1;
9787 else {
9788
9789 if (err)
9790 synerror("Bad fd number");
9791 else
9792 n->ndup.vname = makename();
9793 }
9794}
9795
9796
Eric Andersenc470f442003-07-28 09:56:35 +00009797static void
9798parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009799{
Eric Andersencb57d552001-06-28 07:25:16 +00009800 union node *n = redirnode;
9801
9802 if (readtoken() != TWORD)
9803 synexpect(-1);
9804 if (n->type == NHERE) {
9805 struct heredoc *here = heredoc;
9806 struct heredoc *p;
9807 int i;
9808
9809 if (quoteflag == 0)
9810 n->type = NXHERE;
9811 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009812 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009813 synerror("Illegal eof marker for << redirection");
9814 rmescapes(wordtext);
9815 here->eofmark = wordtext;
9816 here->next = NULL;
9817 if (heredoclist == NULL)
9818 heredoclist = here;
9819 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009820 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009821 p->next = here;
9822 }
9823 } else if (n->type == NTOFD || n->type == NFROMFD) {
9824 fixredir(n, wordtext, 0);
9825 } else {
9826 n->nfile.fname = makename();
9827 }
9828}
9829
9830
9831/*
9832 * Input any here documents.
9833 */
9834
Eric Andersenc470f442003-07-28 09:56:35 +00009835static void
9836parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009837{
Eric Andersencb57d552001-06-28 07:25:16 +00009838 struct heredoc *here;
9839 union node *n;
9840
Eric Andersenc470f442003-07-28 09:56:35 +00009841 here = heredoclist;
9842 heredoclist = 0;
9843
9844 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009845 if (needprompt) {
9846 setprompt(2);
9847 needprompt = 0;
9848 }
Eric Andersenc470f442003-07-28 09:56:35 +00009849 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9850 here->eofmark, here->striptabs);
9851 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009852 n->narg.type = NARG;
9853 n->narg.next = NULL;
9854 n->narg.text = wordtext;
9855 n->narg.backquote = backquotelist;
9856 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009857 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009858 }
9859}
9860
Eric Andersenc470f442003-07-28 09:56:35 +00009861static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009862{
Eric Andersencb57d552001-06-28 07:25:16 +00009863 int t;
9864
9865 t = readtoken();
9866 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009867 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009868}
9869
Eric Andersenc470f442003-07-28 09:56:35 +00009870static int
9871readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009872{
Eric Andersencb57d552001-06-28 07:25:16 +00009873 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009874#ifdef DEBUG
9875 int alreadyseen = tokpushback;
9876#endif
9877
Eric Andersend35c5df2002-01-09 15:37:36 +00009878#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009879top:
Eric Andersen2870d962001-07-02 17:27:21 +00009880#endif
9881
Eric Andersencb57d552001-06-28 07:25:16 +00009882 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009883
Eric Andersenc470f442003-07-28 09:56:35 +00009884 /*
9885 * eat newlines
9886 */
9887 if (checkkwd & CHKNL) {
9888 while (t == TNL) {
9889 parseheredoc();
9890 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009891 }
9892 }
9893
Eric Andersenc470f442003-07-28 09:56:35 +00009894 if (t != TWORD || quoteflag) {
9895 goto out;
9896 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009897
Eric Andersenc470f442003-07-28 09:56:35 +00009898 /*
9899 * check for keywords
9900 */
9901 if (checkkwd & CHKKWD) {
9902 const char *const *pp;
9903
9904 if ((pp = findkwd(wordtext))) {
9905 lasttoken = t = pp - tokname_array;
9906 TRACE(("keyword %s recognized\n", tokname(t)));
9907 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009908 }
Eric Andersenc470f442003-07-28 09:56:35 +00009909 }
9910
9911 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009912#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009913 struct alias *ap;
9914 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009915 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009916 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009917 }
Eric Andersencb57d552001-06-28 07:25:16 +00009918 goto top;
9919 }
Eric Andersen2870d962001-07-02 17:27:21 +00009920#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009921 }
Eric Andersenc470f442003-07-28 09:56:35 +00009922out:
9923 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009924#ifdef DEBUG
9925 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009926 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009927 else
Eric Andersenc470f442003-07-28 09:56:35 +00009928 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009929#endif
9930 return (t);
9931}
9932
9933
9934/*
9935 * Read the next input token.
9936 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009937 * backquotes. We set quoteflag to true if any part of the word was
9938 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009939 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009940 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009941 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009942 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009943 *
9944 * [Change comment: here documents and internal procedures]
9945 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9946 * word parsing code into a separate routine. In this case, readtoken
9947 * doesn't need to have any internal procedures, but parseword does.
9948 * We could also make parseoperator in essence the main routine, and
9949 * have parseword (readtoken1?) handle both words and redirection.]
9950 */
9951
Eric Andersen81fe1232003-07-29 06:38:40 +00009952#define NEW_xxreadtoken
9953#ifdef NEW_xxreadtoken
9954
9955/* singles must be first! */
9956static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9957
9958static const char xxreadtoken_tokens[] = {
9959 TNL, TLP, TRP, /* only single occurrence allowed */
9960 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9961 TEOF, /* corresponds to trailing nul */
9962 TAND, TOR, TENDCASE, /* if double occurrence */
9963};
9964
9965#define xxreadtoken_doubles \
9966 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9967#define xxreadtoken_singles \
9968 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9969
9970static int xxreadtoken()
9971{
9972 int c;
9973
9974 if (tokpushback) {
9975 tokpushback = 0;
9976 return lasttoken;
9977 }
9978 if (needprompt) {
9979 setprompt(2);
9980 needprompt = 0;
9981 }
9982 startlinno = plinno;
9983 for (;;) { /* until token or start of word found */
9984 c = pgetc_macro();
9985
9986 if ((c != ' ') && (c != '\t')
9987#ifdef CONFIG_ASH_ALIAS
9988 && (c != PEOA)
9989#endif
9990 ) {
9991 if (c == '#') {
9992 while ((c = pgetc()) != '\n' && c != PEOF);
9993 pungetc();
9994 } else if (c == '\\') {
9995 if (pgetc() != '\n') {
9996 pungetc();
9997 goto READTOKEN1;
9998 }
9999 startlinno = ++plinno;
10000 if (doprompt)
10001 setprompt(2);
10002 } else {
10003 const char *p
10004 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10005
10006 if (c != PEOF) {
10007 if (c == '\n') {
10008 plinno++;
10009 needprompt = doprompt;
10010 }
10011
10012 p = strchr(xxreadtoken_chars, c);
10013 if (p == NULL) {
10014 READTOKEN1:
10015 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10016 }
10017
10018 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10019 if (pgetc() == *p) { /* double occurrence? */
10020 p += xxreadtoken_doubles + 1;
10021 } else {
10022 pungetc();
10023 }
10024 }
10025 }
10026
10027 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10028 }
10029 }
10030 }
10031}
10032
10033
10034#else
Eric Andersen2870d962001-07-02 17:27:21 +000010035#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010036
Eric Andersenc470f442003-07-28 09:56:35 +000010037static int
10038xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010039{
Eric Andersencb57d552001-06-28 07:25:16 +000010040 int c;
10041
10042 if (tokpushback) {
10043 tokpushback = 0;
10044 return lasttoken;
10045 }
10046 if (needprompt) {
10047 setprompt(2);
10048 needprompt = 0;
10049 }
10050 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010051 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010052 c = pgetc_macro();
10053 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010054 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010055#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010056 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010057#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010058 continue;
10059 case '#':
10060 while ((c = pgetc()) != '\n' && c != PEOF);
10061 pungetc();
10062 continue;
10063 case '\\':
10064 if (pgetc() == '\n') {
10065 startlinno = ++plinno;
10066 if (doprompt)
10067 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010068 continue;
10069 }
10070 pungetc();
10071 goto breakloop;
10072 case '\n':
10073 plinno++;
10074 needprompt = doprompt;
10075 RETURN(TNL);
10076 case PEOF:
10077 RETURN(TEOF);
10078 case '&':
10079 if (pgetc() == '&')
10080 RETURN(TAND);
10081 pungetc();
10082 RETURN(TBACKGND);
10083 case '|':
10084 if (pgetc() == '|')
10085 RETURN(TOR);
10086 pungetc();
10087 RETURN(TPIPE);
10088 case ';':
10089 if (pgetc() == ';')
10090 RETURN(TENDCASE);
10091 pungetc();
10092 RETURN(TSEMI);
10093 case '(':
10094 RETURN(TLP);
10095 case ')':
10096 RETURN(TRP);
10097 default:
10098 goto breakloop;
10099 }
10100 }
Eric Andersenc470f442003-07-28 09:56:35 +000010101breakloop:
10102 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010103#undef RETURN
10104}
Eric Andersen81fe1232003-07-29 06:38:40 +000010105#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010106
Eric Andersencb57d552001-06-28 07:25:16 +000010107
Eric Andersencb57d552001-06-28 07:25:16 +000010108/*
10109 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10110 * is not NULL, read a here document. In the latter case, eofmark is the
10111 * word which marks the end of the document and striptabs is true if
10112 * leading tabs should be stripped from the document. The argument firstc
10113 * is the first character of the input token or document.
10114 *
10115 * Because C does not have internal subroutines, I have simulated them
10116 * using goto's to implement the subroutine linkage. The following macros
10117 * will run code that appears at the end of readtoken1.
10118 */
10119
Eric Andersen2870d962001-07-02 17:27:21 +000010120#define CHECKEND() {goto checkend; checkend_return:;}
10121#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10122#define PARSESUB() {goto parsesub; parsesub_return:;}
10123#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10124#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10125#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010126
10127static int
Eric Andersenc470f442003-07-28 09:56:35 +000010128readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010129{
Eric Andersencb57d552001-06-28 07:25:16 +000010130 int c = firstc;
10131 char *out;
10132 int len;
10133 char line[EOFMARKLEN + 1];
10134 struct nodelist *bqlist;
10135 int quotef;
10136 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010137 int varnest; /* levels of variables expansion */
10138 int arinest; /* levels of arithmetic expansion */
10139 int parenlevel; /* levels of parens in arithmetic */
10140 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010141 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010142 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010143#if __GNUC__
10144 /* Avoid longjmp clobbering */
10145 (void) &out;
10146 (void) &quotef;
10147 (void) &dblquote;
10148 (void) &varnest;
10149 (void) &arinest;
10150 (void) &parenlevel;
10151 (void) &dqvarnest;
10152 (void) &oldstyle;
10153 (void) &prevsyntax;
10154 (void) &syntax;
10155#endif
10156
10157 startlinno = plinno;
10158 dblquote = 0;
10159 if (syntax == DQSYNTAX)
10160 dblquote = 1;
10161 quotef = 0;
10162 bqlist = NULL;
10163 varnest = 0;
10164 arinest = 0;
10165 parenlevel = 0;
10166 dqvarnest = 0;
10167
10168 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010169 loop: { /* for each line, until end of word */
10170 CHECKEND(); /* set c to PEOF if at end of here document */
10171 for (;;) { /* until end of line or end of word */
10172 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10173 switch(SIT(c, syntax)) {
10174 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010175 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010176 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010177 USTPUTC(c, out);
10178 plinno++;
10179 if (doprompt)
10180 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010181 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010182 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010183 case CWORD:
10184 USTPUTC(c, out);
10185 break;
10186 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010187 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010188 USTPUTC(CTLESC, out);
10189 USTPUTC(c, out);
10190 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010191 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010192 c = pgetc2();
10193 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010194 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010195 USTPUTC('\\', out);
10196 pungetc();
10197 } else if (c == '\n') {
10198 if (doprompt)
10199 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010200 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010201 if (
10202 dblquote &&
10203 c != '\\' && c != '`' &&
10204 c != '$' && (
10205 c != '"' ||
10206 eofmark != NULL
10207 )
10208 ) {
10209 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010210 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010211 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010212 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010213 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010214 USTPUTC(c, out);
10215 quotef++;
10216 }
10217 break;
10218 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010219 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010220quotemark:
10221 if (eofmark == NULL) {
10222 USTPUTC(CTLQUOTEMARK, out);
10223 }
Eric Andersencb57d552001-06-28 07:25:16 +000010224 break;
10225 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010226 syntax = DQSYNTAX;
10227 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010228 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010229 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010230 if (eofmark != NULL && arinest == 0 &&
10231 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010232 USTPUTC(c, out);
10233 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010234 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010235 syntax = BASESYNTAX;
10236 dblquote = 0;
10237 }
10238 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010239 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010240 }
10241 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010242 case CVAR: /* '$' */
10243 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010244 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010245 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010246 if (varnest > 0) {
10247 varnest--;
10248 if (dqvarnest > 0) {
10249 dqvarnest--;
10250 }
10251 USTPUTC(CTLENDVAR, out);
10252 } else {
10253 USTPUTC(c, out);
10254 }
10255 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010256#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010257 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010258 parenlevel++;
10259 USTPUTC(c, out);
10260 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010261 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010262 if (parenlevel > 0) {
10263 USTPUTC(c, out);
10264 --parenlevel;
10265 } else {
10266 if (pgetc() == ')') {
10267 if (--arinest == 0) {
10268 USTPUTC(CTLENDARI, out);
10269 syntax = prevsyntax;
10270 if (syntax == DQSYNTAX)
10271 dblquote = 1;
10272 else
10273 dblquote = 0;
10274 } else
10275 USTPUTC(')', out);
10276 } else {
10277 /*
10278 * unbalanced parens
10279 * (don't 2nd guess - no error)
10280 */
10281 pungetc();
10282 USTPUTC(')', out);
10283 }
10284 }
10285 break;
10286#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010287 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010288 PARSEBACKQOLD();
10289 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010290 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010291 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010292 case CIGN:
10293 break;
10294 default:
10295 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010296 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010297#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010298 if (c != PEOA)
10299#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010300 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010301
Eric Andersencb57d552001-06-28 07:25:16 +000010302 }
10303 c = pgetc_macro();
10304 }
10305 }
Eric Andersenc470f442003-07-28 09:56:35 +000010306endword:
10307#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010308 if (syntax == ARISYNTAX)
10309 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010310#endif
10311 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010312 synerror("Unterminated quoted string");
10313 if (varnest != 0) {
10314 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010315 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010316 synerror("Missing '}'");
10317 }
10318 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010319 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010320 out = stackblock();
10321 if (eofmark == NULL) {
10322 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010323 && quotef == 0
10324 && len <= 2
10325 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010326 PARSEREDIR();
10327 return lasttoken = TREDIR;
10328 } else {
10329 pungetc();
10330 }
10331 }
10332 quoteflag = quotef;
10333 backquotelist = bqlist;
10334 grabstackblock(len);
10335 wordtext = out;
10336 return lasttoken = TWORD;
10337/* end of readtoken routine */
10338
10339
10340
10341/*
10342 * Check to see whether we are at the end of the here document. When this
10343 * is called, c is set to the first character of the next input line. If
10344 * we are at the end of the here document, this routine sets the c to PEOF.
10345 */
10346
Eric Andersenc470f442003-07-28 09:56:35 +000010347checkend: {
10348 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010349#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010350 if (c == PEOA) {
10351 c = pgetc2();
10352 }
10353#endif
10354 if (striptabs) {
10355 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010356 c = pgetc2();
10357 }
Eric Andersenc470f442003-07-28 09:56:35 +000010358 }
10359 if (c == *eofmark) {
10360 if (pfgets(line, sizeof line) != NULL) {
10361 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010362
Eric Andersenc470f442003-07-28 09:56:35 +000010363 p = line;
10364 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10365 if (*p == '\n' && *q == '\0') {
10366 c = PEOF;
10367 plinno++;
10368 needprompt = doprompt;
10369 } else {
10370 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010371 }
10372 }
10373 }
10374 }
Eric Andersenc470f442003-07-28 09:56:35 +000010375 goto checkend_return;
10376}
Eric Andersencb57d552001-06-28 07:25:16 +000010377
10378
10379/*
10380 * Parse a redirection operator. The variable "out" points to a string
10381 * specifying the fd to be redirected. The variable "c" contains the
10382 * first character of the redirection operator.
10383 */
10384
Eric Andersenc470f442003-07-28 09:56:35 +000010385parseredir: {
10386 char fd = *out;
10387 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010388
Eric Andersenc470f442003-07-28 09:56:35 +000010389 np = (union node *)stalloc(sizeof (struct nfile));
10390 if (c == '>') {
10391 np->nfile.fd = 1;
10392 c = pgetc();
10393 if (c == '>')
10394 np->type = NAPPEND;
10395 else if (c == '|')
10396 np->type = NCLOBBER;
10397 else if (c == '&')
10398 np->type = NTOFD;
10399 else {
10400 np->type = NTO;
10401 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010402 }
Eric Andersenc470f442003-07-28 09:56:35 +000010403 } else { /* c == '<' */
10404 np->nfile.fd = 0;
10405 switch (c = pgetc()) {
10406 case '<':
10407 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10408 np = (union node *)stalloc(sizeof (struct nhere));
10409 np->nfile.fd = 0;
10410 }
10411 np->type = NHERE;
10412 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10413 heredoc->here = np;
10414 if ((c = pgetc()) == '-') {
10415 heredoc->striptabs = 1;
10416 } else {
10417 heredoc->striptabs = 0;
10418 pungetc();
10419 }
10420 break;
10421
10422 case '&':
10423 np->type = NFROMFD;
10424 break;
10425
10426 case '>':
10427 np->type = NFROMTO;
10428 break;
10429
10430 default:
10431 np->type = NFROM;
10432 pungetc();
10433 break;
10434 }
Eric Andersencb57d552001-06-28 07:25:16 +000010435 }
Eric Andersenc470f442003-07-28 09:56:35 +000010436 if (fd != '\0')
10437 np->nfile.fd = digit_val(fd);
10438 redirnode = np;
10439 goto parseredir_return;
10440}
Eric Andersencb57d552001-06-28 07:25:16 +000010441
10442
10443/*
10444 * Parse a substitution. At this point, we have read the dollar sign
10445 * and nothing else.
10446 */
10447
Eric Andersenc470f442003-07-28 09:56:35 +000010448parsesub: {
10449 int subtype;
10450 int typeloc;
10451 int flags;
10452 char *p;
10453 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010454
Eric Andersenc470f442003-07-28 09:56:35 +000010455 c = pgetc();
10456 if (
10457 c <= PEOA_OR_PEOF ||
10458 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10459 ) {
10460 USTPUTC('$', out);
10461 pungetc();
10462 } else if (c == '(') { /* $(command) or $((arith)) */
10463 if (pgetc() == '(') {
10464#ifdef CONFIG_ASH_MATH_SUPPORT
10465 PARSEARITH();
10466#else
10467 synerror("We unsupport $((arith))");
10468#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010469 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010470 pungetc();
10471 PARSEBACKQNEW();
10472 }
10473 } else {
10474 USTPUTC(CTLVAR, out);
10475 typeloc = out - (char *)stackblock();
10476 USTPUTC(VSNORMAL, out);
10477 subtype = VSNORMAL;
10478 if (c == '{') {
10479 c = pgetc();
10480 if (c == '#') {
10481 if ((c = pgetc()) == '}')
10482 c = '#';
10483 else
10484 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010485 }
Eric Andersenc470f442003-07-28 09:56:35 +000010486 else
10487 subtype = 0;
10488 }
10489 if (c > PEOA_OR_PEOF && is_name(c)) {
10490 do {
10491 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010492 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010493 } while (c > PEOA_OR_PEOF && is_in_name(c));
10494 } else if (is_digit(c)) {
10495 do {
10496 STPUTC(c, out);
10497 c = pgetc();
10498 } while (is_digit(c));
10499 }
10500 else if (is_special(c)) {
10501 USTPUTC(c, out);
10502 c = pgetc();
10503 }
10504 else
10505badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010506
Eric Andersenc470f442003-07-28 09:56:35 +000010507 STPUTC('=', out);
10508 flags = 0;
10509 if (subtype == 0) {
10510 switch (c) {
10511 case ':':
10512 flags = VSNUL;
10513 c = pgetc();
10514 /*FALLTHROUGH*/
10515 default:
10516 p = strchr(types, c);
10517 if (p == NULL)
10518 goto badsub;
10519 subtype = p - types + VSNORMAL;
10520 break;
10521 case '%':
10522 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010523 {
10524 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010525 subtype = c == '#' ? VSTRIMLEFT :
10526 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010527 c = pgetc();
10528 if (c == cc)
10529 subtype++;
10530 else
10531 pungetc();
10532 break;
10533 }
10534 }
Eric Andersenc470f442003-07-28 09:56:35 +000010535 } else {
10536 pungetc();
10537 }
10538 if (dblquote || arinest)
10539 flags |= VSQUOTE;
10540 *((char *)stackblock() + typeloc) = subtype | flags;
10541 if (subtype != VSNORMAL) {
10542 varnest++;
10543 if (dblquote || arinest) {
10544 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010545 }
10546 }
10547 }
Eric Andersenc470f442003-07-28 09:56:35 +000010548 goto parsesub_return;
10549}
Eric Andersencb57d552001-06-28 07:25:16 +000010550
10551
10552/*
10553 * Called to parse command substitutions. Newstyle is set if the command
10554 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10555 * list of commands (passed by reference), and savelen is the number of
10556 * characters on the top of the stack which must be preserved.
10557 */
10558
Eric Andersenc470f442003-07-28 09:56:35 +000010559parsebackq: {
10560 struct nodelist **nlpp;
10561 int savepbq;
10562 union node *n;
10563 char *volatile str;
10564 struct jmploc jmploc;
10565 struct jmploc *volatile savehandler;
10566 size_t savelen;
10567 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010568#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010569 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010570#endif
10571
Eric Andersenc470f442003-07-28 09:56:35 +000010572 savepbq = parsebackquote;
10573 if (setjmp(jmploc.loc)) {
10574 if (str)
10575 ckfree(str);
10576 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010577 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010578 longjmp(handler->loc, 1);
10579 }
10580 INTOFF;
10581 str = NULL;
10582 savelen = out - (char *)stackblock();
10583 if (savelen > 0) {
10584 str = ckmalloc(savelen);
10585 memcpy(str, stackblock(), savelen);
10586 }
10587 savehandler = handler;
10588 handler = &jmploc;
10589 INTON;
10590 if (oldstyle) {
10591 /* We must read until the closing backquote, giving special
10592 treatment to some slashes, and then push the string and
10593 reread it as input, interpreting it normally. */
10594 char *pout;
10595 int pc;
10596 size_t psavelen;
10597 char *pstr;
10598
10599
10600 STARTSTACKSTR(pout);
10601 for (;;) {
10602 if (needprompt) {
10603 setprompt(2);
10604 needprompt = 0;
10605 }
10606 switch (pc = pgetc()) {
10607 case '`':
10608 goto done;
10609
10610 case '\\':
10611 if ((pc = pgetc()) == '\n') {
10612 plinno++;
10613 if (doprompt)
10614 setprompt(2);
10615 /*
10616 * If eating a newline, avoid putting
10617 * the newline into the new character
10618 * stream (via the STPUTC after the
10619 * switch).
10620 */
10621 continue;
10622 }
10623 if (pc != '\\' && pc != '`' && pc != '$'
10624 && (!dblquote || pc != '"'))
10625 STPUTC('\\', pout);
10626 if (pc > PEOA_OR_PEOF) {
10627 break;
10628 }
10629 /* fall through */
10630
10631 case PEOF:
10632#ifdef CONFIG_ASH_ALIAS
10633 case PEOA:
10634#endif
10635 startlinno = plinno;
10636 synerror("EOF in backquote substitution");
10637
10638 case '\n':
10639 plinno++;
10640 needprompt = doprompt;
10641 break;
10642
10643 default:
10644 break;
10645 }
10646 STPUTC(pc, pout);
10647 }
10648done:
10649 STPUTC('\0', pout);
10650 psavelen = pout - (char *)stackblock();
10651 if (psavelen > 0) {
10652 pstr = grabstackstr(pout);
10653 setinputstring(pstr);
10654 }
10655 }
10656 nlpp = &bqlist;
10657 while (*nlpp)
10658 nlpp = &(*nlpp)->next;
10659 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10660 (*nlpp)->next = NULL;
10661 parsebackquote = oldstyle;
10662
10663 if (oldstyle) {
10664 saveprompt = doprompt;
10665 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010666 }
10667
Eric Andersenc470f442003-07-28 09:56:35 +000010668 n = list(2);
10669
10670 if (oldstyle)
10671 doprompt = saveprompt;
10672 else {
10673 if (readtoken() != TRP)
10674 synexpect(TRP);
10675 }
10676
10677 (*nlpp)->n = n;
10678 if (oldstyle) {
10679 /*
10680 * Start reading from old file again, ignoring any pushed back
10681 * tokens left from the backquote parsing
10682 */
10683 popfile();
10684 tokpushback = 0;
10685 }
10686 while (stackblocksize() <= savelen)
10687 growstackblock();
10688 STARTSTACKSTR(out);
10689 if (str) {
10690 memcpy(out, str, savelen);
10691 STADJUST(savelen, out);
10692 INTOFF;
10693 ckfree(str);
10694 str = NULL;
10695 INTON;
10696 }
10697 parsebackquote = savepbq;
10698 handler = savehandler;
10699 if (arinest || dblquote)
10700 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10701 else
10702 USTPUTC(CTLBACKQ, out);
10703 if (oldstyle)
10704 goto parsebackq_oldreturn;
10705 else
10706 goto parsebackq_newreturn;
10707}
10708
10709#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010710/*
10711 * Parse an arithmetic expansion (indicate start of one and set state)
10712 */
Eric Andersenc470f442003-07-28 09:56:35 +000010713parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010714
Eric Andersenc470f442003-07-28 09:56:35 +000010715 if (++arinest == 1) {
10716 prevsyntax = syntax;
10717 syntax = ARISYNTAX;
10718 USTPUTC(CTLARI, out);
10719 if (dblquote)
10720 USTPUTC('"',out);
10721 else
10722 USTPUTC(' ',out);
10723 } else {
10724 /*
10725 * we collapse embedded arithmetic expansion to
10726 * parenthesis, which should be equivalent
10727 */
10728 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010729 }
Eric Andersenc470f442003-07-28 09:56:35 +000010730 goto parsearith_return;
10731}
10732#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010733
Eric Andersenc470f442003-07-28 09:56:35 +000010734} /* end of readtoken */
10735
Eric Andersencb57d552001-06-28 07:25:16 +000010736
10737
Eric Andersencb57d552001-06-28 07:25:16 +000010738/*
10739 * Returns true if the text contains nothing to expand (no dollar signs
10740 * or backquotes).
10741 */
10742
Eric Andersenc470f442003-07-28 09:56:35 +000010743static int
10744noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010745{
Eric Andersencb57d552001-06-28 07:25:16 +000010746 char *p;
10747 char c;
10748
10749 p = text;
10750 while ((c = *p++) != '\0') {
10751 if (c == CTLQUOTEMARK)
10752 continue;
10753 if (c == CTLESC)
10754 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010755 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010756 return 0;
10757 }
10758 return 1;
10759}
10760
10761
10762/*
Eric Andersenc470f442003-07-28 09:56:35 +000010763 * Return of a legal variable name (a letter or underscore followed by zero or
10764 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010765 */
10766
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010767static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010768endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010769{
Eric Andersenc470f442003-07-28 09:56:35 +000010770 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010771
Eric Andersenc470f442003-07-28 09:56:35 +000010772 p = (char *) name;
10773 if (! is_name(*p))
10774 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010775 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010776 if (! is_in_name(*p))
10777 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010778 }
Eric Andersenc470f442003-07-28 09:56:35 +000010779 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010780}
10781
10782
10783/*
10784 * Called when an unexpected token is read during the parse. The argument
10785 * is the token that is expected, or -1 if more than one type of token can
10786 * occur at this point.
10787 */
10788
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010789static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010790{
10791 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010792 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010793
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010794 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10795 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010796 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010797 synerror(msg);
10798 /* NOTREACHED */
10799}
10800
Eric Andersenc470f442003-07-28 09:56:35 +000010801static void
10802synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010803{
Eric Andersenc470f442003-07-28 09:56:35 +000010804 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010805 /* NOTREACHED */
10806}
10807
Eric Andersencb57d552001-06-28 07:25:16 +000010808
10809/*
10810 * called by editline -- any expansions to the prompt
10811 * should be added here.
10812 */
Eric Andersenc470f442003-07-28 09:56:35 +000010813
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010814static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010815{
Eric Andersenc470f442003-07-28 09:56:35 +000010816 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010817
10818 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010819 case 1:
10820 prompt = ps1val();
10821 break;
10822 case 2:
10823 prompt = ps2val();
10824 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010825 default: /* 0 */
10826 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010827 }
10828 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010829}
10830
Eric Andersencb57d552001-06-28 07:25:16 +000010831
Eric Andersenc470f442003-07-28 09:56:35 +000010832static const char *const *findkwd(const char *s)
10833{
10834 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010835 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010836 sizeof(const char *), pstrcmp);
10837}
10838
10839/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10840
Eric Andersencb57d552001-06-28 07:25:16 +000010841/*
10842 * Code for dealing with input/output redirection.
10843 */
10844
Eric Andersenc470f442003-07-28 09:56:35 +000010845#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010846#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010847# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010848#else
10849# define PIPESIZE PIPE_BUF
10850#endif
10851
Eric Andersen62483552001-07-10 06:09:16 +000010852/*
10853 * Open a file in noclobber mode.
10854 * The code was copied from bash.
10855 */
Eric Andersenc470f442003-07-28 09:56:35 +000010856static inline int
10857noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010858{
10859 int r, fd;
10860 struct stat finfo, finfo2;
10861
10862 /*
10863 * If the file exists and is a regular file, return an error
10864 * immediately.
10865 */
10866 r = stat(fname, &finfo);
10867 if (r == 0 && S_ISREG(finfo.st_mode)) {
10868 errno = EEXIST;
10869 return -1;
10870 }
10871
10872 /*
10873 * If the file was not present (r != 0), make sure we open it
10874 * exclusively so that if it is created before we open it, our open
10875 * will fail. Make sure that we do not truncate an existing file.
10876 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10877 * file was not a regular file, we leave O_EXCL off.
10878 */
10879 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010880 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10881 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010882
10883 /* If the open failed, return the file descriptor right away. */
10884 if (fd < 0)
10885 return fd;
10886
10887 /*
10888 * OK, the open succeeded, but the file may have been changed from a
10889 * non-regular file to a regular file between the stat and the open.
10890 * We are assuming that the O_EXCL open handles the case where FILENAME
10891 * did not exist and is symlinked to an existing file between the stat
10892 * and open.
10893 */
10894
10895 /*
10896 * If we can open it and fstat the file descriptor, and neither check
10897 * revealed that it was a regular file, and the file has not been
10898 * replaced, return the file descriptor.
10899 */
Eric Andersenc470f442003-07-28 09:56:35 +000010900 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10901 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010902 return fd;
10903
10904 /* The file has been replaced. badness. */
10905 close(fd);
10906 errno = EEXIST;
10907 return -1;
10908}
Eric Andersencb57d552001-06-28 07:25:16 +000010909
10910/*
Eric Andersen62483552001-07-10 06:09:16 +000010911 * Handle here documents. Normally we fork off a process to write the
10912 * data to a pipe. If the document is short, we can stuff the data in
10913 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010914 */
10915
Eric Andersenc470f442003-07-28 09:56:35 +000010916static inline int
10917openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010918{
10919 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010920 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010921
Eric Andersen62483552001-07-10 06:09:16 +000010922 if (pipe(pip) < 0)
10923 error("Pipe call failed");
10924 if (redir->type == NHERE) {
10925 len = strlen(redir->nhere.doc->narg.text);
10926 if (len <= PIPESIZE) {
10927 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10928 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010929 }
Eric Andersencb57d552001-06-28 07:25:16 +000010930 }
Eric Andersenc470f442003-07-28 09:56:35 +000010931 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010932 close(pip[0]);
10933 signal(SIGINT, SIG_IGN);
10934 signal(SIGQUIT, SIG_IGN);
10935 signal(SIGHUP, SIG_IGN);
10936#ifdef SIGTSTP
10937 signal(SIGTSTP, SIG_IGN);
10938#endif
10939 signal(SIGPIPE, SIG_DFL);
10940 if (redir->type == NHERE)
10941 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10942 else
10943 expandhere(redir->nhere.doc, pip[1]);
10944 _exit(0);
10945 }
Eric Andersenc470f442003-07-28 09:56:35 +000010946out:
Eric Andersen62483552001-07-10 06:09:16 +000010947 close(pip[1]);
10948 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010949}
10950
Eric Andersenc470f442003-07-28 09:56:35 +000010951static int
10952openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010953{
Eric Andersencb57d552001-06-28 07:25:16 +000010954 char *fname;
10955 int f;
10956
10957 switch (redir->nfile.type) {
10958 case NFROM:
10959 fname = redir->nfile.expfname;
10960 if ((f = open(fname, O_RDONLY)) < 0)
10961 goto eopen;
10962 break;
10963 case NFROMTO:
10964 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010965 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010966 goto ecreate;
10967 break;
10968 case NTO:
10969 /* Take care of noclobber mode. */
10970 if (Cflag) {
10971 fname = redir->nfile.expfname;
10972 if ((f = noclobberopen(fname)) < 0)
10973 goto ecreate;
10974 break;
10975 }
Eric Andersenc470f442003-07-28 09:56:35 +000010976 /* FALLTHROUGH */
10977 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000010978 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010979 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010980 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010981 break;
10982 case NAPPEND:
10983 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010984 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010985 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010986 break;
10987 default:
10988#ifdef DEBUG
10989 abort();
10990#endif
10991 /* Fall through to eliminate warning. */
10992 case NTOFD:
10993 case NFROMFD:
10994 f = -1;
10995 break;
10996 case NHERE:
10997 case NXHERE:
10998 f = openhere(redir);
10999 break;
11000 }
11001
11002 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011003ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011004 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011005eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011006 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11007}
11008
Eric Andersenc470f442003-07-28 09:56:35 +000011009static inline void
11010dupredirect(union node *redir, int f)
11011{
11012 int fd = redir->nfile.fd;
11013
11014 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11015 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11016 copyfd(redir->ndup.dupfd, fd);
11017 }
11018 return;
11019 }
11020
11021 if (f != fd) {
11022 copyfd(f, fd);
11023 close(f);
11024 }
11025 return;
11026}
Eric Andersencb57d552001-06-28 07:25:16 +000011027
Eric Andersen62483552001-07-10 06:09:16 +000011028/*
11029 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11030 * old file descriptors are stashed away so that the redirection can be
11031 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11032 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011033 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011034 */
11035
Eric Andersenc470f442003-07-28 09:56:35 +000011036static void
11037redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011038{
11039 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011040 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011041 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011042 int fd;
11043 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011044 int *p;
11045 nullredirs++;
11046 if (!redir) {
11047 return;
Eric Andersen62483552001-07-10 06:09:16 +000011048 }
Eric Andersenc470f442003-07-28 09:56:35 +000011049 sv = NULL;
11050 INTOFF;
11051 if (flags & REDIR_PUSH) {
11052 struct redirtab *q;
11053 q = ckmalloc(sizeof (struct redirtab));
11054 q->next = redirlist;
11055 redirlist = q;
11056 q->nullredirs = nullredirs - 1;
11057 for (i = 0 ; i < 10 ; i++)
11058 q->renamed[i] = EMPTY;
11059 nullredirs = 0;
11060 sv = q;
11061 }
11062 n = redir;
11063 do {
Eric Andersen62483552001-07-10 06:09:16 +000011064 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011065 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011066 n->ndup.dupfd == fd)
11067 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011068
Eric Andersen62483552001-07-10 06:09:16 +000011069 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011070 if (fd == newfd)
11071 continue;
11072 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11073 i = fcntl(fd, F_DUPFD, 10);
11074
11075 if (i == -1) {
11076 i = errno;
11077 if (i != EBADF) {
11078 close(newfd);
11079 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011080 error("%d: %m", fd);
11081 /* NOTREACHED */
11082 }
Eric Andersenc470f442003-07-28 09:56:35 +000011083 } else {
11084 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011085 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011086 }
Eric Andersenc470f442003-07-28 09:56:35 +000011087 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011088 close(fd);
11089 }
Eric Andersenc470f442003-07-28 09:56:35 +000011090 dupredirect(n, newfd);
11091 } while ((n = n->nfile.next));
11092 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011093 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11094 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011095}
11096
11097
Eric Andersencb57d552001-06-28 07:25:16 +000011098/*
11099 * Undo the effects of the last redirection.
11100 */
11101
Eric Andersenc470f442003-07-28 09:56:35 +000011102void
11103popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011104{
Eric Andersenc470f442003-07-28 09:56:35 +000011105 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011106 int i;
11107
Eric Andersenc470f442003-07-28 09:56:35 +000011108 if (--nullredirs >= 0)
11109 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011110 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011111 rp = redirlist;
11112 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011113 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011114 if (!drop) {
11115 close(i);
11116 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011117 }
Eric Andersenc470f442003-07-28 09:56:35 +000011118 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011119 }
11120 }
11121 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011122 nullredirs = rp->nullredirs;
11123 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011124 INTON;
11125}
11126
11127/*
Eric Andersenc470f442003-07-28 09:56:35 +000011128 * Undo all redirections. Called on error or interrupt.
11129 */
11130
11131/*
Eric Andersencb57d552001-06-28 07:25:16 +000011132 * Discard all saved file descriptors.
11133 */
11134
Eric Andersenc470f442003-07-28 09:56:35 +000011135void
11136clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011137{
Eric Andersenc470f442003-07-28 09:56:35 +000011138 for (;;) {
11139 nullredirs = 0;
11140 if (!redirlist)
11141 break;
11142 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011143 }
Eric Andersencb57d552001-06-28 07:25:16 +000011144}
11145
11146
Eric Andersencb57d552001-06-28 07:25:16 +000011147/*
11148 * Copy a file descriptor to be >= to. Returns -1
11149 * if the source file descriptor is closed, EMPTY if there are no unused
11150 * file descriptors left.
11151 */
11152
Eric Andersenc470f442003-07-28 09:56:35 +000011153int
11154copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011155{
11156 int newfd;
11157
11158 newfd = fcntl(from, F_DUPFD, to);
11159 if (newfd < 0) {
11160 if (errno == EMFILE)
11161 return EMPTY;
11162 else
Eric Andersen2870d962001-07-02 17:27:21 +000011163 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011164 }
11165 return newfd;
11166}
11167
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011168
Eric Andersenc470f442003-07-28 09:56:35 +000011169int
11170redirectsafe(union node *redir, int flags)
11171{
11172 int err;
11173 volatile int saveint;
11174 struct jmploc *volatile savehandler = handler;
11175 struct jmploc jmploc;
11176
11177 SAVEINT(saveint);
11178 if (!(err = setjmp(jmploc.loc) * 2)) {
11179 handler = &jmploc;
11180 redirect(redir, flags);
11181 }
11182 handler = savehandler;
11183 if (err && exception != EXERROR)
11184 longjmp(handler->loc, 1);
11185 RESTOREINT(saveint);
11186 return err;
11187}
11188
11189/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11190
11191#ifdef DEBUG
11192static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011193static void shcmd(union node *, FILE *);
11194static void sharg(union node *, FILE *);
11195static void indent(int, char *, FILE *);
11196static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011197
11198
Eric Andersenc470f442003-07-28 09:56:35 +000011199void
11200showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011201{
11202 trputs("showtree called\n");
11203 shtree(n, 1, NULL, stdout);
11204}
Eric Andersencb57d552001-06-28 07:25:16 +000011205
Eric Andersenc470f442003-07-28 09:56:35 +000011206
11207static void
11208shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011209{
11210 struct nodelist *lp;
11211 const char *s;
11212
11213 if (n == NULL)
11214 return;
11215
11216 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011217 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011218 case NSEMI:
11219 s = "; ";
11220 goto binop;
11221 case NAND:
11222 s = " && ";
11223 goto binop;
11224 case NOR:
11225 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011226binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011227 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011228 /* if (ind < 0) */
11229 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011230 shtree(n->nbinary.ch2, ind, NULL, fp);
11231 break;
11232 case NCMD:
11233 shcmd(n, fp);
11234 if (ind >= 0)
11235 putc('\n', fp);
11236 break;
11237 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011238 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011239 shcmd(lp->n, fp);
11240 if (lp->next)
11241 fputs(" | ", fp);
11242 }
11243 if (n->npipe.backgnd)
11244 fputs(" &", fp);
11245 if (ind >= 0)
11246 putc('\n', fp);
11247 break;
11248 default:
11249 fprintf(fp, "<node type %d>", n->type);
11250 if (ind >= 0)
11251 putc('\n', fp);
11252 break;
11253 }
11254}
11255
11256
Eric Andersenc470f442003-07-28 09:56:35 +000011257static void
11258shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011259{
11260 union node *np;
11261 int first;
11262 const char *s;
11263 int dftfd;
11264
11265 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011266 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11267 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011268 putchar(' ');
11269 sharg(np, fp);
11270 first = 0;
11271 }
Eric Andersenc470f442003-07-28 09:56:35 +000011272 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11273 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011274 putchar(' ');
11275 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011276 case NTO: s = ">"; dftfd = 1; break;
11277 case NCLOBBER: s = ">|"; dftfd = 1; break;
11278 case NAPPEND: s = ">>"; dftfd = 1; break;
11279 case NTOFD: s = ">&"; dftfd = 1; break;
11280 case NFROM: s = "<"; dftfd = 0; break;
11281 case NFROMFD: s = "<&"; dftfd = 0; break;
11282 case NFROMTO: s = "<>"; dftfd = 0; break;
11283 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011284 }
11285 if (np->nfile.fd != dftfd)
11286 fprintf(fp, "%d", np->nfile.fd);
11287 fputs(s, fp);
11288 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11289 fprintf(fp, "%d", np->ndup.dupfd);
11290 } else {
11291 sharg(np->nfile.fname, fp);
11292 }
11293 first = 0;
11294 }
11295}
11296
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011297
Eric Andersenc470f442003-07-28 09:56:35 +000011298
11299static void
11300sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011301{
Eric Andersencb57d552001-06-28 07:25:16 +000011302 char *p;
11303 struct nodelist *bqlist;
11304 int subtype;
11305
11306 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011307 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011308 abort();
11309 }
11310 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011311 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011312 switch (*p) {
11313 case CTLESC:
11314 putc(*++p, fp);
11315 break;
11316 case CTLVAR:
11317 putc('$', fp);
11318 putc('{', fp);
11319 subtype = *++p;
11320 if (subtype == VSLENGTH)
11321 putc('#', fp);
11322
11323 while (*p != '=')
11324 putc(*p++, fp);
11325
11326 if (subtype & VSNUL)
11327 putc(':', fp);
11328
11329 switch (subtype & VSTYPE) {
11330 case VSNORMAL:
11331 putc('}', fp);
11332 break;
11333 case VSMINUS:
11334 putc('-', fp);
11335 break;
11336 case VSPLUS:
11337 putc('+', fp);
11338 break;
11339 case VSQUESTION:
11340 putc('?', fp);
11341 break;
11342 case VSASSIGN:
11343 putc('=', fp);
11344 break;
11345 case VSTRIMLEFT:
11346 putc('#', fp);
11347 break;
11348 case VSTRIMLEFTMAX:
11349 putc('#', fp);
11350 putc('#', fp);
11351 break;
11352 case VSTRIMRIGHT:
11353 putc('%', fp);
11354 break;
11355 case VSTRIMRIGHTMAX:
11356 putc('%', fp);
11357 putc('%', fp);
11358 break;
11359 case VSLENGTH:
11360 break;
11361 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011362 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011363 }
11364 break;
11365 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011366 putc('}', fp);
11367 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011368 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011369 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011370 putc('$', fp);
11371 putc('(', fp);
11372 shtree(bqlist->n, -1, NULL, fp);
11373 putc(')', fp);
11374 break;
11375 default:
11376 putc(*p, fp);
11377 break;
11378 }
11379 }
11380}
11381
11382
Eric Andersenc470f442003-07-28 09:56:35 +000011383static void
11384indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011385{
11386 int i;
11387
Eric Andersenc470f442003-07-28 09:56:35 +000011388 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011389 if (pfx && i == amount - 1)
11390 fputs(pfx, fp);
11391 putc('\t', fp);
11392 }
11393}
Eric Andersencb57d552001-06-28 07:25:16 +000011394
Eric Andersenc470f442003-07-28 09:56:35 +000011395
11396
11397/*
11398 * Debugging stuff.
11399 */
11400
11401
Eric Andersencb57d552001-06-28 07:25:16 +000011402FILE *tracefile;
11403
Eric Andersencb57d552001-06-28 07:25:16 +000011404
Eric Andersenc470f442003-07-28 09:56:35 +000011405void
11406trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011407{
Eric Andersenc470f442003-07-28 09:56:35 +000011408 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011409 return;
11410 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011411}
11412
Eric Andersenc470f442003-07-28 09:56:35 +000011413void
11414trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011415{
11416 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011417
Eric Andersenc470f442003-07-28 09:56:35 +000011418 if (debug != 1)
11419 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011420 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011421 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011422 va_end(va);
11423}
11424
Eric Andersenc470f442003-07-28 09:56:35 +000011425void
11426tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011427{
Eric Andersenc470f442003-07-28 09:56:35 +000011428 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011429 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011430 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011431}
11432
11433
Eric Andersenc470f442003-07-28 09:56:35 +000011434void
11435trputs(const char *s)
11436{
11437 if (debug != 1)
11438 return;
11439 fputs(s, tracefile);
11440}
11441
11442
11443static void
11444trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011445{
11446 char *p;
11447 char c;
11448
Eric Andersenc470f442003-07-28 09:56:35 +000011449 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011450 return;
11451 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011452 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011453 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011454 case '\n': c = 'n'; goto backslash;
11455 case '\t': c = 't'; goto backslash;
11456 case '\r': c = 'r'; goto backslash;
11457 case '"': c = '"'; goto backslash;
11458 case '\\': c = '\\'; goto backslash;
11459 case CTLESC: c = 'e'; goto backslash;
11460 case CTLVAR: c = 'v'; goto backslash;
11461 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11462 case CTLBACKQ: c = 'q'; goto backslash;
11463 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11464backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011465 putc(c, tracefile);
11466 break;
11467 default:
11468 if (*p >= ' ' && *p <= '~')
11469 putc(*p, tracefile);
11470 else {
11471 putc('\\', tracefile);
11472 putc(*p >> 6 & 03, tracefile);
11473 putc(*p >> 3 & 07, tracefile);
11474 putc(*p & 07, tracefile);
11475 }
11476 break;
11477 }
11478 }
11479 putc('"', tracefile);
11480}
11481
11482
Eric Andersenc470f442003-07-28 09:56:35 +000011483void
11484trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011485{
Eric Andersenc470f442003-07-28 09:56:35 +000011486 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011487 return;
11488 while (*ap) {
11489 trstring(*ap++);
11490 if (*ap)
11491 putc(' ', tracefile);
11492 else
11493 putc('\n', tracefile);
11494 }
Eric Andersencb57d552001-06-28 07:25:16 +000011495}
11496
11497
Eric Andersenc470f442003-07-28 09:56:35 +000011498void
11499opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011500{
Eric Andersencb57d552001-06-28 07:25:16 +000011501 char s[100];
11502#ifdef O_APPEND
11503 int flags;
11504#endif
11505
Eric Andersenc470f442003-07-28 09:56:35 +000011506 if (debug != 1) {
11507 if (tracefile)
11508 fflush(tracefile);
11509 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011510 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011511 }
Eric Andersenc470f442003-07-28 09:56:35 +000011512 scopy("./trace", s);
11513 if (tracefile) {
11514 if (!freopen(s, "a", tracefile)) {
11515 fprintf(stderr, "Can't re-open %s\n", s);
11516 debug = 0;
11517 return;
11518 }
11519 } else {
11520 if ((tracefile = fopen(s, "a")) == NULL) {
11521 fprintf(stderr, "Can't open %s\n", s);
11522 debug = 0;
11523 return;
11524 }
11525 }
Eric Andersencb57d552001-06-28 07:25:16 +000011526#ifdef O_APPEND
11527 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11528 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11529#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011530 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011531 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011532}
Eric Andersenc470f442003-07-28 09:56:35 +000011533#endif /* DEBUG */
11534
11535
11536/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11537
11538/*
11539 * Sigmode records the current value of the signal handlers for the various
11540 * modes. A value of zero means that the current handler is not known.
11541 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11542 */
11543
11544#define S_DFL 1 /* default signal handling (SIG_DFL) */
11545#define S_CATCH 2 /* signal is caught */
11546#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11547#define S_HARD_IGN 4 /* signal is ignored permenantly */
11548#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11549
Eric Andersencb57d552001-06-28 07:25:16 +000011550
11551
11552/*
Eric Andersencb57d552001-06-28 07:25:16 +000011553 * The trap builtin.
11554 */
11555
Eric Andersenc470f442003-07-28 09:56:35 +000011556int
11557trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011558{
11559 char *action;
11560 char **ap;
11561 int signo;
11562
Eric Andersenc470f442003-07-28 09:56:35 +000011563 nextopt(nullstr);
11564 ap = argptr;
11565 if (!*ap) {
11566 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011567 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011568 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011569
Eric Andersenc470f442003-07-28 09:56:35 +000011570 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011571 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011572 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011573 out1fmt("trap -- %s %s\n",
11574 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011575 }
11576 }
11577 return 0;
11578 }
Eric Andersenc470f442003-07-28 09:56:35 +000011579 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011580 action = NULL;
11581 else
11582 action = *ap++;
11583 while (*ap) {
11584 if ((signo = decode_signal(*ap, 0)) < 0)
11585 error("%s: bad trap", *ap);
11586 INTOFF;
11587 if (action) {
11588 if (action[0] == '-' && action[1] == '\0')
11589 action = NULL;
11590 else
Eric Andersenc470f442003-07-28 09:56:35 +000011591 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011592 }
Eric Andersenc470f442003-07-28 09:56:35 +000011593 if (trap[signo])
11594 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011595 trap[signo] = action;
11596 if (signo != 0)
11597 setsignal(signo);
11598 INTON;
11599 ap++;
11600 }
11601 return 0;
11602}
11603
11604
Eric Andersenc470f442003-07-28 09:56:35 +000011605/*
11606 * Clear traps on a fork.
11607 */
11608
11609void
11610clear_traps(void)
11611{
11612 char **tp;
11613
11614 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11615 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11616 INTOFF;
11617 ckfree(*tp);
11618 *tp = NULL;
11619 if (tp != &trap[0])
11620 setsignal(tp - trap);
11621 INTON;
11622 }
11623 }
11624}
11625
11626
Eric Andersencb57d552001-06-28 07:25:16 +000011627/*
11628 * Set the signal handler for the specified signal. The routine figures
11629 * out what it should be set to.
11630 */
11631
Eric Andersenc470f442003-07-28 09:56:35 +000011632void
11633setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011634{
11635 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011636 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011637 struct sigaction act;
11638
11639 if ((t = trap[signo]) == NULL)
11640 action = S_DFL;
11641 else if (*t != '\0')
11642 action = S_CATCH;
11643 else
11644 action = S_IGN;
11645 if (rootshell && action == S_DFL) {
11646 switch (signo) {
11647 case SIGINT:
11648 if (iflag || minusc || sflag == 0)
11649 action = S_CATCH;
11650 break;
11651 case SIGQUIT:
11652#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011653 if (debug)
11654 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011655#endif
11656 /* FALLTHROUGH */
11657 case SIGTERM:
11658 if (iflag)
11659 action = S_IGN;
11660 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011661#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011662 case SIGTSTP:
11663 case SIGTTOU:
11664 if (mflag)
11665 action = S_IGN;
11666 break;
11667#endif
11668 }
11669 }
11670
11671 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011672 tsig = *t;
11673 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011674 /*
11675 * current setting unknown
11676 */
11677 if (sigaction(signo, 0, &act) == -1) {
11678 /*
11679 * Pretend it worked; maybe we should give a warning
11680 * here, but other shells don't. We don't alter
11681 * sigmode, so that we retry every time.
11682 */
11683 return;
11684 }
11685 if (act.sa_handler == SIG_IGN) {
11686 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011687 signo == SIGTTIN || signo == SIGTTOU)) {
11688 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011689 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011690 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011691 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011692 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011693 }
11694 }
Eric Andersenc470f442003-07-28 09:56:35 +000011695 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011696 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011697 switch (action) {
11698 case S_CATCH:
11699 act.sa_handler = onsig;
11700 break;
11701 case S_IGN:
11702 act.sa_handler = SIG_IGN;
11703 break;
11704 default:
11705 act.sa_handler = SIG_DFL;
11706 }
Eric Andersencb57d552001-06-28 07:25:16 +000011707 *t = action;
11708 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011709 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011710 sigaction(signo, &act, 0);
11711}
11712
11713/*
11714 * Ignore a signal.
11715 */
11716
Eric Andersenc470f442003-07-28 09:56:35 +000011717void
11718ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011719{
11720 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11721 signal(signo, SIG_IGN);
11722 }
11723 sigmode[signo - 1] = S_HARD_IGN;
11724}
11725
11726
Eric Andersencb57d552001-06-28 07:25:16 +000011727/*
11728 * Signal handler.
11729 */
11730
Eric Andersenc470f442003-07-28 09:56:35 +000011731void
11732onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011733{
Eric Andersencb57d552001-06-28 07:25:16 +000011734 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011735 pendingsigs = signo;
11736
11737 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11738 if (!suppressint)
11739 onint();
11740 intpending = 1;
11741 }
Eric Andersencb57d552001-06-28 07:25:16 +000011742}
11743
11744
Eric Andersencb57d552001-06-28 07:25:16 +000011745/*
11746 * Called to execute a trap. Perhaps we should avoid entering new trap
11747 * handlers while we are executing a trap handler.
11748 */
11749
Eric Andersenc470f442003-07-28 09:56:35 +000011750void
11751dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011752{
Eric Andersenc470f442003-07-28 09:56:35 +000011753 char *p;
11754 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011755 int savestatus;
11756
Eric Andersenc470f442003-07-28 09:56:35 +000011757 savestatus = exitstatus;
11758 q = gotsig;
11759 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11760 *p = 0;
11761 p = trap[p - q + 1];
11762 if (!p)
11763 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011764 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011765 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011766 }
Eric Andersencb57d552001-06-28 07:25:16 +000011767}
11768
Eric Andersenc470f442003-07-28 09:56:35 +000011769
Eric Andersenc470f442003-07-28 09:56:35 +000011770/*
11771 * Controls whether the shell is interactive or not.
11772 */
11773
Eric Andersenc470f442003-07-28 09:56:35 +000011774void
11775setinteractive(int on)
11776{
11777 static int is_interactive;
11778
11779 if (++on == is_interactive)
11780 return;
11781 is_interactive = on;
11782 setsignal(SIGINT);
11783 setsignal(SIGQUIT);
11784 setsignal(SIGTERM);
11785#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11786 if(is_interactive > 1) {
11787 /* Looks like they want an interactive shell */
11788 static int do_banner;
11789
11790 if(!do_banner) {
11791 out1fmt(
11792 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11793 "Enter 'help' for a list of built-in commands.\n\n");
11794 do_banner++;
11795 }
11796 }
11797#endif
11798}
11799
11800
11801#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11802/*** List the available builtins ***/
11803
11804static int helpcmd(int argc, char **argv)
11805{
11806 int col, i;
11807
11808 out1fmt("\nBuilt-in commands:\n-------------------\n");
11809 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11810 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11811 builtincmd[i].name + 1);
11812 if (col > 60) {
11813 out1fmt("\n");
11814 col = 0;
11815 }
11816 }
11817#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11818 {
11819 extern const struct BB_applet applets[];
11820 extern const size_t NUM_APPLETS;
11821
11822 for (i = 0; i < NUM_APPLETS; i++) {
11823
11824 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11825 if (col > 60) {
11826 out1fmt("\n");
11827 col = 0;
11828 }
11829 }
11830 }
11831#endif
11832 out1fmt("\n\n");
11833 return EXIT_SUCCESS;
11834}
11835#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11836
Eric Andersencb57d552001-06-28 07:25:16 +000011837/*
11838 * Called to exit the shell.
11839 */
11840
Eric Andersenc470f442003-07-28 09:56:35 +000011841void
11842exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011843{
Eric Andersenc470f442003-07-28 09:56:35 +000011844 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011845 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011846 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011847 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011848
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011849 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011850 status = exitstatus;
11851 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011852 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011853 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011854 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011855 if ((p = trap[0]) != NULL && *p != '\0') {
11856 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011857 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011858 }
Eric Andersencb57d552001-06-28 07:25:16 +000011859 flushall();
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011860#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11861 if (iflag && rootshell) {
11862 const char *hp = lookupvar("HISTFILE");
11863
11864 if(hp != NULL )
11865 save_history ( hp );
11866 }
11867#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011868out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011869 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011870 /* NOTREACHED */
11871}
11872
11873static int decode_signal(const char *string, int minsig)
11874{
11875 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011876 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011877
Eric Andersen34506362001-08-02 05:02:46 +000011878 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011879}
Eric Andersen34506362001-08-02 05:02:46 +000011880
Eric Andersenc470f442003-07-28 09:56:35 +000011881/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11882
11883static struct var *vartab[VTABSIZE];
11884
11885static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011886static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011887
11888/*
11889 * Initialize the varable symbol tables and import the environment
11890 */
11891
Eric Andersenc470f442003-07-28 09:56:35 +000011892
11893#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011894/*
Eric Andersenc470f442003-07-28 09:56:35 +000011895 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011896 */
11897
Eric Andersenc470f442003-07-28 09:56:35 +000011898int
11899setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011900{
Eric Andersenc470f442003-07-28 09:56:35 +000011901 int err;
11902 volatile int saveint;
11903 struct jmploc *volatile savehandler = handler;
11904 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011905
Eric Andersenc470f442003-07-28 09:56:35 +000011906 SAVEINT(saveint);
11907 if (setjmp(jmploc.loc))
11908 err = 1;
11909 else {
11910 handler = &jmploc;
11911 setvar(name, val, flags);
11912 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011913 }
Eric Andersenc470f442003-07-28 09:56:35 +000011914 handler = savehandler;
11915 RESTOREINT(saveint);
11916 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011917}
Eric Andersenc470f442003-07-28 09:56:35 +000011918#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011919
11920/*
11921 * Set the value of a variable. The flags argument is ored with the
11922 * flags of the variable. If val is NULL, the variable is unset.
11923 */
11924
Eric Andersenc470f442003-07-28 09:56:35 +000011925static void
11926setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011927{
Eric Andersenc470f442003-07-28 09:56:35 +000011928 char *p, *q;
11929 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011930 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011931 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011932
Eric Andersenc470f442003-07-28 09:56:35 +000011933 q = endofname(name);
11934 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011935 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011936 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011937 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011938 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011939 if (val == NULL) {
11940 flags |= VUNSET;
11941 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011942 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011943 }
11944 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011945 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11946 *p++ = '\0';
11947 if (vallen) {
11948 p[-1] = '=';
11949 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011950 }
Eric Andersenc470f442003-07-28 09:56:35 +000011951 *p = '\0';
11952 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011953 INTON;
11954}
11955
11956
Eric Andersencb57d552001-06-28 07:25:16 +000011957/*
11958 * Same as setvar except that the variable and value are passed in
11959 * the first argument as name=value. Since the first argument will
11960 * be actually stored in the table, it should not be a string that
11961 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000011962 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000011963 */
11964
Eric Andersenc470f442003-07-28 09:56:35 +000011965void
11966setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011967{
11968 struct var *vp, **vpp;
11969
11970 vpp = hashvar(s);
11971 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000011972 vp = *findvar(vpp, s);
11973 if (vp) {
Eric Andersencb57d552001-06-28 07:25:16 +000011974 if (vp->flags & VREADONLY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011975 if (flags & VNOSAVE)
11976 free(s);
11977 error("%.*s: is read only", strchrnul(s, '=') - s, s);
Eric Andersencb57d552001-06-28 07:25:16 +000011978 }
Eric Andersenc470f442003-07-28 09:56:35 +000011979
11980 if (flags & VNOSET)
11981 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011982
11983 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000011984 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000011985
Eric Andersenc470f442003-07-28 09:56:35 +000011986 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11987 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011988
Eric Andersenc470f442003-07-28 09:56:35 +000011989 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11990 } else {
11991 if (flags & VNOSET)
11992 return;
11993 /* not found */
11994 vp = ckmalloc(sizeof (*vp));
11995 vp->next = *vpp;
11996 vp->func = NULL;
11997 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000011998 }
Eric Andersenc470f442003-07-28 09:56:35 +000011999 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12000 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012001 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012002 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012003}
12004
12005
Eric Andersencb57d552001-06-28 07:25:16 +000012006/*
12007 * Process a linked list of variable assignments.
12008 */
12009
Eric Andersenc470f442003-07-28 09:56:35 +000012010static void
12011listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012012{
Eric Andersenc470f442003-07-28 09:56:35 +000012013 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012014
Eric Andersenc470f442003-07-28 09:56:35 +000012015 if (!lp)
12016 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012017 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012018 do {
12019 setvareq(lp->text, flags);
12020 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012021 INTON;
12022}
12023
12024
Eric Andersencb57d552001-06-28 07:25:16 +000012025/*
12026 * Find the value of a variable. Returns NULL if not set.
12027 */
12028
Eric Andersenc470f442003-07-28 09:56:35 +000012029static char *
12030lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012031{
Eric Andersencb57d552001-06-28 07:25:16 +000012032 struct var *v;
12033
12034 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
Eric Andersenc470f442003-07-28 09:56:35 +000012035 return strchrnul(v->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012036 }
12037 return NULL;
12038}
12039
12040
Eric Andersencb57d552001-06-28 07:25:16 +000012041/*
12042 * Search the environment of a builtin command.
12043 */
12044
Eric Andersenc470f442003-07-28 09:56:35 +000012045static char *
12046bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012047{
Eric Andersenc470f442003-07-28 09:56:35 +000012048 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012049
Eric Andersenc470f442003-07-28 09:56:35 +000012050 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012051 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012052 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012053 }
12054 return lookupvar(name);
12055}
12056
12057
Eric Andersencb57d552001-06-28 07:25:16 +000012058/*
Eric Andersenc470f442003-07-28 09:56:35 +000012059 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012060 */
12061
Eric Andersenc470f442003-07-28 09:56:35 +000012062static char **
12063listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012064{
Eric Andersencb57d552001-06-28 07:25:16 +000012065 struct var **vpp;
12066 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012067 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012068 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012069
Eric Andersenc470f442003-07-28 09:56:35 +000012070 STARTSTACKSTR(ep);
12071 vpp = vartab;
12072 mask = on | off;
12073 do {
12074 for (vp = *vpp ; vp ; vp = vp->next)
12075 if ((vp->flags & mask) == on) {
12076 if (ep == stackstrend())
12077 ep = growstackstr();
12078 *ep++ = (char *) vp->text;
12079 }
12080 } while (++vpp < vartab + VTABSIZE);
12081 if (ep == stackstrend())
12082 ep = growstackstr();
12083 if (end)
12084 *end = ep;
12085 *ep++ = NULL;
12086 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012087}
12088
12089
12090/*
Eric Andersenc470f442003-07-28 09:56:35 +000012091 * POSIX requires that 'set' (but not export or readonly) output the
12092 * variables in lexicographic order - by the locale's collating order (sigh).
12093 * Maybe we could keep them in an ordered balanced binary tree
12094 * instead of hashed lists.
12095 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012096 */
12097
Eric Andersenc470f442003-07-28 09:56:35 +000012098static int
12099showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012100{
Eric Andersenc470f442003-07-28 09:56:35 +000012101 const char *sep;
12102 char **ep, **epend;
12103
12104 ep = listvars(on, off, &epend);
12105 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12106
12107 sep = *sep_prefix ? spcstr : sep_prefix;
12108
12109 for (; ep < epend; ep++) {
12110 const char *p;
12111 const char *q;
12112
12113 p = strchrnul(*ep, '=');
12114 q = nullstr;
12115 if (*p)
12116 q = single_quote(++p);
12117
12118 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12119 }
12120
Eric Andersencb57d552001-06-28 07:25:16 +000012121 return 0;
12122}
12123
12124
12125
12126/*
12127 * The export and readonly commands.
12128 */
12129
Eric Andersenc470f442003-07-28 09:56:35 +000012130static int
12131exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012132{
12133 struct var *vp;
12134 char *name;
12135 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012136 char **aptr;
12137 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12138 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012139
Eric Andersenc470f442003-07-28 09:56:35 +000012140 notp = nextopt("p") - 'p';
12141 if (notp && ((name = *(aptr = argptr)))) {
12142 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012143 if ((p = strchr(name, '=')) != NULL) {
12144 p++;
12145 } else {
12146 if ((vp = *findvar(hashvar(name), name))) {
12147 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012148 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012149 }
12150 }
12151 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012152 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012153 } else {
12154 showvars(argv[0], flag, 0);
12155 }
12156 return 0;
12157}
12158
Eric Andersen34506362001-08-02 05:02:46 +000012159
Eric Andersencb57d552001-06-28 07:25:16 +000012160/*
Eric Andersencb57d552001-06-28 07:25:16 +000012161 * Make a variable a local variable. When a variable is made local, it's
12162 * value and flags are saved in a localvar structure. The saved values
12163 * will be restored when the shell function returns. We handle the name
12164 * "-" as a special case.
12165 */
12166
Eric Andersenc470f442003-07-28 09:56:35 +000012167static inline void
12168mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012169{
Eric Andersencb57d552001-06-28 07:25:16 +000012170 struct localvar *lvp;
12171 struct var **vpp;
12172 struct var *vp;
12173
12174 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012175 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012176 if (name[0] == '-' && name[1] == '\0') {
12177 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012178 p = ckmalloc(sizeof(optlist));
12179 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012180 vp = NULL;
12181 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012182 char *eq;
12183
Eric Andersencb57d552001-06-28 07:25:16 +000012184 vpp = hashvar(name);
12185 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012186 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012187 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012188 if (eq)
12189 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012190 else
12191 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012192 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012193 lvp->flags = VUNSET;
12194 } else {
12195 lvp->text = vp->text;
12196 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012197 vp->flags |= VSTRFIXED|VTEXTFIXED;
12198 if (eq)
12199 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012200 }
12201 }
12202 lvp->vp = vp;
12203 lvp->next = localvars;
12204 localvars = lvp;
12205 INTON;
12206}
12207
Eric Andersenc470f442003-07-28 09:56:35 +000012208/*
12209 * The "local" command.
12210 */
12211
12212static int
12213localcmd(int argc, char **argv)
12214{
12215 char *name;
12216
12217 argv = argptr;
12218 while ((name = *argv++) != NULL) {
12219 mklocal(name);
12220 }
12221 return 0;
12222}
12223
12224
Eric Andersencb57d552001-06-28 07:25:16 +000012225/*
12226 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012227 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012228 */
12229
Eric Andersenc470f442003-07-28 09:56:35 +000012230static void
12231poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012232{
Eric Andersencb57d552001-06-28 07:25:16 +000012233 struct localvar *lvp;
12234 struct var *vp;
12235
12236 while ((lvp = localvars) != NULL) {
12237 localvars = lvp->next;
12238 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012239 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12240 if (vp == NULL) { /* $- saved */
12241 memcpy(optlist, lvp->text, sizeof(optlist));
12242 ckfree(lvp->text);
12243 optschanged();
12244 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12245 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012246 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012247 if (vp->func)
12248 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12249 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12250 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012251 vp->flags = lvp->flags;
12252 vp->text = lvp->text;
12253 }
Eric Andersenc470f442003-07-28 09:56:35 +000012254 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012255 }
12256}
12257
12258
Eric Andersencb57d552001-06-28 07:25:16 +000012259/*
12260 * The unset builtin command. We unset the function before we unset the
12261 * variable to allow a function to be unset when there is a readonly variable
12262 * with the same name.
12263 */
12264
Eric Andersenc470f442003-07-28 09:56:35 +000012265int
12266unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012267{
12268 char **ap;
12269 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012270 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012271 int ret = 0;
12272
12273 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012274 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012275 }
Eric Andersencb57d552001-06-28 07:25:16 +000012276
Eric Andersenc470f442003-07-28 09:56:35 +000012277 for (ap = argptr; *ap ; ap++) {
12278 if (flag != 'f') {
12279 i = unsetvar(*ap);
12280 ret |= i;
12281 if (!(i & 2))
12282 continue;
12283 }
12284 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012285 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012286 }
Eric Andersenc470f442003-07-28 09:56:35 +000012287 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012288}
12289
12290
12291/*
12292 * Unset the specified variable.
12293 */
12294
Eric Andersenc470f442003-07-28 09:56:35 +000012295int
12296unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012297{
Eric Andersencb57d552001-06-28 07:25:16 +000012298 struct var **vpp;
12299 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012300 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012301
12302 vpp = findvar(hashvar(s), s);
12303 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012304 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012305 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012306 int flags = vp->flags;
12307
12308 retval = 1;
12309 if (flags & VREADONLY)
12310 goto out;
12311 if (flags & VUNSET)
12312 goto ok;
12313 if ((flags & VSTRFIXED) == 0) {
12314 INTOFF;
12315 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12316 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012317 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012318 ckfree(vp);
12319 INTON;
12320 } else {
12321 setvar(s, 0, 0);
12322 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012323 }
Eric Andersenc470f442003-07-28 09:56:35 +000012324ok:
12325 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012326 }
12327
Eric Andersenc470f442003-07-28 09:56:35 +000012328out:
12329 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012330}
12331
12332
12333
12334/*
12335 * Find the appropriate entry in the hash table from the name.
12336 */
12337
Eric Andersenc470f442003-07-28 09:56:35 +000012338static struct var **
12339hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012340{
Eric Andersencb57d552001-06-28 07:25:16 +000012341 unsigned int hashval;
12342
12343 hashval = ((unsigned char) *p) << 4;
12344 while (*p && *p != '=')
12345 hashval += (unsigned char) *p++;
12346 return &vartab[hashval % VTABSIZE];
12347}
12348
12349
12350
12351/*
Eric Andersenc470f442003-07-28 09:56:35 +000012352 * Compares two strings up to the first = or '\0'. The first
12353 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012354 * either '=' or '\0'.
12355 */
12356
Eric Andersenc470f442003-07-28 09:56:35 +000012357int
12358varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012359{
Eric Andersenc470f442003-07-28 09:56:35 +000012360 int c, d;
12361
12362 while ((c = *p) == (d = *q)) {
12363 if (!c || c == '=')
12364 goto out;
12365 p++;
12366 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012367 }
Eric Andersenc470f442003-07-28 09:56:35 +000012368 if (c == '=')
12369 c = 0;
12370 if (d == '=')
12371 d = 0;
12372out:
12373 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012374}
12375
Eric Andersenc470f442003-07-28 09:56:35 +000012376static int
12377vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012378{
Eric Andersenc470f442003-07-28 09:56:35 +000012379 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012380}
12381
Eric Andersenc470f442003-07-28 09:56:35 +000012382static struct var **
12383findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012384{
12385 for (; *vpp; vpp = &(*vpp)->next) {
12386 if (varequal((*vpp)->text, name)) {
12387 break;
12388 }
12389 }
12390 return vpp;
12391}
Eric Andersenc470f442003-07-28 09:56:35 +000012392/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012393
Eric Andersenc470f442003-07-28 09:56:35 +000012394#include <sys/times.h>
12395
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012396static const unsigned char timescmd_str[] = {
12397 ' ', offsetof(struct tms, tms_utime),
12398 '\n', offsetof(struct tms, tms_stime),
12399 ' ', offsetof(struct tms, tms_cutime),
12400 '\n', offsetof(struct tms, tms_cstime),
12401 0
12402};
Eric Andersencb57d552001-06-28 07:25:16 +000012403
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012404static int timescmd(int ac, char **av)
12405{
12406 long int clk_tck, s, t;
12407 const unsigned char *p;
12408 struct tms buf;
12409
12410 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012411 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012412
12413 p = timescmd_str;
12414 do {
12415 t = *(clock_t *)(((char *) &buf) + p[1]);
12416 s = t / clk_tck;
12417 out1fmt("%ldm%ld.%.3lds%c",
12418 s/60, s%60,
12419 ((t - s * clk_tck) * 1000) / clk_tck,
12420 p[0]);
12421 } while (*(p += 2));
12422
Eric Andersencb57d552001-06-28 07:25:16 +000012423 return 0;
12424}
12425
Eric Andersend35c5df2002-01-09 15:37:36 +000012426#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012427static int
12428dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012429{
Eric Andersen90898442003-08-06 11:20:52 +000012430 long result;
Eric Andersenc470f442003-07-28 09:56:35 +000012431 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012432
Eric Andersenc470f442003-07-28 09:56:35 +000012433 INTOFF;
12434 result = arith(s, &errcode);
12435 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012436 if (errcode == -3)
12437 error("exponent less than 0");
12438 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012439 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012440 else if (errcode == -5)
12441 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012442 else
12443 synerror(s);
12444 }
12445 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012446
Eric Andersenc470f442003-07-28 09:56:35 +000012447 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012448}
Eric Andersenc470f442003-07-28 09:56:35 +000012449
12450
12451/*
Eric Andersen90898442003-08-06 11:20:52 +000012452 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12453 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12454 *
12455 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012456 */
Eric Andersen90898442003-08-06 11:20:52 +000012457
Eric Andersenc470f442003-07-28 09:56:35 +000012458static int
Eric Andersen90898442003-08-06 11:20:52 +000012459letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012460{
Eric Andersenc470f442003-07-28 09:56:35 +000012461 char **ap;
12462 long i;
12463
Eric Andersen90898442003-08-06 11:20:52 +000012464 ap = argv + 1;
12465 if(!*ap)
12466 error("expression expected");
12467 for (ap = argv + 1; *ap; ap++) {
12468 i = dash_arith(*ap);
12469 }
Eric Andersenc470f442003-07-28 09:56:35 +000012470
Eric Andersen90898442003-08-06 11:20:52 +000012471 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012472}
12473#endif /* CONFIG_ASH_MATH_SUPPORT */
12474
12475/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12476
12477/*
12478 * Miscelaneous builtins.
12479 */
12480
12481#undef rflag
12482
12483#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012484#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012485typedef enum __rlimit_resource rlim_t;
12486#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012487#endif
12488
12489
Eric Andersenc470f442003-07-28 09:56:35 +000012490/*
12491 * The read builtin. The -e option causes backslashes to escape the
12492 * following character.
12493 *
12494 * This uses unbuffered input, which may be avoidable in some cases.
12495 */
12496
12497static int
12498readcmd(int argc, char **argv)
12499{
12500 char **ap;
12501 int backslash;
12502 char c;
12503 int rflag;
12504 char *prompt;
12505 const char *ifs;
12506 char *p;
12507 int startword;
12508 int status;
12509 int i;
12510
12511 rflag = 0;
12512 prompt = NULL;
12513 while ((i = nextopt("p:r")) != '\0') {
12514 if (i == 'p')
12515 prompt = optionarg;
12516 else
12517 rflag = 1;
12518 }
12519 if (prompt && isatty(0)) {
12520 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012521 }
12522 if (*(ap = argptr) == NULL)
12523 error("arg count");
12524 if ((ifs = bltinlookup("IFS")) == NULL)
12525 ifs = defifs;
12526 status = 0;
12527 startword = 1;
12528 backslash = 0;
12529 STARTSTACKSTR(p);
12530 for (;;) {
12531 if (read(0, &c, 1) != 1) {
12532 status = 1;
12533 break;
12534 }
12535 if (c == '\0')
12536 continue;
12537 if (backslash) {
12538 backslash = 0;
12539 if (c != '\n')
12540 goto put;
12541 continue;
12542 }
12543 if (!rflag && c == '\\') {
12544 backslash++;
12545 continue;
12546 }
12547 if (c == '\n')
12548 break;
12549 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12550 continue;
12551 }
12552 startword = 0;
12553 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12554 STACKSTRNUL(p);
12555 setvar(*ap, stackblock(), 0);
12556 ap++;
12557 startword = 1;
12558 STARTSTACKSTR(p);
12559 } else {
12560put:
12561 STPUTC(c, p);
12562 }
12563 }
12564 STACKSTRNUL(p);
12565 /* Remove trailing blanks */
12566 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12567 *p = '\0';
12568 setvar(*ap, stackblock(), 0);
12569 while (*++ap != NULL)
12570 setvar(*ap, nullstr, 0);
12571 return status;
12572}
12573
12574
12575static int umaskcmd(int argc, char **argv)
12576{
12577 static const char permuser[3] = "ugo";
12578 static const char permmode[3] = "rwx";
12579 static const short int permmask[] = {
12580 S_IRUSR, S_IWUSR, S_IXUSR,
12581 S_IRGRP, S_IWGRP, S_IXGRP,
12582 S_IROTH, S_IWOTH, S_IXOTH
12583 };
12584
12585 char *ap;
12586 mode_t mask;
12587 int i;
12588 int symbolic_mode = 0;
12589
12590 while (nextopt("S") != '\0') {
12591 symbolic_mode = 1;
12592 }
12593
12594 INTOFF;
12595 mask = umask(0);
12596 umask(mask);
12597 INTON;
12598
12599 if ((ap = *argptr) == NULL) {
12600 if (symbolic_mode) {
12601 char buf[18];
12602 char *p = buf;
12603
12604 for (i = 0; i < 3; i++) {
12605 int j;
12606
12607 *p++ = permuser[i];
12608 *p++ = '=';
12609 for (j = 0; j < 3; j++) {
12610 if ((mask & permmask[3 * i + j]) == 0) {
12611 *p++ = permmode[j];
12612 }
12613 }
12614 *p++ = ',';
12615 }
12616 *--p = 0;
12617 puts(buf);
12618 } else {
12619 out1fmt("%.4o\n", mask);
12620 }
12621 } else {
12622 if (is_digit((unsigned char) *ap)) {
12623 mask = 0;
12624 do {
12625 if (*ap >= '8' || *ap < '0')
12626 error(illnum, argv[1]);
12627 mask = (mask << 3) + (*ap - '0');
12628 } while (*++ap != '\0');
12629 umask(mask);
12630 } else {
12631 mask = ~mask & 0777;
12632 if (!bb_parse_mode(ap, &mask)) {
12633 error("Illegal mode: %s", ap);
12634 }
12635 umask(~mask & 0777);
12636 }
12637 }
12638 return 0;
12639}
12640
12641/*
12642 * ulimit builtin
12643 *
12644 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12645 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12646 * ash by J.T. Conklin.
12647 *
12648 * Public domain.
12649 */
12650
12651struct limits {
12652 const char *name;
12653 int cmd;
12654 int factor; /* multiply by to get rlim_{cur,max} values */
12655 char option;
12656};
12657
12658static const struct limits limits[] = {
12659#ifdef RLIMIT_CPU
12660 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12661#endif
12662#ifdef RLIMIT_FSIZE
12663 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12664#endif
12665#ifdef RLIMIT_DATA
12666 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12667#endif
12668#ifdef RLIMIT_STACK
12669 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12670#endif
12671#ifdef RLIMIT_CORE
12672 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12673#endif
12674#ifdef RLIMIT_RSS
12675 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12676#endif
12677#ifdef RLIMIT_MEMLOCK
12678 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12679#endif
12680#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012681 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012682#endif
12683#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012684 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012685#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012686#ifdef RLIMIT_AS
12687 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012688#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012689#ifdef RLIMIT_LOCKS
12690 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012691#endif
12692 { (char *) 0, 0, 0, '\0' }
12693};
12694
Glenn L McGrath76620622004-01-13 10:19:37 +000012695enum limtype { SOFT = 0x1, HARD = 0x2 };
12696
12697static void printlim(enum limtype how, const struct rlimit *limit,
12698 const struct limits *l)
12699{
12700 rlim_t val;
12701
12702 val = limit->rlim_max;
12703 if (how & SOFT)
12704 val = limit->rlim_cur;
12705
12706 if (val == RLIM_INFINITY)
12707 out1fmt("unlimited\n");
12708 else {
12709 val /= l->factor;
12710 out1fmt("%lld\n", (long long) val);
12711 }
12712}
12713
Eric Andersenc470f442003-07-28 09:56:35 +000012714int
12715ulimitcmd(int argc, char **argv)
12716{
12717 int c;
12718 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012719 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012720 const struct limits *l;
12721 int set, all = 0;
12722 int optc, what;
12723 struct rlimit limit;
12724
12725 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012726 while ((optc = nextopt("HSa"
12727#ifdef RLIMIT_CPU
12728 "t"
12729#endif
12730#ifdef RLIMIT_FSIZE
12731 "f"
12732#endif
12733#ifdef RLIMIT_DATA
12734 "d"
12735#endif
12736#ifdef RLIMIT_STACK
12737 "s"
12738#endif
12739#ifdef RLIMIT_CORE
12740 "c"
12741#endif
12742#ifdef RLIMIT_RSS
12743 "m"
12744#endif
12745#ifdef RLIMIT_MEMLOCK
12746 "l"
12747#endif
12748#ifdef RLIMIT_NPROC
12749 "p"
12750#endif
12751#ifdef RLIMIT_NOFILE
12752 "n"
12753#endif
12754#ifdef RLIMIT_AS
12755 "v"
12756#endif
12757#ifdef RLIMIT_LOCKS
12758 "w"
12759#endif
12760 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012761 switch (optc) {
12762 case 'H':
12763 how = HARD;
12764 break;
12765 case 'S':
12766 how = SOFT;
12767 break;
12768 case 'a':
12769 all = 1;
12770 break;
12771 default:
12772 what = optc;
12773 }
12774
Glenn L McGrath76620622004-01-13 10:19:37 +000012775 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012776 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012777
12778 set = *argptr ? 1 : 0;
12779 if (set) {
12780 char *p = *argptr;
12781
12782 if (all || argptr[1])
12783 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012784 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012785 val = RLIM_INFINITY;
12786 else {
12787 val = (rlim_t) 0;
12788
12789 while ((c = *p++) >= '0' && c <= '9')
12790 {
12791 val = (val * 10) + (long)(c - '0');
12792 if (val < (rlim_t) 0)
12793 break;
12794 }
12795 if (c)
12796 error("bad number");
12797 val *= l->factor;
12798 }
12799 }
12800 if (all) {
12801 for (l = limits; l->name; l++) {
12802 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012803 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012804 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012805 }
12806 return 0;
12807 }
12808
12809 getrlimit(l->cmd, &limit);
12810 if (set) {
12811 if (how & HARD)
12812 limit.rlim_max = val;
12813 if (how & SOFT)
12814 limit.rlim_cur = val;
12815 if (setrlimit(l->cmd, &limit) < 0)
12816 error("error setting limit (%m)");
12817 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012818 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012819 }
12820 return 0;
12821}
12822
Eric Andersen90898442003-08-06 11:20:52 +000012823
12824#ifdef CONFIG_ASH_MATH_SUPPORT
12825
12826/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12827
12828 Permission is hereby granted, free of charge, to any person obtaining
12829 a copy of this software and associated documentation files (the
12830 "Software"), to deal in the Software without restriction, including
12831 without limitation the rights to use, copy, modify, merge, publish,
12832 distribute, sublicense, and/or sell copies of the Software, and to
12833 permit persons to whom the Software is furnished to do so, subject to
12834 the following conditions:
12835
12836 The above copyright notice and this permission notice shall be
12837 included in all copies or substantial portions of the Software.
12838
12839 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12840 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12841 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12842 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12843 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12844 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12845 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12846*/
12847
12848/* This is my infix parser/evaluator. It is optimized for size, intended
12849 * as a replacement for yacc-based parsers. However, it may well be faster
12850 * than a comparable parser writen in yacc. The supported operators are
12851 * listed in #defines below. Parens, order of operations, and error handling
12852 * are supported. This code is threadsafe. The exact expression format should
12853 * be that which POSIX specifies for shells. */
12854
12855/* The code uses a simple two-stack algorithm. See
12856 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12857 * for a detailed explaination of the infix-to-postfix algorithm on which
12858 * this is based (this code differs in that it applies operators immediately
12859 * to the stack instead of adding them to a queue to end up with an
12860 * expression). */
12861
12862/* To use the routine, call it with an expression string and error return
12863 * pointer */
12864
12865/*
12866 * Aug 24, 2001 Manuel Novoa III
12867 *
12868 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12869 *
12870 * 1) In arith_apply():
12871 * a) Cached values of *numptr and &(numptr[-1]).
12872 * b) Removed redundant test for zero denominator.
12873 *
12874 * 2) In arith():
12875 * a) Eliminated redundant code for processing operator tokens by moving
12876 * to a table-based implementation. Also folded handling of parens
12877 * into the table.
12878 * b) Combined all 3 loops which called arith_apply to reduce generated
12879 * code size at the cost of speed.
12880 *
12881 * 3) The following expressions were treated as valid by the original code:
12882 * 1() , 0! , 1 ( *3 ) .
12883 * These bugs have been fixed by internally enclosing the expression in
12884 * parens and then checking that all binary ops and right parens are
12885 * preceded by a valid expression (NUM_TOKEN).
12886 *
12887 * Note: It may be desireable to replace Aaron's test for whitespace with
12888 * ctype's isspace() if it is used by another busybox applet or if additional
12889 * whitespace chars should be considered. Look below the "#include"s for a
12890 * precompiler test.
12891 */
12892
12893/*
12894 * Aug 26, 2001 Manuel Novoa III
12895 *
12896 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12897 *
12898 * Merge in Aaron's comments previously posted to the busybox list,
12899 * modified slightly to take account of my changes to the code.
12900 *
12901 */
12902
12903/*
12904 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12905 *
12906 * - allow access to variable,
12907 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12908 * - realize assign syntax (VAR=expr, +=, *= etc)
12909 * - realize exponentiation (** operator)
12910 * - realize comma separated - expr, expr
12911 * - realise ++expr --expr expr++ expr--
12912 * - realise expr ? expr : expr (but, second expr calculate always)
12913 * - allow hexdecimal and octal numbers
12914 * - was restored loses XOR operator
12915 * - remove one goto label, added three ;-)
12916 * - protect $((num num)) as true zero expr (Manuel`s error)
12917 * - always use special isspace(), see comment from bash ;-)
12918 */
12919
12920
12921#define arith_isspace(arithval) \
12922 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12923
12924
12925typedef unsigned char operator;
12926
12927/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12928 * precedence, and 3 high bits are an ID unique accross operators of that
12929 * precedence. The ID portion is so that multiple operators can have the
12930 * same precedence, ensuring that the leftmost one is evaluated first.
12931 * Consider * and /. */
12932
12933#define tok_decl(prec,id) (((id)<<5)|(prec))
12934#define PREC(op) ((op) & 0x1F)
12935
12936#define TOK_LPAREN tok_decl(0,0)
12937
12938#define TOK_COMMA tok_decl(1,0)
12939
12940#define TOK_ASSIGN tok_decl(2,0)
12941#define TOK_AND_ASSIGN tok_decl(2,1)
12942#define TOK_OR_ASSIGN tok_decl(2,2)
12943#define TOK_XOR_ASSIGN tok_decl(2,3)
12944#define TOK_PLUS_ASSIGN tok_decl(2,4)
12945#define TOK_MINUS_ASSIGN tok_decl(2,5)
12946#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12947#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12948
12949#define TOK_MUL_ASSIGN tok_decl(3,0)
12950#define TOK_DIV_ASSIGN tok_decl(3,1)
12951#define TOK_REM_ASSIGN tok_decl(3,2)
12952
12953/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12954#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12955
12956/* conditional is right associativity too */
12957#define TOK_CONDITIONAL tok_decl(4,0)
12958#define TOK_CONDITIONAL_SEP tok_decl(4,1)
12959
12960#define TOK_OR tok_decl(5,0)
12961
12962#define TOK_AND tok_decl(6,0)
12963
12964#define TOK_BOR tok_decl(7,0)
12965
12966#define TOK_BXOR tok_decl(8,0)
12967
12968#define TOK_BAND tok_decl(9,0)
12969
12970#define TOK_EQ tok_decl(10,0)
12971#define TOK_NE tok_decl(10,1)
12972
12973#define TOK_LT tok_decl(11,0)
12974#define TOK_GT tok_decl(11,1)
12975#define TOK_GE tok_decl(11,2)
12976#define TOK_LE tok_decl(11,3)
12977
12978#define TOK_LSHIFT tok_decl(12,0)
12979#define TOK_RSHIFT tok_decl(12,1)
12980
12981#define TOK_ADD tok_decl(13,0)
12982#define TOK_SUB tok_decl(13,1)
12983
12984#define TOK_MUL tok_decl(14,0)
12985#define TOK_DIV tok_decl(14,1)
12986#define TOK_REM tok_decl(14,2)
12987
12988/* exponent is right associativity */
12989#define TOK_EXPONENT tok_decl(15,1)
12990
12991/* For now unary operators. */
12992#define UNARYPREC 16
12993#define TOK_BNOT tok_decl(UNARYPREC,0)
12994#define TOK_NOT tok_decl(UNARYPREC,1)
12995
12996#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12997#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12998
12999#define PREC_PRE (UNARYPREC+2)
13000
13001#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13002#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13003
13004#define PREC_POST (UNARYPREC+3)
13005
13006#define TOK_POST_INC tok_decl(PREC_POST, 0)
13007#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13008
13009#define SPEC_PREC (UNARYPREC+4)
13010
13011#define TOK_NUM tok_decl(SPEC_PREC, 0)
13012#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13013
13014#define NUMPTR (*numstackptr)
13015
13016static inline int tok_have_assign(operator op)
13017{
13018 operator prec = PREC(op);
13019
13020 convert_prec_is_assing(prec);
13021 return (prec == PREC(TOK_ASSIGN) ||
13022 prec == PREC_PRE || prec == PREC_POST);
13023}
13024
13025static inline int is_right_associativity(operator prec)
13026{
13027 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13028 prec == PREC(TOK_CONDITIONAL));
13029}
13030
13031
13032typedef struct ARITCH_VAR_NUM {
13033 long val;
13034 long contidional_second_val;
13035 char contidional_second_val_initialized;
13036 char *var; /* if NULL then is regular number,
13037 else is varable name */
13038} v_n_t;
13039
13040
13041typedef struct CHK_VAR_RECURSIVE_LOOPED {
13042 const char *var;
13043 struct CHK_VAR_RECURSIVE_LOOPED *next;
13044} chk_var_recursive_looped_t;
13045
13046static chk_var_recursive_looped_t *prev_chk_var_recursive;
13047
13048
13049static int arith_lookup_val(v_n_t *t)
13050{
13051 if(t->var) {
13052 const char * p = lookupvar(t->var);
13053
13054 if(p) {
13055 int errcode;
13056
13057 /* recursive try as expression */
13058 chk_var_recursive_looped_t *cur;
13059 chk_var_recursive_looped_t cur_save;
13060
13061 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13062 if(strcmp(cur->var, t->var) == 0) {
13063 /* expression recursion loop detected */
13064 return -5;
13065 }
13066 }
13067 /* save current lookuped var name */
13068 cur = prev_chk_var_recursive;
13069 cur_save.var = t->var;
13070 cur_save.next = cur;
13071 prev_chk_var_recursive = &cur_save;
13072
13073 t->val = arith (p, &errcode);
13074 /* restore previous ptr after recursiving */
13075 prev_chk_var_recursive = cur;
13076 return errcode;
13077 } else {
13078 /* allow undefined var as 0 */
13079 t->val = 0;
13080 }
13081 }
13082 return 0;
13083}
13084
13085/* "applying" a token means performing it on the top elements on the integer
13086 * stack. For a unary operator it will only change the top element, but a
13087 * binary operator will pop two arguments and push a result */
13088static inline int
13089arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13090{
13091 long numptr_val;
13092 v_n_t *numptr_m1;
13093 long rez;
13094 int ret_arith_lookup_val;
13095
13096 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13097 without arguments */
13098 numptr_m1 = NUMPTR - 1;
13099
13100 /* check operand is var with noninteger value */
13101 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13102 if(ret_arith_lookup_val)
13103 return ret_arith_lookup_val;
13104
13105 rez = numptr_m1->val;
13106 if (op == TOK_UMINUS)
13107 rez *= -1;
13108 else if (op == TOK_NOT)
13109 rez = !rez;
13110 else if (op == TOK_BNOT)
13111 rez = ~rez;
13112 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13113 rez++;
13114 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13115 rez--;
13116 else if (op != TOK_UPLUS) {
13117 /* Binary operators */
13118
13119 /* check and binary operators need two arguments */
13120 if (numptr_m1 == numstack) goto err;
13121
13122 /* ... and they pop one */
13123 --NUMPTR;
13124 numptr_val = rez;
13125 if (op == TOK_CONDITIONAL) {
13126 if(! numptr_m1->contidional_second_val_initialized) {
13127 /* protect $((expr1 ? expr2)) without ": expr" */
13128 goto err;
13129 }
13130 rez = numptr_m1->contidional_second_val;
13131 } else if(numptr_m1->contidional_second_val_initialized) {
13132 /* protect $((expr1 : expr2)) without "expr ? " */
13133 goto err;
13134 }
13135 numptr_m1 = NUMPTR - 1;
13136 if(op != TOK_ASSIGN) {
13137 /* check operand is var with noninteger value for not '=' */
13138 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13139 if(ret_arith_lookup_val)
13140 return ret_arith_lookup_val;
13141 }
13142 if (op == TOK_CONDITIONAL) {
13143 numptr_m1->contidional_second_val = rez;
13144 }
13145 rez = numptr_m1->val;
13146 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13147 rez |= numptr_val;
13148 else if (op == TOK_OR)
13149 rez = numptr_val || rez;
13150 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13151 rez &= numptr_val;
13152 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13153 rez ^= numptr_val;
13154 else if (op == TOK_AND)
13155 rez = rez && numptr_val;
13156 else if (op == TOK_EQ)
13157 rez = (rez == numptr_val);
13158 else if (op == TOK_NE)
13159 rez = (rez != numptr_val);
13160 else if (op == TOK_GE)
13161 rez = (rez >= numptr_val);
13162 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13163 rez >>= numptr_val;
13164 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13165 rez <<= numptr_val;
13166 else if (op == TOK_GT)
13167 rez = (rez > numptr_val);
13168 else if (op == TOK_LT)
13169 rez = (rez < numptr_val);
13170 else if (op == TOK_LE)
13171 rez = (rez <= numptr_val);
13172 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13173 rez *= numptr_val;
13174 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13175 rez += numptr_val;
13176 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13177 rez -= numptr_val;
13178 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13179 rez = numptr_val;
13180 else if (op == TOK_CONDITIONAL_SEP) {
13181 if (numptr_m1 == numstack) {
13182 /* protect $((expr : expr)) without "expr ? " */
13183 goto err;
13184 }
13185 numptr_m1->contidional_second_val_initialized = op;
13186 numptr_m1->contidional_second_val = numptr_val;
13187 }
13188 else if (op == TOK_CONDITIONAL) {
13189 rez = rez ?
13190 numptr_val : numptr_m1->contidional_second_val;
13191 }
13192 else if(op == TOK_EXPONENT) {
13193 if(numptr_val < 0)
13194 return -3; /* exponent less than 0 */
13195 else {
13196 long c = 1;
13197
13198 if(numptr_val)
13199 while(numptr_val--)
13200 c *= rez;
13201 rez = c;
13202 }
13203 }
13204 else if(numptr_val==0) /* zero divisor check */
13205 return -2;
13206 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13207 rez /= numptr_val;
13208 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13209 rez %= numptr_val;
13210 }
13211 if(tok_have_assign(op)) {
13212 char buf[32];
13213
13214 if(numptr_m1->var == NULL) {
13215 /* Hmm, 1=2 ? */
13216 goto err;
13217 }
13218 /* save to shell variable */
13219 sprintf(buf, "%ld", rez);
13220 setvar(numptr_m1->var, buf, 0);
13221 /* after saving, make previous value for v++ or v-- */
13222 if(op == TOK_POST_INC)
13223 rez--;
13224 else if(op == TOK_POST_DEC)
13225 rez++;
13226 }
13227 numptr_m1->val = rez;
13228 /* protect geting var value, is number now */
13229 numptr_m1->var = NULL;
13230 return 0;
13231err: return(-1);
13232}
13233
13234/* longest must first */
13235static const char op_tokens[] = {
13236 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13237 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13238 '<','<', 0, TOK_LSHIFT,
13239 '>','>', 0, TOK_RSHIFT,
13240 '|','|', 0, TOK_OR,
13241 '&','&', 0, TOK_AND,
13242 '!','=', 0, TOK_NE,
13243 '<','=', 0, TOK_LE,
13244 '>','=', 0, TOK_GE,
13245 '=','=', 0, TOK_EQ,
13246 '|','=', 0, TOK_OR_ASSIGN,
13247 '&','=', 0, TOK_AND_ASSIGN,
13248 '*','=', 0, TOK_MUL_ASSIGN,
13249 '/','=', 0, TOK_DIV_ASSIGN,
13250 '%','=', 0, TOK_REM_ASSIGN,
13251 '+','=', 0, TOK_PLUS_ASSIGN,
13252 '-','=', 0, TOK_MINUS_ASSIGN,
13253 '-','-', 0, TOK_POST_DEC,
13254 '^','=', 0, TOK_XOR_ASSIGN,
13255 '+','+', 0, TOK_POST_INC,
13256 '*','*', 0, TOK_EXPONENT,
13257 '!', 0, TOK_NOT,
13258 '<', 0, TOK_LT,
13259 '>', 0, TOK_GT,
13260 '=', 0, TOK_ASSIGN,
13261 '|', 0, TOK_BOR,
13262 '&', 0, TOK_BAND,
13263 '*', 0, TOK_MUL,
13264 '/', 0, TOK_DIV,
13265 '%', 0, TOK_REM,
13266 '+', 0, TOK_ADD,
13267 '-', 0, TOK_SUB,
13268 '^', 0, TOK_BXOR,
13269 /* uniq */
13270 '~', 0, TOK_BNOT,
13271 ',', 0, TOK_COMMA,
13272 '?', 0, TOK_CONDITIONAL,
13273 ':', 0, TOK_CONDITIONAL_SEP,
13274 ')', 0, TOK_RPAREN,
13275 '(', 0, TOK_LPAREN,
13276 0
13277};
13278/* ptr to ")" */
13279#define endexpression &op_tokens[sizeof(op_tokens)-7]
13280
13281
13282extern long arith (const char *expr, int *perrcode)
13283{
13284 register char arithval; /* Current character under analysis */
13285 operator lasttok, op;
13286 operator prec;
13287
13288 const char *p = endexpression;
13289 int errcode;
13290
13291 size_t datasizes = strlen(expr) + 2;
13292
13293 /* Stack of integers */
13294 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13295 * in any given correct or incorrect expression is left as an excersize to
13296 * the reader. */
13297 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13298 *numstackptr = numstack;
13299 /* Stack of operator tokens */
13300 operator *stack = alloca((datasizes) * sizeof(operator)),
13301 *stackptr = stack;
13302
13303 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13304 *perrcode = errcode = 0;
13305
13306 while(1) {
13307 if ((arithval = *expr) == 0) {
13308 if (p == endexpression) {
13309 /* Null expression. */
13310 return 0;
13311 }
13312
13313 /* This is only reached after all tokens have been extracted from the
13314 * input stream. If there are still tokens on the operator stack, they
13315 * are to be applied in order. At the end, there should be a final
13316 * result on the integer stack */
13317
13318 if (expr != endexpression + 1) {
13319 /* If we haven't done so already, */
13320 /* append a closing right paren */
13321 expr = endexpression;
13322 /* and let the loop process it. */
13323 continue;
13324 }
13325 /* At this point, we're done with the expression. */
13326 if (numstackptr != numstack+1) {
13327 /* ... but if there isn't, it's bad */
13328 err:
13329 return (*perrcode = -1);
13330 }
13331 if(numstack->var) {
13332 /* expression is $((var)) only, lookup now */
13333 errcode = arith_lookup_val(numstack);
13334 }
13335 ret:
13336 *perrcode = errcode;
13337 return numstack->val;
13338 } else {
13339 /* Continue processing the expression. */
13340 if (arith_isspace(arithval)) {
13341 /* Skip whitespace */
13342 goto prologue;
13343 }
13344 if((p = endofname(expr)) != expr) {
13345 int var_name_size = (p-expr) + 1; /* trailing zero */
13346
13347 numstackptr->var = alloca(var_name_size);
13348 safe_strncpy(numstackptr->var, expr, var_name_size);
13349 expr = p;
13350 num:
13351 numstackptr->contidional_second_val_initialized = 0;
13352 numstackptr++;
13353 lasttok = TOK_NUM;
13354 continue;
13355 } else if (is_digit(arithval)) {
13356 numstackptr->var = NULL;
13357 numstackptr->val = strtol(expr, (char **) &expr, 0);
13358 goto num;
13359 }
13360 for(p = op_tokens; ; p++) {
13361 const char *o;
13362
13363 if(*p == 0) {
13364 /* strange operator not found */
13365 goto err;
13366 }
13367 for(o = expr; *p && *o == *p; p++)
13368 o++;
13369 if(! *p) {
13370 /* found */
13371 expr = o - 1;
13372 break;
13373 }
13374 /* skip tail uncompared token */
13375 while(*p)
13376 p++;
13377 /* skip zero delim */
13378 p++;
13379 }
13380 op = p[1];
13381
13382 /* post grammar: a++ reduce to num */
13383 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13384 lasttok = TOK_NUM;
13385
13386 /* Plus and minus are binary (not unary) _only_ if the last
13387 * token was as number, or a right paren (which pretends to be
13388 * a number, since it evaluates to one). Think about it.
13389 * It makes sense. */
13390 if (lasttok != TOK_NUM) {
13391 switch(op) {
13392 case TOK_ADD:
13393 op = TOK_UPLUS;
13394 break;
13395 case TOK_SUB:
13396 op = TOK_UMINUS;
13397 break;
13398 case TOK_POST_INC:
13399 op = TOK_PRE_INC;
13400 break;
13401 case TOK_POST_DEC:
13402 op = TOK_PRE_DEC;
13403 break;
13404 }
13405 }
13406 /* We don't want a unary operator to cause recursive descent on the
13407 * stack, because there can be many in a row and it could cause an
13408 * operator to be evaluated before its argument is pushed onto the
13409 * integer stack. */
13410 /* But for binary operators, "apply" everything on the operator
13411 * stack until we find an operator with a lesser priority than the
13412 * one we have just extracted. */
13413 /* Left paren is given the lowest priority so it will never be
13414 * "applied" in this way.
13415 * if associativity is right and priority eq, applied also skip
13416 */
13417 prec = PREC(op);
13418 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13419 /* not left paren or unary */
13420 if (lasttok != TOK_NUM) {
13421 /* binary op must be preceded by a num */
13422 goto err;
13423 }
13424 while (stackptr != stack) {
13425 if (op == TOK_RPAREN) {
13426 /* The algorithm employed here is simple: while we don't
13427 * hit an open paren nor the bottom of the stack, pop
13428 * tokens and apply them */
13429 if (stackptr[-1] == TOK_LPAREN) {
13430 --stackptr;
13431 /* Any operator directly after a */
13432 lasttok = TOK_NUM;
13433 /* close paren should consider itself binary */
13434 goto prologue;
13435 }
13436 } else {
13437 operator prev_prec = PREC(stackptr[-1]);
13438
13439 convert_prec_is_assing(prec);
13440 convert_prec_is_assing(prev_prec);
13441 if (prev_prec < prec)
13442 break;
13443 /* check right assoc */
13444 if(prev_prec == prec && is_right_associativity(prec))
13445 break;
13446 }
13447 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13448 if(errcode) goto ret;
13449 }
13450 if (op == TOK_RPAREN) {
13451 goto err;
13452 }
13453 }
13454
13455 /* Push this operator to the stack and remember it. */
13456 *stackptr++ = lasttok = op;
13457
13458 prologue:
13459 ++expr;
13460 }
13461 }
13462}
13463#endif /* CONFIG_ASH_MATH_SUPPORT */
13464
13465
Eric Andersenc470f442003-07-28 09:56:35 +000013466#ifdef DEBUG
13467const char *bb_applet_name = "debug stuff usage";
13468int main(int argc, char **argv)
13469{
13470 return ash_main(argc, argv);
13471}
13472#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013473
Eric Andersendf82f612001-06-28 07:46:40 +000013474/*-
13475 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013476 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013477 *
13478 * This code is derived from software contributed to Berkeley by
13479 * Kenneth Almquist.
13480 *
13481 * Redistribution and use in source and binary forms, with or without
13482 * modification, are permitted provided that the following conditions
13483 * are met:
13484 * 1. Redistributions of source code must retain the above copyright
13485 * notice, this list of conditions and the following disclaimer.
13486 * 2. Redistributions in binary form must reproduce the above copyright
13487 * notice, this list of conditions and the following disclaimer in the
13488 * documentation and/or other materials provided with the distribution.
13489 *
Eric Andersen2870d962001-07-02 17:27:21 +000013490 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13491 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013492 *
13493 * 4. Neither the name of the University nor the names of its contributors
13494 * may be used to endorse or promote products derived from this software
13495 * without specific prior written permission.
13496 *
13497 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13498 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13499 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13500 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13501 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13502 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13503 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13504 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13505 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13506 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13507 * SUCH DAMAGE.
13508 */