blob: 1fe1e8290c72fadd196e56312f69c6087f5dae98 [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;
Glenn L McGrathbbbe21d2004-01-25 08:46:10 +00004129#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Glenn L McGrath67285962004-01-14 09:34:51 +00004130 cmdedit_path_lookup = newval;
4131#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004132}
4133
4134
4135/*
4136 * Clear out command entries. The argument specifies the first entry in
4137 * PATH which has changed.
4138 */
4139
Eric Andersenc470f442003-07-28 09:56:35 +00004140static void
4141clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004142{
4143 struct tblentry **tblp;
4144 struct tblentry **pp;
4145 struct tblentry *cmdp;
4146
4147 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004148 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004149 pp = tblp;
4150 while ((cmdp = *pp) != NULL) {
4151 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004152 cmdp->param.index >= firstchange)
4153 || (cmdp->cmdtype == CMDBUILTIN &&
4154 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004155 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004156 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004157 } else {
4158 pp = &cmdp->next;
4159 }
4160 }
4161 }
4162 INTON;
4163}
4164
4165
Eric Andersenc470f442003-07-28 09:56:35 +00004166
Eric Andersencb57d552001-06-28 07:25:16 +00004167/*
Eric Andersencb57d552001-06-28 07:25:16 +00004168 * Locate a command in the command hash table. If "add" is nonzero,
4169 * add the command to the table if it is not already present. The
4170 * variable "lastcmdentry" is set to point to the address of the link
4171 * pointing to the entry, so that delete_cmd_entry can delete the
4172 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004173 *
4174 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004175 */
4176
Eric Andersen2870d962001-07-02 17:27:21 +00004177static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004178
Eric Andersenc470f442003-07-28 09:56:35 +00004179
4180static struct tblentry *
4181cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004182{
Eric Andersenc470f442003-07-28 09:56:35 +00004183 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004184 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004185 struct tblentry *cmdp;
4186 struct tblentry **pp;
4187
4188 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004189 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004190 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004191 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004192 hashval &= 0x7FFF;
4193 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004194 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004195 if (equal(cmdp->cmdname, name))
4196 break;
4197 pp = &cmdp->next;
4198 }
4199 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004200 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4201 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004202 cmdp->next = NULL;
4203 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004204 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004205 }
4206 lastcmdentry = pp;
4207 return cmdp;
4208}
4209
4210/*
4211 * Delete the command entry returned on the last lookup.
4212 */
4213
Eric Andersenc470f442003-07-28 09:56:35 +00004214static void
4215delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004216{
Eric Andersencb57d552001-06-28 07:25:16 +00004217 struct tblentry *cmdp;
4218
4219 INTOFF;
4220 cmdp = *lastcmdentry;
4221 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004222 if (cmdp->cmdtype == CMDFUNCTION)
4223 freefunc(cmdp->param.func);
4224 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004225 INTON;
4226}
4227
4228
Eric Andersenc470f442003-07-28 09:56:35 +00004229/*
4230 * Add a new command entry, replacing any existing command entry for
4231 * the same name - except special builtins.
4232 */
Eric Andersencb57d552001-06-28 07:25:16 +00004233
Eric Andersenc470f442003-07-28 09:56:35 +00004234static inline void
4235addcmdentry(char *name, struct cmdentry *entry)
4236{
4237 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004238
Eric Andersenc470f442003-07-28 09:56:35 +00004239 cmdp = cmdlookup(name, 1);
4240 if (cmdp->cmdtype == CMDFUNCTION) {
4241 freefunc(cmdp->param.func);
4242 }
4243 cmdp->cmdtype = entry->cmdtype;
4244 cmdp->param = entry->u;
4245 cmdp->rehash = 0;
4246}
Eric Andersencb57d552001-06-28 07:25:16 +00004247
Eric Andersenc470f442003-07-28 09:56:35 +00004248/*
4249 * Make a copy of a parse tree.
4250 */
Eric Andersencb57d552001-06-28 07:25:16 +00004251
Eric Andersenc470f442003-07-28 09:56:35 +00004252static inline struct funcnode *
4253copyfunc(union node *n)
4254{
4255 struct funcnode *f;
4256 size_t blocksize;
4257
4258 funcblocksize = offsetof(struct funcnode, n);
4259 funcstringsize = 0;
4260 calcsize(n);
4261 blocksize = funcblocksize;
4262 f = ckmalloc(blocksize + funcstringsize);
4263 funcblock = (char *) f + offsetof(struct funcnode, n);
4264 funcstring = (char *) f + blocksize;
4265 copynode(n);
4266 f->count = 0;
4267 return f;
4268}
4269
4270/*
4271 * Define a shell function.
4272 */
4273
4274static void
4275defun(char *name, union node *func)
4276{
4277 struct cmdentry entry;
4278
4279 INTOFF;
4280 entry.cmdtype = CMDFUNCTION;
4281 entry.u.func = copyfunc(func);
4282 addcmdentry(name, &entry);
4283 INTON;
4284}
Eric Andersencb57d552001-06-28 07:25:16 +00004285
4286
4287/*
4288 * Delete a function if it exists.
4289 */
4290
Eric Andersenc470f442003-07-28 09:56:35 +00004291static void
4292unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004293{
Eric Andersencb57d552001-06-28 07:25:16 +00004294 struct tblentry *cmdp;
4295
Eric Andersenc470f442003-07-28 09:56:35 +00004296 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4297 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004298 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004299}
4300
Eric Andersen2870d962001-07-02 17:27:21 +00004301/*
Eric Andersencb57d552001-06-28 07:25:16 +00004302 * Locate and print what a word is...
4303 */
4304
Eric Andersenc470f442003-07-28 09:56:35 +00004305
4306#ifdef CONFIG_ASH_CMDCMD
4307static int
4308describe_command(char *command, int describe_command_verbose)
4309#else
4310#define describe_command_verbose 1
4311static int
4312describe_command(char *command)
4313#endif
4314{
4315 struct cmdentry entry;
4316 struct tblentry *cmdp;
4317#ifdef CONFIG_ASH_ALIAS
4318 const struct alias *ap;
4319#endif
4320 const char *path = pathval();
4321
4322 if (describe_command_verbose) {
4323 out1str(command);
4324 }
4325
4326 /* First look at the keywords */
4327 if (findkwd(command)) {
4328 out1str(describe_command_verbose ? " is a shell keyword" : command);
4329 goto out;
4330 }
4331
4332#ifdef CONFIG_ASH_ALIAS
4333 /* Then look at the aliases */
4334 if ((ap = lookupalias(command, 0)) != NULL) {
4335 if (describe_command_verbose) {
4336 out1fmt(" is an alias for %s", ap->val);
4337 } else {
4338 out1str("alias ");
4339 printalias(ap);
4340 return 0;
4341 }
4342 goto out;
4343 }
4344#endif
4345 /* Then check if it is a tracked alias */
4346 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4347 entry.cmdtype = cmdp->cmdtype;
4348 entry.u = cmdp->param;
4349 } else {
4350 /* Finally use brute force */
4351 find_command(command, &entry, DO_ABS, path);
4352 }
4353
4354 switch (entry.cmdtype) {
4355 case CMDNORMAL: {
4356 int j = entry.u.index;
4357 char *p;
4358 if (j == -1) {
4359 p = command;
4360 } else {
4361 do {
4362 p = padvance(&path, command);
4363 stunalloc(p);
4364 } while (--j >= 0);
4365 }
4366 if (describe_command_verbose) {
4367 out1fmt(" is%s %s",
4368 (cmdp ? " a tracked alias for" : nullstr), p
4369 );
4370 } else {
4371 out1str(p);
4372 }
4373 break;
4374 }
4375
4376 case CMDFUNCTION:
4377 if (describe_command_verbose) {
4378 out1str(" is a shell function");
4379 } else {
4380 out1str(command);
4381 }
4382 break;
4383
4384 case CMDBUILTIN:
4385 if (describe_command_verbose) {
4386 out1fmt(" is a %sshell builtin",
4387 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4388 "special " : nullstr
4389 );
4390 } else {
4391 out1str(command);
4392 }
4393 break;
4394
4395 default:
4396 if (describe_command_verbose) {
4397 out1str(": not found\n");
4398 }
4399 return 127;
4400 }
4401
4402out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004403 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004404 return 0;
4405}
4406
4407static int
4408typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004409{
4410 int i;
4411 int err = 0;
4412
4413 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004414#ifdef CONFIG_ASH_CMDCMD
4415 err |= describe_command(argv[i], 1);
4416#else
4417 err |= describe_command(argv[i]);
4418#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004419 }
4420 return err;
4421}
4422
Eric Andersend35c5df2002-01-09 15:37:36 +00004423#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004424static int
4425commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004426{
4427 int c;
4428 int default_path = 0;
4429 int verify_only = 0;
4430 int verbose_verify_only = 0;
4431
4432 while ((c = nextopt("pvV")) != '\0')
4433 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004434 default:
4435#ifdef DEBUG
4436 fprintf(stderr,
4437"command: nextopt returned character code 0%o\n", c);
4438 return EX_SOFTWARE;
4439#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004440 case 'p':
4441 default_path = 1;
4442 break;
4443 case 'v':
4444 verify_only = 1;
4445 break;
4446 case 'V':
4447 verbose_verify_only = 1;
4448 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004449 }
4450
Eric Andersenc470f442003-07-28 09:56:35 +00004451 if (default_path + verify_only + verbose_verify_only > 1 ||
4452 !*argptr) {
4453 fprintf(stderr,
4454 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004455 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004456 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004457 }
4458
Eric Andersencb57d552001-06-28 07:25:16 +00004459 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004460 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004461 }
Eric Andersencb57d552001-06-28 07:25:16 +00004462
4463 return 0;
4464}
Eric Andersen2870d962001-07-02 17:27:21 +00004465#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004466
Eric Andersenc470f442003-07-28 09:56:35 +00004467/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004468
Eric Andersencb57d552001-06-28 07:25:16 +00004469/*
4470 * Routines to expand arguments to commands. We have to deal with
4471 * backquotes, shell variables, and file metacharacters.
4472 */
Eric Andersenc470f442003-07-28 09:56:35 +00004473
Eric Andersencb57d552001-06-28 07:25:16 +00004474/*
4475 * _rmescape() flags
4476 */
Eric Andersenc470f442003-07-28 09:56:35 +00004477#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4478#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4479#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4480#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4481#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004482
4483/*
4484 * Structure specifying which parts of the string should be searched
4485 * for IFS characters.
4486 */
4487
4488struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004489 struct ifsregion *next; /* next region in list */
4490 int begoff; /* offset of start of region */
4491 int endoff; /* offset of end of region */
4492 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004493};
4494
Eric Andersenc470f442003-07-28 09:56:35 +00004495/* output of current string */
4496static char *expdest;
4497/* list of back quote expressions */
4498static struct nodelist *argbackq;
4499/* first struct in list of ifs regions */
4500static struct ifsregion ifsfirst;
4501/* last struct in list */
4502static struct ifsregion *ifslastp;
4503/* holds expanded arg list */
4504static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004505
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004506static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004507static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004508static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004509static const char *subevalvar(char *, char *, int, int, int, int, int);
4510static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004511static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004512static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004513static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004514static void recordregion(int, int, int);
4515static void removerecordregions(int);
4516static void ifsbreakup(char *, struct arglist *);
4517static void ifsfree(void);
4518static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004519static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004520
Eric Andersenc470f442003-07-28 09:56:35 +00004521static int cvtnum(long);
4522static size_t esclen(const char *, const char *);
4523static char *scanleft(char *, char *, char *, char *, int, int);
4524static char *scanright(char *, char *, char *, char *, int, int);
4525static void varunset(const char *, const char *, const char *, int)
4526 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004527
Eric Andersenc470f442003-07-28 09:56:35 +00004528
4529#define pmatch(a, b) !fnmatch((a), (b), 0)
4530/*
Eric Andersen90898442003-08-06 11:20:52 +00004531 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004532 *
4533 * Returns an stalloced string.
4534 */
4535
4536static inline char *
4537preglob(const char *pattern, int quoted, int flag) {
4538 flag |= RMESCAPE_GLOB;
4539 if (quoted) {
4540 flag |= RMESCAPE_QUOTED;
4541 }
4542 return _rmescapes((char *)pattern, flag);
4543}
4544
4545
4546static size_t
4547esclen(const char *start, const char *p) {
4548 size_t esc = 0;
4549
4550 while (p > start && *--p == CTLESC) {
4551 esc++;
4552 }
4553 return esc;
4554}
4555
Eric Andersencb57d552001-06-28 07:25:16 +00004556
4557/*
4558 * Expand shell variables and backquotes inside a here document.
4559 */
4560
Eric Andersenc470f442003-07-28 09:56:35 +00004561static inline void
4562expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004563{
Eric Andersencb57d552001-06-28 07:25:16 +00004564 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004565 expandarg(arg, (struct arglist *)NULL, 0);
4566 xwrite(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004567}
4568
4569
4570/*
4571 * Perform variable substitution and command substitution on an argument,
4572 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4573 * perform splitting and file name expansion. When arglist is NULL, perform
4574 * here document expansion.
4575 */
4576
Eric Andersenc470f442003-07-28 09:56:35 +00004577void
4578expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004579{
4580 struct strlist *sp;
4581 char *p;
4582
4583 argbackq = arg->narg.backquote;
4584 STARTSTACKSTR(expdest);
4585 ifsfirst.next = NULL;
4586 ifslastp = NULL;
4587 argstr(arg->narg.text, flag);
4588 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004589 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004590 }
4591 STPUTC('\0', expdest);
4592 p = grabstackstr(expdest);
4593 exparg.lastp = &exparg.list;
4594 /*
4595 * TODO - EXP_REDIR
4596 */
4597 if (flag & EXP_FULL) {
4598 ifsbreakup(p, &exparg);
4599 *exparg.lastp = NULL;
4600 exparg.lastp = &exparg.list;
4601 expandmeta(exparg.list, flag);
4602 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004603 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004604 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004605 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004606 sp->text = p;
4607 *exparg.lastp = sp;
4608 exparg.lastp = &sp->next;
4609 }
Eric Andersenc470f442003-07-28 09:56:35 +00004610 if (ifsfirst.next)
4611 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004612 *exparg.lastp = NULL;
4613 if (exparg.list) {
4614 *arglist->lastp = exparg.list;
4615 arglist->lastp = exparg.lastp;
4616 }
4617}
4618
4619
Eric Andersenc470f442003-07-28 09:56:35 +00004620/*
4621 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4622 * characters to allow for further processing. Otherwise treat
4623 * $@ like $* since no splitting will be performed.
4624 */
4625
4626static void
4627argstr(char *p, int flag)
4628{
4629 static const char spclchars[] = {
4630 '=',
4631 ':',
4632 CTLQUOTEMARK,
4633 CTLENDVAR,
4634 CTLESC,
4635 CTLVAR,
4636 CTLBACKQ,
4637 CTLBACKQ | CTLQUOTE,
4638#ifdef CONFIG_ASH_MATH_SUPPORT
4639 CTLENDARI,
4640#endif
4641 0
4642 };
4643 const char *reject = spclchars;
4644 int c;
4645 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4646 int breakall = flag & EXP_WORD;
4647 int inquotes;
4648 size_t length;
4649 int startloc;
4650
4651 if (!(flag & EXP_VARTILDE)) {
4652 reject += 2;
4653 } else if (flag & EXP_VARTILDE2) {
4654 reject++;
4655 }
4656 inquotes = 0;
4657 length = 0;
4658 if (flag & EXP_TILDE) {
4659 char *q;
4660
4661 flag &= ~EXP_TILDE;
4662tilde:
4663 q = p;
4664 if (*q == CTLESC && (flag & EXP_QWORD))
4665 q++;
4666 if (*q == '~')
4667 p = exptilde(p, q, flag);
4668 }
4669start:
4670 startloc = expdest - (char *)stackblock();
4671 for (;;) {
4672 length += strcspn(p + length, reject);
4673 c = p[length];
4674 if (c && (!(c & 0x80)
4675#ifdef CONFIG_ASH_MATH_SUPPORT
4676 || c == CTLENDARI
4677#endif
4678 )) {
4679 /* c == '=' || c == ':' || c == CTLENDARI */
4680 length++;
4681 }
4682 if (length > 0) {
4683 int newloc;
4684 expdest = stnputs(p, length, expdest);
4685 newloc = expdest - (char *)stackblock();
4686 if (breakall && !inquotes && newloc > startloc) {
4687 recordregion(startloc, newloc, 0);
4688 }
4689 startloc = newloc;
4690 }
4691 p += length + 1;
4692 length = 0;
4693
4694 switch (c) {
4695 case '\0':
4696 goto breakloop;
4697 case '=':
4698 if (flag & EXP_VARTILDE2) {
4699 p--;
4700 continue;
4701 }
4702 flag |= EXP_VARTILDE2;
4703 reject++;
4704 /* fall through */
4705 case ':':
4706 /*
4707 * sort of a hack - expand tildes in variable
4708 * assignments (after the first '=' and after ':'s).
4709 */
4710 if (*--p == '~') {
4711 goto tilde;
4712 }
4713 continue;
4714 }
4715
4716 switch (c) {
4717 case CTLENDVAR: /* ??? */
4718 goto breakloop;
4719 case CTLQUOTEMARK:
4720 /* "$@" syntax adherence hack */
4721 if (
4722 !inquotes &&
4723 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4724 (p[4] == CTLQUOTEMARK || (
4725 p[4] == CTLENDVAR &&
4726 p[5] == CTLQUOTEMARK
4727 ))
4728 ) {
4729 p = evalvar(p + 1, flag) + 1;
4730 goto start;
4731 }
4732 inquotes = !inquotes;
4733addquote:
4734 if (quotes) {
4735 p--;
4736 length++;
4737 startloc++;
4738 }
4739 break;
4740 case CTLESC:
4741 startloc++;
4742 length++;
4743 goto addquote;
4744 case CTLVAR:
4745 p = evalvar(p, flag);
4746 goto start;
4747 case CTLBACKQ:
4748 c = 0;
4749 case CTLBACKQ|CTLQUOTE:
4750 expbackq(argbackq->n, c, quotes);
4751 argbackq = argbackq->next;
4752 goto start;
4753#ifdef CONFIG_ASH_MATH_SUPPORT
4754 case CTLENDARI:
4755 p--;
4756 expari(quotes);
4757 goto start;
4758#endif
4759 }
4760 }
4761breakloop:
4762 ;
4763}
4764
4765static char *
4766exptilde(char *startp, char *p, int flag)
4767{
4768 char c;
4769 char *name;
4770 struct passwd *pw;
4771 const char *home;
4772 int quotes = flag & (EXP_FULL | EXP_CASE);
4773 int startloc;
4774
4775 name = p + 1;
4776
4777 while ((c = *++p) != '\0') {
4778 switch(c) {
4779 case CTLESC:
4780 return (startp);
4781 case CTLQUOTEMARK:
4782 return (startp);
4783 case ':':
4784 if (flag & EXP_VARTILDE)
4785 goto done;
4786 break;
4787 case '/':
4788 case CTLENDVAR:
4789 goto done;
4790 }
4791 }
4792done:
4793 *p = '\0';
4794 if (*name == '\0') {
4795 if ((home = lookupvar(homestr)) == NULL)
4796 goto lose;
4797 } else {
4798 if ((pw = getpwnam(name)) == NULL)
4799 goto lose;
4800 home = pw->pw_dir;
4801 }
4802 if (*home == '\0')
4803 goto lose;
4804 *p = c;
4805 startloc = expdest - (char *)stackblock();
4806 strtodest(home, SQSYNTAX, quotes);
4807 recordregion(startloc, expdest - (char *)stackblock(), 0);
4808 return (p);
4809lose:
4810 *p = c;
4811 return (startp);
4812}
4813
4814
4815static void
4816removerecordregions(int endoff)
4817{
4818 if (ifslastp == NULL)
4819 return;
4820
4821 if (ifsfirst.endoff > endoff) {
4822 while (ifsfirst.next != NULL) {
4823 struct ifsregion *ifsp;
4824 INTOFF;
4825 ifsp = ifsfirst.next->next;
4826 ckfree(ifsfirst.next);
4827 ifsfirst.next = ifsp;
4828 INTON;
4829 }
4830 if (ifsfirst.begoff > endoff)
4831 ifslastp = NULL;
4832 else {
4833 ifslastp = &ifsfirst;
4834 ifsfirst.endoff = endoff;
4835 }
4836 return;
4837 }
4838
4839 ifslastp = &ifsfirst;
4840 while (ifslastp->next && ifslastp->next->begoff < endoff)
4841 ifslastp=ifslastp->next;
4842 while (ifslastp->next != NULL) {
4843 struct ifsregion *ifsp;
4844 INTOFF;
4845 ifsp = ifslastp->next->next;
4846 ckfree(ifslastp->next);
4847 ifslastp->next = ifsp;
4848 INTON;
4849 }
4850 if (ifslastp->endoff > endoff)
4851 ifslastp->endoff = endoff;
4852}
4853
4854
4855#ifdef CONFIG_ASH_MATH_SUPPORT
4856/*
4857 * Expand arithmetic expression. Backup to start of expression,
4858 * evaluate, place result in (backed up) result, adjust string position.
4859 */
4860void
4861expari(int quotes)
4862{
4863 char *p, *start;
4864 int begoff;
4865 int flag;
4866 int len;
4867
4868 /* ifsfree(); */
4869
4870 /*
4871 * This routine is slightly over-complicated for
4872 * efficiency. Next we scan backwards looking for the
4873 * start of arithmetic.
4874 */
4875 start = stackblock();
4876 p = expdest - 1;
4877 *p = '\0';
4878 p--;
4879 do {
4880 int esc;
4881
4882 while (*p != CTLARI) {
4883 p--;
4884#ifdef DEBUG
4885 if (p < start) {
4886 error("missing CTLARI (shouldn't happen)");
4887 }
4888#endif
4889 }
4890
4891 esc = esclen(start, p);
4892 if (!(esc % 2)) {
4893 break;
4894 }
4895
4896 p -= esc + 1;
4897 } while (1);
4898
4899 begoff = p - start;
4900
4901 removerecordregions(begoff);
4902
4903 flag = p[1];
4904
4905 expdest = p;
4906
4907 if (quotes)
4908 rmescapes(p + 2);
4909
4910 len = cvtnum(dash_arith(p + 2));
4911
4912 if (flag != '"')
4913 recordregion(begoff, begoff + len, 0);
4914}
4915#endif
4916
4917/*
4918 * Expand stuff in backwards quotes.
4919 */
4920
4921static void
4922expbackq(union node *cmd, int quoted, int quotes)
4923{
4924 struct backcmd in;
4925 int i;
4926 char buf[128];
4927 char *p;
4928 char *dest;
4929 int startloc;
4930 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4931 struct stackmark smark;
4932
4933 INTOFF;
4934 setstackmark(&smark);
4935 dest = expdest;
4936 startloc = dest - (char *)stackblock();
4937 grabstackstr(dest);
4938 evalbackcmd(cmd, (struct backcmd *) &in);
4939 popstackmark(&smark);
4940
4941 p = in.buf;
4942 i = in.nleft;
4943 if (i == 0)
4944 goto read;
4945 for (;;) {
4946 memtodest(p, i, syntax, quotes);
4947read:
4948 if (in.fd < 0)
4949 break;
4950 i = safe_read(in.fd, buf, sizeof buf);
4951 TRACE(("expbackq: read returns %d\n", i));
4952 if (i <= 0)
4953 break;
4954 p = buf;
4955 }
4956
4957 if (in.buf)
4958 ckfree(in.buf);
4959 if (in.fd >= 0) {
4960 close(in.fd);
4961 back_exitstatus = waitforjob(in.jp);
4962 }
4963 INTON;
4964
4965 /* Eat all trailing newlines */
4966 dest = expdest;
4967 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4968 STUNPUTC(dest);
4969 expdest = dest;
4970
4971 if (quoted == 0)
4972 recordregion(startloc, dest - (char *)stackblock(), 0);
4973 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4974 (dest - (char *)stackblock()) - startloc,
4975 (dest - (char *)stackblock()) - startloc,
4976 stackblock() + startloc));
4977}
4978
4979
4980static char *
Eric Andersen90898442003-08-06 11:20:52 +00004981scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4982 int zero)
4983{
Eric Andersenc470f442003-07-28 09:56:35 +00004984 char *loc;
4985 char *loc2;
4986 char c;
4987
4988 loc = startp;
4989 loc2 = rmesc;
4990 do {
4991 int match;
4992 const char *s = loc2;
4993 c = *loc2;
4994 if (zero) {
4995 *loc2 = '\0';
4996 s = rmesc;
4997 }
4998 match = pmatch(str, s);
4999 *loc2 = c;
5000 if (match)
5001 return loc;
5002 if (quotes && *loc == CTLESC)
5003 loc++;
5004 loc++;
5005 loc2++;
5006 } while (c);
5007 return 0;
5008}
5009
5010
5011static char *
Eric Andersen90898442003-08-06 11:20:52 +00005012scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5013 int zero)
5014{
Eric Andersenc470f442003-07-28 09:56:35 +00005015 int esc = 0;
5016 char *loc;
5017 char *loc2;
5018
5019 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5020 int match;
5021 char c = *loc2;
5022 const char *s = loc2;
5023 if (zero) {
5024 *loc2 = '\0';
5025 s = rmesc;
5026 }
5027 match = pmatch(str, s);
5028 *loc2 = c;
5029 if (match)
5030 return loc;
5031 loc--;
5032 if (quotes) {
5033 if (--esc < 0) {
5034 esc = esclen(startp, loc);
5035 }
5036 if (esc % 2) {
5037 esc--;
5038 loc--;
5039 }
5040 }
5041 }
5042 return 0;
5043}
5044
5045static const char *
5046subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5047{
5048 char *startp;
5049 char *loc;
5050 int saveherefd = herefd;
5051 struct nodelist *saveargbackq = argbackq;
5052 int amount;
5053 char *rmesc, *rmescend;
5054 int zero;
5055 char *(*scan)(char *, char *, char *, char *, int , int);
5056
5057 herefd = -1;
5058 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5059 STPUTC('\0', expdest);
5060 herefd = saveherefd;
5061 argbackq = saveargbackq;
5062 startp = stackblock() + startloc;
5063
5064 switch (subtype) {
5065 case VSASSIGN:
5066 setvar(str, startp, 0);
5067 amount = startp - expdest;
5068 STADJUST(amount, expdest);
5069 return startp;
5070
5071 case VSQUESTION:
5072 varunset(p, str, startp, varflags);
5073 /* NOTREACHED */
5074 }
5075
5076 subtype -= VSTRIMRIGHT;
5077#ifdef DEBUG
5078 if (subtype < 0 || subtype > 3)
5079 abort();
5080#endif
5081
5082 rmesc = startp;
5083 rmescend = stackblock() + strloc;
5084 if (quotes) {
5085 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5086 if (rmesc != startp) {
5087 rmescend = expdest;
5088 startp = stackblock() + startloc;
5089 }
5090 }
5091 rmescend--;
5092 str = stackblock() + strloc;
5093 preglob(str, varflags & VSQUOTE, 0);
5094
5095 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5096 zero = subtype >> 1;
5097 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5098 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5099
5100 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5101 if (loc) {
5102 if (zero) {
5103 memmove(startp, loc, str - loc);
5104 loc = startp + (str - loc) - 1;
5105 }
5106 *loc = '\0';
5107 amount = loc - expdest;
5108 STADJUST(amount, expdest);
5109 }
5110 return loc;
5111}
5112
5113
Eric Andersen62483552001-07-10 06:09:16 +00005114/*
5115 * Expand a variable, and return a pointer to the next character in the
5116 * input string.
5117 */
Eric Andersenc470f442003-07-28 09:56:35 +00005118static char *
5119evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005120{
5121 int subtype;
5122 int varflags;
5123 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005124 int patloc;
5125 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005126 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005127 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005128 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005129 int quotes;
5130 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005131
Eric Andersenc470f442003-07-28 09:56:35 +00005132 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005133 varflags = *p++;
5134 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005135 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005136 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005137 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005138 startloc = expdest - (char *)stackblock();
5139 p = strchr(p, '=') + 1;
5140
Eric Andersenc470f442003-07-28 09:56:35 +00005141again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005142 varlen = varvalue(var, varflags, flag);
5143 if (varflags & VSNUL)
5144 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005145
Glenn L McGrath76620622004-01-13 10:19:37 +00005146 if (subtype == VSPLUS) {
5147 varlen = -1 - varlen;
5148 goto vsplus;
5149 }
Eric Andersen62483552001-07-10 06:09:16 +00005150
Eric Andersenc470f442003-07-28 09:56:35 +00005151 if (subtype == VSMINUS) {
5152vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005153 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005154 argstr(
5155 p, flag | EXP_TILDE |
5156 (quoted ? EXP_QWORD : EXP_WORD)
5157 );
5158 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005159 }
5160 if (easy)
5161 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005162 goto end;
5163 }
Eric Andersen62483552001-07-10 06:09:16 +00005164
Eric Andersenc470f442003-07-28 09:56:35 +00005165 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005166 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005167 if (subevalvar(p, var, 0, subtype, startloc,
5168 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005169 varflags &= ~VSNUL;
5170 /*
5171 * Remove any recorded regions beyond
5172 * start of variable
5173 */
5174 removerecordregions(startloc);
5175 goto again;
5176 }
Eric Andersenc470f442003-07-28 09:56:35 +00005177 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005178 }
5179 if (easy)
5180 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005181 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005182 }
5183
Glenn L McGrath76620622004-01-13 10:19:37 +00005184 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005185 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005186
Eric Andersenc470f442003-07-28 09:56:35 +00005187 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005188 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005189 goto record;
5190 }
5191
5192 if (subtype == VSNORMAL) {
5193 if (!easy)
5194 goto end;
5195record:
5196 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5197 goto end;
5198 }
5199
5200#ifdef DEBUG
5201 switch (subtype) {
5202 case VSTRIMLEFT:
5203 case VSTRIMLEFTMAX:
5204 case VSTRIMRIGHT:
5205 case VSTRIMRIGHTMAX:
5206 break;
5207 default:
5208 abort();
5209 }
5210#endif
5211
Glenn L McGrath76620622004-01-13 10:19:37 +00005212 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005213 /*
5214 * Terminate the string and start recording the pattern
5215 * right after it
5216 */
5217 STPUTC('\0', expdest);
5218 patloc = expdest - (char *)stackblock();
5219 if (subevalvar(p, NULL, patloc, subtype,
5220 startloc, varflags, quotes) == 0) {
5221 int amount = expdest - (
5222 (char *)stackblock() + patloc - 1
5223 );
5224 STADJUST(-amount, expdest);
5225 }
5226 /* Remove any recorded regions beyond start of variable */
5227 removerecordregions(startloc);
5228 goto record;
5229 }
5230
5231end:
5232 if (subtype != VSNORMAL) { /* skip to end of alternative */
5233 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005234 for (;;) {
5235 if ((c = *p++) == CTLESC)
5236 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005237 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005238 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005239 argbackq = argbackq->next;
5240 } else if (c == CTLVAR) {
5241 if ((*p++ & VSTYPE) != VSNORMAL)
5242 nesting++;
5243 } else if (c == CTLENDVAR) {
5244 if (--nesting == 0)
5245 break;
5246 }
5247 }
5248 }
5249 return p;
5250}
5251
Eric Andersencb57d552001-06-28 07:25:16 +00005252
Eric Andersencb57d552001-06-28 07:25:16 +00005253/*
5254 * Put a string on the stack.
5255 */
5256
Eric Andersenc470f442003-07-28 09:56:35 +00005257static void
5258memtodest(const char *p, size_t len, int syntax, int quotes) {
5259 char *q = expdest;
5260
5261 q = makestrspace(len * 2, q);
5262
5263 while (len--) {
5264 int c = *p++;
5265 if (!c)
5266 continue;
5267 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5268 USTPUTC(CTLESC, q);
5269 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005270 }
Eric Andersenc470f442003-07-28 09:56:35 +00005271
5272 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005273}
5274
Eric Andersenc470f442003-07-28 09:56:35 +00005275
5276static void
5277strtodest(const char *p, int syntax, int quotes)
5278{
5279 memtodest(p, strlen(p), syntax, quotes);
5280}
5281
5282
Eric Andersencb57d552001-06-28 07:25:16 +00005283/*
5284 * Add the value of a specialized variable to the stack string.
5285 */
5286
Glenn L McGrath76620622004-01-13 10:19:37 +00005287static ssize_t
5288varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005289{
5290 int num;
5291 char *p;
5292 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005293 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005294 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005295 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005296 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005297 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005298 int quoted = varflags & VSQUOTE;
5299 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005300 int quotes = flags & (EXP_FULL | EXP_CASE);
5301
Glenn L McGrath76620622004-01-13 10:19:37 +00005302 if (quoted && (flags & EXP_FULL))
5303 sep = 1 << CHAR_BIT;
5304
Eric Andersencb57d552001-06-28 07:25:16 +00005305 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5306 switch (*name) {
5307 case '$':
5308 num = rootpid;
5309 goto numvar;
5310 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005311 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005312 goto numvar;
5313 case '#':
5314 num = shellparam.nparam;
5315 goto numvar;
5316 case '!':
5317 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005318 if (num == 0)
5319 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005320numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005321 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005322 break;
5323 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005324 p = makestrspace(NOPTS, expdest);
5325 for (i = NOPTS - 1; i >= 0; i--) {
5326 if (optlist[i]) {
5327 USTPUTC(optletters(i), p);
5328 len++;
5329 }
Eric Andersencb57d552001-06-28 07:25:16 +00005330 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005331 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005332 break;
5333 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005334 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005335 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005336 /* fall through */
5337 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005338 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005339 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5340 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005341param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005342 if (!(ap = shellparam.p))
5343 return -1;
5344 while ((p = *ap++)) {
5345 size_t partlen;
5346
5347 partlen = strlen(p);
5348
5349 len += partlen;
5350 if (len > partlen && sep) {
5351 char *q;
5352
5353 len++;
5354 if (subtype == VSPLUS || subtype == VSLENGTH) {
5355 continue;
5356 }
5357 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005358 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005359 STPUTC(CTLESC, q);
5360 STPUTC(sep, q);
5361 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005362 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005363
5364 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5365 memtodest(p, partlen, syntax, quotes);
Eric Andersencb57d552001-06-28 07:25:16 +00005366 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005367 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005368 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005369 case '1':
5370 case '2':
5371 case '3':
5372 case '4':
5373 case '5':
5374 case '6':
5375 case '7':
5376 case '8':
5377 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005378 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005379 if (num < 0 || num > shellparam.nparam)
5380 return -1;
5381 p = num ? shellparam.p[num - 1] : arg0;
5382 goto value;
5383 default:
5384 p = lookupvar(name);
5385value:
5386 if (!p)
5387 return -1;
5388
5389 len = strlen(p);
5390 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5391 memtodest(p, len, syntax, quotes);
5392 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005393 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005394
5395 if (subtype == VSPLUS || subtype == VSLENGTH)
5396 STADJUST(-len, expdest);
5397 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005398}
5399
5400
Eric Andersencb57d552001-06-28 07:25:16 +00005401/*
5402 * Record the fact that we have to scan this region of the
5403 * string for IFS characters.
5404 */
5405
Eric Andersenc470f442003-07-28 09:56:35 +00005406static void
5407recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005408{
5409 struct ifsregion *ifsp;
5410
5411 if (ifslastp == NULL) {
5412 ifsp = &ifsfirst;
5413 } else {
5414 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005415 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005416 ifsp->next = NULL;
5417 ifslastp->next = ifsp;
5418 INTON;
5419 }
5420 ifslastp = ifsp;
5421 ifslastp->begoff = start;
5422 ifslastp->endoff = end;
5423 ifslastp->nulonly = nulonly;
5424}
5425
5426
Eric Andersencb57d552001-06-28 07:25:16 +00005427/*
5428 * Break the argument string into pieces based upon IFS and add the
5429 * strings to the argument list. The regions of the string to be
5430 * searched for IFS characters have been stored by recordregion.
5431 */
Eric Andersenc470f442003-07-28 09:56:35 +00005432static void
5433ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005434{
Eric Andersencb57d552001-06-28 07:25:16 +00005435 struct ifsregion *ifsp;
5436 struct strlist *sp;
5437 char *start;
5438 char *p;
5439 char *q;
5440 const char *ifs, *realifs;
5441 int ifsspc;
5442 int nulonly;
5443
5444
5445 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005446 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005447 ifsspc = 0;
5448 nulonly = 0;
5449 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005450 ifsp = &ifsfirst;
5451 do {
5452 p = string + ifsp->begoff;
5453 nulonly = ifsp->nulonly;
5454 ifs = nulonly ? nullstr : realifs;
5455 ifsspc = 0;
5456 while (p < string + ifsp->endoff) {
5457 q = p;
5458 if (*p == CTLESC)
5459 p++;
5460 if (strchr(ifs, *p)) {
5461 if (!nulonly)
5462 ifsspc = (strchr(defifs, *p) != NULL);
5463 /* Ignore IFS whitespace at start */
5464 if (q == start && ifsspc) {
5465 p++;
5466 start = p;
5467 continue;
5468 }
5469 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005470 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005471 sp->text = start;
5472 *arglist->lastp = sp;
5473 arglist->lastp = &sp->next;
5474 p++;
5475 if (!nulonly) {
5476 for (;;) {
5477 if (p >= string + ifsp->endoff) {
5478 break;
5479 }
5480 q = p;
5481 if (*p == CTLESC)
5482 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005483 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005484 p = q;
5485 break;
5486 } else if (strchr(defifs, *p) == NULL) {
5487 if (ifsspc) {
5488 p++;
5489 ifsspc = 0;
5490 } else {
5491 p = q;
5492 break;
5493 }
5494 } else
5495 p++;
5496 }
5497 }
5498 start = p;
5499 } else
5500 p++;
5501 }
5502 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005503 if (nulonly)
5504 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005505 }
5506
Eric Andersenc470f442003-07-28 09:56:35 +00005507 if (!*start)
5508 return;
5509
5510add:
5511 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005512 sp->text = start;
5513 *arglist->lastp = sp;
5514 arglist->lastp = &sp->next;
5515}
5516
Eric Andersenc470f442003-07-28 09:56:35 +00005517static void
5518ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005519{
Eric Andersenc470f442003-07-28 09:56:35 +00005520 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005521
Eric Andersenc470f442003-07-28 09:56:35 +00005522 INTOFF;
5523 p = ifsfirst.next;
5524 do {
5525 struct ifsregion *ifsp;
5526 ifsp = p->next;
5527 ckfree(p);
5528 p = ifsp;
5529 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005530 ifslastp = NULL;
5531 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005532 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005533}
5534
Eric Andersen90898442003-08-06 11:20:52 +00005535static void expmeta(char *, char *);
5536static struct strlist *expsort(struct strlist *);
5537static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005538
Eric Andersen90898442003-08-06 11:20:52 +00005539static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005540
Eric Andersencb57d552001-06-28 07:25:16 +00005541
Eric Andersenc470f442003-07-28 09:56:35 +00005542static void
Eric Andersen90898442003-08-06 11:20:52 +00005543expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005544{
Eric Andersen90898442003-08-06 11:20:52 +00005545 static const char metachars[] = {
5546 '*', '?', '[', 0
5547 };
Eric Andersencb57d552001-06-28 07:25:16 +00005548 /* TODO - EXP_REDIR */
5549
5550 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005551 struct strlist **savelastp;
5552 struct strlist *sp;
5553 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005554
Eric Andersencb57d552001-06-28 07:25:16 +00005555 if (fflag)
5556 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005557 if (!strpbrk(str->text, metachars))
5558 goto nometa;
5559 savelastp = exparg.lastp;
5560
Eric Andersencb57d552001-06-28 07:25:16 +00005561 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005562 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005563 {
5564 int i = strlen(str->text);
5565 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5566 }
5567
5568 expmeta(expdir, p);
5569 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005570 if (p != str->text)
5571 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005572 INTON;
5573 if (exparg.lastp == savelastp) {
5574 /*
5575 * no matches
5576 */
Eric Andersenc470f442003-07-28 09:56:35 +00005577nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005578 *exparg.lastp = str;
5579 rmescapes(str->text);
5580 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005581 } else {
5582 *exparg.lastp = NULL;
5583 *savelastp = sp = expsort(*savelastp);
5584 while (sp->next != NULL)
5585 sp = sp->next;
5586 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005587 }
5588 str = str->next;
5589 }
5590}
5591
Eric Andersencb57d552001-06-28 07:25:16 +00005592/*
Eric Andersenc470f442003-07-28 09:56:35 +00005593 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005594 */
5595
Eric Andersenc470f442003-07-28 09:56:35 +00005596static void
Eric Andersen90898442003-08-06 11:20:52 +00005597addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005598{
Eric Andersencb57d552001-06-28 07:25:16 +00005599 struct strlist *sp;
5600
Eric Andersenc470f442003-07-28 09:56:35 +00005601 sp = (struct strlist *)stalloc(sizeof *sp);
5602 sp->text = sstrdup(name);
5603 *exparg.lastp = sp;
5604 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005605}
5606
5607
Eric Andersencb57d552001-06-28 07:25:16 +00005608/*
Eric Andersen90898442003-08-06 11:20:52 +00005609 * Do metacharacter (i.e. *, ?, [...]) expansion.
5610 */
5611
5612static void
5613expmeta(char *enddir, char *name)
5614{
5615 char *p;
5616 const char *cp;
5617 char *start;
5618 char *endname;
5619 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005620 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005621 DIR *dirp;
5622 struct dirent *dp;
5623 int atend;
5624 int matchdot;
5625
5626 metaflag = 0;
5627 start = name;
5628 for (p = name; *p; p++) {
5629 if (*p == '*' || *p == '?')
5630 metaflag = 1;
5631 else if (*p == '[') {
5632 char *q = p + 1;
5633 if (*q == '!')
5634 q++;
5635 for (;;) {
5636 if (*q == '\\')
5637 q++;
5638 if (*q == '/' || *q == '\0')
5639 break;
5640 if (*++q == ']') {
5641 metaflag = 1;
5642 break;
5643 }
5644 }
5645 } else if (*p == '\\')
5646 p++;
5647 else if (*p == '/') {
5648 if (metaflag)
5649 goto out;
5650 start = p + 1;
5651 }
5652 }
5653out:
5654 if (metaflag == 0) { /* we've reached the end of the file name */
5655 if (enddir != expdir)
5656 metaflag++;
5657 p = name;
5658 do {
5659 if (*p == '\\')
5660 p++;
5661 *enddir++ = *p;
5662 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005663 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005664 addfname(expdir);
5665 return;
5666 }
5667 endname = p;
5668 if (name < start) {
5669 p = name;
5670 do {
5671 if (*p == '\\')
5672 p++;
5673 *enddir++ = *p++;
5674 } while (p < start);
5675 }
5676 if (enddir == expdir) {
5677 cp = ".";
5678 } else if (enddir == expdir + 1 && *expdir == '/') {
5679 cp = "/";
5680 } else {
5681 cp = expdir;
5682 enddir[-1] = '\0';
5683 }
5684 if ((dirp = opendir(cp)) == NULL)
5685 return;
5686 if (enddir != expdir)
5687 enddir[-1] = '/';
5688 if (*endname == 0) {
5689 atend = 1;
5690 } else {
5691 atend = 0;
5692 *endname++ = '\0';
5693 }
5694 matchdot = 0;
5695 p = start;
5696 if (*p == '\\')
5697 p++;
5698 if (*p == '.')
5699 matchdot++;
5700 while (! intpending && (dp = readdir(dirp)) != NULL) {
5701 if (dp->d_name[0] == '.' && ! matchdot)
5702 continue;
5703 if (pmatch(start, dp->d_name)) {
5704 if (atend) {
5705 scopy(dp->d_name, enddir);
5706 addfname(expdir);
5707 } else {
5708 for (p = enddir, cp = dp->d_name;
5709 (*p++ = *cp++) != '\0';)
5710 continue;
5711 p[-1] = '/';
5712 expmeta(p, endname);
5713 }
5714 }
5715 }
5716 closedir(dirp);
5717 if (! atend)
5718 endname[-1] = '/';
5719}
5720
5721/*
5722 * Sort the results of file name expansion. It calculates the number of
5723 * strings to sort and then calls msort (short for merge sort) to do the
5724 * work.
5725 */
5726
5727static struct strlist *
5728expsort(struct strlist *str)
5729{
5730 int len;
5731 struct strlist *sp;
5732
5733 len = 0;
5734 for (sp = str ; sp ; sp = sp->next)
5735 len++;
5736 return msort(str, len);
5737}
5738
5739
5740static struct strlist *
5741msort(struct strlist *list, int len)
5742{
5743 struct strlist *p, *q = NULL;
5744 struct strlist **lpp;
5745 int half;
5746 int n;
5747
5748 if (len <= 1)
5749 return list;
5750 half = len >> 1;
5751 p = list;
5752 for (n = half ; --n >= 0 ; ) {
5753 q = p;
5754 p = p->next;
5755 }
5756 q->next = NULL; /* terminate first half of list */
5757 q = msort(list, half); /* sort first half of list */
5758 p = msort(p, len - half); /* sort second half */
5759 lpp = &list;
5760 for (;;) {
5761#ifdef CONFIG_LOCALE_SUPPORT
5762 if (strcoll(p->text, q->text) < 0)
5763#else
5764 if (strcmp(p->text, q->text) < 0)
5765#endif
5766 {
5767 *lpp = p;
5768 lpp = &p->next;
5769 if ((p = *lpp) == NULL) {
5770 *lpp = q;
5771 break;
5772 }
5773 } else {
5774 *lpp = q;
5775 lpp = &q->next;
5776 if ((q = *lpp) == NULL) {
5777 *lpp = p;
5778 break;
5779 }
5780 }
5781 }
5782 return list;
5783}
5784
5785
5786/*
Eric Andersencb57d552001-06-28 07:25:16 +00005787 * Returns true if the pattern matches the string.
5788 */
5789
Eric Andersenc470f442003-07-28 09:56:35 +00005790static inline int
5791patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005792{
Eric Andersenc470f442003-07-28 09:56:35 +00005793 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005794}
5795
5796
Eric Andersencb57d552001-06-28 07:25:16 +00005797/*
5798 * Remove any CTLESC characters from a string.
5799 */
5800
Eric Andersenc470f442003-07-28 09:56:35 +00005801static char *
5802_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005803{
5804 char *p, *q, *r;
5805 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005806 unsigned inquotes;
5807 int notescaped;
5808 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005809
5810 p = strpbrk(str, qchars);
5811 if (!p) {
5812 return str;
5813 }
5814 q = p;
5815 r = str;
5816 if (flag & RMESCAPE_ALLOC) {
5817 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005818 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005819
Eric Andersenc470f442003-07-28 09:56:35 +00005820 if (flag & RMESCAPE_GROW) {
5821 r = makestrspace(fulllen, expdest);
5822 } else if (flag & RMESCAPE_HEAP) {
5823 r = ckmalloc(fulllen);
5824 } else {
5825 r = stalloc(fulllen);
5826 }
5827 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005828 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005829 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005830 }
5831 }
Eric Andersenc470f442003-07-28 09:56:35 +00005832 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5833 globbing = flag & RMESCAPE_GLOB;
5834 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005835 while (*p) {
5836 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005837 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005838 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005839 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005840 continue;
5841 }
Eric Andersenc470f442003-07-28 09:56:35 +00005842 if (*p == '\\') {
5843 /* naked back slash */
5844 notescaped = 0;
5845 goto copy;
5846 }
Eric Andersencb57d552001-06-28 07:25:16 +00005847 if (*p == CTLESC) {
5848 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005849 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005850 *q++ = '\\';
5851 }
5852 }
Eric Andersenc470f442003-07-28 09:56:35 +00005853 notescaped = globbing;
5854copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005855 *q++ = *p++;
5856 }
5857 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005858 if (flag & RMESCAPE_GROW) {
5859 expdest = r;
5860 STADJUST(q - r + 1, expdest);
5861 }
Eric Andersencb57d552001-06-28 07:25:16 +00005862 return r;
5863}
Eric Andersencb57d552001-06-28 07:25:16 +00005864
5865
Eric Andersencb57d552001-06-28 07:25:16 +00005866/*
5867 * See if a pattern matches in a case statement.
5868 */
5869
Eric Andersenc470f442003-07-28 09:56:35 +00005870int
5871casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005872{
Eric Andersencb57d552001-06-28 07:25:16 +00005873 struct stackmark smark;
5874 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005875
5876 setstackmark(&smark);
5877 argbackq = pattern->narg.backquote;
5878 STARTSTACKSTR(expdest);
5879 ifslastp = NULL;
5880 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005881 STACKSTRNUL(expdest);
5882 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005883 popstackmark(&smark);
5884 return result;
5885}
5886
5887/*
5888 * Our own itoa().
5889 */
5890
Eric Andersenc470f442003-07-28 09:56:35 +00005891static int
5892cvtnum(long num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005893{
Eric Andersencb57d552001-06-28 07:25:16 +00005894 int len;
5895
Eric Andersenc470f442003-07-28 09:56:35 +00005896 expdest = makestrspace(32, expdest);
5897 len = fmtstr(expdest, 32, "%ld", num);
5898 STADJUST(len, expdest);
5899 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005900}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005901
Eric Andersenc470f442003-07-28 09:56:35 +00005902static void
5903varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005904{
Eric Andersenc470f442003-07-28 09:56:35 +00005905 const char *msg;
5906 const char *tail;
5907
5908 tail = nullstr;
5909 msg = "parameter not set";
5910 if (umsg) {
5911 if (*end == CTLENDVAR) {
5912 if (varflags & VSNUL)
5913 tail = " or null";
5914 } else
5915 msg = umsg;
5916 }
5917 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005918}
Eric Andersen90898442003-08-06 11:20:52 +00005919
5920
Eric Andersenc470f442003-07-28 09:56:35 +00005921/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005922
Eric Andersencb57d552001-06-28 07:25:16 +00005923/*
Eric Andersen90898442003-08-06 11:20:52 +00005924 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005925 */
5926
Eric Andersenc470f442003-07-28 09:56:35 +00005927#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5928#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005929
Eric Andersenc470f442003-07-28 09:56:35 +00005930static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005931
Eric Andersencb57d552001-06-28 07:25:16 +00005932/*
5933 * Read a line from the script.
5934 */
5935
Eric Andersenc470f442003-07-28 09:56:35 +00005936static inline char *
5937pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005938{
5939 char *p = line;
5940 int nleft = len;
5941 int c;
5942
5943 while (--nleft > 0) {
5944 c = pgetc2();
5945 if (c == PEOF) {
5946 if (p == line)
5947 return NULL;
5948 break;
5949 }
5950 *p++ = c;
5951 if (c == '\n')
5952 break;
5953 }
5954 *p = '\0';
5955 return line;
5956}
5957
Eric Andersenc470f442003-07-28 09:56:35 +00005958
5959/*
5960 * Read a character from the script, returning PEOF on end of file.
5961 * Nul characters in the input are silently discarded.
5962 */
5963
5964#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5965
5966#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5967#define pgetc_macro() pgetc()
5968static int
5969pgetc(void)
5970{
5971 return pgetc_as_macro();
5972}
5973#else
5974#define pgetc_macro() pgetc_as_macro()
5975static int
5976pgetc(void)
5977{
5978 return pgetc_macro();
5979}
5980#endif
5981
5982
5983/*
5984 * Same as pgetc(), but ignores PEOA.
5985 */
5986#ifdef CONFIG_ASH_ALIAS
5987static int pgetc2(void)
5988{
5989 int c;
5990
5991 do {
5992 c = pgetc_macro();
5993 } while (c == PEOA);
5994 return c;
5995}
5996#else
5997static inline int pgetc2(void)
5998{
5999 return pgetc_macro();
6000}
6001#endif
6002
6003
6004#ifdef CONFIG_FEATURE_COMMAND_EDITING
6005static const char *cmdedit_prompt;
6006static inline void putprompt(const char *s)
6007{
6008 cmdedit_prompt = s;
6009}
6010#else
6011static inline void putprompt(const char *s)
6012{
6013 out2str(s);
6014}
6015#endif
6016
6017static inline int
6018preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006019{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006020 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006021 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006022 parsenextc = buf;
6023
Eric Andersenc470f442003-07-28 09:56:35 +00006024retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006025#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006026 if (!iflag || parsefile->fd)
6027 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6028 else {
6029 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6030 if(nr == 0) {
6031 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006032 if(trap[SIGINT]) {
6033 buf[0] = '\n';
6034 buf[1] = 0;
6035 raise(SIGINT);
6036 return 1;
6037 }
Eric Andersenc470f442003-07-28 09:56:35 +00006038 goto retry;
6039 }
6040 if(nr < 0) {
6041 /* Ctrl+D presend */
6042 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006043 }
Eric Andersencb57d552001-06-28 07:25:16 +00006044 }
6045#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006046 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006047#endif
6048
6049 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006050 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6051 int flags = fcntl(0, F_GETFL, 0);
6052 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006053 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006054 if (fcntl(0, F_SETFL, flags) >= 0) {
6055 out2str("sh: turning off NDELAY mode\n");
6056 goto retry;
6057 }
6058 }
6059 }
6060 }
6061 return nr;
6062}
6063
6064/*
6065 * Refill the input buffer and return the next input character:
6066 *
6067 * 1) If a string was pushed back on the input, pop it;
6068 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6069 * from a string so we can't refill the buffer, return EOF.
6070 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6071 * 4) Process input up to the next newline, deleting nul characters.
6072 */
6073
Eric Andersenc470f442003-07-28 09:56:35 +00006074int
6075preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006076{
6077 char *p, *q;
6078 int more;
6079 char savec;
6080
6081 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006082#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006083 if (parsenleft == -1 && parsefile->strpush->ap &&
6084 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006085 return PEOA;
6086 }
Eric Andersen2870d962001-07-02 17:27:21 +00006087#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006088 popstring();
6089 if (--parsenleft >= 0)
6090 return (*parsenextc++);
6091 }
6092 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6093 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006094 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006095
Eric Andersenc470f442003-07-28 09:56:35 +00006096again:
Eric Andersencb57d552001-06-28 07:25:16 +00006097 if (parselleft <= 0) {
6098 if ((parselleft = preadfd()) <= 0) {
6099 parselleft = parsenleft = EOF_NLEFT;
6100 return PEOF;
6101 }
6102 }
6103
6104 q = p = parsenextc;
6105
6106 /* delete nul characters */
6107 for (more = 1; more;) {
6108 switch (*p) {
6109 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006110 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006111 goto check;
6112
Eric Andersencb57d552001-06-28 07:25:16 +00006113 case '\n':
6114 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006115 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006116 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006117
Eric Andersencb57d552001-06-28 07:25:16 +00006118 }
6119
6120 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006121check:
Eric Andersencb57d552001-06-28 07:25:16 +00006122 if (--parselleft <= 0 && more) {
6123 parsenleft = q - parsenextc - 1;
6124 if (parsenleft < 0)
6125 goto again;
6126 more = 0;
6127 }
6128 }
6129
6130 savec = *q;
6131 *q = '\0';
6132
6133 if (vflag) {
6134 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006135 }
6136
6137 *q = savec;
6138
6139 return *parsenextc++;
6140}
6141
Eric Andersenc470f442003-07-28 09:56:35 +00006142/*
6143 * Undo the last call to pgetc. Only one character may be pushed back.
6144 * PEOF may be pushed back.
6145 */
6146
6147void
6148pungetc(void)
6149{
6150 parsenleft++;
6151 parsenextc--;
6152}
Eric Andersencb57d552001-06-28 07:25:16 +00006153
6154/*
6155 * Push a string back onto the input at this current parsefile level.
6156 * We handle aliases this way.
6157 */
Eric Andersenc470f442003-07-28 09:56:35 +00006158void
6159pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006160{
Eric Andersencb57d552001-06-28 07:25:16 +00006161 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006162 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006163
Eric Andersenc470f442003-07-28 09:56:35 +00006164 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006165 INTOFF;
6166/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6167 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006168 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006169 sp->prev = parsefile->strpush;
6170 parsefile->strpush = sp;
6171 } else
6172 sp = parsefile->strpush = &(parsefile->basestrpush);
6173 sp->prevstring = parsenextc;
6174 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006175#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006176 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006177 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006178 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006179 sp->string = s;
6180 }
Eric Andersen2870d962001-07-02 17:27:21 +00006181#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006182 parsenextc = s;
6183 parsenleft = len;
6184 INTON;
6185}
6186
Eric Andersenc470f442003-07-28 09:56:35 +00006187void
6188popstring(void)
6189{
6190 struct strpush *sp = parsefile->strpush;
6191
6192 INTOFF;
6193#ifdef CONFIG_ASH_ALIAS
6194 if (sp->ap) {
6195 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6196 checkkwd |= CHKALIAS;
6197 }
6198 if (sp->string != sp->ap->val) {
6199 ckfree(sp->string);
6200 }
6201 sp->ap->flag &= ~ALIASINUSE;
6202 if (sp->ap->flag & ALIASDEAD) {
6203 unalias(sp->ap->name);
6204 }
6205 }
6206#endif
6207 parsenextc = sp->prevstring;
6208 parsenleft = sp->prevnleft;
6209/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6210 parsefile->strpush = sp->prev;
6211 if (sp != &(parsefile->basestrpush))
6212 ckfree(sp);
6213 INTON;
6214}
6215
6216/*
6217 * Set the input to take input from a file. If push is set, push the
6218 * old input onto the stack first.
6219 */
6220
6221void
6222setinputfile(const char *fname, int push)
6223{
6224 int fd;
6225 int fd2;
6226
6227 INTOFF;
6228 if ((fd = open(fname, O_RDONLY)) < 0)
6229 error("Can't open %s", fname);
6230 if (fd < 10) {
6231 fd2 = copyfd(fd, 10);
6232 close(fd);
6233 if (fd2 < 0)
6234 error("Out of file descriptors");
6235 fd = fd2;
6236 }
6237 setinputfd(fd, push);
6238 INTON;
6239}
6240
6241
6242/*
6243 * Like setinputfile, but takes an open file descriptor. Call this with
6244 * interrupts off.
6245 */
6246
6247static void
6248setinputfd(int fd, int push)
6249{
6250 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6251 if (push) {
6252 pushfile();
6253 parsefile->buf = 0;
6254 }
6255 parsefile->fd = fd;
6256 if (parsefile->buf == NULL)
6257 parsefile->buf = ckmalloc(IBUFSIZ);
6258 parselleft = parsenleft = 0;
6259 plinno = 1;
6260}
6261
Eric Andersencb57d552001-06-28 07:25:16 +00006262
Eric Andersencb57d552001-06-28 07:25:16 +00006263/*
6264 * Like setinputfile, but takes input from a string.
6265 */
6266
Eric Andersenc470f442003-07-28 09:56:35 +00006267static void
6268setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006269{
Eric Andersencb57d552001-06-28 07:25:16 +00006270 INTOFF;
6271 pushfile();
6272 parsenextc = string;
6273 parsenleft = strlen(string);
6274 parsefile->buf = NULL;
6275 plinno = 1;
6276 INTON;
6277}
6278
6279
Eric Andersencb57d552001-06-28 07:25:16 +00006280/*
6281 * To handle the "." command, a stack of input files is used. Pushfile
6282 * adds a new entry to the stack and popfile restores the previous level.
6283 */
6284
Eric Andersenc470f442003-07-28 09:56:35 +00006285static void
6286pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006287{
Eric Andersencb57d552001-06-28 07:25:16 +00006288 struct parsefile *pf;
6289
6290 parsefile->nleft = parsenleft;
6291 parsefile->lleft = parselleft;
6292 parsefile->nextc = parsenextc;
6293 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006294 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006295 pf->prev = parsefile;
6296 pf->fd = -1;
6297 pf->strpush = NULL;
6298 pf->basestrpush.prev = NULL;
6299 parsefile = pf;
6300}
6301
Eric Andersenc470f442003-07-28 09:56:35 +00006302
6303static void
6304popfile(void)
6305{
6306 struct parsefile *pf = parsefile;
6307
6308 INTOFF;
6309 if (pf->fd >= 0)
6310 close(pf->fd);
6311 if (pf->buf)
6312 ckfree(pf->buf);
6313 while (pf->strpush)
6314 popstring();
6315 parsefile = pf->prev;
6316 ckfree(pf);
6317 parsenleft = parsefile->nleft;
6318 parselleft = parsefile->lleft;
6319 parsenextc = parsefile->nextc;
6320 plinno = parsefile->linno;
6321 INTON;
6322}
Eric Andersencb57d552001-06-28 07:25:16 +00006323
6324
Eric Andersen2870d962001-07-02 17:27:21 +00006325/*
Eric Andersenc470f442003-07-28 09:56:35 +00006326 * Return to top level.
6327 */
Eric Andersen2870d962001-07-02 17:27:21 +00006328
Eric Andersenc470f442003-07-28 09:56:35 +00006329static void
6330popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006331{
Eric Andersenc470f442003-07-28 09:56:35 +00006332 while (parsefile != &basepf)
6333 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006334}
6335
Eric Andersen2870d962001-07-02 17:27:21 +00006336
Eric Andersenc470f442003-07-28 09:56:35 +00006337/*
6338 * Close the file(s) that the shell is reading commands from. Called
6339 * after a fork is done.
6340 */
6341
6342static void
6343closescript(void)
6344{
6345 popallfiles();
6346 if (parsefile->fd > 0) {
6347 close(parsefile->fd);
6348 parsefile->fd = 0;
6349 }
6350}
Eric Andersenc470f442003-07-28 09:56:35 +00006351
Eric Andersen90898442003-08-06 11:20:52 +00006352/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006353
6354/* mode flags for set_curjob */
6355#define CUR_DELETE 2
6356#define CUR_RUNNING 1
6357#define CUR_STOPPED 0
6358
6359/* mode flags for dowait */
6360#define DOWAIT_NORMAL 0
6361#define DOWAIT_BLOCK 1
6362
6363/* array of jobs */
6364static struct job *jobtab;
6365/* size of array */
6366static unsigned njobs;
6367#if JOBS
6368/* pgrp of shell on invocation */
6369static int initialpgrp;
6370static int ttyfd = -1;
6371#endif
6372/* current job */
6373static struct job *curjob;
6374/* number of presumed living untracked jobs */
6375static int jobless;
6376
6377static void set_curjob(struct job *, unsigned);
6378#if JOBS
6379static int restartjob(struct job *, int);
6380static void xtcsetpgrp(int, pid_t);
6381static char *commandtext(union node *);
6382static void cmdlist(union node *, int);
6383static void cmdtxt(union node *);
6384static void cmdputs(const char *);
6385static void showpipe(struct job *, FILE *);
6386#endif
6387static int sprint_status(char *, int, int);
6388static void freejob(struct job *);
6389static struct job *getjob(const char *, int);
6390static struct job *growjobtab(void);
6391static void forkchild(struct job *, union node *, int);
6392static void forkparent(struct job *, union node *, int, pid_t);
6393static int dowait(int, struct job *);
6394static int getstatus(struct job *);
6395
6396static void
6397set_curjob(struct job *jp, unsigned mode)
6398{
6399 struct job *jp1;
6400 struct job **jpp, **curp;
6401
6402 /* first remove from list */
6403 jpp = curp = &curjob;
6404 do {
6405 jp1 = *jpp;
6406 if (jp1 == jp)
6407 break;
6408 jpp = &jp1->prev_job;
6409 } while (1);
6410 *jpp = jp1->prev_job;
6411
6412 /* Then re-insert in correct position */
6413 jpp = curp;
6414 switch (mode) {
6415 default:
6416#ifdef DEBUG
6417 abort();
6418#endif
6419 case CUR_DELETE:
6420 /* job being deleted */
6421 break;
6422 case CUR_RUNNING:
6423 /* newly created job or backgrounded job,
6424 put after all stopped jobs. */
6425 do {
6426 jp1 = *jpp;
6427#ifdef JOBS
6428 if (!jp1 || jp1->state != JOBSTOPPED)
6429#endif
6430 break;
6431 jpp = &jp1->prev_job;
6432 } while (1);
6433 /* FALLTHROUGH */
6434#ifdef JOBS
6435 case CUR_STOPPED:
6436#endif
6437 /* newly stopped job - becomes curjob */
6438 jp->prev_job = *jpp;
6439 *jpp = jp;
6440 break;
6441 }
6442}
6443
6444#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006445/*
6446 * Turn job control on and off.
6447 *
6448 * Note: This code assumes that the third arg to ioctl is a character
6449 * pointer, which is true on Berkeley systems but not System V. Since
6450 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006451 *
6452 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006453 */
6454
Eric Andersenc470f442003-07-28 09:56:35 +00006455void
6456setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006457{
Eric Andersenc470f442003-07-28 09:56:35 +00006458 int fd;
6459 int pgrp;
6460
6461 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006462 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006463 if (on) {
6464 int ofd;
6465 ofd = fd = open(_PATH_TTY, O_RDWR);
6466 if (fd < 0) {
6467 fd += 3;
6468 while (!isatty(fd) && --fd >= 0)
6469 ;
6470 }
6471 fd = fcntl(fd, F_DUPFD, 10);
6472 close(ofd);
6473 if (fd < 0)
6474 goto out;
6475 fcntl(fd, F_SETFD, FD_CLOEXEC);
6476 do { /* while we are in the background */
6477 if ((pgrp = tcgetpgrp(fd)) < 0) {
6478out:
6479 sh_warnx("can't access tty; job control turned off");
6480 mflag = on = 0;
6481 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006482 }
Eric Andersenc470f442003-07-28 09:56:35 +00006483 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006484 break;
6485 killpg(0, SIGTTIN);
6486 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006487 initialpgrp = pgrp;
6488
Eric Andersencb57d552001-06-28 07:25:16 +00006489 setsignal(SIGTSTP);
6490 setsignal(SIGTTOU);
6491 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006492 pgrp = rootpid;
6493 setpgid(0, pgrp);
6494 xtcsetpgrp(fd, pgrp);
6495 } else {
6496 /* turning job control off */
6497 fd = ttyfd;
6498 pgrp = initialpgrp;
6499 xtcsetpgrp(fd, pgrp);
6500 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006501 setsignal(SIGTSTP);
6502 setsignal(SIGTTOU);
6503 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006504close:
6505 close(fd);
6506 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006507 }
Eric Andersenc470f442003-07-28 09:56:35 +00006508 ttyfd = fd;
6509 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006510}
Eric Andersencb57d552001-06-28 07:25:16 +00006511
Eric Andersenc470f442003-07-28 09:56:35 +00006512static int
Eric Andersen90898442003-08-06 11:20:52 +00006513killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006514{
6515 int signo = -1;
6516 int list = 0;
6517 int i;
6518 pid_t pid;
6519 struct job *jp;
6520
6521 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006522usage:
6523 error(
6524"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6525"kill -l [exitstatus]"
6526 );
Eric Andersencb57d552001-06-28 07:25:16 +00006527 }
6528
Eric Andersenc470f442003-07-28 09:56:35 +00006529 if (**++argv == '-') {
6530 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006531 if (signo < 0) {
6532 int c;
6533
6534 while ((c = nextopt("ls:")) != '\0')
6535 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006536 default:
6537#ifdef DEBUG
6538 abort();
6539#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006540 case 'l':
6541 list = 1;
6542 break;
6543 case 's':
6544 signo = decode_signal(optionarg, 1);
6545 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006546 error(
6547 "invalid signal number or name: %s",
6548 optionarg
6549 );
Eric Andersencb57d552001-06-28 07:25:16 +00006550 }
Eric Andersen2870d962001-07-02 17:27:21 +00006551 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006552 }
Eric Andersenc470f442003-07-28 09:56:35 +00006553 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006554 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006555 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006556 }
6557
6558 if (!list && signo < 0)
6559 signo = SIGTERM;
6560
Eric Andersenc470f442003-07-28 09:56:35 +00006561 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006562 goto usage;
6563 }
6564
6565 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006566 const char *name;
6567
Eric Andersenc470f442003-07-28 09:56:35 +00006568 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006569 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006570 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006571 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006572 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006573 }
6574 return 0;
6575 }
Eric Andersen34506362001-08-02 05:02:46 +00006576 name = u_signal_names(*argptr, &signo, -1);
6577 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006578 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006579 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006580 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006581 return 0;
6582 }
6583
Eric Andersenc470f442003-07-28 09:56:35 +00006584 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006585 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006586 if (**argv == '%') {
6587 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006588 pid = -jp->ps[0].pid;
6589 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006590 pid = number(*argv);
6591 if (kill(pid, signo) != 0) {
6592 sh_warnx("%m\n");
6593 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006594 }
Eric Andersenc470f442003-07-28 09:56:35 +00006595 } while (*++argv);
6596
6597 return i;
6598}
6599#endif /* JOBS */
6600
6601#if defined(JOBS) || defined(DEBUG)
6602static int
6603jobno(const struct job *jp)
6604{
6605 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006606}
6607#endif
6608
Eric Andersenc470f442003-07-28 09:56:35 +00006609#ifdef JOBS
6610static int
6611fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006612{
Eric Andersenc470f442003-07-28 09:56:35 +00006613 struct job *jp;
6614 FILE *out;
6615 int mode;
6616 int retval;
6617
6618 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6619 nextopt(nullstr);
6620 argv = argptr;
6621 out = stdout;
6622 do {
6623 jp = getjob(*argv, 1);
6624 if (mode == FORK_BG) {
6625 set_curjob(jp, CUR_RUNNING);
6626 fprintf(out, "[%d] ", jobno(jp));
6627 }
6628 outstr(jp->ps->cmd, out);
6629 showpipe(jp, out);
6630 retval = restartjob(jp, mode);
6631 } while (*argv && *++argv);
6632 return retval;
6633}
6634
6635static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6636
6637
6638static int
6639restartjob(struct job *jp, int mode)
6640{
6641 struct procstat *ps;
6642 int i;
6643 int status;
6644 pid_t pgid;
6645
6646 INTOFF;
6647 if (jp->state == JOBDONE)
6648 goto out;
6649 jp->state = JOBRUNNING;
6650 pgid = jp->ps->pid;
6651 if (mode == FORK_FG)
6652 xtcsetpgrp(ttyfd, pgid);
6653 killpg(pgid, SIGCONT);
6654 ps = jp->ps;
6655 i = jp->nprocs;
6656 do {
6657 if (WIFSTOPPED(ps->status)) {
6658 ps->status = -1;
6659 }
6660 } while (ps++, --i);
6661out:
6662 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6663 INTON;
6664 return status;
6665}
6666#endif
6667
6668static int
6669sprint_status(char *s, int status, int sigonly)
6670{
6671 int col;
6672 int st;
6673
6674 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006675 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006676#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006677 if (WIFSTOPPED(status))
6678 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006679 else
Eric Andersenc470f442003-07-28 09:56:35 +00006680#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006681 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006682 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006683 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006684 goto out;
6685#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006686 if (WIFSTOPPED(status))
6687 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006688#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006689 }
6690 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006691 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006692 if (WCOREDUMP(status)) {
6693 col += fmtstr(s + col, 16, " (core dumped)");
6694 }
6695 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006696 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006697 if (st)
6698 col = fmtstr(s, 16, "Done(%d)", st);
6699 else
6700 col = fmtstr(s, 16, "Done");
6701 }
6702
6703out:
6704 return col;
6705}
6706
6707#if JOBS
6708static void
6709showjob(FILE *out, struct job *jp, int mode)
6710{
6711 struct procstat *ps;
6712 struct procstat *psend;
6713 int col;
6714 int indent;
6715 char s[80];
6716
6717 ps = jp->ps;
6718
6719 if (mode & SHOW_PGID) {
6720 /* just output process (group) id of pipeline */
6721 fprintf(out, "%d\n", ps->pid);
6722 return;
6723 }
6724
6725 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6726 indent = col;
6727
6728 if (jp == curjob)
6729 s[col - 2] = '+';
6730 else if (curjob && jp == curjob->prev_job)
6731 s[col - 2] = '-';
6732
6733 if (mode & SHOW_PID)
6734 col += fmtstr(s + col, 16, "%d ", ps->pid);
6735
6736 psend = ps + jp->nprocs;
6737
6738 if (jp->state == JOBRUNNING) {
6739 scopy("Running", s + col);
6740 col += strlen("Running");
6741 } else {
6742 int status = psend[-1].status;
6743#if JOBS
6744 if (jp->state == JOBSTOPPED)
6745 status = jp->stopstatus;
6746#endif
6747 col += sprint_status(s + col, status, 0);
6748 }
6749
6750 goto start;
6751
6752 do {
6753 /* for each process */
6754 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6755
6756start:
Eric Andersen90898442003-08-06 11:20:52 +00006757 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006758 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6759 );
6760 if (!(mode & SHOW_PID)) {
6761 showpipe(jp, out);
6762 break;
6763 }
6764 if (++ps == psend) {
6765 outcslow('\n', out);
6766 break;
6767 }
6768 } while (1);
6769
6770 jp->changed = 0;
6771
6772 if (jp->state == JOBDONE) {
6773 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6774 freejob(jp);
6775 }
6776}
6777
6778
6779static int
6780jobscmd(int argc, char **argv)
6781{
6782 int mode, m;
6783 FILE *out;
6784
6785 mode = 0;
6786 while ((m = nextopt("lp")))
6787 if (m == 'l')
6788 mode = SHOW_PID;
6789 else
6790 mode = SHOW_PGID;
6791
6792 out = stdout;
6793 argv = argptr;
6794 if (*argv)
6795 do
6796 showjob(out, getjob(*argv,0), mode);
6797 while (*++argv);
6798 else
6799 showjobs(out, mode);
6800
Eric Andersencb57d552001-06-28 07:25:16 +00006801 return 0;
6802}
6803
6804
6805/*
6806 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6807 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006808 */
6809
Eric Andersenc470f442003-07-28 09:56:35 +00006810static void
6811showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006812{
Eric Andersencb57d552001-06-28 07:25:16 +00006813 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006814
Eric Andersenc470f442003-07-28 09:56:35 +00006815 TRACE(("showjobs(%x) called\n", mode));
6816
6817 /* If not even one one job changed, there is nothing to do */
6818 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6819 continue;
6820
6821 for (jp = curjob; jp; jp = jp->prev_job) {
6822 if (!(mode & SHOW_CHANGED) || jp->changed)
6823 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006824 }
6825}
Eric Andersenc470f442003-07-28 09:56:35 +00006826#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006827
6828/*
6829 * Mark a job structure as unused.
6830 */
6831
Eric Andersenc470f442003-07-28 09:56:35 +00006832static void
6833freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006834{
Eric Andersenc470f442003-07-28 09:56:35 +00006835 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006836 int i;
6837
6838 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006839 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006840 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006841 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006842 }
6843 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006844 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006845 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006846 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006847 INTON;
6848}
6849
6850
Eric Andersenc470f442003-07-28 09:56:35 +00006851static int
6852waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006853{
6854 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006855 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006856 struct job *jp;
6857
Eric Andersenc470f442003-07-28 09:56:35 +00006858 EXSIGON();
6859
6860 nextopt(nullstr);
6861 retval = 0;
6862
6863 argv = argptr;
6864 if (!*argv) {
6865 /* wait for all jobs */
6866 for (;;) {
6867 jp = curjob;
6868 while (1) {
6869 if (!jp) {
6870 /* no running procs */
6871 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006872 }
Eric Andersenc470f442003-07-28 09:56:35 +00006873 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006874 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006875 jp->waited = 1;
6876 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006877 }
Eric Andersenc470f442003-07-28 09:56:35 +00006878 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006879 }
6880 }
Eric Andersenc470f442003-07-28 09:56:35 +00006881
6882 retval = 127;
6883 do {
6884 if (**argv != '%') {
6885 pid_t pid = number(*argv);
6886 job = curjob;
6887 goto start;
6888 do {
6889 if (job->ps[job->nprocs - 1].pid == pid)
6890 break;
6891 job = job->prev_job;
6892start:
6893 if (!job)
6894 goto repeat;
6895 } while (1);
6896 } else
6897 job = getjob(*argv, 0);
6898 /* loop until process terminated or stopped */
6899 while (job->state == JOBRUNNING)
6900 dowait(DOWAIT_BLOCK, 0);
6901 job->waited = 1;
6902 retval = getstatus(job);
6903repeat:
6904 ;
6905 } while (*++argv);
6906
6907out:
6908 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006909}
6910
6911
Eric Andersencb57d552001-06-28 07:25:16 +00006912/*
6913 * Convert a job name to a job structure.
6914 */
6915
Eric Andersenc470f442003-07-28 09:56:35 +00006916static struct job *
6917getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006918{
Eric Andersencb57d552001-06-28 07:25:16 +00006919 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006920 struct job *found;
6921 const char *err_msg = "No such job: %s";
6922 unsigned num;
6923 int c;
6924 const char *p;
6925 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006926
Eric Andersenc470f442003-07-28 09:56:35 +00006927 jp = curjob;
6928 p = name;
6929 if (!p)
6930 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006931
Eric Andersenc470f442003-07-28 09:56:35 +00006932 if (*p != '%')
6933 goto err;
6934
6935 c = *++p;
6936 if (!c)
6937 goto currentjob;
6938
6939 if (!p[1]) {
6940 if (c == '+' || c == '%') {
6941currentjob:
6942 err_msg = "No current job";
6943 goto check;
6944 } else if (c == '-') {
6945 if (jp)
6946 jp = jp->prev_job;
6947 err_msg = "No previous job";
6948check:
6949 if (!jp)
6950 goto err;
6951 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006952 }
6953 }
Eric Andersenc470f442003-07-28 09:56:35 +00006954
6955 if (is_number(p)) {
6956 num = atoi(p);
6957 if (num < njobs) {
6958 jp = jobtab + num - 1;
6959 if (jp->used)
6960 goto gotit;
6961 goto err;
6962 }
6963 }
6964
6965 match = prefix;
6966 if (*p == '?') {
6967 match = strstr;
6968 p++;
6969 }
6970
6971 found = 0;
6972 while (1) {
6973 if (!jp)
6974 goto err;
6975 if (match(jp->ps[0].cmd, p)) {
6976 if (found)
6977 goto err;
6978 found = jp;
6979 err_msg = "%s: ambiguous";
6980 }
6981 jp = jp->prev_job;
6982 }
6983
6984gotit:
6985#if JOBS
6986 err_msg = "job %s not created under job control";
6987 if (getctl && jp->jobctl == 0)
6988 goto err;
6989#endif
6990 return jp;
6991err:
6992 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006993}
6994
6995
Eric Andersencb57d552001-06-28 07:25:16 +00006996/*
Eric Andersenc470f442003-07-28 09:56:35 +00006997 * Return a new job structure.
6998 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006999 */
7000
Eric Andersenc470f442003-07-28 09:56:35 +00007001static struct job *
7002makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007003{
7004 int i;
7005 struct job *jp;
7006
Eric Andersenc470f442003-07-28 09:56:35 +00007007 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007008 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007009 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007010 break;
7011 }
7012 if (jp->used == 0)
7013 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007014 if (jp->state != JOBDONE || !jp->waited)
7015 continue;
7016#if JOBS
7017 if (jobctl)
7018 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007019#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007020 freejob(jp);
7021 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007022 }
Eric Andersenc470f442003-07-28 09:56:35 +00007023 memset(jp, 0, sizeof(*jp));
7024#if JOBS
7025 if (jobctl)
7026 jp->jobctl = 1;
7027#endif
7028 jp->prev_job = curjob;
7029 curjob = jp;
7030 jp->used = 1;
7031 jp->ps = &jp->ps0;
7032 if (nprocs > 1) {
7033 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7034 }
7035 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7036 jobno(jp)));
7037 return jp;
7038}
7039
7040static struct job *
7041growjobtab(void)
7042{
7043 size_t len;
7044 ptrdiff_t offset;
7045 struct job *jp, *jq;
7046
7047 len = njobs * sizeof(*jp);
7048 jq = jobtab;
7049 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7050
7051 offset = (char *)jp - (char *)jq;
7052 if (offset) {
7053 /* Relocate pointers */
7054 size_t l = len;
7055
7056 jq = (struct job *)((char *)jq + l);
7057 while (l) {
7058 l -= sizeof(*jp);
7059 jq--;
7060#define joff(p) ((struct job *)((char *)(p) + l))
7061#define jmove(p) (p) = (void *)((char *)(p) + offset)
7062 if (likely(joff(jp)->ps == &jq->ps0))
7063 jmove(joff(jp)->ps);
7064 if (joff(jp)->prev_job)
7065 jmove(joff(jp)->prev_job);
7066 }
7067 if (curjob)
7068 jmove(curjob);
7069#undef joff
7070#undef jmove
7071 }
7072
7073 njobs += 4;
7074 jobtab = jp;
7075 jp = (struct job *)((char *)jp + len);
7076 jq = jp + 3;
7077 do {
7078 jq->used = 0;
7079 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007080 return jp;
7081}
7082
7083
7084/*
Eric Andersenc470f442003-07-28 09:56:35 +00007085 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007086 * own process group. Jp is a job structure that the job is to be added to.
7087 * N is the command that will be evaluated by the child. Both jp and n may
7088 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007089 * FORK_FG - Fork off a foreground process.
7090 * FORK_BG - Fork off a background process.
7091 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7092 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007093 *
7094 * When job control is turned off, background processes have their standard
7095 * input redirected to /dev/null (except for the second and later processes
7096 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007097 *
7098 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007099 */
7100
Eric Andersenc470f442003-07-28 09:56:35 +00007101static inline void
7102forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007103{
Eric Andersenc470f442003-07-28 09:56:35 +00007104 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007105
Eric Andersenc470f442003-07-28 09:56:35 +00007106 TRACE(("Child shell %d\n", getpid()));
7107 wasroot = rootshell;
7108 rootshell = 0;
7109
7110 closescript();
7111 clear_traps();
7112#if JOBS
7113 /* do job control only in root shell */
7114 jobctl = 0;
7115 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7116 pid_t pgrp;
7117
7118 if (jp->nprocs == 0)
7119 pgrp = getpid();
7120 else
7121 pgrp = jp->ps[0].pid;
7122 /* This can fail because we are doing it in the parent also */
7123 (void)setpgid(0, pgrp);
7124 if (mode == FORK_FG)
7125 xtcsetpgrp(ttyfd, pgrp);
7126 setsignal(SIGTSTP);
7127 setsignal(SIGTTOU);
7128 } else
Eric Andersen62483552001-07-10 06:09:16 +00007129#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007130 if (mode == FORK_BG) {
7131 ignoresig(SIGINT);
7132 ignoresig(SIGQUIT);
7133 if (jp->nprocs == 0) {
7134 close(0);
7135 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7136 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007137 }
Eric Andersencb57d552001-06-28 07:25:16 +00007138 }
Eric Andersenc470f442003-07-28 09:56:35 +00007139 if (wasroot && iflag) {
7140 setsignal(SIGINT);
7141 setsignal(SIGQUIT);
7142 setsignal(SIGTERM);
7143 }
7144 for (jp = curjob; jp; jp = jp->prev_job)
7145 freejob(jp);
7146 jobless = 0;
7147}
7148
7149static inline void
7150forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7151{
7152 TRACE(("In parent shell: child = %d\n", pid));
7153 if (!jp) {
7154 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7155 jobless++;
7156 return;
7157 }
7158#if JOBS
7159 if (mode != FORK_NOJOB && jp->jobctl) {
7160 int pgrp;
7161
7162 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007163 pgrp = pid;
7164 else
7165 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007166 /* This can fail because we are doing it in the child also */
7167 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007168 }
Eric Andersen62483552001-07-10 06:09:16 +00007169#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007170 if (mode == FORK_BG) {
7171 backgndpid = pid; /* set $! */
7172 set_curjob(jp, CUR_RUNNING);
7173 }
Eric Andersencb57d552001-06-28 07:25:16 +00007174 if (jp) {
7175 struct procstat *ps = &jp->ps[jp->nprocs++];
7176 ps->pid = pid;
7177 ps->status = -1;
7178 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007179#if JOBS
7180 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007181 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007182#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007183 }
Eric Andersencb57d552001-06-28 07:25:16 +00007184}
7185
Eric Andersenc470f442003-07-28 09:56:35 +00007186static int
7187forkshell(struct job *jp, union node *n, int mode)
7188{
7189 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007190
Eric Andersenc470f442003-07-28 09:56:35 +00007191 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7192 pid = fork();
7193 if (pid < 0) {
7194 TRACE(("Fork failed, errno=%d", errno));
7195 if (jp)
7196 freejob(jp);
7197 error("Cannot fork");
7198 }
7199 if (pid == 0)
7200 forkchild(jp, n, mode);
7201 else
7202 forkparent(jp, n, mode, pid);
7203 return pid;
7204}
Eric Andersencb57d552001-06-28 07:25:16 +00007205
7206/*
7207 * Wait for job to finish.
7208 *
7209 * Under job control we have the problem that while a child process is
7210 * running interrupts generated by the user are sent to the child but not
7211 * to the shell. This means that an infinite loop started by an inter-
7212 * active user may be hard to kill. With job control turned off, an
7213 * interactive user may place an interactive program inside a loop. If
7214 * the interactive program catches interrupts, the user doesn't want
7215 * these interrupts to also abort the loop. The approach we take here
7216 * is to have the shell ignore interrupt signals while waiting for a
7217 * forground process to terminate, and then send itself an interrupt
7218 * signal if the child process was terminated by an interrupt signal.
7219 * Unfortunately, some programs want to do a bit of cleanup and then
7220 * exit on interrupt; unless these processes terminate themselves by
7221 * sending a signal to themselves (instead of calling exit) they will
7222 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007223 *
7224 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007225 */
7226
Eric Andersenc470f442003-07-28 09:56:35 +00007227int
7228waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007229{
Eric Andersencb57d552001-06-28 07:25:16 +00007230 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007231
Eric Andersenc470f442003-07-28 09:56:35 +00007232 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7233 while (jp->state == JOBRUNNING) {
7234 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007235 }
Eric Andersenc470f442003-07-28 09:56:35 +00007236 st = getstatus(jp);
7237#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007238 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007239 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007240 /*
7241 * This is truly gross.
7242 * If we're doing job control, then we did a TIOCSPGRP which
7243 * caused us (the shell) to no longer be in the controlling
7244 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7245 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007246 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007247 */
Eric Andersenc470f442003-07-28 09:56:35 +00007248 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007249 raise(SIGINT);
7250 }
Eric Andersen2870d962001-07-02 17:27:21 +00007251 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007252#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007253 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007254 return st;
7255}
7256
7257
Eric Andersen62483552001-07-10 06:09:16 +00007258/*
7259 * Do a wait system call. If job control is compiled in, we accept
7260 * stopped processes. If block is zero, we return a value of zero
7261 * rather than blocking.
7262 *
7263 * System V doesn't have a non-blocking wait system call. It does
7264 * have a SIGCLD signal that is sent to a process when one of it's
7265 * children dies. The obvious way to use SIGCLD would be to install
7266 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7267 * was received, and have waitproc bump another counter when it got
7268 * the status of a process. Waitproc would then know that a wait
7269 * system call would not block if the two counters were different.
7270 * This approach doesn't work because if a process has children that
7271 * have not been waited for, System V will send it a SIGCLD when it
7272 * installs a signal handler for SIGCLD. What this means is that when
7273 * a child exits, the shell will be sent SIGCLD signals continuously
7274 * until is runs out of stack space, unless it does a wait call before
7275 * restoring the signal handler. The code below takes advantage of
7276 * this (mis)feature by installing a signal handler for SIGCLD and
7277 * then checking to see whether it was called. If there are any
7278 * children to be waited for, it will be.
7279 *
Eric Andersenc470f442003-07-28 09:56:35 +00007280 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7281 * waits at all. In this case, the user will not be informed when
7282 * a background process until the next time she runs a real program
7283 * (as opposed to running a builtin command or just typing return),
7284 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007285 */
7286
Eric Andersenc470f442003-07-28 09:56:35 +00007287static inline int
7288waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007289{
Eric Andersenc470f442003-07-28 09:56:35 +00007290 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007291
Eric Andersenc470f442003-07-28 09:56:35 +00007292#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007293 if (jobctl)
7294 flags |= WUNTRACED;
7295#endif
7296 if (block == 0)
7297 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007298 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007299}
7300
Eric Andersenc470f442003-07-28 09:56:35 +00007301/*
7302 * Wait for a process to terminate.
7303 */
7304
7305static int
7306dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007307{
7308 int pid;
7309 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007310 struct job *jp;
7311 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007312 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007313
7314 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007315 pid = waitproc(block, &status);
7316 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007317 if (pid <= 0)
7318 return pid;
7319 INTOFF;
7320 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007321 for (jp = curjob; jp; jp = jp->prev_job) {
7322 struct procstat *sp;
7323 struct procstat *spend;
7324 if (jp->state == JOBDONE)
7325 continue;
7326 state = JOBDONE;
7327 spend = jp->ps + jp->nprocs;
7328 sp = jp->ps;
7329 do {
7330 if (sp->pid == pid) {
7331 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7332 sp->status = status;
7333 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007334 }
Eric Andersenc470f442003-07-28 09:56:35 +00007335 if (sp->status == -1)
7336 state = JOBRUNNING;
7337#ifdef JOBS
7338 if (state == JOBRUNNING)
7339 continue;
7340 if (WIFSTOPPED(sp->status)) {
7341 jp->stopstatus = sp->status;
7342 state = JOBSTOPPED;
7343 }
Eric Andersencb57d552001-06-28 07:25:16 +00007344#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007345 } while (++sp < spend);
7346 if (thisjob)
7347 goto gotjob;
7348 }
7349#ifdef JOBS
7350 if (!WIFSTOPPED(status))
7351#endif
7352
7353 jobless--;
7354 goto out;
7355
7356gotjob:
7357 if (state != JOBRUNNING) {
7358 thisjob->changed = 1;
7359
7360 if (thisjob->state != state) {
7361 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7362 thisjob->state = state;
7363#ifdef JOBS
7364 if (state == JOBSTOPPED) {
7365 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007366 }
Eric Andersenc470f442003-07-28 09:56:35 +00007367#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007368 }
7369 }
Eric Andersencb57d552001-06-28 07:25:16 +00007370
Eric Andersenc470f442003-07-28 09:56:35 +00007371out:
7372 INTON;
7373
7374 if (thisjob && thisjob == job) {
7375 char s[48 + 1];
7376 int len;
7377
7378 len = sprint_status(s, status, 1);
7379 if (len) {
7380 s[len] = '\n';
7381 s[len + 1] = 0;
7382 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007383 }
Eric Andersencb57d552001-06-28 07:25:16 +00007384 }
7385 return pid;
7386}
7387
7388
Eric Andersencb57d552001-06-28 07:25:16 +00007389/*
7390 * return 1 if there are stopped jobs, otherwise 0
7391 */
Eric Andersen90898442003-08-06 11:20:52 +00007392
Eric Andersenc470f442003-07-28 09:56:35 +00007393int
7394stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007395{
Eric Andersencb57d552001-06-28 07:25:16 +00007396 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007397 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007398
Eric Andersenc470f442003-07-28 09:56:35 +00007399 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007400 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007401 goto out;
7402 jp = curjob;
7403 if (jp && jp->state == JOBSTOPPED) {
7404 out2str("You have stopped jobs.\n");
7405 job_warning = 2;
7406 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007407 }
7408
Eric Andersenc470f442003-07-28 09:56:35 +00007409out:
7410 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007411}
7412
7413/*
7414 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007415 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007416 */
7417
Eric Andersenc470f442003-07-28 09:56:35 +00007418#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007419static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007420
Eric Andersenc470f442003-07-28 09:56:35 +00007421static char *
7422commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007423{
Eric Andersenc470f442003-07-28 09:56:35 +00007424 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007425
Eric Andersenc470f442003-07-28 09:56:35 +00007426 STARTSTACKSTR(cmdnextc);
7427 cmdtxt(n);
7428 name = stackblock();
7429 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7430 name, cmdnextc, cmdnextc));
7431 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007432}
7433
Eric Andersenc470f442003-07-28 09:56:35 +00007434static void
7435cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007436{
Eric Andersencb57d552001-06-28 07:25:16 +00007437 union node *np;
7438 struct nodelist *lp;
7439 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007440 char s[2];
7441
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007442 if (!n)
7443 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007444 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007445 default:
7446#if DEBUG
7447 abort();
7448#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007449 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007450 lp = n->npipe.cmdlist;
7451 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007452 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007453 lp = lp->next;
7454 if (!lp)
7455 break;
7456 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007457 }
7458 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007459 case NSEMI:
7460 p = "; ";
7461 goto binop;
7462 case NAND:
7463 p = " && ";
7464 goto binop;
7465 case NOR:
7466 p = " || ";
7467binop:
7468 cmdtxt(n->nbinary.ch1);
7469 cmdputs(p);
7470 n = n->nbinary.ch2;
7471 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007472 case NREDIR:
7473 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007474 n = n->nredir.n;
7475 goto donode;
7476 case NNOT:
7477 cmdputs("!");
7478 n = n->nnot.com;
7479donode:
7480 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007481 break;
7482 case NIF:
7483 cmdputs("if ");
7484 cmdtxt(n->nif.test);
7485 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007486 n = n->nif.ifpart;
7487 if (n->nif.elsepart) {
7488 cmdtxt(n);
7489 cmdputs("; else ");
7490 n = n->nif.elsepart;
7491 }
7492 p = "; fi";
7493 goto dotail;
7494 case NSUBSHELL:
7495 cmdputs("(");
7496 n = n->nredir.n;
7497 p = ")";
7498 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007499 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007500 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007501 goto until;
7502 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007503 p = "until ";
7504until:
7505 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007506 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007507 n = n->nbinary.ch2;
7508 p = "; done";
7509dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007510 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007511dotail:
7512 cmdtxt(n);
7513 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007514 case NFOR:
7515 cmdputs("for ");
7516 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007517 cmdputs(" in ");
7518 cmdlist(n->nfor.args, 1);
7519 n = n->nfor.body;
7520 p = "; done";
7521 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007522 case NDEFUN:
7523 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007524 p = "() { ... }";
7525 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007526 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007527 cmdlist(n->ncmd.args, 1);
7528 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007529 break;
7530 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007531 p = n->narg.text;
7532dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007533 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007534 break;
7535 case NHERE:
7536 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007537 p = "<<...";
7538 goto dotail2;
7539 case NCASE:
7540 cmdputs("case ");
7541 cmdputs(n->ncase.expr->narg.text);
7542 cmdputs(" in ");
7543 for (np = n->ncase.cases; np; np = np->nclist.next) {
7544 cmdtxt(np->nclist.pattern);
7545 cmdputs(") ");
7546 cmdtxt(np->nclist.body);
7547 cmdputs(";; ");
7548 }
7549 p = "esac";
7550 goto dotail2;
7551 case NTO:
7552 p = ">";
7553 goto redir;
7554 case NCLOBBER:
7555 p = ">|";
7556 goto redir;
7557 case NAPPEND:
7558 p = ">>";
7559 goto redir;
7560 case NTOFD:
7561 p = ">&";
7562 goto redir;
7563 case NFROM:
7564 p = "<";
7565 goto redir;
7566 case NFROMFD:
7567 p = "<&";
7568 goto redir;
7569 case NFROMTO:
7570 p = "<>";
7571redir:
7572 s[0] = n->nfile.fd + '0';
7573 s[1] = '\0';
7574 cmdputs(s);
7575 cmdputs(p);
7576 if (n->type == NTOFD || n->type == NFROMFD) {
7577 s[0] = n->ndup.dupfd + '0';
7578 p = s;
7579 goto dotail2;
7580 } else {
7581 n = n->nfile.fname;
7582 goto donode;
7583 }
Eric Andersencb57d552001-06-28 07:25:16 +00007584 }
7585}
Eric Andersencb57d552001-06-28 07:25:16 +00007586
Eric Andersenc470f442003-07-28 09:56:35 +00007587static void
7588cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007589{
Eric Andersenc470f442003-07-28 09:56:35 +00007590 for (; np; np = np->narg.next) {
7591 if (!sep)
7592 cmdputs(spcstr);
7593 cmdtxt(np);
7594 if (sep && np->narg.next)
7595 cmdputs(spcstr);
7596 }
Eric Andersencb57d552001-06-28 07:25:16 +00007597}
7598
Eric Andersenc470f442003-07-28 09:56:35 +00007599static void
7600cmdputs(const char *s)
7601{
7602 const char *p, *str;
7603 char c, cc[2] = " ";
7604 char *nextc;
7605 int subtype = 0;
7606 int quoted = 0;
7607 static const char *const vstype[16] = {
7608 nullstr, "}", "-", "+", "?", "=",
7609 "#", "##", "%", "%%"
7610 };
7611
7612 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7613 p = s;
7614 while ((c = *p++) != 0) {
7615 str = 0;
7616 switch (c) {
7617 case CTLESC:
7618 c = *p++;
7619 break;
7620 case CTLVAR:
7621 subtype = *p++;
7622 if ((subtype & VSTYPE) == VSLENGTH)
7623 str = "${#";
7624 else
7625 str = "${";
7626 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7627 quoted ^= 1;
7628 c = '"';
7629 } else
7630 goto dostr;
7631 break;
7632 case CTLENDVAR:
7633 quoted >>= 1;
7634 subtype = 0;
7635 if (quoted & 1) {
7636 str = "\"}";
7637 goto dostr;
7638 }
7639 c = '}';
7640 break;
7641 case CTLBACKQ:
7642 str = "$(...)";
7643 goto dostr;
7644 case CTLBACKQ+CTLQUOTE:
7645 str = "\"$(...)\"";
7646 goto dostr;
7647#ifdef CONFIG_ASH_MATH_SUPPORT
7648 case CTLARI:
7649 str = "$((";
7650 goto dostr;
7651 case CTLENDARI:
7652 str = "))";
7653 goto dostr;
7654#endif
7655 case CTLQUOTEMARK:
7656 quoted ^= 1;
7657 c = '"';
7658 break;
7659 case '=':
7660 if (subtype == 0)
7661 break;
7662 str = vstype[subtype & VSTYPE];
7663 if (subtype & VSNUL)
7664 c = ':';
7665 else
7666 c = *str++;
7667 if (c != '}')
7668 quoted <<= 1;
7669 break;
7670 case '\'':
7671 case '\\':
7672 case '"':
7673 case '$':
7674 /* These can only happen inside quotes */
7675 cc[0] = c;
7676 str = cc;
7677 c = '\\';
7678 break;
7679 default:
7680 break;
7681 }
7682 USTPUTC(c, nextc);
7683 if (!str)
7684 continue;
7685dostr:
7686 while ((c = *str++)) {
7687 USTPUTC(c, nextc);
7688 }
7689 }
7690 if (quoted & 1) {
7691 USTPUTC('"', nextc);
7692 }
7693 *nextc = 0;
7694 cmdnextc = nextc;
7695}
7696
7697
7698static void
7699showpipe(struct job *jp, FILE *out)
7700{
7701 struct procstat *sp;
7702 struct procstat *spend;
7703
7704 spend = jp->ps + jp->nprocs;
7705 for (sp = jp->ps + 1; sp < spend; sp++)
7706 fprintf(out, " | %s", sp->cmd);
7707 outcslow('\n', out);
7708 flushall();
7709}
7710
7711static void
7712xtcsetpgrp(int fd, pid_t pgrp)
7713{
7714 if (tcsetpgrp(fd, pgrp))
7715 error("Cannot set tty process group (%m)");
7716}
7717#endif /* JOBS */
7718
7719static int
7720getstatus(struct job *job) {
7721 int status;
7722 int retval;
7723
7724 status = job->ps[job->nprocs - 1].status;
7725 retval = WEXITSTATUS(status);
7726 if (!WIFEXITED(status)) {
7727#if JOBS
7728 retval = WSTOPSIG(status);
7729 if (!WIFSTOPPED(status))
7730#endif
7731 {
7732 /* XXX: limits number of signals */
7733 retval = WTERMSIG(status);
7734#if JOBS
7735 if (retval == SIGINT)
7736 job->sigint = 1;
7737#endif
7738 }
7739 retval += 128;
7740 }
7741 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7742 jobno(job), job->nprocs, status, retval));
7743 return retval;
7744}
7745
Eric Andersend35c5df2002-01-09 15:37:36 +00007746#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007747/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007748
Eric Andersencb57d552001-06-28 07:25:16 +00007749/*
Eric Andersenc470f442003-07-28 09:56:35 +00007750 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007751 */
7752
Eric Andersencb57d552001-06-28 07:25:16 +00007753#define MAXMBOXES 10
7754
Eric Andersenc470f442003-07-28 09:56:35 +00007755/* times of mailboxes */
7756static time_t mailtime[MAXMBOXES];
7757/* Set if MAIL or MAILPATH is changed. */
7758static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007759
7760
7761
7762/*
Eric Andersenc470f442003-07-28 09:56:35 +00007763 * Print appropriate message(s) if mail has arrived.
7764 * If mail_var_path_changed is set,
7765 * then the value of MAIL has mail_var_path_changed,
7766 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007767 */
7768
Eric Andersenc470f442003-07-28 09:56:35 +00007769static void
7770chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007771{
Eric Andersencb57d552001-06-28 07:25:16 +00007772 const char *mpath;
7773 char *p;
7774 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007775 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007776 struct stackmark smark;
7777 struct stat statb;
7778
Eric Andersencb57d552001-06-28 07:25:16 +00007779 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007780 mpath = mpathset() ? mpathval() : mailval();
7781 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007782 p = padvance(&mpath, nullstr);
7783 if (p == NULL)
7784 break;
7785 if (*p == '\0')
7786 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007787 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007788#ifdef DEBUG
7789 if (q[-1] != '/')
7790 abort();
7791#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007792 q[-1] = '\0'; /* delete trailing '/' */
7793 if (stat(p, &statb) < 0) {
7794 *mtp = 0;
7795 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007796 }
Eric Andersenc470f442003-07-28 09:56:35 +00007797 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7798 fprintf(
7799 stderr, snlfmt,
7800 pathopt ? pathopt : "you have mail"
7801 );
7802 }
7803 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007804 }
Eric Andersenc470f442003-07-28 09:56:35 +00007805 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007806 popstackmark(&smark);
7807}
Eric Andersencb57d552001-06-28 07:25:16 +00007808
Eric Andersenec074692001-10-31 11:05:49 +00007809
Eric Andersenc470f442003-07-28 09:56:35 +00007810static void
7811changemail(const char *val)
7812{
7813 mail_var_path_changed++;
7814}
7815
7816#endif /* CONFIG_ASH_MAIL */
7817
7818/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7819
Eric Andersencb57d552001-06-28 07:25:16 +00007820
Eric Andersencb57d552001-06-28 07:25:16 +00007821#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007822static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007823extern int etext();
7824#endif
7825
Eric Andersenc470f442003-07-28 09:56:35 +00007826static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007827
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007828static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007829
Eric Andersencb57d552001-06-28 07:25:16 +00007830/*
7831 * Main routine. We initialize things, parse the arguments, execute
7832 * profiles if we're a login shell, and then call cmdloop to execute
7833 * commands. The setjmp call sets up the location to jump to when an
7834 * exception occurs. When an exception occurs the variable "state"
7835 * is used to figure out how far we had gotten.
7836 */
7837
Eric Andersenc470f442003-07-28 09:56:35 +00007838int
7839ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007840{
Eric Andersenc470f442003-07-28 09:56:35 +00007841 char *shinit;
7842 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007843 struct jmploc jmploc;
7844 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007845
Eric Andersenc470f442003-07-28 09:56:35 +00007846#ifdef __GLIBC__
7847 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007848#endif
7849
Eric Andersencb57d552001-06-28 07:25:16 +00007850#if PROFILE
7851 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7852#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007853 state = 0;
7854 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007855 int status;
7856 int e;
7857
Eric Andersencb57d552001-06-28 07:25:16 +00007858 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007859
7860 e = exception;
7861 switch (exception) {
7862 case EXEXEC:
7863 status = exerrno;
7864 break;
7865
7866 case EXERROR:
7867 status = 2;
7868 break;
7869
7870 default:
7871 status = exitstatus;
7872 break;
7873 }
7874 exitstatus = status;
7875
7876 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7877 exitshell();
7878
Eric Andersen90898442003-08-06 11:20:52 +00007879 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007880 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007881 }
7882 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007883 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007884 if (state == 1)
7885 goto state1;
7886 else if (state == 2)
7887 goto state2;
7888 else if (state == 3)
7889 goto state3;
7890 else
7891 goto state4;
7892 }
7893 handler = &jmploc;
7894#ifdef DEBUG
7895 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007896 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007897#endif
7898 rootpid = getpid();
7899 rootshell = 1;
7900 init();
7901 setstackmark(&smark);
7902 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007903#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7904 if ( iflag ) {
7905 const char *hp = lookupvar("HISTFILE");
7906
7907 if(hp == NULL ) {
7908 hp = lookupvar("HOME");
7909 if(hp != NULL) {
7910 char *defhp = concat_path_file(hp, ".ash_history");
7911 setvar("HISTFILE", defhp, 0);
7912 free(defhp);
7913 }
7914 }
7915 }
7916#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007917 if (argv[0] && argv[0][0] == '-')
7918 isloginsh = 1;
7919 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007920 state = 1;
7921 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007922state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007923 state = 2;
7924 read_profile(".profile");
7925 }
Eric Andersenc470f442003-07-28 09:56:35 +00007926state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007927 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007928 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007929#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007930 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007931#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007932 iflag
7933 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007934 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007935 read_profile(shinit);
7936 }
Eric Andersencb57d552001-06-28 07:25:16 +00007937 }
Eric Andersenc470f442003-07-28 09:56:35 +00007938state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007939 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007940 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007941 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007942
7943 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007944#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007945 if ( iflag ) {
7946 const char *hp = lookupvar("HISTFILE");
7947
7948 if(hp != NULL )
7949 load_history ( hp );
7950 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007951#endif
Eric Andersen90898442003-08-06 11:20:52 +00007952state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007953 cmdloop(1);
7954 }
7955#if PROFILE
7956 monitor(0);
7957#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007958#if GPROF
7959 {
7960 extern void _mcleanup(void);
7961 _mcleanup();
7962 }
7963#endif
7964 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007965 /* NOTREACHED */
7966}
7967
7968
7969/*
7970 * Read and execute commands. "Top" is nonzero for the top level command
7971 * loop; it turns on prompting if the shell is interactive.
7972 */
7973
Eric Andersenc470f442003-07-28 09:56:35 +00007974static void
7975cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007976{
7977 union node *n;
7978 struct stackmark smark;
7979 int inter;
7980 int numeof = 0;
7981
7982 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00007983 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00007984 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00007985 if (pendingsigs)
7986 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00007987#if JOBS
7988 if (jobctl)
7989 showjobs(stderr, SHOW_CHANGED);
7990#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007991 inter = 0;
7992 if (iflag && top) {
7993 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00007994#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007995 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00007996#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007997 }
7998 n = parsecmd(inter);
7999 /* showtree(n); DEBUG */
8000 if (n == NEOF) {
8001 if (!top || numeof >= 50)
8002 break;
8003 if (!stoppedjobs()) {
8004 if (!Iflag)
8005 break;
8006 out2str("\nUse \"exit\" to leave shell.\n");
8007 }
8008 numeof++;
8009 } else if (n != NULL && nflag == 0) {
8010 job_warning = (job_warning == 2) ? 1 : 0;
8011 numeof = 0;
8012 evaltree(n, 0);
8013 }
8014 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008015 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008016 evalskip = 0;
8017 break;
8018 }
8019 }
Eric Andersencb57d552001-06-28 07:25:16 +00008020}
8021
8022
Eric Andersencb57d552001-06-28 07:25:16 +00008023/*
8024 * Read /etc/profile or .profile. Return on error.
8025 */
8026
Eric Andersenc470f442003-07-28 09:56:35 +00008027static void
8028read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008029{
8030 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008031 int xflag_set = 0;
8032 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008033
8034 INTOFF;
8035 if ((fd = open(name, O_RDONLY)) >= 0)
8036 setinputfd(fd, 1);
8037 INTON;
8038 if (fd < 0)
8039 return;
8040 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008041 if (qflag) {
8042 if (xflag)
8043 xflag = 0, xflag_set = 1;
8044 if (vflag)
8045 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008046 }
8047 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008048 if (qflag) {
8049 if (xflag_set)
8050 xflag = 1;
8051 if (vflag_set)
8052 vflag = 1;
8053 }
Eric Andersencb57d552001-06-28 07:25:16 +00008054 popfile();
8055}
8056
8057
Eric Andersencb57d552001-06-28 07:25:16 +00008058/*
8059 * Read a file containing shell functions.
8060 */
8061
Eric Andersenc470f442003-07-28 09:56:35 +00008062static void
8063readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008064{
8065 int fd;
8066
8067 INTOFF;
8068 if ((fd = open(name, O_RDONLY)) >= 0)
8069 setinputfd(fd, 1);
8070 else
8071 error("Can't open %s", name);
8072 INTON;
8073 cmdloop(0);
8074 popfile();
8075}
8076
8077
Eric Andersencb57d552001-06-28 07:25:16 +00008078/*
Eric Andersenc470f442003-07-28 09:56:35 +00008079 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008080 * search for the file, which is necessary to find sub-commands.
8081 */
8082
Eric Andersenc470f442003-07-28 09:56:35 +00008083static inline char *
8084find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008085{
8086 char *fullname;
8087 const char *path = pathval();
8088 struct stat statb;
8089
8090 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008091 if (strchr(name, '/'))
8092 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008093
Eric Andersenc470f442003-07-28 09:56:35 +00008094 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008095 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8096 /*
8097 * Don't bother freeing here, since it will
8098 * be freed by the caller.
8099 */
8100 return fullname;
8101 }
8102 stunalloc(fullname);
8103 }
8104
8105 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008106 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008107 /* NOTREACHED */
8108}
8109
Eric Andersenc470f442003-07-28 09:56:35 +00008110int
8111dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008112{
Eric Andersencb57d552001-06-28 07:25:16 +00008113 exitstatus = 0;
8114
Eric Andersenc470f442003-07-28 09:56:35 +00008115 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008116 char *fullname;
8117 struct stackmark smark;
8118
8119 setstackmark(&smark);
8120 fullname = find_dot_file(argv[1]);
8121 setinputfile(fullname, 1);
8122 commandname = fullname;
8123 cmdloop(0);
8124 popfile();
8125 popstackmark(&smark);
8126 }
8127 return exitstatus;
8128}
8129
8130
Eric Andersenc470f442003-07-28 09:56:35 +00008131static int
8132exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008133{
8134 if (stoppedjobs())
8135 return 0;
8136 if (argc > 1)
8137 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008138 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008139 /* NOTREACHED */
8140}
Eric Andersen62483552001-07-10 06:09:16 +00008141
Eric Andersenc470f442003-07-28 09:56:35 +00008142/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8143
8144/*
Eric Andersen90898442003-08-06 11:20:52 +00008145 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008146 */
8147
8148static pointer
8149ckrealloc(pointer p, size_t nbytes)
8150{
8151 p = realloc(p, nbytes);
8152 if (p == NULL)
8153 error(bb_msg_memory_exhausted);
8154 return p;
8155}
8156
Eric Andersen90898442003-08-06 11:20:52 +00008157static pointer
8158ckmalloc(size_t nbytes)
8159{
8160 return ckrealloc(NULL, nbytes);
8161}
Eric Andersenc470f442003-07-28 09:56:35 +00008162
8163/*
8164 * Make a copy of a string in safe storage.
8165 */
8166
8167static char *
8168savestr(const char *s)
8169{
8170 char *p = strdup(s);
8171 if (!p)
8172 error(bb_msg_memory_exhausted);
8173 return p;
8174}
8175
8176
8177/*
8178 * Parse trees for commands are allocated in lifo order, so we use a stack
8179 * to make this more efficient, and also to avoid all sorts of exception
8180 * handling code to handle interrupts in the middle of a parse.
8181 *
8182 * The size 504 was chosen because the Ultrix malloc handles that size
8183 * well.
8184 */
8185
8186
8187static pointer
8188stalloc(size_t nbytes)
8189{
8190 char *p;
8191 size_t aligned;
8192
8193 aligned = SHELL_ALIGN(nbytes);
8194 if (aligned > stacknleft) {
8195 size_t len;
8196 size_t blocksize;
8197 struct stack_block *sp;
8198
8199 blocksize = aligned;
8200 if (blocksize < MINSIZE)
8201 blocksize = MINSIZE;
8202 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8203 if (len < blocksize)
8204 error(bb_msg_memory_exhausted);
8205 INTOFF;
8206 sp = ckmalloc(len);
8207 sp->prev = stackp;
8208 stacknxt = sp->space;
8209 stacknleft = blocksize;
8210 sstrend = stacknxt + blocksize;
8211 stackp = sp;
8212 INTON;
8213 }
8214 p = stacknxt;
8215 stacknxt += aligned;
8216 stacknleft -= aligned;
8217 return p;
8218}
8219
8220
8221void
8222stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008223{
Eric Andersencb57d552001-06-28 07:25:16 +00008224#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008225 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008226 write(2, "stunalloc\n", 10);
8227 abort();
8228 }
8229#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008230 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008231 stacknxt = p;
8232}
8233
8234
Eric Andersenc470f442003-07-28 09:56:35 +00008235void
8236setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008237{
Eric Andersencb57d552001-06-28 07:25:16 +00008238 mark->stackp = stackp;
8239 mark->stacknxt = stacknxt;
8240 mark->stacknleft = stacknleft;
8241 mark->marknext = markp;
8242 markp = mark;
8243}
8244
8245
Eric Andersenc470f442003-07-28 09:56:35 +00008246void
8247popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008248{
Eric Andersencb57d552001-06-28 07:25:16 +00008249 struct stack_block *sp;
8250
8251 INTOFF;
8252 markp = mark->marknext;
8253 while (stackp != mark->stackp) {
8254 sp = stackp;
8255 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008256 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008257 }
8258 stacknxt = mark->stacknxt;
8259 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008260 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008261 INTON;
8262}
8263
8264
8265/*
8266 * When the parser reads in a string, it wants to stick the string on the
8267 * stack and only adjust the stack pointer when it knows how big the
8268 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8269 * of space on top of the stack and stackblocklen returns the length of
8270 * this block. Growstackblock will grow this space by at least one byte,
8271 * possibly moving it (like realloc). Grabstackblock actually allocates the
8272 * part of the block that has been used.
8273 */
8274
Eric Andersenc470f442003-07-28 09:56:35 +00008275void
8276growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008277{
Eric Andersenc470f442003-07-28 09:56:35 +00008278 size_t newlen;
8279
8280 newlen = stacknleft * 2;
8281 if (newlen < stacknleft)
8282 error(bb_msg_memory_exhausted);
8283 if (newlen < 128)
8284 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008285
8286 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008287 struct stack_block *oldstackp;
8288 struct stackmark *xmark;
8289 struct stack_block *sp;
8290 struct stack_block *prevstackp;
8291 size_t grosslen;
8292
Eric Andersencb57d552001-06-28 07:25:16 +00008293 INTOFF;
8294 oldstackp = stackp;
8295 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008296 prevstackp = sp->prev;
8297 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8298 sp = ckrealloc((pointer)sp, grosslen);
8299 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008300 stackp = sp;
8301 stacknxt = sp->space;
8302 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008303 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008304
Eric Andersenc470f442003-07-28 09:56:35 +00008305 /*
8306 * Stack marks pointing to the start of the old block
8307 * must be relocated to point to the new block
8308 */
8309 xmark = markp;
8310 while (xmark != NULL && xmark->stackp == oldstackp) {
8311 xmark->stackp = stackp;
8312 xmark->stacknxt = stacknxt;
8313 xmark->stacknleft = stacknleft;
8314 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008315 }
8316 INTON;
8317 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008318 char *oldspace = stacknxt;
8319 int oldlen = stacknleft;
8320 char *p = stalloc(newlen);
8321
8322 /* free the space we just allocated */
8323 stacknxt = memcpy(p, oldspace, oldlen);
8324 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008325 }
8326}
8327
Eric Andersenc470f442003-07-28 09:56:35 +00008328static inline void
8329grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008330{
Eric Andersenc470f442003-07-28 09:56:35 +00008331 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008332 stacknxt += len;
8333 stacknleft -= len;
8334}
8335
Eric Andersencb57d552001-06-28 07:25:16 +00008336/*
Eric Andersenc470f442003-07-28 09:56:35 +00008337 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008338 * The user declares a variable of type STACKSTR, which may be declared
8339 * to be a register. The macro STARTSTACKSTR initializes things. Then
8340 * the user uses the macro STPUTC to add characters to the string. In
8341 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8342 * grown as necessary. When the user is done, she can just leave the
8343 * string there and refer to it using stackblock(). Or she can allocate
8344 * the space for it using grabstackstr(). If it is necessary to allow
8345 * someone else to use the stack temporarily and then continue to grow
8346 * the string, the user should use grabstack to allocate the space, and
8347 * then call ungrabstr(p) to return to the previous mode of operation.
8348 *
8349 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8350 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8351 * is space for at least one character.
8352 */
8353
Eric Andersenc470f442003-07-28 09:56:35 +00008354void *
8355growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008356{
Eric Andersenc470f442003-07-28 09:56:35 +00008357 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008358 if (herefd >= 0 && len >= 1024) {
8359 xwrite(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008360 return stackblock();
8361 }
8362 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008363 return stackblock() + len;
8364}
8365
Eric Andersencb57d552001-06-28 07:25:16 +00008366/*
8367 * Called from CHECKSTRSPACE.
8368 */
8369
Eric Andersenc470f442003-07-28 09:56:35 +00008370char *
8371makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008372{
Eric Andersenc470f442003-07-28 09:56:35 +00008373 size_t len = p - stacknxt;
8374 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008375
Eric Andersenc470f442003-07-28 09:56:35 +00008376 for (;;) {
8377 size_t nleft;
8378
8379 size = stackblocksize();
8380 nleft = size - len;
8381 if (nleft >= newlen)
8382 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008383 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008384 }
Eric Andersencb57d552001-06-28 07:25:16 +00008385 return stackblock() + len;
8386}
8387
Eric Andersenc470f442003-07-28 09:56:35 +00008388char *
8389stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008390{
Eric Andersenc470f442003-07-28 09:56:35 +00008391 p = makestrspace(n, p);
8392 p = mempcpy(p, s, n);
8393 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008394}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008395
Eric Andersenc470f442003-07-28 09:56:35 +00008396char *
8397stputs(const char *s, char *p)
8398{
8399 return stnputs(s, strlen(s), p);
8400}
8401
8402/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8403
Eric Andersencb57d552001-06-28 07:25:16 +00008404/*
Eric Andersenc470f442003-07-28 09:56:35 +00008405 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008406 *
Eric Andersenc470f442003-07-28 09:56:35 +00008407 * number(s) Convert a string of digits to an integer.
8408 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008409 */
8410
Eric Andersencb57d552001-06-28 07:25:16 +00008411/*
8412 * prefix -- see if pfx is a prefix of string.
8413 */
8414
Eric Andersenc470f442003-07-28 09:56:35 +00008415char *
8416prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008417{
Eric Andersencb57d552001-06-28 07:25:16 +00008418 while (*pfx) {
8419 if (*pfx++ != *string++)
8420 return 0;
8421 }
Eric Andersenc470f442003-07-28 09:56:35 +00008422 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008423}
8424
8425
8426/*
8427 * Convert a string of digits to an integer, printing an error message on
8428 * failure.
8429 */
8430
Eric Andersenc470f442003-07-28 09:56:35 +00008431int
8432number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008433{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008434
Eric Andersenc470f442003-07-28 09:56:35 +00008435 if (! is_number(s))
8436 error(illnum, s);
8437 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008438}
8439
Eric Andersenc470f442003-07-28 09:56:35 +00008440
Eric Andersenc470f442003-07-28 09:56:35 +00008441/*
8442 * Check for a valid number. This should be elsewhere.
8443 */
8444
8445int
8446is_number(const char *p)
8447{
8448 do {
8449 if (! is_digit(*p))
8450 return 0;
8451 } while (*++p != '\0');
8452 return 1;
8453}
8454
8455
Eric Andersencb57d552001-06-28 07:25:16 +00008456/*
8457 * Produce a possibly single quoted string suitable as input to the shell.
8458 * The return string is allocated on the stack.
8459 */
8460
Eric Andersenc470f442003-07-28 09:56:35 +00008461char *
8462single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008463 char *p;
8464
8465 STARTSTACKSTR(p);
8466
8467 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008468 char *q;
8469 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008470
Eric Andersenc470f442003-07-28 09:56:35 +00008471 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008472
Eric Andersenc470f442003-07-28 09:56:35 +00008473 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008474
Eric Andersenc470f442003-07-28 09:56:35 +00008475 *q++ = '\'';
8476 q = mempcpy(q, s, len);
8477 *q++ = '\'';
8478 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008479
Eric Andersenc470f442003-07-28 09:56:35 +00008480 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008481
Eric Andersenc470f442003-07-28 09:56:35 +00008482 len = strspn(s, "'");
8483 if (!len)
8484 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008485
Eric Andersenc470f442003-07-28 09:56:35 +00008486 q = p = makestrspace(len + 3, p);
8487
8488 *q++ = '"';
8489 q = mempcpy(q, s, len);
8490 *q++ = '"';
8491 s += len;
8492
8493 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008494 } while (*s);
8495
8496 USTPUTC(0, p);
8497
Eric Andersenc470f442003-07-28 09:56:35 +00008498 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008499}
8500
8501/*
Eric Andersenc470f442003-07-28 09:56:35 +00008502 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008503 */
8504
Eric Andersenc470f442003-07-28 09:56:35 +00008505char *
8506sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008507{
Eric Andersenc470f442003-07-28 09:56:35 +00008508 size_t len = strlen(p) + 1;
8509 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008510}
Eric Andersenc470f442003-07-28 09:56:35 +00008511
8512
8513static void
8514calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008515{
Eric Andersenc470f442003-07-28 09:56:35 +00008516 if (n == NULL)
8517 return;
8518 funcblocksize += nodesize[n->type];
8519 switch (n->type) {
8520 case NCMD:
8521 calcsize(n->ncmd.redirect);
8522 calcsize(n->ncmd.args);
8523 calcsize(n->ncmd.assign);
8524 break;
8525 case NPIPE:
8526 sizenodelist(n->npipe.cmdlist);
8527 break;
8528 case NREDIR:
8529 case NBACKGND:
8530 case NSUBSHELL:
8531 calcsize(n->nredir.redirect);
8532 calcsize(n->nredir.n);
8533 break;
8534 case NAND:
8535 case NOR:
8536 case NSEMI:
8537 case NWHILE:
8538 case NUNTIL:
8539 calcsize(n->nbinary.ch2);
8540 calcsize(n->nbinary.ch1);
8541 break;
8542 case NIF:
8543 calcsize(n->nif.elsepart);
8544 calcsize(n->nif.ifpart);
8545 calcsize(n->nif.test);
8546 break;
8547 case NFOR:
8548 funcstringsize += strlen(n->nfor.var) + 1;
8549 calcsize(n->nfor.body);
8550 calcsize(n->nfor.args);
8551 break;
8552 case NCASE:
8553 calcsize(n->ncase.cases);
8554 calcsize(n->ncase.expr);
8555 break;
8556 case NCLIST:
8557 calcsize(n->nclist.body);
8558 calcsize(n->nclist.pattern);
8559 calcsize(n->nclist.next);
8560 break;
8561 case NDEFUN:
8562 case NARG:
8563 sizenodelist(n->narg.backquote);
8564 funcstringsize += strlen(n->narg.text) + 1;
8565 calcsize(n->narg.next);
8566 break;
8567 case NTO:
8568 case NCLOBBER:
8569 case NFROM:
8570 case NFROMTO:
8571 case NAPPEND:
8572 calcsize(n->nfile.fname);
8573 calcsize(n->nfile.next);
8574 break;
8575 case NTOFD:
8576 case NFROMFD:
8577 calcsize(n->ndup.vname);
8578 calcsize(n->ndup.next);
8579 break;
8580 case NHERE:
8581 case NXHERE:
8582 calcsize(n->nhere.doc);
8583 calcsize(n->nhere.next);
8584 break;
8585 case NNOT:
8586 calcsize(n->nnot.com);
8587 break;
8588 };
Eric Andersencb57d552001-06-28 07:25:16 +00008589}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008590
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008591
Eric Andersenc470f442003-07-28 09:56:35 +00008592static void
8593sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008594{
8595 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008596 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008597 calcsize(lp->n);
8598 lp = lp->next;
8599 }
8600}
Eric Andersencb57d552001-06-28 07:25:16 +00008601
8602
Eric Andersenc470f442003-07-28 09:56:35 +00008603static union node *
8604copynode(union node *n)
8605{
8606 union node *new;
8607
8608 if (n == NULL)
8609 return NULL;
8610 new = funcblock;
8611 funcblock = (char *) funcblock + nodesize[n->type];
8612 switch (n->type) {
8613 case NCMD:
8614 new->ncmd.redirect = copynode(n->ncmd.redirect);
8615 new->ncmd.args = copynode(n->ncmd.args);
8616 new->ncmd.assign = copynode(n->ncmd.assign);
8617 break;
8618 case NPIPE:
8619 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8620 new->npipe.backgnd = n->npipe.backgnd;
8621 break;
8622 case NREDIR:
8623 case NBACKGND:
8624 case NSUBSHELL:
8625 new->nredir.redirect = copynode(n->nredir.redirect);
8626 new->nredir.n = copynode(n->nredir.n);
8627 break;
8628 case NAND:
8629 case NOR:
8630 case NSEMI:
8631 case NWHILE:
8632 case NUNTIL:
8633 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8634 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8635 break;
8636 case NIF:
8637 new->nif.elsepart = copynode(n->nif.elsepart);
8638 new->nif.ifpart = copynode(n->nif.ifpart);
8639 new->nif.test = copynode(n->nif.test);
8640 break;
8641 case NFOR:
8642 new->nfor.var = nodesavestr(n->nfor.var);
8643 new->nfor.body = copynode(n->nfor.body);
8644 new->nfor.args = copynode(n->nfor.args);
8645 break;
8646 case NCASE:
8647 new->ncase.cases = copynode(n->ncase.cases);
8648 new->ncase.expr = copynode(n->ncase.expr);
8649 break;
8650 case NCLIST:
8651 new->nclist.body = copynode(n->nclist.body);
8652 new->nclist.pattern = copynode(n->nclist.pattern);
8653 new->nclist.next = copynode(n->nclist.next);
8654 break;
8655 case NDEFUN:
8656 case NARG:
8657 new->narg.backquote = copynodelist(n->narg.backquote);
8658 new->narg.text = nodesavestr(n->narg.text);
8659 new->narg.next = copynode(n->narg.next);
8660 break;
8661 case NTO:
8662 case NCLOBBER:
8663 case NFROM:
8664 case NFROMTO:
8665 case NAPPEND:
8666 new->nfile.fname = copynode(n->nfile.fname);
8667 new->nfile.fd = n->nfile.fd;
8668 new->nfile.next = copynode(n->nfile.next);
8669 break;
8670 case NTOFD:
8671 case NFROMFD:
8672 new->ndup.vname = copynode(n->ndup.vname);
8673 new->ndup.dupfd = n->ndup.dupfd;
8674 new->ndup.fd = n->ndup.fd;
8675 new->ndup.next = copynode(n->ndup.next);
8676 break;
8677 case NHERE:
8678 case NXHERE:
8679 new->nhere.doc = copynode(n->nhere.doc);
8680 new->nhere.fd = n->nhere.fd;
8681 new->nhere.next = copynode(n->nhere.next);
8682 break;
8683 case NNOT:
8684 new->nnot.com = copynode(n->nnot.com);
8685 break;
8686 };
8687 new->type = n->type;
8688 return new;
8689}
8690
8691
8692static struct nodelist *
8693copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008694{
8695 struct nodelist *start;
8696 struct nodelist **lpp;
8697
8698 lpp = &start;
8699 while (lp) {
8700 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008701 funcblock = (char *) funcblock +
8702 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008703 (*lpp)->n = copynode(lp->n);
8704 lp = lp->next;
8705 lpp = &(*lpp)->next;
8706 }
8707 *lpp = NULL;
8708 return start;
8709}
8710
8711
Eric Andersenc470f442003-07-28 09:56:35 +00008712static char *
8713nodesavestr(char *s)
8714{
8715 char *rtn = funcstring;
8716
8717 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008718 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008719}
8720
Eric Andersenc470f442003-07-28 09:56:35 +00008721
Eric Andersenc470f442003-07-28 09:56:35 +00008722/*
8723 * Free a parse tree.
8724 */
8725
8726static void
8727freefunc(struct funcnode *f)
8728{
8729 if (f && --f->count < 0)
8730 ckfree(f);
8731}
8732
8733
8734static void options(int);
8735static void setoption(int, int);
8736
Eric Andersencb57d552001-06-28 07:25:16 +00008737
Eric Andersencb57d552001-06-28 07:25:16 +00008738/*
8739 * Process the shell command line arguments.
8740 */
8741
Eric Andersenc470f442003-07-28 09:56:35 +00008742void
8743procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008744{
8745 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008746 const char *xminusc;
8747 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008748
Eric Andersenc470f442003-07-28 09:56:35 +00008749 xargv = argv;
8750 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008751 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008752 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008753 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008754 optlist[i] = 2;
8755 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008756 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008757 xargv = argptr;
8758 xminusc = minusc;
8759 if (*xargv == NULL) {
8760 if (xminusc)
8761 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008762 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008763 }
Eric Andersencb57d552001-06-28 07:25:16 +00008764 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8765 iflag = 1;
8766 if (mflag == 2)
8767 mflag = iflag;
8768 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008769 if (optlist[i] == 2)
8770 optlist[i] = 0;
8771#if DEBUG == 2
8772 debug = 1;
8773#endif
8774 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8775 if (xminusc) {
8776 minusc = *xargv++;
8777 if (*xargv)
8778 goto setarg0;
8779 } else if (!sflag) {
8780 setinputfile(*xargv, 0);
8781setarg0:
8782 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008783 commandname = arg0;
8784 }
Eric Andersencb57d552001-06-28 07:25:16 +00008785
Eric Andersenc470f442003-07-28 09:56:35 +00008786 shellparam.p = xargv;
8787#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008788 shellparam.optind = 1;
8789 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008790#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008791 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008792 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008793 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008794 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008795 }
8796 optschanged();
8797}
8798
8799
Eric Andersenc470f442003-07-28 09:56:35 +00008800void
8801optschanged(void)
8802{
8803#ifdef DEBUG
8804 opentrace();
8805#endif
8806 setinteractive(iflag);
8807 setjobctl(mflag);
8808}
Eric Andersencb57d552001-06-28 07:25:16 +00008809
Eric Andersenc470f442003-07-28 09:56:35 +00008810static inline void
8811minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008812{
8813 int i;
8814
8815 if (name == NULL) {
8816 out1str("Current option settings\n");
8817 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008818 out1fmt("%-16s%s\n", optnames(i),
8819 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008820 } else {
8821 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008822 if (equal(name, optnames(i))) {
8823 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008824 return;
8825 }
8826 error("Illegal option -o %s", name);
8827 }
8828}
8829
Eric Andersenc470f442003-07-28 09:56:35 +00008830/*
8831 * Process shell options. The global variable argptr contains a pointer
8832 * to the argument list; we advance it past the options.
8833 */
Eric Andersen62483552001-07-10 06:09:16 +00008834
Eric Andersenc470f442003-07-28 09:56:35 +00008835static void
8836options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008837{
8838 char *p;
8839 int val;
8840 int c;
8841
8842 if (cmdline)
8843 minusc = NULL;
8844 while ((p = *argptr) != NULL) {
8845 argptr++;
8846 if ((c = *p++) == '-') {
8847 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008848 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8849 if (!cmdline) {
8850 /* "-" means turn off -x and -v */
8851 if (p[0] == '\0')
8852 xflag = vflag = 0;
8853 /* "--" means reset params */
8854 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008855 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008856 }
Eric Andersenc470f442003-07-28 09:56:35 +00008857 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008858 }
8859 } else if (c == '+') {
8860 val = 0;
8861 } else {
8862 argptr--;
8863 break;
8864 }
8865 while ((c = *p++) != '\0') {
8866 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008867 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008868 } else if (c == 'o') {
8869 minus_o(*argptr, val);
8870 if (*argptr)
8871 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008872 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008873 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008874 isloginsh = 1;
8875 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008876 } else {
8877 setoption(c, val);
8878 }
8879 }
8880 }
8881}
8882
Eric Andersencb57d552001-06-28 07:25:16 +00008883
Eric Andersenc470f442003-07-28 09:56:35 +00008884static void
8885setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008886{
Eric Andersencb57d552001-06-28 07:25:16 +00008887 int i;
8888
8889 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008890 if (optletters(i) == flag) {
8891 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008892 return;
8893 }
8894 error("Illegal option -%c", flag);
8895 /* NOTREACHED */
8896}
8897
8898
8899
Eric Andersencb57d552001-06-28 07:25:16 +00008900/*
8901 * Set the shell parameters.
8902 */
8903
Eric Andersenc470f442003-07-28 09:56:35 +00008904void
8905setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008906{
Eric Andersencb57d552001-06-28 07:25:16 +00008907 char **newparam;
8908 char **ap;
8909 int nparam;
8910
Eric Andersenc470f442003-07-28 09:56:35 +00008911 for (nparam = 0 ; argv[nparam] ; nparam++);
8912 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008913 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008914 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008915 }
8916 *ap = NULL;
8917 freeparam(&shellparam);
8918 shellparam.malloc = 1;
8919 shellparam.nparam = nparam;
8920 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008921#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008922 shellparam.optind = 1;
8923 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008924#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008925}
8926
8927
8928/*
8929 * Free the list of positional parameters.
8930 */
8931
Eric Andersenc470f442003-07-28 09:56:35 +00008932void
8933freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008934{
Eric Andersencb57d552001-06-28 07:25:16 +00008935 char **ap;
8936
8937 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008938 for (ap = param->p ; *ap ; ap++)
8939 ckfree(*ap);
8940 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008941 }
8942}
8943
8944
8945
8946/*
8947 * The shift builtin command.
8948 */
8949
Eric Andersenc470f442003-07-28 09:56:35 +00008950int
8951shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008952{
8953 int n;
8954 char **ap1, **ap2;
8955
8956 n = 1;
8957 if (argc > 1)
8958 n = number(argv[1]);
8959 if (n > shellparam.nparam)
8960 error("can't shift that many");
8961 INTOFF;
8962 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008963 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008964 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008965 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008966 }
8967 ap2 = shellparam.p;
8968 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008969#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008970 shellparam.optind = 1;
8971 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008972#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008973 INTON;
8974 return 0;
8975}
8976
8977
8978
8979/*
8980 * The set command builtin.
8981 */
8982
Eric Andersenc470f442003-07-28 09:56:35 +00008983int
8984setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008985{
8986 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00008987 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00008988 INTOFF;
8989 options(0);
8990 optschanged();
8991 if (*argptr != NULL) {
8992 setparam(argptr);
8993 }
8994 INTON;
8995 return 0;
8996}
8997
8998
Eric Andersenc470f442003-07-28 09:56:35 +00008999#ifdef CONFIG_ASH_GETOPTS
9000static void
9001getoptsreset(value)
9002 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009003{
9004 shellparam.optind = number(value);
9005 shellparam.optoff = -1;
9006}
Eric Andersenc470f442003-07-28 09:56:35 +00009007#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009008
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009009#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009010static void change_lc_all(const char *value)
9011{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009012 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009013 setlocale(LC_ALL, value);
9014}
9015
9016static void change_lc_ctype(const char *value)
9017{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009018 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009019 setlocale(LC_CTYPE, value);
9020}
9021
9022#endif
9023
Eric Andersend35c5df2002-01-09 15:37:36 +00009024#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009025static int
Eric Andersenc470f442003-07-28 09:56:35 +00009026getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009027{
9028 char *p, *q;
9029 char c = '?';
9030 int done = 0;
9031 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009032 char s[12];
9033 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009034
Eric Andersena48b0a32003-10-22 10:56:47 +00009035 if(*param_optind < 1)
9036 return 1;
9037 optnext = optfirst + *param_optind - 1;
9038
9039 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009040 p = NULL;
9041 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009042 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009043 if (p == NULL || *p == '\0') {
9044 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009045 p = *optnext;
9046 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009047atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009048 p = NULL;
9049 done = 1;
9050 goto out;
9051 }
9052 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009053 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009054 goto atend;
9055 }
9056
9057 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009058 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009059 if (*q == '\0') {
9060 if (optstr[0] == ':') {
9061 s[0] = c;
9062 s[1] = '\0';
9063 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009064 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009065 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009066 (void) unsetvar("OPTARG");
9067 }
9068 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009069 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009070 }
9071 if (*++q == ':')
9072 q++;
9073 }
9074
9075 if (*++q == ':') {
9076 if (*p == '\0' && (p = *optnext) == NULL) {
9077 if (optstr[0] == ':') {
9078 s[0] = c;
9079 s[1] = '\0';
9080 err |= setvarsafe("OPTARG", s, 0);
9081 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009082 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009083 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009084 (void) unsetvar("OPTARG");
9085 c = '?';
9086 }
Eric Andersenc470f442003-07-28 09:56:35 +00009087 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009088 }
9089
9090 if (p == *optnext)
9091 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009092 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009093 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009094 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009095 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009096
Eric Andersenc470f442003-07-28 09:56:35 +00009097out:
Eric Andersencb57d552001-06-28 07:25:16 +00009098 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009099 *param_optind = optnext - optfirst + 1;
9100 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009101 err |= setvarsafe("OPTIND", s, VNOFUNC);
9102 s[0] = c;
9103 s[1] = '\0';
9104 err |= setvarsafe(optvar, s, 0);
9105 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009106 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009107 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009108 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009109 exraise(EXERROR);
9110 }
9111 return done;
9112}
Eric Andersenc470f442003-07-28 09:56:35 +00009113
9114/*
9115 * The getopts builtin. Shellparam.optnext points to the next argument
9116 * to be processed. Shellparam.optptr points to the next character to
9117 * be processed in the current argument. If shellparam.optnext is NULL,
9118 * then it's the first time getopts has been called.
9119 */
9120
9121int
9122getoptscmd(int argc, char **argv)
9123{
9124 char **optbase;
9125
9126 if (argc < 3)
9127 error("Usage: getopts optstring var [arg]");
9128 else if (argc == 3) {
9129 optbase = shellparam.p;
9130 if (shellparam.optind > shellparam.nparam + 1) {
9131 shellparam.optind = 1;
9132 shellparam.optoff = -1;
9133 }
9134 }
9135 else {
9136 optbase = &argv[3];
9137 if (shellparam.optind > argc - 2) {
9138 shellparam.optind = 1;
9139 shellparam.optoff = -1;
9140 }
9141 }
9142
9143 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9144 &shellparam.optoff);
9145}
9146#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009147
9148/*
9149 * XXX - should get rid of. have all builtins use getopt(3). the
9150 * library getopt must have the BSD extension static variable "optreset"
9151 * otherwise it can't be used within the shell safely.
9152 *
9153 * Standard option processing (a la getopt) for builtin routines. The
9154 * only argument that is passed to nextopt is the option string; the
9155 * other arguments are unnecessary. It return the character, or '\0' on
9156 * end of input.
9157 */
9158
Eric Andersenc470f442003-07-28 09:56:35 +00009159static int
9160nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009161{
Eric Andersencb57d552001-06-28 07:25:16 +00009162 char *p;
9163 const char *q;
9164 char c;
9165
9166 if ((p = optptr) == NULL || *p == '\0') {
9167 p = *argptr;
9168 if (p == NULL || *p != '-' || *++p == '\0')
9169 return '\0';
9170 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009171 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009172 return '\0';
9173 }
9174 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009175 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009176 if (*q == '\0')
9177 error("Illegal option -%c", c);
9178 if (*++q == ':')
9179 q++;
9180 }
9181 if (*++q == ':') {
9182 if (*p == '\0' && (p = *argptr++) == NULL)
9183 error("No arg for -%c option", c);
9184 optionarg = p;
9185 p = NULL;
9186 }
9187 optptr = p;
9188 return c;
9189}
9190
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009191
Eric Andersenc470f442003-07-28 09:56:35 +00009192/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9193
Eric Andersenc470f442003-07-28 09:56:35 +00009194void
9195outstr(const char *p, FILE *file)
9196{
9197 INTOFF;
9198 fputs(p, file);
9199 INTON;
9200}
9201
9202void
9203flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009204{
Eric Andersencb57d552001-06-28 07:25:16 +00009205 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009206 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009207 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009208 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009209}
9210
Eric Andersenc470f442003-07-28 09:56:35 +00009211void
9212flushout(FILE *dest)
9213{
9214 INTOFF;
9215 fflush(dest);
9216 INTON;
9217}
9218
9219static void
9220outcslow(int c, FILE *dest)
9221{
9222 INTOFF;
9223 putc(c, dest);
9224 fflush(dest);
9225 INTON;
9226}
9227
9228
9229static int
9230out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009231{
9232 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009233 int r;
9234
9235 INTOFF;
9236 va_start(ap, fmt);
9237 r = vprintf(fmt, ap);
9238 va_end(ap);
9239 INTON;
9240 return r;
9241}
9242
9243
9244int
9245fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9246{
9247 va_list ap;
9248 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009249
Eric Andersencb57d552001-06-28 07:25:16 +00009250 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009251 INTOFF;
9252 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009253 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009254 INTON;
9255 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009256}
9257
Eric Andersenc470f442003-07-28 09:56:35 +00009258
Eric Andersencb57d552001-06-28 07:25:16 +00009259/*
9260 * Version of write which resumes after a signal is caught.
9261 */
9262
Eric Andersenc470f442003-07-28 09:56:35 +00009263static void
9264xwrite(int fd, const void *p, size_t n)
Eric Andersen2870d962001-07-02 17:27:21 +00009265{
Eric Andersenc470f442003-07-28 09:56:35 +00009266 ssize_t i;
Eric Andersencb57d552001-06-28 07:25:16 +00009267
Eric Andersenc470f442003-07-28 09:56:35 +00009268 do {
9269 i = bb_full_write(fd, p, n);
9270 } while (i < 0 && errno == EINTR);
Eric Andersencb57d552001-06-28 07:25:16 +00009271}
9272
9273
Eric Andersenc470f442003-07-28 09:56:35 +00009274/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9275
9276
Eric Andersencb57d552001-06-28 07:25:16 +00009277/*
9278 * Shell command parser.
9279 */
9280
9281#define EOFMARKLEN 79
9282
9283
Eric Andersencb57d552001-06-28 07:25:16 +00009284struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009285 struct heredoc *next; /* next here document in list */
9286 union node *here; /* redirection node */
9287 char *eofmark; /* string indicating end of input */
9288 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009289};
9290
9291
9292
Eric Andersenc470f442003-07-28 09:56:35 +00009293static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009294
9295
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009296static union node *list(int);
9297static union node *andor(void);
9298static union node *pipeline(void);
9299static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009300static union node *simplecmd(void);
9301static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009302static void parsefname(void);
9303static void parseheredoc(void);
9304static char peektoken(void);
9305static int readtoken(void);
9306static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009307static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009308static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009309static void synexpect(int) __attribute__((__noreturn__));
9310static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009311static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009312
9313
Eric Andersenc470f442003-07-28 09:56:35 +00009314
9315static inline int
9316isassignment(const char *p)
9317{
9318 const char *q = endofname(p);
9319 if (p == q)
9320 return 0;
9321 return *q == '=';
9322}
9323
9324
Eric Andersencb57d552001-06-28 07:25:16 +00009325/*
9326 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9327 * valid parse tree indicating a blank line.)
9328 */
9329
Eric Andersenc470f442003-07-28 09:56:35 +00009330union node *
9331parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009332{
9333 int t;
9334
9335 tokpushback = 0;
9336 doprompt = interact;
9337 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009338 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009339 needprompt = 0;
9340 t = readtoken();
9341 if (t == TEOF)
9342 return NEOF;
9343 if (t == TNL)
9344 return NULL;
9345 tokpushback++;
9346 return list(1);
9347}
9348
9349
Eric Andersenc470f442003-07-28 09:56:35 +00009350static union node *
9351list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009352{
9353 union node *n1, *n2, *n3;
9354 int tok;
9355
Eric Andersenc470f442003-07-28 09:56:35 +00009356 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9357 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009358 return NULL;
9359 n1 = NULL;
9360 for (;;) {
9361 n2 = andor();
9362 tok = readtoken();
9363 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009364 if (n2->type == NPIPE) {
9365 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009366 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009367 if (n2->type != NREDIR) {
9368 n3 = stalloc(sizeof(struct nredir));
9369 n3->nredir.n = n2;
9370 n3->nredir.redirect = NULL;
9371 n2 = n3;
9372 }
9373 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009374 }
9375 }
9376 if (n1 == NULL) {
9377 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009378 }
9379 else {
9380 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009381 n3->type = NSEMI;
9382 n3->nbinary.ch1 = n1;
9383 n3->nbinary.ch2 = n2;
9384 n1 = n3;
9385 }
9386 switch (tok) {
9387 case TBACKGND:
9388 case TSEMI:
9389 tok = readtoken();
9390 /* fall through */
9391 case TNL:
9392 if (tok == TNL) {
9393 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009394 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009395 return n1;
9396 } else {
9397 tokpushback++;
9398 }
Eric Andersenc470f442003-07-28 09:56:35 +00009399 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009400 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009401 return n1;
9402 break;
9403 case TEOF:
9404 if (heredoclist)
9405 parseheredoc();
9406 else
Eric Andersenc470f442003-07-28 09:56:35 +00009407 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009408 return n1;
9409 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009410 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009411 synexpect(-1);
9412 tokpushback++;
9413 return n1;
9414 }
9415 }
9416}
9417
9418
9419
Eric Andersenc470f442003-07-28 09:56:35 +00009420static union node *
9421andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009422{
Eric Andersencb57d552001-06-28 07:25:16 +00009423 union node *n1, *n2, *n3;
9424 int t;
9425
Eric Andersencb57d552001-06-28 07:25:16 +00009426 n1 = pipeline();
9427 for (;;) {
9428 if ((t = readtoken()) == TAND) {
9429 t = NAND;
9430 } else if (t == TOR) {
9431 t = NOR;
9432 } else {
9433 tokpushback++;
9434 return n1;
9435 }
Eric Andersenc470f442003-07-28 09:56:35 +00009436 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009437 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009438 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009439 n3->type = t;
9440 n3->nbinary.ch1 = n1;
9441 n3->nbinary.ch2 = n2;
9442 n1 = n3;
9443 }
9444}
9445
9446
9447
Eric Andersenc470f442003-07-28 09:56:35 +00009448static union node *
9449pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009450{
Eric Andersencb57d552001-06-28 07:25:16 +00009451 union node *n1, *n2, *pipenode;
9452 struct nodelist *lp, *prev;
9453 int negate;
9454
9455 negate = 0;
9456 TRACE(("pipeline: entered\n"));
9457 if (readtoken() == TNOT) {
9458 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009459 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009460 } else
9461 tokpushback++;
9462 n1 = command();
9463 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009464 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009465 pipenode->type = NPIPE;
9466 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009467 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009468 pipenode->npipe.cmdlist = lp;
9469 lp->n = n1;
9470 do {
9471 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009472 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9473 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009474 lp->n = command();
9475 prev->next = lp;
9476 } while (readtoken() == TPIPE);
9477 lp->next = NULL;
9478 n1 = pipenode;
9479 }
9480 tokpushback++;
9481 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009482 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009483 n2->type = NNOT;
9484 n2->nnot.com = n1;
9485 return n2;
9486 } else
9487 return n1;
9488}
9489
9490
9491
Eric Andersenc470f442003-07-28 09:56:35 +00009492static union node *
9493command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009494{
Eric Andersencb57d552001-06-28 07:25:16 +00009495 union node *n1, *n2;
9496 union node *ap, **app;
9497 union node *cp, **cpp;
9498 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009499 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009500 int t;
9501
9502 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009503 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009504
Eric Andersencb57d552001-06-28 07:25:16 +00009505 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009506 default:
9507 synexpect(-1);
9508 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009509 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009510 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009511 n1->type = NIF;
9512 n1->nif.test = list(0);
9513 if (readtoken() != TTHEN)
9514 synexpect(TTHEN);
9515 n1->nif.ifpart = list(0);
9516 n2 = n1;
9517 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009518 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009519 n2 = n2->nif.elsepart;
9520 n2->type = NIF;
9521 n2->nif.test = list(0);
9522 if (readtoken() != TTHEN)
9523 synexpect(TTHEN);
9524 n2->nif.ifpart = list(0);
9525 }
9526 if (lasttoken == TELSE)
9527 n2->nif.elsepart = list(0);
9528 else {
9529 n2->nif.elsepart = NULL;
9530 tokpushback++;
9531 }
Eric Andersenc470f442003-07-28 09:56:35 +00009532 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009533 break;
9534 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009535 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009536 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009537 n1 = (union node *)stalloc(sizeof (struct nbinary));
9538 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009539 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009540 if ((got=readtoken()) != TDO) {
9541TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009542 synexpect(TDO);
9543 }
9544 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009545 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009546 break;
9547 }
9548 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009549 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009550 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009551 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009552 n1->type = NFOR;
9553 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009554 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009555 if (readtoken() == TIN) {
9556 app = &ap;
9557 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009558 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009559 n2->type = NARG;
9560 n2->narg.text = wordtext;
9561 n2->narg.backquote = backquotelist;
9562 *app = n2;
9563 app = &n2->narg.next;
9564 }
9565 *app = NULL;
9566 n1->nfor.args = ap;
9567 if (lasttoken != TNL && lasttoken != TSEMI)
9568 synexpect(-1);
9569 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009570 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009571 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009572 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009573 n2->narg.backquote = NULL;
9574 n2->narg.next = NULL;
9575 n1->nfor.args = n2;
9576 /*
9577 * Newline or semicolon here is optional (but note
9578 * that the original Bourne shell only allowed NL).
9579 */
9580 if (lasttoken != TNL && lasttoken != TSEMI)
9581 tokpushback++;
9582 }
Eric Andersenc470f442003-07-28 09:56:35 +00009583 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009584 if (readtoken() != TDO)
9585 synexpect(TDO);
9586 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009587 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009588 break;
9589 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009590 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009591 n1->type = NCASE;
9592 if (readtoken() != TWORD)
9593 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009594 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009595 n2->type = NARG;
9596 n2->narg.text = wordtext;
9597 n2->narg.backquote = backquotelist;
9598 n2->narg.next = NULL;
9599 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009600 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009601 } while (readtoken() == TNL);
9602 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009603 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009604 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009605next_case:
9606 checkkwd = CHKNL | CHKKWD;
9607 t = readtoken();
9608 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009609 if (lasttoken == TLP)
9610 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009611 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009612 cp->type = NCLIST;
9613 app = &cp->nclist.pattern;
9614 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009615 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009616 ap->type = NARG;
9617 ap->narg.text = wordtext;
9618 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009619 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009620 break;
9621 app = &ap->narg.next;
9622 readtoken();
9623 }
9624 ap->narg.next = NULL;
9625 if (lasttoken != TRP)
9626 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009627 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009628
Eric Andersenc470f442003-07-28 09:56:35 +00009629 cpp = &cp->nclist.next;
9630
9631 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009632 if ((t = readtoken()) != TESAC) {
9633 if (t != TENDCASE)
9634 synexpect(TENDCASE);
9635 else
Eric Andersenc470f442003-07-28 09:56:35 +00009636 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009637 }
Eric Andersenc470f442003-07-28 09:56:35 +00009638 }
Eric Andersencb57d552001-06-28 07:25:16 +00009639 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009640 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009641 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009642 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009643 n1->type = NSUBSHELL;
9644 n1->nredir.n = list(0);
9645 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009646 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009647 break;
9648 case TBEGIN:
9649 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009650 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009651 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009652 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009653 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009654 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009655 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009656 }
9657
Eric Andersenc470f442003-07-28 09:56:35 +00009658 if (readtoken() != t)
9659 synexpect(t);
9660
9661redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009662 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009663 checkkwd = CHKKWD | CHKALIAS;
9664 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009665 while (readtoken() == TREDIR) {
9666 *rpp = n2 = redirnode;
9667 rpp = &n2->nfile.next;
9668 parsefname();
9669 }
9670 tokpushback++;
9671 *rpp = NULL;
9672 if (redir) {
9673 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009674 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009675 n2->type = NREDIR;
9676 n2->nredir.n = n1;
9677 n1 = n2;
9678 }
9679 n1->nredir.redirect = redir;
9680 }
9681
9682 return n1;
9683}
9684
9685
Eric Andersenc470f442003-07-28 09:56:35 +00009686static union node *
9687simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009688 union node *args, **app;
9689 union node *n = NULL;
9690 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009691 union node **rpp, *redir;
9692 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009693
9694 args = NULL;
9695 app = &args;
9696 vars = NULL;
9697 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009698 redir = NULL;
9699 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009700
Eric Andersenc470f442003-07-28 09:56:35 +00009701 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009702 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009703 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009704 switch (readtoken()) {
9705 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009706 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009707 n->type = NARG;
9708 n->narg.text = wordtext;
9709 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009710 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009711 *vpp = n;
9712 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009713 } else {
9714 *app = n;
9715 app = &n->narg.next;
9716 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009717 }
9718 break;
9719 case TREDIR:
9720 *rpp = n = redirnode;
9721 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009722 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009723 break;
9724 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009725 if (
9726 args && app == &args->narg.next &&
9727 !vars && !redir
9728 ) {
9729 struct builtincmd *bcmd;
9730 const char *name;
9731
Eric Andersencb57d552001-06-28 07:25:16 +00009732 /* We have a function */
9733 if (readtoken() != TRP)
9734 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009735 name = n->narg.text;
9736 if (
9737 !goodname(name) || (
9738 (bcmd = find_builtin(name)) &&
9739 IS_BUILTIN_SPECIAL(bcmd)
9740 )
9741 )
9742 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009743 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009744 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009745 n->narg.next = command();
9746 return n;
9747 }
9748 /* fall through */
9749 default:
9750 tokpushback++;
9751 goto out;
9752 }
9753 }
Eric Andersenc470f442003-07-28 09:56:35 +00009754out:
Eric Andersencb57d552001-06-28 07:25:16 +00009755 *app = NULL;
9756 *vpp = NULL;
9757 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009758 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009759 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009760 n->ncmd.args = args;
9761 n->ncmd.assign = vars;
9762 n->ncmd.redirect = redir;
9763 return n;
9764}
9765
Eric Andersenc470f442003-07-28 09:56:35 +00009766static union node *
9767makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009768{
Eric Andersencb57d552001-06-28 07:25:16 +00009769 union node *n;
9770
Eric Andersenc470f442003-07-28 09:56:35 +00009771 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009772 n->type = NARG;
9773 n->narg.next = NULL;
9774 n->narg.text = wordtext;
9775 n->narg.backquote = backquotelist;
9776 return n;
9777}
9778
Eric Andersenc470f442003-07-28 09:56:35 +00009779void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009780{
Eric Andersencb57d552001-06-28 07:25:16 +00009781 TRACE(("Fix redir %s %d\n", text, err));
9782 if (!err)
9783 n->ndup.vname = NULL;
9784
9785 if (is_digit(text[0]) && text[1] == '\0')
9786 n->ndup.dupfd = digit_val(text[0]);
9787 else if (text[0] == '-' && text[1] == '\0')
9788 n->ndup.dupfd = -1;
9789 else {
9790
9791 if (err)
9792 synerror("Bad fd number");
9793 else
9794 n->ndup.vname = makename();
9795 }
9796}
9797
9798
Eric Andersenc470f442003-07-28 09:56:35 +00009799static void
9800parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009801{
Eric Andersencb57d552001-06-28 07:25:16 +00009802 union node *n = redirnode;
9803
9804 if (readtoken() != TWORD)
9805 synexpect(-1);
9806 if (n->type == NHERE) {
9807 struct heredoc *here = heredoc;
9808 struct heredoc *p;
9809 int i;
9810
9811 if (quoteflag == 0)
9812 n->type = NXHERE;
9813 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009814 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009815 synerror("Illegal eof marker for << redirection");
9816 rmescapes(wordtext);
9817 here->eofmark = wordtext;
9818 here->next = NULL;
9819 if (heredoclist == NULL)
9820 heredoclist = here;
9821 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009822 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009823 p->next = here;
9824 }
9825 } else if (n->type == NTOFD || n->type == NFROMFD) {
9826 fixredir(n, wordtext, 0);
9827 } else {
9828 n->nfile.fname = makename();
9829 }
9830}
9831
9832
9833/*
9834 * Input any here documents.
9835 */
9836
Eric Andersenc470f442003-07-28 09:56:35 +00009837static void
9838parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009839{
Eric Andersencb57d552001-06-28 07:25:16 +00009840 struct heredoc *here;
9841 union node *n;
9842
Eric Andersenc470f442003-07-28 09:56:35 +00009843 here = heredoclist;
9844 heredoclist = 0;
9845
9846 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009847 if (needprompt) {
9848 setprompt(2);
9849 needprompt = 0;
9850 }
Eric Andersenc470f442003-07-28 09:56:35 +00009851 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9852 here->eofmark, here->striptabs);
9853 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009854 n->narg.type = NARG;
9855 n->narg.next = NULL;
9856 n->narg.text = wordtext;
9857 n->narg.backquote = backquotelist;
9858 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009859 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009860 }
9861}
9862
Eric Andersenc470f442003-07-28 09:56:35 +00009863static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009864{
Eric Andersencb57d552001-06-28 07:25:16 +00009865 int t;
9866
9867 t = readtoken();
9868 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009869 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009870}
9871
Eric Andersenc470f442003-07-28 09:56:35 +00009872static int
9873readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009874{
Eric Andersencb57d552001-06-28 07:25:16 +00009875 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009876#ifdef DEBUG
9877 int alreadyseen = tokpushback;
9878#endif
9879
Eric Andersend35c5df2002-01-09 15:37:36 +00009880#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009881top:
Eric Andersen2870d962001-07-02 17:27:21 +00009882#endif
9883
Eric Andersencb57d552001-06-28 07:25:16 +00009884 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009885
Eric Andersenc470f442003-07-28 09:56:35 +00009886 /*
9887 * eat newlines
9888 */
9889 if (checkkwd & CHKNL) {
9890 while (t == TNL) {
9891 parseheredoc();
9892 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009893 }
9894 }
9895
Eric Andersenc470f442003-07-28 09:56:35 +00009896 if (t != TWORD || quoteflag) {
9897 goto out;
9898 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009899
Eric Andersenc470f442003-07-28 09:56:35 +00009900 /*
9901 * check for keywords
9902 */
9903 if (checkkwd & CHKKWD) {
9904 const char *const *pp;
9905
9906 if ((pp = findkwd(wordtext))) {
9907 lasttoken = t = pp - tokname_array;
9908 TRACE(("keyword %s recognized\n", tokname(t)));
9909 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009910 }
Eric Andersenc470f442003-07-28 09:56:35 +00009911 }
9912
9913 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009914#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009915 struct alias *ap;
9916 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009917 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009918 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009919 }
Eric Andersencb57d552001-06-28 07:25:16 +00009920 goto top;
9921 }
Eric Andersen2870d962001-07-02 17:27:21 +00009922#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009923 }
Eric Andersenc470f442003-07-28 09:56:35 +00009924out:
9925 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009926#ifdef DEBUG
9927 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009928 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009929 else
Eric Andersenc470f442003-07-28 09:56:35 +00009930 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009931#endif
9932 return (t);
9933}
9934
9935
9936/*
9937 * Read the next input token.
9938 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009939 * backquotes. We set quoteflag to true if any part of the word was
9940 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009941 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009942 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009943 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009944 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009945 *
9946 * [Change comment: here documents and internal procedures]
9947 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9948 * word parsing code into a separate routine. In this case, readtoken
9949 * doesn't need to have any internal procedures, but parseword does.
9950 * We could also make parseoperator in essence the main routine, and
9951 * have parseword (readtoken1?) handle both words and redirection.]
9952 */
9953
Eric Andersen81fe1232003-07-29 06:38:40 +00009954#define NEW_xxreadtoken
9955#ifdef NEW_xxreadtoken
9956
9957/* singles must be first! */
9958static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9959
9960static const char xxreadtoken_tokens[] = {
9961 TNL, TLP, TRP, /* only single occurrence allowed */
9962 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9963 TEOF, /* corresponds to trailing nul */
9964 TAND, TOR, TENDCASE, /* if double occurrence */
9965};
9966
9967#define xxreadtoken_doubles \
9968 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9969#define xxreadtoken_singles \
9970 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9971
9972static int xxreadtoken()
9973{
9974 int c;
9975
9976 if (tokpushback) {
9977 tokpushback = 0;
9978 return lasttoken;
9979 }
9980 if (needprompt) {
9981 setprompt(2);
9982 needprompt = 0;
9983 }
9984 startlinno = plinno;
9985 for (;;) { /* until token or start of word found */
9986 c = pgetc_macro();
9987
9988 if ((c != ' ') && (c != '\t')
9989#ifdef CONFIG_ASH_ALIAS
9990 && (c != PEOA)
9991#endif
9992 ) {
9993 if (c == '#') {
9994 while ((c = pgetc()) != '\n' && c != PEOF);
9995 pungetc();
9996 } else if (c == '\\') {
9997 if (pgetc() != '\n') {
9998 pungetc();
9999 goto READTOKEN1;
10000 }
10001 startlinno = ++plinno;
10002 if (doprompt)
10003 setprompt(2);
10004 } else {
10005 const char *p
10006 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10007
10008 if (c != PEOF) {
10009 if (c == '\n') {
10010 plinno++;
10011 needprompt = doprompt;
10012 }
10013
10014 p = strchr(xxreadtoken_chars, c);
10015 if (p == NULL) {
10016 READTOKEN1:
10017 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10018 }
10019
10020 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10021 if (pgetc() == *p) { /* double occurrence? */
10022 p += xxreadtoken_doubles + 1;
10023 } else {
10024 pungetc();
10025 }
10026 }
10027 }
10028
10029 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10030 }
10031 }
10032 }
10033}
10034
10035
10036#else
Eric Andersen2870d962001-07-02 17:27:21 +000010037#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010038
Eric Andersenc470f442003-07-28 09:56:35 +000010039static int
10040xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010041{
Eric Andersencb57d552001-06-28 07:25:16 +000010042 int c;
10043
10044 if (tokpushback) {
10045 tokpushback = 0;
10046 return lasttoken;
10047 }
10048 if (needprompt) {
10049 setprompt(2);
10050 needprompt = 0;
10051 }
10052 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010053 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010054 c = pgetc_macro();
10055 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010056 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010057#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010058 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010059#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010060 continue;
10061 case '#':
10062 while ((c = pgetc()) != '\n' && c != PEOF);
10063 pungetc();
10064 continue;
10065 case '\\':
10066 if (pgetc() == '\n') {
10067 startlinno = ++plinno;
10068 if (doprompt)
10069 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010070 continue;
10071 }
10072 pungetc();
10073 goto breakloop;
10074 case '\n':
10075 plinno++;
10076 needprompt = doprompt;
10077 RETURN(TNL);
10078 case PEOF:
10079 RETURN(TEOF);
10080 case '&':
10081 if (pgetc() == '&')
10082 RETURN(TAND);
10083 pungetc();
10084 RETURN(TBACKGND);
10085 case '|':
10086 if (pgetc() == '|')
10087 RETURN(TOR);
10088 pungetc();
10089 RETURN(TPIPE);
10090 case ';':
10091 if (pgetc() == ';')
10092 RETURN(TENDCASE);
10093 pungetc();
10094 RETURN(TSEMI);
10095 case '(':
10096 RETURN(TLP);
10097 case ')':
10098 RETURN(TRP);
10099 default:
10100 goto breakloop;
10101 }
10102 }
Eric Andersenc470f442003-07-28 09:56:35 +000010103breakloop:
10104 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010105#undef RETURN
10106}
Eric Andersen81fe1232003-07-29 06:38:40 +000010107#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010108
Eric Andersencb57d552001-06-28 07:25:16 +000010109
Eric Andersencb57d552001-06-28 07:25:16 +000010110/*
10111 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10112 * is not NULL, read a here document. In the latter case, eofmark is the
10113 * word which marks the end of the document and striptabs is true if
10114 * leading tabs should be stripped from the document. The argument firstc
10115 * is the first character of the input token or document.
10116 *
10117 * Because C does not have internal subroutines, I have simulated them
10118 * using goto's to implement the subroutine linkage. The following macros
10119 * will run code that appears at the end of readtoken1.
10120 */
10121
Eric Andersen2870d962001-07-02 17:27:21 +000010122#define CHECKEND() {goto checkend; checkend_return:;}
10123#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10124#define PARSESUB() {goto parsesub; parsesub_return:;}
10125#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10126#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10127#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010128
10129static int
Eric Andersenc470f442003-07-28 09:56:35 +000010130readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010131{
Eric Andersencb57d552001-06-28 07:25:16 +000010132 int c = firstc;
10133 char *out;
10134 int len;
10135 char line[EOFMARKLEN + 1];
10136 struct nodelist *bqlist;
10137 int quotef;
10138 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010139 int varnest; /* levels of variables expansion */
10140 int arinest; /* levels of arithmetic expansion */
10141 int parenlevel; /* levels of parens in arithmetic */
10142 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010143 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010144 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010145#if __GNUC__
10146 /* Avoid longjmp clobbering */
10147 (void) &out;
10148 (void) &quotef;
10149 (void) &dblquote;
10150 (void) &varnest;
10151 (void) &arinest;
10152 (void) &parenlevel;
10153 (void) &dqvarnest;
10154 (void) &oldstyle;
10155 (void) &prevsyntax;
10156 (void) &syntax;
10157#endif
10158
10159 startlinno = plinno;
10160 dblquote = 0;
10161 if (syntax == DQSYNTAX)
10162 dblquote = 1;
10163 quotef = 0;
10164 bqlist = NULL;
10165 varnest = 0;
10166 arinest = 0;
10167 parenlevel = 0;
10168 dqvarnest = 0;
10169
10170 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010171 loop: { /* for each line, until end of word */
10172 CHECKEND(); /* set c to PEOF if at end of here document */
10173 for (;;) { /* until end of line or end of word */
10174 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10175 switch(SIT(c, syntax)) {
10176 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010177 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010178 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010179 USTPUTC(c, out);
10180 plinno++;
10181 if (doprompt)
10182 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010183 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010184 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010185 case CWORD:
10186 USTPUTC(c, out);
10187 break;
10188 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010189 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010190 USTPUTC(CTLESC, out);
10191 USTPUTC(c, out);
10192 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010193 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010194 c = pgetc2();
10195 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010196 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010197 USTPUTC('\\', out);
10198 pungetc();
10199 } else if (c == '\n') {
10200 if (doprompt)
10201 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010202 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010203 if (
10204 dblquote &&
10205 c != '\\' && c != '`' &&
10206 c != '$' && (
10207 c != '"' ||
10208 eofmark != NULL
10209 )
10210 ) {
10211 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010212 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010213 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010214 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010215 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010216 USTPUTC(c, out);
10217 quotef++;
10218 }
10219 break;
10220 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010221 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010222quotemark:
10223 if (eofmark == NULL) {
10224 USTPUTC(CTLQUOTEMARK, out);
10225 }
Eric Andersencb57d552001-06-28 07:25:16 +000010226 break;
10227 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010228 syntax = DQSYNTAX;
10229 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010230 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010231 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010232 if (eofmark != NULL && arinest == 0 &&
10233 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010234 USTPUTC(c, out);
10235 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010236 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010237 syntax = BASESYNTAX;
10238 dblquote = 0;
10239 }
10240 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010241 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010242 }
10243 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010244 case CVAR: /* '$' */
10245 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010246 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010247 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010248 if (varnest > 0) {
10249 varnest--;
10250 if (dqvarnest > 0) {
10251 dqvarnest--;
10252 }
10253 USTPUTC(CTLENDVAR, out);
10254 } else {
10255 USTPUTC(c, out);
10256 }
10257 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010258#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010259 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010260 parenlevel++;
10261 USTPUTC(c, out);
10262 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010263 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010264 if (parenlevel > 0) {
10265 USTPUTC(c, out);
10266 --parenlevel;
10267 } else {
10268 if (pgetc() == ')') {
10269 if (--arinest == 0) {
10270 USTPUTC(CTLENDARI, out);
10271 syntax = prevsyntax;
10272 if (syntax == DQSYNTAX)
10273 dblquote = 1;
10274 else
10275 dblquote = 0;
10276 } else
10277 USTPUTC(')', out);
10278 } else {
10279 /*
10280 * unbalanced parens
10281 * (don't 2nd guess - no error)
10282 */
10283 pungetc();
10284 USTPUTC(')', out);
10285 }
10286 }
10287 break;
10288#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010289 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010290 PARSEBACKQOLD();
10291 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010292 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010293 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010294 case CIGN:
10295 break;
10296 default:
10297 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010298 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010299#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010300 if (c != PEOA)
10301#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010302 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010303
Eric Andersencb57d552001-06-28 07:25:16 +000010304 }
10305 c = pgetc_macro();
10306 }
10307 }
Eric Andersenc470f442003-07-28 09:56:35 +000010308endword:
10309#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010310 if (syntax == ARISYNTAX)
10311 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010312#endif
10313 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010314 synerror("Unterminated quoted string");
10315 if (varnest != 0) {
10316 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010317 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010318 synerror("Missing '}'");
10319 }
10320 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010321 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010322 out = stackblock();
10323 if (eofmark == NULL) {
10324 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010325 && quotef == 0
10326 && len <= 2
10327 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010328 PARSEREDIR();
10329 return lasttoken = TREDIR;
10330 } else {
10331 pungetc();
10332 }
10333 }
10334 quoteflag = quotef;
10335 backquotelist = bqlist;
10336 grabstackblock(len);
10337 wordtext = out;
10338 return lasttoken = TWORD;
10339/* end of readtoken routine */
10340
10341
10342
10343/*
10344 * Check to see whether we are at the end of the here document. When this
10345 * is called, c is set to the first character of the next input line. If
10346 * we are at the end of the here document, this routine sets the c to PEOF.
10347 */
10348
Eric Andersenc470f442003-07-28 09:56:35 +000010349checkend: {
10350 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010351#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010352 if (c == PEOA) {
10353 c = pgetc2();
10354 }
10355#endif
10356 if (striptabs) {
10357 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010358 c = pgetc2();
10359 }
Eric Andersenc470f442003-07-28 09:56:35 +000010360 }
10361 if (c == *eofmark) {
10362 if (pfgets(line, sizeof line) != NULL) {
10363 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010364
Eric Andersenc470f442003-07-28 09:56:35 +000010365 p = line;
10366 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10367 if (*p == '\n' && *q == '\0') {
10368 c = PEOF;
10369 plinno++;
10370 needprompt = doprompt;
10371 } else {
10372 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010373 }
10374 }
10375 }
10376 }
Eric Andersenc470f442003-07-28 09:56:35 +000010377 goto checkend_return;
10378}
Eric Andersencb57d552001-06-28 07:25:16 +000010379
10380
10381/*
10382 * Parse a redirection operator. The variable "out" points to a string
10383 * specifying the fd to be redirected. The variable "c" contains the
10384 * first character of the redirection operator.
10385 */
10386
Eric Andersenc470f442003-07-28 09:56:35 +000010387parseredir: {
10388 char fd = *out;
10389 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010390
Eric Andersenc470f442003-07-28 09:56:35 +000010391 np = (union node *)stalloc(sizeof (struct nfile));
10392 if (c == '>') {
10393 np->nfile.fd = 1;
10394 c = pgetc();
10395 if (c == '>')
10396 np->type = NAPPEND;
10397 else if (c == '|')
10398 np->type = NCLOBBER;
10399 else if (c == '&')
10400 np->type = NTOFD;
10401 else {
10402 np->type = NTO;
10403 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010404 }
Eric Andersenc470f442003-07-28 09:56:35 +000010405 } else { /* c == '<' */
10406 np->nfile.fd = 0;
10407 switch (c = pgetc()) {
10408 case '<':
10409 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10410 np = (union node *)stalloc(sizeof (struct nhere));
10411 np->nfile.fd = 0;
10412 }
10413 np->type = NHERE;
10414 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10415 heredoc->here = np;
10416 if ((c = pgetc()) == '-') {
10417 heredoc->striptabs = 1;
10418 } else {
10419 heredoc->striptabs = 0;
10420 pungetc();
10421 }
10422 break;
10423
10424 case '&':
10425 np->type = NFROMFD;
10426 break;
10427
10428 case '>':
10429 np->type = NFROMTO;
10430 break;
10431
10432 default:
10433 np->type = NFROM;
10434 pungetc();
10435 break;
10436 }
Eric Andersencb57d552001-06-28 07:25:16 +000010437 }
Eric Andersenc470f442003-07-28 09:56:35 +000010438 if (fd != '\0')
10439 np->nfile.fd = digit_val(fd);
10440 redirnode = np;
10441 goto parseredir_return;
10442}
Eric Andersencb57d552001-06-28 07:25:16 +000010443
10444
10445/*
10446 * Parse a substitution. At this point, we have read the dollar sign
10447 * and nothing else.
10448 */
10449
Eric Andersenc470f442003-07-28 09:56:35 +000010450parsesub: {
10451 int subtype;
10452 int typeloc;
10453 int flags;
10454 char *p;
10455 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010456
Eric Andersenc470f442003-07-28 09:56:35 +000010457 c = pgetc();
10458 if (
10459 c <= PEOA_OR_PEOF ||
10460 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10461 ) {
10462 USTPUTC('$', out);
10463 pungetc();
10464 } else if (c == '(') { /* $(command) or $((arith)) */
10465 if (pgetc() == '(') {
10466#ifdef CONFIG_ASH_MATH_SUPPORT
10467 PARSEARITH();
10468#else
10469 synerror("We unsupport $((arith))");
10470#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010471 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010472 pungetc();
10473 PARSEBACKQNEW();
10474 }
10475 } else {
10476 USTPUTC(CTLVAR, out);
10477 typeloc = out - (char *)stackblock();
10478 USTPUTC(VSNORMAL, out);
10479 subtype = VSNORMAL;
10480 if (c == '{') {
10481 c = pgetc();
10482 if (c == '#') {
10483 if ((c = pgetc()) == '}')
10484 c = '#';
10485 else
10486 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010487 }
Eric Andersenc470f442003-07-28 09:56:35 +000010488 else
10489 subtype = 0;
10490 }
10491 if (c > PEOA_OR_PEOF && is_name(c)) {
10492 do {
10493 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010494 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010495 } while (c > PEOA_OR_PEOF && is_in_name(c));
10496 } else if (is_digit(c)) {
10497 do {
10498 STPUTC(c, out);
10499 c = pgetc();
10500 } while (is_digit(c));
10501 }
10502 else if (is_special(c)) {
10503 USTPUTC(c, out);
10504 c = pgetc();
10505 }
10506 else
10507badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010508
Eric Andersenc470f442003-07-28 09:56:35 +000010509 STPUTC('=', out);
10510 flags = 0;
10511 if (subtype == 0) {
10512 switch (c) {
10513 case ':':
10514 flags = VSNUL;
10515 c = pgetc();
10516 /*FALLTHROUGH*/
10517 default:
10518 p = strchr(types, c);
10519 if (p == NULL)
10520 goto badsub;
10521 subtype = p - types + VSNORMAL;
10522 break;
10523 case '%':
10524 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010525 {
10526 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010527 subtype = c == '#' ? VSTRIMLEFT :
10528 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010529 c = pgetc();
10530 if (c == cc)
10531 subtype++;
10532 else
10533 pungetc();
10534 break;
10535 }
10536 }
Eric Andersenc470f442003-07-28 09:56:35 +000010537 } else {
10538 pungetc();
10539 }
10540 if (dblquote || arinest)
10541 flags |= VSQUOTE;
10542 *((char *)stackblock() + typeloc) = subtype | flags;
10543 if (subtype != VSNORMAL) {
10544 varnest++;
10545 if (dblquote || arinest) {
10546 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010547 }
10548 }
10549 }
Eric Andersenc470f442003-07-28 09:56:35 +000010550 goto parsesub_return;
10551}
Eric Andersencb57d552001-06-28 07:25:16 +000010552
10553
10554/*
10555 * Called to parse command substitutions. Newstyle is set if the command
10556 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10557 * list of commands (passed by reference), and savelen is the number of
10558 * characters on the top of the stack which must be preserved.
10559 */
10560
Eric Andersenc470f442003-07-28 09:56:35 +000010561parsebackq: {
10562 struct nodelist **nlpp;
10563 int savepbq;
10564 union node *n;
10565 char *volatile str;
10566 struct jmploc jmploc;
10567 struct jmploc *volatile savehandler;
10568 size_t savelen;
10569 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010570#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010571 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010572#endif
10573
Eric Andersenc470f442003-07-28 09:56:35 +000010574 savepbq = parsebackquote;
10575 if (setjmp(jmploc.loc)) {
10576 if (str)
10577 ckfree(str);
10578 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010579 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010580 longjmp(handler->loc, 1);
10581 }
10582 INTOFF;
10583 str = NULL;
10584 savelen = out - (char *)stackblock();
10585 if (savelen > 0) {
10586 str = ckmalloc(savelen);
10587 memcpy(str, stackblock(), savelen);
10588 }
10589 savehandler = handler;
10590 handler = &jmploc;
10591 INTON;
10592 if (oldstyle) {
10593 /* We must read until the closing backquote, giving special
10594 treatment to some slashes, and then push the string and
10595 reread it as input, interpreting it normally. */
10596 char *pout;
10597 int pc;
10598 size_t psavelen;
10599 char *pstr;
10600
10601
10602 STARTSTACKSTR(pout);
10603 for (;;) {
10604 if (needprompt) {
10605 setprompt(2);
10606 needprompt = 0;
10607 }
10608 switch (pc = pgetc()) {
10609 case '`':
10610 goto done;
10611
10612 case '\\':
10613 if ((pc = pgetc()) == '\n') {
10614 plinno++;
10615 if (doprompt)
10616 setprompt(2);
10617 /*
10618 * If eating a newline, avoid putting
10619 * the newline into the new character
10620 * stream (via the STPUTC after the
10621 * switch).
10622 */
10623 continue;
10624 }
10625 if (pc != '\\' && pc != '`' && pc != '$'
10626 && (!dblquote || pc != '"'))
10627 STPUTC('\\', pout);
10628 if (pc > PEOA_OR_PEOF) {
10629 break;
10630 }
10631 /* fall through */
10632
10633 case PEOF:
10634#ifdef CONFIG_ASH_ALIAS
10635 case PEOA:
10636#endif
10637 startlinno = plinno;
10638 synerror("EOF in backquote substitution");
10639
10640 case '\n':
10641 plinno++;
10642 needprompt = doprompt;
10643 break;
10644
10645 default:
10646 break;
10647 }
10648 STPUTC(pc, pout);
10649 }
10650done:
10651 STPUTC('\0', pout);
10652 psavelen = pout - (char *)stackblock();
10653 if (psavelen > 0) {
10654 pstr = grabstackstr(pout);
10655 setinputstring(pstr);
10656 }
10657 }
10658 nlpp = &bqlist;
10659 while (*nlpp)
10660 nlpp = &(*nlpp)->next;
10661 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10662 (*nlpp)->next = NULL;
10663 parsebackquote = oldstyle;
10664
10665 if (oldstyle) {
10666 saveprompt = doprompt;
10667 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010668 }
10669
Eric Andersenc470f442003-07-28 09:56:35 +000010670 n = list(2);
10671
10672 if (oldstyle)
10673 doprompt = saveprompt;
10674 else {
10675 if (readtoken() != TRP)
10676 synexpect(TRP);
10677 }
10678
10679 (*nlpp)->n = n;
10680 if (oldstyle) {
10681 /*
10682 * Start reading from old file again, ignoring any pushed back
10683 * tokens left from the backquote parsing
10684 */
10685 popfile();
10686 tokpushback = 0;
10687 }
10688 while (stackblocksize() <= savelen)
10689 growstackblock();
10690 STARTSTACKSTR(out);
10691 if (str) {
10692 memcpy(out, str, savelen);
10693 STADJUST(savelen, out);
10694 INTOFF;
10695 ckfree(str);
10696 str = NULL;
10697 INTON;
10698 }
10699 parsebackquote = savepbq;
10700 handler = savehandler;
10701 if (arinest || dblquote)
10702 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10703 else
10704 USTPUTC(CTLBACKQ, out);
10705 if (oldstyle)
10706 goto parsebackq_oldreturn;
10707 else
10708 goto parsebackq_newreturn;
10709}
10710
10711#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010712/*
10713 * Parse an arithmetic expansion (indicate start of one and set state)
10714 */
Eric Andersenc470f442003-07-28 09:56:35 +000010715parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010716
Eric Andersenc470f442003-07-28 09:56:35 +000010717 if (++arinest == 1) {
10718 prevsyntax = syntax;
10719 syntax = ARISYNTAX;
10720 USTPUTC(CTLARI, out);
10721 if (dblquote)
10722 USTPUTC('"',out);
10723 else
10724 USTPUTC(' ',out);
10725 } else {
10726 /*
10727 * we collapse embedded arithmetic expansion to
10728 * parenthesis, which should be equivalent
10729 */
10730 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010731 }
Eric Andersenc470f442003-07-28 09:56:35 +000010732 goto parsearith_return;
10733}
10734#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010735
Eric Andersenc470f442003-07-28 09:56:35 +000010736} /* end of readtoken */
10737
Eric Andersencb57d552001-06-28 07:25:16 +000010738
10739
Eric Andersencb57d552001-06-28 07:25:16 +000010740/*
10741 * Returns true if the text contains nothing to expand (no dollar signs
10742 * or backquotes).
10743 */
10744
Eric Andersenc470f442003-07-28 09:56:35 +000010745static int
10746noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010747{
Eric Andersencb57d552001-06-28 07:25:16 +000010748 char *p;
10749 char c;
10750
10751 p = text;
10752 while ((c = *p++) != '\0') {
10753 if (c == CTLQUOTEMARK)
10754 continue;
10755 if (c == CTLESC)
10756 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010757 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010758 return 0;
10759 }
10760 return 1;
10761}
10762
10763
10764/*
Eric Andersenc470f442003-07-28 09:56:35 +000010765 * Return of a legal variable name (a letter or underscore followed by zero or
10766 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010767 */
10768
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010769static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010770endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010771{
Eric Andersenc470f442003-07-28 09:56:35 +000010772 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010773
Eric Andersenc470f442003-07-28 09:56:35 +000010774 p = (char *) name;
10775 if (! is_name(*p))
10776 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010777 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010778 if (! is_in_name(*p))
10779 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010780 }
Eric Andersenc470f442003-07-28 09:56:35 +000010781 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010782}
10783
10784
10785/*
10786 * Called when an unexpected token is read during the parse. The argument
10787 * is the token that is expected, or -1 if more than one type of token can
10788 * occur at this point.
10789 */
10790
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010791static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010792{
10793 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010794 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010795
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010796 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10797 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010798 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010799 synerror(msg);
10800 /* NOTREACHED */
10801}
10802
Eric Andersenc470f442003-07-28 09:56:35 +000010803static void
10804synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010805{
Eric Andersenc470f442003-07-28 09:56:35 +000010806 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010807 /* NOTREACHED */
10808}
10809
Eric Andersencb57d552001-06-28 07:25:16 +000010810
10811/*
10812 * called by editline -- any expansions to the prompt
10813 * should be added here.
10814 */
Eric Andersenc470f442003-07-28 09:56:35 +000010815
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010816static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010817{
Eric Andersenc470f442003-07-28 09:56:35 +000010818 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010819
10820 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010821 case 1:
10822 prompt = ps1val();
10823 break;
10824 case 2:
10825 prompt = ps2val();
10826 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010827 default: /* 0 */
10828 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010829 }
10830 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010831}
10832
Eric Andersencb57d552001-06-28 07:25:16 +000010833
Eric Andersenc470f442003-07-28 09:56:35 +000010834static const char *const *findkwd(const char *s)
10835{
10836 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010837 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010838 sizeof(const char *), pstrcmp);
10839}
10840
10841/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10842
Eric Andersencb57d552001-06-28 07:25:16 +000010843/*
10844 * Code for dealing with input/output redirection.
10845 */
10846
Eric Andersenc470f442003-07-28 09:56:35 +000010847#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010848#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010849# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010850#else
10851# define PIPESIZE PIPE_BUF
10852#endif
10853
Eric Andersen62483552001-07-10 06:09:16 +000010854/*
10855 * Open a file in noclobber mode.
10856 * The code was copied from bash.
10857 */
Eric Andersenc470f442003-07-28 09:56:35 +000010858static inline int
10859noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010860{
10861 int r, fd;
10862 struct stat finfo, finfo2;
10863
10864 /*
10865 * If the file exists and is a regular file, return an error
10866 * immediately.
10867 */
10868 r = stat(fname, &finfo);
10869 if (r == 0 && S_ISREG(finfo.st_mode)) {
10870 errno = EEXIST;
10871 return -1;
10872 }
10873
10874 /*
10875 * If the file was not present (r != 0), make sure we open it
10876 * exclusively so that if it is created before we open it, our open
10877 * will fail. Make sure that we do not truncate an existing file.
10878 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10879 * file was not a regular file, we leave O_EXCL off.
10880 */
10881 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010882 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10883 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010884
10885 /* If the open failed, return the file descriptor right away. */
10886 if (fd < 0)
10887 return fd;
10888
10889 /*
10890 * OK, the open succeeded, but the file may have been changed from a
10891 * non-regular file to a regular file between the stat and the open.
10892 * We are assuming that the O_EXCL open handles the case where FILENAME
10893 * did not exist and is symlinked to an existing file between the stat
10894 * and open.
10895 */
10896
10897 /*
10898 * If we can open it and fstat the file descriptor, and neither check
10899 * revealed that it was a regular file, and the file has not been
10900 * replaced, return the file descriptor.
10901 */
Eric Andersenc470f442003-07-28 09:56:35 +000010902 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10903 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010904 return fd;
10905
10906 /* The file has been replaced. badness. */
10907 close(fd);
10908 errno = EEXIST;
10909 return -1;
10910}
Eric Andersencb57d552001-06-28 07:25:16 +000010911
10912/*
Eric Andersen62483552001-07-10 06:09:16 +000010913 * Handle here documents. Normally we fork off a process to write the
10914 * data to a pipe. If the document is short, we can stuff the data in
10915 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010916 */
10917
Eric Andersenc470f442003-07-28 09:56:35 +000010918static inline int
10919openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010920{
10921 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010922 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010923
Eric Andersen62483552001-07-10 06:09:16 +000010924 if (pipe(pip) < 0)
10925 error("Pipe call failed");
10926 if (redir->type == NHERE) {
10927 len = strlen(redir->nhere.doc->narg.text);
10928 if (len <= PIPESIZE) {
10929 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10930 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010931 }
Eric Andersencb57d552001-06-28 07:25:16 +000010932 }
Eric Andersenc470f442003-07-28 09:56:35 +000010933 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010934 close(pip[0]);
10935 signal(SIGINT, SIG_IGN);
10936 signal(SIGQUIT, SIG_IGN);
10937 signal(SIGHUP, SIG_IGN);
10938#ifdef SIGTSTP
10939 signal(SIGTSTP, SIG_IGN);
10940#endif
10941 signal(SIGPIPE, SIG_DFL);
10942 if (redir->type == NHERE)
10943 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10944 else
10945 expandhere(redir->nhere.doc, pip[1]);
10946 _exit(0);
10947 }
Eric Andersenc470f442003-07-28 09:56:35 +000010948out:
Eric Andersen62483552001-07-10 06:09:16 +000010949 close(pip[1]);
10950 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010951}
10952
Eric Andersenc470f442003-07-28 09:56:35 +000010953static int
10954openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010955{
Eric Andersencb57d552001-06-28 07:25:16 +000010956 char *fname;
10957 int f;
10958
10959 switch (redir->nfile.type) {
10960 case NFROM:
10961 fname = redir->nfile.expfname;
10962 if ((f = open(fname, O_RDONLY)) < 0)
10963 goto eopen;
10964 break;
10965 case NFROMTO:
10966 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010967 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010968 goto ecreate;
10969 break;
10970 case NTO:
10971 /* Take care of noclobber mode. */
10972 if (Cflag) {
10973 fname = redir->nfile.expfname;
10974 if ((f = noclobberopen(fname)) < 0)
10975 goto ecreate;
10976 break;
10977 }
Eric Andersenc470f442003-07-28 09:56:35 +000010978 /* FALLTHROUGH */
10979 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000010980 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010981 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010982 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010983 break;
10984 case NAPPEND:
10985 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010986 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010987 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010988 break;
10989 default:
10990#ifdef DEBUG
10991 abort();
10992#endif
10993 /* Fall through to eliminate warning. */
10994 case NTOFD:
10995 case NFROMFD:
10996 f = -1;
10997 break;
10998 case NHERE:
10999 case NXHERE:
11000 f = openhere(redir);
11001 break;
11002 }
11003
11004 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011005ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011006 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011007eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011008 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11009}
11010
Eric Andersenc470f442003-07-28 09:56:35 +000011011static inline void
11012dupredirect(union node *redir, int f)
11013{
11014 int fd = redir->nfile.fd;
11015
11016 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11017 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11018 copyfd(redir->ndup.dupfd, fd);
11019 }
11020 return;
11021 }
11022
11023 if (f != fd) {
11024 copyfd(f, fd);
11025 close(f);
11026 }
11027 return;
11028}
Eric Andersencb57d552001-06-28 07:25:16 +000011029
Eric Andersen62483552001-07-10 06:09:16 +000011030/*
11031 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11032 * old file descriptors are stashed away so that the redirection can be
11033 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11034 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011035 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011036 */
11037
Eric Andersenc470f442003-07-28 09:56:35 +000011038static void
11039redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011040{
11041 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011042 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011043 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011044 int fd;
11045 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011046 int *p;
11047 nullredirs++;
11048 if (!redir) {
11049 return;
Eric Andersen62483552001-07-10 06:09:16 +000011050 }
Eric Andersenc470f442003-07-28 09:56:35 +000011051 sv = NULL;
11052 INTOFF;
11053 if (flags & REDIR_PUSH) {
11054 struct redirtab *q;
11055 q = ckmalloc(sizeof (struct redirtab));
11056 q->next = redirlist;
11057 redirlist = q;
11058 q->nullredirs = nullredirs - 1;
11059 for (i = 0 ; i < 10 ; i++)
11060 q->renamed[i] = EMPTY;
11061 nullredirs = 0;
11062 sv = q;
11063 }
11064 n = redir;
11065 do {
Eric Andersen62483552001-07-10 06:09:16 +000011066 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011067 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011068 n->ndup.dupfd == fd)
11069 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011070
Eric Andersen62483552001-07-10 06:09:16 +000011071 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011072 if (fd == newfd)
11073 continue;
11074 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11075 i = fcntl(fd, F_DUPFD, 10);
11076
11077 if (i == -1) {
11078 i = errno;
11079 if (i != EBADF) {
11080 close(newfd);
11081 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011082 error("%d: %m", fd);
11083 /* NOTREACHED */
11084 }
Eric Andersenc470f442003-07-28 09:56:35 +000011085 } else {
11086 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011087 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011088 }
Eric Andersenc470f442003-07-28 09:56:35 +000011089 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011090 close(fd);
11091 }
Eric Andersenc470f442003-07-28 09:56:35 +000011092 dupredirect(n, newfd);
11093 } while ((n = n->nfile.next));
11094 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011095 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11096 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011097}
11098
11099
Eric Andersencb57d552001-06-28 07:25:16 +000011100/*
11101 * Undo the effects of the last redirection.
11102 */
11103
Eric Andersenc470f442003-07-28 09:56:35 +000011104void
11105popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011106{
Eric Andersenc470f442003-07-28 09:56:35 +000011107 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011108 int i;
11109
Eric Andersenc470f442003-07-28 09:56:35 +000011110 if (--nullredirs >= 0)
11111 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011112 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011113 rp = redirlist;
11114 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011115 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011116 if (!drop) {
11117 close(i);
11118 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011119 }
Eric Andersenc470f442003-07-28 09:56:35 +000011120 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011121 }
11122 }
11123 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011124 nullredirs = rp->nullredirs;
11125 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011126 INTON;
11127}
11128
11129/*
Eric Andersenc470f442003-07-28 09:56:35 +000011130 * Undo all redirections. Called on error or interrupt.
11131 */
11132
11133/*
Eric Andersencb57d552001-06-28 07:25:16 +000011134 * Discard all saved file descriptors.
11135 */
11136
Eric Andersenc470f442003-07-28 09:56:35 +000011137void
11138clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011139{
Eric Andersenc470f442003-07-28 09:56:35 +000011140 for (;;) {
11141 nullredirs = 0;
11142 if (!redirlist)
11143 break;
11144 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011145 }
Eric Andersencb57d552001-06-28 07:25:16 +000011146}
11147
11148
Eric Andersencb57d552001-06-28 07:25:16 +000011149/*
11150 * Copy a file descriptor to be >= to. Returns -1
11151 * if the source file descriptor is closed, EMPTY if there are no unused
11152 * file descriptors left.
11153 */
11154
Eric Andersenc470f442003-07-28 09:56:35 +000011155int
11156copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011157{
11158 int newfd;
11159
11160 newfd = fcntl(from, F_DUPFD, to);
11161 if (newfd < 0) {
11162 if (errno == EMFILE)
11163 return EMPTY;
11164 else
Eric Andersen2870d962001-07-02 17:27:21 +000011165 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011166 }
11167 return newfd;
11168}
11169
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011170
Eric Andersenc470f442003-07-28 09:56:35 +000011171int
11172redirectsafe(union node *redir, int flags)
11173{
11174 int err;
11175 volatile int saveint;
11176 struct jmploc *volatile savehandler = handler;
11177 struct jmploc jmploc;
11178
11179 SAVEINT(saveint);
11180 if (!(err = setjmp(jmploc.loc) * 2)) {
11181 handler = &jmploc;
11182 redirect(redir, flags);
11183 }
11184 handler = savehandler;
11185 if (err && exception != EXERROR)
11186 longjmp(handler->loc, 1);
11187 RESTOREINT(saveint);
11188 return err;
11189}
11190
11191/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11192
11193#ifdef DEBUG
11194static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011195static void shcmd(union node *, FILE *);
11196static void sharg(union node *, FILE *);
11197static void indent(int, char *, FILE *);
11198static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011199
11200
Eric Andersenc470f442003-07-28 09:56:35 +000011201void
11202showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011203{
11204 trputs("showtree called\n");
11205 shtree(n, 1, NULL, stdout);
11206}
Eric Andersencb57d552001-06-28 07:25:16 +000011207
Eric Andersenc470f442003-07-28 09:56:35 +000011208
11209static void
11210shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011211{
11212 struct nodelist *lp;
11213 const char *s;
11214
11215 if (n == NULL)
11216 return;
11217
11218 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011219 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011220 case NSEMI:
11221 s = "; ";
11222 goto binop;
11223 case NAND:
11224 s = " && ";
11225 goto binop;
11226 case NOR:
11227 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011228binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011229 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011230 /* if (ind < 0) */
11231 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011232 shtree(n->nbinary.ch2, ind, NULL, fp);
11233 break;
11234 case NCMD:
11235 shcmd(n, fp);
11236 if (ind >= 0)
11237 putc('\n', fp);
11238 break;
11239 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011240 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011241 shcmd(lp->n, fp);
11242 if (lp->next)
11243 fputs(" | ", fp);
11244 }
11245 if (n->npipe.backgnd)
11246 fputs(" &", fp);
11247 if (ind >= 0)
11248 putc('\n', fp);
11249 break;
11250 default:
11251 fprintf(fp, "<node type %d>", n->type);
11252 if (ind >= 0)
11253 putc('\n', fp);
11254 break;
11255 }
11256}
11257
11258
Eric Andersenc470f442003-07-28 09:56:35 +000011259static void
11260shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011261{
11262 union node *np;
11263 int first;
11264 const char *s;
11265 int dftfd;
11266
11267 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011268 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11269 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011270 putchar(' ');
11271 sharg(np, fp);
11272 first = 0;
11273 }
Eric Andersenc470f442003-07-28 09:56:35 +000011274 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11275 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011276 putchar(' ');
11277 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011278 case NTO: s = ">"; dftfd = 1; break;
11279 case NCLOBBER: s = ">|"; dftfd = 1; break;
11280 case NAPPEND: s = ">>"; dftfd = 1; break;
11281 case NTOFD: s = ">&"; dftfd = 1; break;
11282 case NFROM: s = "<"; dftfd = 0; break;
11283 case NFROMFD: s = "<&"; dftfd = 0; break;
11284 case NFROMTO: s = "<>"; dftfd = 0; break;
11285 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011286 }
11287 if (np->nfile.fd != dftfd)
11288 fprintf(fp, "%d", np->nfile.fd);
11289 fputs(s, fp);
11290 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11291 fprintf(fp, "%d", np->ndup.dupfd);
11292 } else {
11293 sharg(np->nfile.fname, fp);
11294 }
11295 first = 0;
11296 }
11297}
11298
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011299
Eric Andersenc470f442003-07-28 09:56:35 +000011300
11301static void
11302sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011303{
Eric Andersencb57d552001-06-28 07:25:16 +000011304 char *p;
11305 struct nodelist *bqlist;
11306 int subtype;
11307
11308 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011309 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011310 abort();
11311 }
11312 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011313 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011314 switch (*p) {
11315 case CTLESC:
11316 putc(*++p, fp);
11317 break;
11318 case CTLVAR:
11319 putc('$', fp);
11320 putc('{', fp);
11321 subtype = *++p;
11322 if (subtype == VSLENGTH)
11323 putc('#', fp);
11324
11325 while (*p != '=')
11326 putc(*p++, fp);
11327
11328 if (subtype & VSNUL)
11329 putc(':', fp);
11330
11331 switch (subtype & VSTYPE) {
11332 case VSNORMAL:
11333 putc('}', fp);
11334 break;
11335 case VSMINUS:
11336 putc('-', fp);
11337 break;
11338 case VSPLUS:
11339 putc('+', fp);
11340 break;
11341 case VSQUESTION:
11342 putc('?', fp);
11343 break;
11344 case VSASSIGN:
11345 putc('=', fp);
11346 break;
11347 case VSTRIMLEFT:
11348 putc('#', fp);
11349 break;
11350 case VSTRIMLEFTMAX:
11351 putc('#', fp);
11352 putc('#', fp);
11353 break;
11354 case VSTRIMRIGHT:
11355 putc('%', fp);
11356 break;
11357 case VSTRIMRIGHTMAX:
11358 putc('%', fp);
11359 putc('%', fp);
11360 break;
11361 case VSLENGTH:
11362 break;
11363 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011364 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011365 }
11366 break;
11367 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011368 putc('}', fp);
11369 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011370 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011371 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011372 putc('$', fp);
11373 putc('(', fp);
11374 shtree(bqlist->n, -1, NULL, fp);
11375 putc(')', fp);
11376 break;
11377 default:
11378 putc(*p, fp);
11379 break;
11380 }
11381 }
11382}
11383
11384
Eric Andersenc470f442003-07-28 09:56:35 +000011385static void
11386indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011387{
11388 int i;
11389
Eric Andersenc470f442003-07-28 09:56:35 +000011390 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011391 if (pfx && i == amount - 1)
11392 fputs(pfx, fp);
11393 putc('\t', fp);
11394 }
11395}
Eric Andersencb57d552001-06-28 07:25:16 +000011396
Eric Andersenc470f442003-07-28 09:56:35 +000011397
11398
11399/*
11400 * Debugging stuff.
11401 */
11402
11403
Eric Andersencb57d552001-06-28 07:25:16 +000011404FILE *tracefile;
11405
Eric Andersencb57d552001-06-28 07:25:16 +000011406
Eric Andersenc470f442003-07-28 09:56:35 +000011407void
11408trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011409{
Eric Andersenc470f442003-07-28 09:56:35 +000011410 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011411 return;
11412 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011413}
11414
Eric Andersenc470f442003-07-28 09:56:35 +000011415void
11416trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011417{
11418 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011419
Eric Andersenc470f442003-07-28 09:56:35 +000011420 if (debug != 1)
11421 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011422 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011423 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011424 va_end(va);
11425}
11426
Eric Andersenc470f442003-07-28 09:56:35 +000011427void
11428tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011429{
Eric Andersenc470f442003-07-28 09:56:35 +000011430 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011431 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011432 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011433}
11434
11435
Eric Andersenc470f442003-07-28 09:56:35 +000011436void
11437trputs(const char *s)
11438{
11439 if (debug != 1)
11440 return;
11441 fputs(s, tracefile);
11442}
11443
11444
11445static void
11446trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011447{
11448 char *p;
11449 char c;
11450
Eric Andersenc470f442003-07-28 09:56:35 +000011451 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011452 return;
11453 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011454 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011455 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011456 case '\n': c = 'n'; goto backslash;
11457 case '\t': c = 't'; goto backslash;
11458 case '\r': c = 'r'; goto backslash;
11459 case '"': c = '"'; goto backslash;
11460 case '\\': c = '\\'; goto backslash;
11461 case CTLESC: c = 'e'; goto backslash;
11462 case CTLVAR: c = 'v'; goto backslash;
11463 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11464 case CTLBACKQ: c = 'q'; goto backslash;
11465 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11466backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011467 putc(c, tracefile);
11468 break;
11469 default:
11470 if (*p >= ' ' && *p <= '~')
11471 putc(*p, tracefile);
11472 else {
11473 putc('\\', tracefile);
11474 putc(*p >> 6 & 03, tracefile);
11475 putc(*p >> 3 & 07, tracefile);
11476 putc(*p & 07, tracefile);
11477 }
11478 break;
11479 }
11480 }
11481 putc('"', tracefile);
11482}
11483
11484
Eric Andersenc470f442003-07-28 09:56:35 +000011485void
11486trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011487{
Eric Andersenc470f442003-07-28 09:56:35 +000011488 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011489 return;
11490 while (*ap) {
11491 trstring(*ap++);
11492 if (*ap)
11493 putc(' ', tracefile);
11494 else
11495 putc('\n', tracefile);
11496 }
Eric Andersencb57d552001-06-28 07:25:16 +000011497}
11498
11499
Eric Andersenc470f442003-07-28 09:56:35 +000011500void
11501opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011502{
Eric Andersencb57d552001-06-28 07:25:16 +000011503 char s[100];
11504#ifdef O_APPEND
11505 int flags;
11506#endif
11507
Eric Andersenc470f442003-07-28 09:56:35 +000011508 if (debug != 1) {
11509 if (tracefile)
11510 fflush(tracefile);
11511 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011512 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011513 }
Eric Andersenc470f442003-07-28 09:56:35 +000011514 scopy("./trace", s);
11515 if (tracefile) {
11516 if (!freopen(s, "a", tracefile)) {
11517 fprintf(stderr, "Can't re-open %s\n", s);
11518 debug = 0;
11519 return;
11520 }
11521 } else {
11522 if ((tracefile = fopen(s, "a")) == NULL) {
11523 fprintf(stderr, "Can't open %s\n", s);
11524 debug = 0;
11525 return;
11526 }
11527 }
Eric Andersencb57d552001-06-28 07:25:16 +000011528#ifdef O_APPEND
11529 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11530 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11531#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011532 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011533 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011534}
Eric Andersenc470f442003-07-28 09:56:35 +000011535#endif /* DEBUG */
11536
11537
11538/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11539
11540/*
11541 * Sigmode records the current value of the signal handlers for the various
11542 * modes. A value of zero means that the current handler is not known.
11543 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11544 */
11545
11546#define S_DFL 1 /* default signal handling (SIG_DFL) */
11547#define S_CATCH 2 /* signal is caught */
11548#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11549#define S_HARD_IGN 4 /* signal is ignored permenantly */
11550#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11551
Eric Andersencb57d552001-06-28 07:25:16 +000011552
11553
11554/*
Eric Andersencb57d552001-06-28 07:25:16 +000011555 * The trap builtin.
11556 */
11557
Eric Andersenc470f442003-07-28 09:56:35 +000011558int
11559trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011560{
11561 char *action;
11562 char **ap;
11563 int signo;
11564
Eric Andersenc470f442003-07-28 09:56:35 +000011565 nextopt(nullstr);
11566 ap = argptr;
11567 if (!*ap) {
11568 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011569 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011570 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011571
Eric Andersenc470f442003-07-28 09:56:35 +000011572 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011573 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011574 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011575 out1fmt("trap -- %s %s\n",
11576 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011577 }
11578 }
11579 return 0;
11580 }
Eric Andersenc470f442003-07-28 09:56:35 +000011581 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011582 action = NULL;
11583 else
11584 action = *ap++;
11585 while (*ap) {
11586 if ((signo = decode_signal(*ap, 0)) < 0)
11587 error("%s: bad trap", *ap);
11588 INTOFF;
11589 if (action) {
11590 if (action[0] == '-' && action[1] == '\0')
11591 action = NULL;
11592 else
Eric Andersenc470f442003-07-28 09:56:35 +000011593 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011594 }
Eric Andersenc470f442003-07-28 09:56:35 +000011595 if (trap[signo])
11596 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011597 trap[signo] = action;
11598 if (signo != 0)
11599 setsignal(signo);
11600 INTON;
11601 ap++;
11602 }
11603 return 0;
11604}
11605
11606
Eric Andersenc470f442003-07-28 09:56:35 +000011607/*
11608 * Clear traps on a fork.
11609 */
11610
11611void
11612clear_traps(void)
11613{
11614 char **tp;
11615
11616 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11617 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11618 INTOFF;
11619 ckfree(*tp);
11620 *tp = NULL;
11621 if (tp != &trap[0])
11622 setsignal(tp - trap);
11623 INTON;
11624 }
11625 }
11626}
11627
11628
Eric Andersencb57d552001-06-28 07:25:16 +000011629/*
11630 * Set the signal handler for the specified signal. The routine figures
11631 * out what it should be set to.
11632 */
11633
Eric Andersenc470f442003-07-28 09:56:35 +000011634void
11635setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011636{
11637 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011638 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011639 struct sigaction act;
11640
11641 if ((t = trap[signo]) == NULL)
11642 action = S_DFL;
11643 else if (*t != '\0')
11644 action = S_CATCH;
11645 else
11646 action = S_IGN;
11647 if (rootshell && action == S_DFL) {
11648 switch (signo) {
11649 case SIGINT:
11650 if (iflag || minusc || sflag == 0)
11651 action = S_CATCH;
11652 break;
11653 case SIGQUIT:
11654#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011655 if (debug)
11656 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011657#endif
11658 /* FALLTHROUGH */
11659 case SIGTERM:
11660 if (iflag)
11661 action = S_IGN;
11662 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011663#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011664 case SIGTSTP:
11665 case SIGTTOU:
11666 if (mflag)
11667 action = S_IGN;
11668 break;
11669#endif
11670 }
11671 }
11672
11673 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011674 tsig = *t;
11675 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011676 /*
11677 * current setting unknown
11678 */
11679 if (sigaction(signo, 0, &act) == -1) {
11680 /*
11681 * Pretend it worked; maybe we should give a warning
11682 * here, but other shells don't. We don't alter
11683 * sigmode, so that we retry every time.
11684 */
11685 return;
11686 }
11687 if (act.sa_handler == SIG_IGN) {
11688 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011689 signo == SIGTTIN || signo == SIGTTOU)) {
11690 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011691 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011692 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011693 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011694 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011695 }
11696 }
Eric Andersenc470f442003-07-28 09:56:35 +000011697 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011698 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011699 switch (action) {
11700 case S_CATCH:
11701 act.sa_handler = onsig;
11702 break;
11703 case S_IGN:
11704 act.sa_handler = SIG_IGN;
11705 break;
11706 default:
11707 act.sa_handler = SIG_DFL;
11708 }
Eric Andersencb57d552001-06-28 07:25:16 +000011709 *t = action;
11710 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011711 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011712 sigaction(signo, &act, 0);
11713}
11714
11715/*
11716 * Ignore a signal.
11717 */
11718
Eric Andersenc470f442003-07-28 09:56:35 +000011719void
11720ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011721{
11722 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11723 signal(signo, SIG_IGN);
11724 }
11725 sigmode[signo - 1] = S_HARD_IGN;
11726}
11727
11728
Eric Andersencb57d552001-06-28 07:25:16 +000011729/*
11730 * Signal handler.
11731 */
11732
Eric Andersenc470f442003-07-28 09:56:35 +000011733void
11734onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011735{
Eric Andersencb57d552001-06-28 07:25:16 +000011736 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011737 pendingsigs = signo;
11738
11739 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11740 if (!suppressint)
11741 onint();
11742 intpending = 1;
11743 }
Eric Andersencb57d552001-06-28 07:25:16 +000011744}
11745
11746
Eric Andersencb57d552001-06-28 07:25:16 +000011747/*
11748 * Called to execute a trap. Perhaps we should avoid entering new trap
11749 * handlers while we are executing a trap handler.
11750 */
11751
Eric Andersenc470f442003-07-28 09:56:35 +000011752void
11753dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011754{
Eric Andersenc470f442003-07-28 09:56:35 +000011755 char *p;
11756 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011757 int savestatus;
11758
Eric Andersenc470f442003-07-28 09:56:35 +000011759 savestatus = exitstatus;
11760 q = gotsig;
11761 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11762 *p = 0;
11763 p = trap[p - q + 1];
11764 if (!p)
11765 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011766 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011767 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011768 }
Eric Andersencb57d552001-06-28 07:25:16 +000011769}
11770
Eric Andersenc470f442003-07-28 09:56:35 +000011771
Eric Andersenc470f442003-07-28 09:56:35 +000011772/*
11773 * Controls whether the shell is interactive or not.
11774 */
11775
Eric Andersenc470f442003-07-28 09:56:35 +000011776void
11777setinteractive(int on)
11778{
11779 static int is_interactive;
11780
11781 if (++on == is_interactive)
11782 return;
11783 is_interactive = on;
11784 setsignal(SIGINT);
11785 setsignal(SIGQUIT);
11786 setsignal(SIGTERM);
11787#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11788 if(is_interactive > 1) {
11789 /* Looks like they want an interactive shell */
11790 static int do_banner;
11791
11792 if(!do_banner) {
11793 out1fmt(
11794 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11795 "Enter 'help' for a list of built-in commands.\n\n");
11796 do_banner++;
11797 }
11798 }
11799#endif
11800}
11801
11802
11803#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11804/*** List the available builtins ***/
11805
11806static int helpcmd(int argc, char **argv)
11807{
11808 int col, i;
11809
11810 out1fmt("\nBuilt-in commands:\n-------------------\n");
11811 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11812 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11813 builtincmd[i].name + 1);
11814 if (col > 60) {
11815 out1fmt("\n");
11816 col = 0;
11817 }
11818 }
11819#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11820 {
11821 extern const struct BB_applet applets[];
11822 extern const size_t NUM_APPLETS;
11823
11824 for (i = 0; i < NUM_APPLETS; i++) {
11825
11826 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11827 if (col > 60) {
11828 out1fmt("\n");
11829 col = 0;
11830 }
11831 }
11832 }
11833#endif
11834 out1fmt("\n\n");
11835 return EXIT_SUCCESS;
11836}
11837#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11838
Eric Andersencb57d552001-06-28 07:25:16 +000011839/*
11840 * Called to exit the shell.
11841 */
11842
Eric Andersenc470f442003-07-28 09:56:35 +000011843void
11844exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011845{
Eric Andersenc470f442003-07-28 09:56:35 +000011846 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011847 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011848 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011849 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011850
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011851 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011852 status = exitstatus;
11853 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011854 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011855 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011856 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011857 if ((p = trap[0]) != NULL && *p != '\0') {
11858 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011859 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011860 }
Eric Andersencb57d552001-06-28 07:25:16 +000011861 flushall();
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011862#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11863 if (iflag && rootshell) {
11864 const char *hp = lookupvar("HISTFILE");
11865
11866 if(hp != NULL )
11867 save_history ( hp );
11868 }
11869#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011870out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011871 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011872 /* NOTREACHED */
11873}
11874
11875static int decode_signal(const char *string, int minsig)
11876{
11877 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011878 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011879
Eric Andersen34506362001-08-02 05:02:46 +000011880 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011881}
Eric Andersen34506362001-08-02 05:02:46 +000011882
Eric Andersenc470f442003-07-28 09:56:35 +000011883/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11884
11885static struct var *vartab[VTABSIZE];
11886
11887static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011888static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011889
11890/*
11891 * Initialize the varable symbol tables and import the environment
11892 */
11893
Eric Andersenc470f442003-07-28 09:56:35 +000011894
11895#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011896/*
Eric Andersenc470f442003-07-28 09:56:35 +000011897 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011898 */
11899
Eric Andersenc470f442003-07-28 09:56:35 +000011900int
11901setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011902{
Eric Andersenc470f442003-07-28 09:56:35 +000011903 int err;
11904 volatile int saveint;
11905 struct jmploc *volatile savehandler = handler;
11906 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011907
Eric Andersenc470f442003-07-28 09:56:35 +000011908 SAVEINT(saveint);
11909 if (setjmp(jmploc.loc))
11910 err = 1;
11911 else {
11912 handler = &jmploc;
11913 setvar(name, val, flags);
11914 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011915 }
Eric Andersenc470f442003-07-28 09:56:35 +000011916 handler = savehandler;
11917 RESTOREINT(saveint);
11918 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011919}
Eric Andersenc470f442003-07-28 09:56:35 +000011920#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011921
11922/*
11923 * Set the value of a variable. The flags argument is ored with the
11924 * flags of the variable. If val is NULL, the variable is unset.
11925 */
11926
Eric Andersenc470f442003-07-28 09:56:35 +000011927static void
11928setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011929{
Eric Andersenc470f442003-07-28 09:56:35 +000011930 char *p, *q;
11931 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011932 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011933 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011934
Eric Andersenc470f442003-07-28 09:56:35 +000011935 q = endofname(name);
11936 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011937 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011938 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011939 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011940 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011941 if (val == NULL) {
11942 flags |= VUNSET;
11943 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011944 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011945 }
11946 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011947 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11948 *p++ = '\0';
11949 if (vallen) {
11950 p[-1] = '=';
11951 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011952 }
Eric Andersenc470f442003-07-28 09:56:35 +000011953 *p = '\0';
11954 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011955 INTON;
11956}
11957
11958
Eric Andersencb57d552001-06-28 07:25:16 +000011959/*
11960 * Same as setvar except that the variable and value are passed in
11961 * the first argument as name=value. Since the first argument will
11962 * be actually stored in the table, it should not be a string that
11963 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000011964 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000011965 */
11966
Eric Andersenc470f442003-07-28 09:56:35 +000011967void
11968setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011969{
11970 struct var *vp, **vpp;
11971
11972 vpp = hashvar(s);
11973 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000011974 vp = *findvar(vpp, s);
11975 if (vp) {
Eric Andersencb57d552001-06-28 07:25:16 +000011976 if (vp->flags & VREADONLY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011977 if (flags & VNOSAVE)
11978 free(s);
11979 error("%.*s: is read only", strchrnul(s, '=') - s, s);
Eric Andersencb57d552001-06-28 07:25:16 +000011980 }
Eric Andersenc470f442003-07-28 09:56:35 +000011981
11982 if (flags & VNOSET)
11983 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011984
11985 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000011986 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000011987
Eric Andersenc470f442003-07-28 09:56:35 +000011988 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11989 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011990
Eric Andersenc470f442003-07-28 09:56:35 +000011991 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11992 } else {
11993 if (flags & VNOSET)
11994 return;
11995 /* not found */
11996 vp = ckmalloc(sizeof (*vp));
11997 vp->next = *vpp;
11998 vp->func = NULL;
11999 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012000 }
Eric Andersenc470f442003-07-28 09:56:35 +000012001 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12002 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012003 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012004 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012005}
12006
12007
Eric Andersencb57d552001-06-28 07:25:16 +000012008/*
12009 * Process a linked list of variable assignments.
12010 */
12011
Eric Andersenc470f442003-07-28 09:56:35 +000012012static void
12013listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012014{
Eric Andersenc470f442003-07-28 09:56:35 +000012015 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012016
Eric Andersenc470f442003-07-28 09:56:35 +000012017 if (!lp)
12018 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012019 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012020 do {
12021 setvareq(lp->text, flags);
12022 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012023 INTON;
12024}
12025
12026
Eric Andersencb57d552001-06-28 07:25:16 +000012027/*
12028 * Find the value of a variable. Returns NULL if not set.
12029 */
12030
Eric Andersenc470f442003-07-28 09:56:35 +000012031static char *
12032lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012033{
Eric Andersencb57d552001-06-28 07:25:16 +000012034 struct var *v;
12035
12036 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
Eric Andersenc470f442003-07-28 09:56:35 +000012037 return strchrnul(v->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012038 }
12039 return NULL;
12040}
12041
12042
Eric Andersencb57d552001-06-28 07:25:16 +000012043/*
12044 * Search the environment of a builtin command.
12045 */
12046
Eric Andersenc470f442003-07-28 09:56:35 +000012047static char *
12048bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012049{
Eric Andersenc470f442003-07-28 09:56:35 +000012050 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012051
Eric Andersenc470f442003-07-28 09:56:35 +000012052 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012053 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012054 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012055 }
12056 return lookupvar(name);
12057}
12058
12059
Eric Andersencb57d552001-06-28 07:25:16 +000012060/*
Eric Andersenc470f442003-07-28 09:56:35 +000012061 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012062 */
12063
Eric Andersenc470f442003-07-28 09:56:35 +000012064static char **
12065listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012066{
Eric Andersencb57d552001-06-28 07:25:16 +000012067 struct var **vpp;
12068 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012069 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012070 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012071
Eric Andersenc470f442003-07-28 09:56:35 +000012072 STARTSTACKSTR(ep);
12073 vpp = vartab;
12074 mask = on | off;
12075 do {
12076 for (vp = *vpp ; vp ; vp = vp->next)
12077 if ((vp->flags & mask) == on) {
12078 if (ep == stackstrend())
12079 ep = growstackstr();
12080 *ep++ = (char *) vp->text;
12081 }
12082 } while (++vpp < vartab + VTABSIZE);
12083 if (ep == stackstrend())
12084 ep = growstackstr();
12085 if (end)
12086 *end = ep;
12087 *ep++ = NULL;
12088 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012089}
12090
12091
12092/*
Eric Andersenc470f442003-07-28 09:56:35 +000012093 * POSIX requires that 'set' (but not export or readonly) output the
12094 * variables in lexicographic order - by the locale's collating order (sigh).
12095 * Maybe we could keep them in an ordered balanced binary tree
12096 * instead of hashed lists.
12097 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012098 */
12099
Eric Andersenc470f442003-07-28 09:56:35 +000012100static int
12101showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012102{
Eric Andersenc470f442003-07-28 09:56:35 +000012103 const char *sep;
12104 char **ep, **epend;
12105
12106 ep = listvars(on, off, &epend);
12107 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12108
12109 sep = *sep_prefix ? spcstr : sep_prefix;
12110
12111 for (; ep < epend; ep++) {
12112 const char *p;
12113 const char *q;
12114
12115 p = strchrnul(*ep, '=');
12116 q = nullstr;
12117 if (*p)
12118 q = single_quote(++p);
12119
12120 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12121 }
12122
Eric Andersencb57d552001-06-28 07:25:16 +000012123 return 0;
12124}
12125
12126
12127
12128/*
12129 * The export and readonly commands.
12130 */
12131
Eric Andersenc470f442003-07-28 09:56:35 +000012132static int
12133exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012134{
12135 struct var *vp;
12136 char *name;
12137 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012138 char **aptr;
12139 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12140 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012141
Eric Andersenc470f442003-07-28 09:56:35 +000012142 notp = nextopt("p") - 'p';
12143 if (notp && ((name = *(aptr = argptr)))) {
12144 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012145 if ((p = strchr(name, '=')) != NULL) {
12146 p++;
12147 } else {
12148 if ((vp = *findvar(hashvar(name), name))) {
12149 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012150 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012151 }
12152 }
12153 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012154 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012155 } else {
12156 showvars(argv[0], flag, 0);
12157 }
12158 return 0;
12159}
12160
Eric Andersen34506362001-08-02 05:02:46 +000012161
Eric Andersencb57d552001-06-28 07:25:16 +000012162/*
Eric Andersencb57d552001-06-28 07:25:16 +000012163 * Make a variable a local variable. When a variable is made local, it's
12164 * value and flags are saved in a localvar structure. The saved values
12165 * will be restored when the shell function returns. We handle the name
12166 * "-" as a special case.
12167 */
12168
Eric Andersenc470f442003-07-28 09:56:35 +000012169static inline void
12170mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012171{
Eric Andersencb57d552001-06-28 07:25:16 +000012172 struct localvar *lvp;
12173 struct var **vpp;
12174 struct var *vp;
12175
12176 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012177 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012178 if (name[0] == '-' && name[1] == '\0') {
12179 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012180 p = ckmalloc(sizeof(optlist));
12181 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012182 vp = NULL;
12183 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012184 char *eq;
12185
Eric Andersencb57d552001-06-28 07:25:16 +000012186 vpp = hashvar(name);
12187 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012188 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012189 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012190 if (eq)
12191 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012192 else
12193 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012194 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012195 lvp->flags = VUNSET;
12196 } else {
12197 lvp->text = vp->text;
12198 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012199 vp->flags |= VSTRFIXED|VTEXTFIXED;
12200 if (eq)
12201 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012202 }
12203 }
12204 lvp->vp = vp;
12205 lvp->next = localvars;
12206 localvars = lvp;
12207 INTON;
12208}
12209
Eric Andersenc470f442003-07-28 09:56:35 +000012210/*
12211 * The "local" command.
12212 */
12213
12214static int
12215localcmd(int argc, char **argv)
12216{
12217 char *name;
12218
12219 argv = argptr;
12220 while ((name = *argv++) != NULL) {
12221 mklocal(name);
12222 }
12223 return 0;
12224}
12225
12226
Eric Andersencb57d552001-06-28 07:25:16 +000012227/*
12228 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012229 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012230 */
12231
Eric Andersenc470f442003-07-28 09:56:35 +000012232static void
12233poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012234{
Eric Andersencb57d552001-06-28 07:25:16 +000012235 struct localvar *lvp;
12236 struct var *vp;
12237
12238 while ((lvp = localvars) != NULL) {
12239 localvars = lvp->next;
12240 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012241 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12242 if (vp == NULL) { /* $- saved */
12243 memcpy(optlist, lvp->text, sizeof(optlist));
12244 ckfree(lvp->text);
12245 optschanged();
12246 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12247 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012248 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012249 if (vp->func)
12250 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12251 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12252 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012253 vp->flags = lvp->flags;
12254 vp->text = lvp->text;
12255 }
Eric Andersenc470f442003-07-28 09:56:35 +000012256 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012257 }
12258}
12259
12260
Eric Andersencb57d552001-06-28 07:25:16 +000012261/*
12262 * The unset builtin command. We unset the function before we unset the
12263 * variable to allow a function to be unset when there is a readonly variable
12264 * with the same name.
12265 */
12266
Eric Andersenc470f442003-07-28 09:56:35 +000012267int
12268unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012269{
12270 char **ap;
12271 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012272 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012273 int ret = 0;
12274
12275 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012276 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012277 }
Eric Andersencb57d552001-06-28 07:25:16 +000012278
Eric Andersenc470f442003-07-28 09:56:35 +000012279 for (ap = argptr; *ap ; ap++) {
12280 if (flag != 'f') {
12281 i = unsetvar(*ap);
12282 ret |= i;
12283 if (!(i & 2))
12284 continue;
12285 }
12286 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012287 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012288 }
Eric Andersenc470f442003-07-28 09:56:35 +000012289 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012290}
12291
12292
12293/*
12294 * Unset the specified variable.
12295 */
12296
Eric Andersenc470f442003-07-28 09:56:35 +000012297int
12298unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012299{
Eric Andersencb57d552001-06-28 07:25:16 +000012300 struct var **vpp;
12301 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012302 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012303
12304 vpp = findvar(hashvar(s), s);
12305 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012306 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012307 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012308 int flags = vp->flags;
12309
12310 retval = 1;
12311 if (flags & VREADONLY)
12312 goto out;
12313 if (flags & VUNSET)
12314 goto ok;
12315 if ((flags & VSTRFIXED) == 0) {
12316 INTOFF;
12317 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12318 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012319 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012320 ckfree(vp);
12321 INTON;
12322 } else {
12323 setvar(s, 0, 0);
12324 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012325 }
Eric Andersenc470f442003-07-28 09:56:35 +000012326ok:
12327 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012328 }
12329
Eric Andersenc470f442003-07-28 09:56:35 +000012330out:
12331 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012332}
12333
12334
12335
12336/*
12337 * Find the appropriate entry in the hash table from the name.
12338 */
12339
Eric Andersenc470f442003-07-28 09:56:35 +000012340static struct var **
12341hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012342{
Eric Andersencb57d552001-06-28 07:25:16 +000012343 unsigned int hashval;
12344
12345 hashval = ((unsigned char) *p) << 4;
12346 while (*p && *p != '=')
12347 hashval += (unsigned char) *p++;
12348 return &vartab[hashval % VTABSIZE];
12349}
12350
12351
12352
12353/*
Eric Andersenc470f442003-07-28 09:56:35 +000012354 * Compares two strings up to the first = or '\0'. The first
12355 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012356 * either '=' or '\0'.
12357 */
12358
Eric Andersenc470f442003-07-28 09:56:35 +000012359int
12360varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012361{
Eric Andersenc470f442003-07-28 09:56:35 +000012362 int c, d;
12363
12364 while ((c = *p) == (d = *q)) {
12365 if (!c || c == '=')
12366 goto out;
12367 p++;
12368 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012369 }
Eric Andersenc470f442003-07-28 09:56:35 +000012370 if (c == '=')
12371 c = 0;
12372 if (d == '=')
12373 d = 0;
12374out:
12375 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012376}
12377
Eric Andersenc470f442003-07-28 09:56:35 +000012378static int
12379vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012380{
Eric Andersenc470f442003-07-28 09:56:35 +000012381 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012382}
12383
Eric Andersenc470f442003-07-28 09:56:35 +000012384static struct var **
12385findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012386{
12387 for (; *vpp; vpp = &(*vpp)->next) {
12388 if (varequal((*vpp)->text, name)) {
12389 break;
12390 }
12391 }
12392 return vpp;
12393}
Eric Andersenc470f442003-07-28 09:56:35 +000012394/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012395
Eric Andersenc470f442003-07-28 09:56:35 +000012396#include <sys/times.h>
12397
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012398static const unsigned char timescmd_str[] = {
12399 ' ', offsetof(struct tms, tms_utime),
12400 '\n', offsetof(struct tms, tms_stime),
12401 ' ', offsetof(struct tms, tms_cutime),
12402 '\n', offsetof(struct tms, tms_cstime),
12403 0
12404};
Eric Andersencb57d552001-06-28 07:25:16 +000012405
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012406static int timescmd(int ac, char **av)
12407{
12408 long int clk_tck, s, t;
12409 const unsigned char *p;
12410 struct tms buf;
12411
12412 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012413 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012414
12415 p = timescmd_str;
12416 do {
12417 t = *(clock_t *)(((char *) &buf) + p[1]);
12418 s = t / clk_tck;
12419 out1fmt("%ldm%ld.%.3lds%c",
12420 s/60, s%60,
12421 ((t - s * clk_tck) * 1000) / clk_tck,
12422 p[0]);
12423 } while (*(p += 2));
12424
Eric Andersencb57d552001-06-28 07:25:16 +000012425 return 0;
12426}
12427
Eric Andersend35c5df2002-01-09 15:37:36 +000012428#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012429static int
12430dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012431{
Eric Andersen90898442003-08-06 11:20:52 +000012432 long result;
Eric Andersenc470f442003-07-28 09:56:35 +000012433 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012434
Eric Andersenc470f442003-07-28 09:56:35 +000012435 INTOFF;
12436 result = arith(s, &errcode);
12437 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012438 if (errcode == -3)
12439 error("exponent less than 0");
12440 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012441 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012442 else if (errcode == -5)
12443 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012444 else
12445 synerror(s);
12446 }
12447 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012448
Eric Andersenc470f442003-07-28 09:56:35 +000012449 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012450}
Eric Andersenc470f442003-07-28 09:56:35 +000012451
12452
12453/*
Eric Andersen90898442003-08-06 11:20:52 +000012454 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12455 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12456 *
12457 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012458 */
Eric Andersen90898442003-08-06 11:20:52 +000012459
Eric Andersenc470f442003-07-28 09:56:35 +000012460static int
Eric Andersen90898442003-08-06 11:20:52 +000012461letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012462{
Eric Andersenc470f442003-07-28 09:56:35 +000012463 char **ap;
12464 long i;
12465
Eric Andersen90898442003-08-06 11:20:52 +000012466 ap = argv + 1;
12467 if(!*ap)
12468 error("expression expected");
12469 for (ap = argv + 1; *ap; ap++) {
12470 i = dash_arith(*ap);
12471 }
Eric Andersenc470f442003-07-28 09:56:35 +000012472
Eric Andersen90898442003-08-06 11:20:52 +000012473 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012474}
12475#endif /* CONFIG_ASH_MATH_SUPPORT */
12476
12477/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12478
12479/*
12480 * Miscelaneous builtins.
12481 */
12482
12483#undef rflag
12484
12485#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012486#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012487typedef enum __rlimit_resource rlim_t;
12488#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012489#endif
12490
12491
Eric Andersenc470f442003-07-28 09:56:35 +000012492/*
12493 * The read builtin. The -e option causes backslashes to escape the
12494 * following character.
12495 *
12496 * This uses unbuffered input, which may be avoidable in some cases.
12497 */
12498
12499static int
12500readcmd(int argc, char **argv)
12501{
12502 char **ap;
12503 int backslash;
12504 char c;
12505 int rflag;
12506 char *prompt;
12507 const char *ifs;
12508 char *p;
12509 int startword;
12510 int status;
12511 int i;
12512
12513 rflag = 0;
12514 prompt = NULL;
12515 while ((i = nextopt("p:r")) != '\0') {
12516 if (i == 'p')
12517 prompt = optionarg;
12518 else
12519 rflag = 1;
12520 }
12521 if (prompt && isatty(0)) {
12522 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012523 }
12524 if (*(ap = argptr) == NULL)
12525 error("arg count");
12526 if ((ifs = bltinlookup("IFS")) == NULL)
12527 ifs = defifs;
12528 status = 0;
12529 startword = 1;
12530 backslash = 0;
12531 STARTSTACKSTR(p);
12532 for (;;) {
12533 if (read(0, &c, 1) != 1) {
12534 status = 1;
12535 break;
12536 }
12537 if (c == '\0')
12538 continue;
12539 if (backslash) {
12540 backslash = 0;
12541 if (c != '\n')
12542 goto put;
12543 continue;
12544 }
12545 if (!rflag && c == '\\') {
12546 backslash++;
12547 continue;
12548 }
12549 if (c == '\n')
12550 break;
12551 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12552 continue;
12553 }
12554 startword = 0;
12555 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12556 STACKSTRNUL(p);
12557 setvar(*ap, stackblock(), 0);
12558 ap++;
12559 startword = 1;
12560 STARTSTACKSTR(p);
12561 } else {
12562put:
12563 STPUTC(c, p);
12564 }
12565 }
12566 STACKSTRNUL(p);
12567 /* Remove trailing blanks */
12568 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12569 *p = '\0';
12570 setvar(*ap, stackblock(), 0);
12571 while (*++ap != NULL)
12572 setvar(*ap, nullstr, 0);
12573 return status;
12574}
12575
12576
12577static int umaskcmd(int argc, char **argv)
12578{
12579 static const char permuser[3] = "ugo";
12580 static const char permmode[3] = "rwx";
12581 static const short int permmask[] = {
12582 S_IRUSR, S_IWUSR, S_IXUSR,
12583 S_IRGRP, S_IWGRP, S_IXGRP,
12584 S_IROTH, S_IWOTH, S_IXOTH
12585 };
12586
12587 char *ap;
12588 mode_t mask;
12589 int i;
12590 int symbolic_mode = 0;
12591
12592 while (nextopt("S") != '\0') {
12593 symbolic_mode = 1;
12594 }
12595
12596 INTOFF;
12597 mask = umask(0);
12598 umask(mask);
12599 INTON;
12600
12601 if ((ap = *argptr) == NULL) {
12602 if (symbolic_mode) {
12603 char buf[18];
12604 char *p = buf;
12605
12606 for (i = 0; i < 3; i++) {
12607 int j;
12608
12609 *p++ = permuser[i];
12610 *p++ = '=';
12611 for (j = 0; j < 3; j++) {
12612 if ((mask & permmask[3 * i + j]) == 0) {
12613 *p++ = permmode[j];
12614 }
12615 }
12616 *p++ = ',';
12617 }
12618 *--p = 0;
12619 puts(buf);
12620 } else {
12621 out1fmt("%.4o\n", mask);
12622 }
12623 } else {
12624 if (is_digit((unsigned char) *ap)) {
12625 mask = 0;
12626 do {
12627 if (*ap >= '8' || *ap < '0')
12628 error(illnum, argv[1]);
12629 mask = (mask << 3) + (*ap - '0');
12630 } while (*++ap != '\0');
12631 umask(mask);
12632 } else {
12633 mask = ~mask & 0777;
12634 if (!bb_parse_mode(ap, &mask)) {
12635 error("Illegal mode: %s", ap);
12636 }
12637 umask(~mask & 0777);
12638 }
12639 }
12640 return 0;
12641}
12642
12643/*
12644 * ulimit builtin
12645 *
12646 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12647 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12648 * ash by J.T. Conklin.
12649 *
12650 * Public domain.
12651 */
12652
12653struct limits {
12654 const char *name;
12655 int cmd;
12656 int factor; /* multiply by to get rlim_{cur,max} values */
12657 char option;
12658};
12659
12660static const struct limits limits[] = {
12661#ifdef RLIMIT_CPU
12662 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12663#endif
12664#ifdef RLIMIT_FSIZE
12665 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12666#endif
12667#ifdef RLIMIT_DATA
12668 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12669#endif
12670#ifdef RLIMIT_STACK
12671 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12672#endif
12673#ifdef RLIMIT_CORE
12674 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12675#endif
12676#ifdef RLIMIT_RSS
12677 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12678#endif
12679#ifdef RLIMIT_MEMLOCK
12680 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12681#endif
12682#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012683 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012684#endif
12685#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012686 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012687#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012688#ifdef RLIMIT_AS
12689 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012690#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012691#ifdef RLIMIT_LOCKS
12692 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012693#endif
12694 { (char *) 0, 0, 0, '\0' }
12695};
12696
Glenn L McGrath76620622004-01-13 10:19:37 +000012697enum limtype { SOFT = 0x1, HARD = 0x2 };
12698
12699static void printlim(enum limtype how, const struct rlimit *limit,
12700 const struct limits *l)
12701{
12702 rlim_t val;
12703
12704 val = limit->rlim_max;
12705 if (how & SOFT)
12706 val = limit->rlim_cur;
12707
12708 if (val == RLIM_INFINITY)
12709 out1fmt("unlimited\n");
12710 else {
12711 val /= l->factor;
12712 out1fmt("%lld\n", (long long) val);
12713 }
12714}
12715
Eric Andersenc470f442003-07-28 09:56:35 +000012716int
12717ulimitcmd(int argc, char **argv)
12718{
12719 int c;
12720 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012721 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012722 const struct limits *l;
12723 int set, all = 0;
12724 int optc, what;
12725 struct rlimit limit;
12726
12727 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012728 while ((optc = nextopt("HSa"
12729#ifdef RLIMIT_CPU
12730 "t"
12731#endif
12732#ifdef RLIMIT_FSIZE
12733 "f"
12734#endif
12735#ifdef RLIMIT_DATA
12736 "d"
12737#endif
12738#ifdef RLIMIT_STACK
12739 "s"
12740#endif
12741#ifdef RLIMIT_CORE
12742 "c"
12743#endif
12744#ifdef RLIMIT_RSS
12745 "m"
12746#endif
12747#ifdef RLIMIT_MEMLOCK
12748 "l"
12749#endif
12750#ifdef RLIMIT_NPROC
12751 "p"
12752#endif
12753#ifdef RLIMIT_NOFILE
12754 "n"
12755#endif
12756#ifdef RLIMIT_AS
12757 "v"
12758#endif
12759#ifdef RLIMIT_LOCKS
12760 "w"
12761#endif
12762 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012763 switch (optc) {
12764 case 'H':
12765 how = HARD;
12766 break;
12767 case 'S':
12768 how = SOFT;
12769 break;
12770 case 'a':
12771 all = 1;
12772 break;
12773 default:
12774 what = optc;
12775 }
12776
Glenn L McGrath76620622004-01-13 10:19:37 +000012777 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012778 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012779
12780 set = *argptr ? 1 : 0;
12781 if (set) {
12782 char *p = *argptr;
12783
12784 if (all || argptr[1])
12785 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012786 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012787 val = RLIM_INFINITY;
12788 else {
12789 val = (rlim_t) 0;
12790
12791 while ((c = *p++) >= '0' && c <= '9')
12792 {
12793 val = (val * 10) + (long)(c - '0');
12794 if (val < (rlim_t) 0)
12795 break;
12796 }
12797 if (c)
12798 error("bad number");
12799 val *= l->factor;
12800 }
12801 }
12802 if (all) {
12803 for (l = limits; l->name; l++) {
12804 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012805 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012806 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012807 }
12808 return 0;
12809 }
12810
12811 getrlimit(l->cmd, &limit);
12812 if (set) {
12813 if (how & HARD)
12814 limit.rlim_max = val;
12815 if (how & SOFT)
12816 limit.rlim_cur = val;
12817 if (setrlimit(l->cmd, &limit) < 0)
12818 error("error setting limit (%m)");
12819 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012820 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012821 }
12822 return 0;
12823}
12824
Eric Andersen90898442003-08-06 11:20:52 +000012825
12826#ifdef CONFIG_ASH_MATH_SUPPORT
12827
12828/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12829
12830 Permission is hereby granted, free of charge, to any person obtaining
12831 a copy of this software and associated documentation files (the
12832 "Software"), to deal in the Software without restriction, including
12833 without limitation the rights to use, copy, modify, merge, publish,
12834 distribute, sublicense, and/or sell copies of the Software, and to
12835 permit persons to whom the Software is furnished to do so, subject to
12836 the following conditions:
12837
12838 The above copyright notice and this permission notice shall be
12839 included in all copies or substantial portions of the Software.
12840
12841 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12842 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12843 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12844 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12845 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12846 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12847 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12848*/
12849
12850/* This is my infix parser/evaluator. It is optimized for size, intended
12851 * as a replacement for yacc-based parsers. However, it may well be faster
12852 * than a comparable parser writen in yacc. The supported operators are
12853 * listed in #defines below. Parens, order of operations, and error handling
12854 * are supported. This code is threadsafe. The exact expression format should
12855 * be that which POSIX specifies for shells. */
12856
12857/* The code uses a simple two-stack algorithm. See
12858 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12859 * for a detailed explaination of the infix-to-postfix algorithm on which
12860 * this is based (this code differs in that it applies operators immediately
12861 * to the stack instead of adding them to a queue to end up with an
12862 * expression). */
12863
12864/* To use the routine, call it with an expression string and error return
12865 * pointer */
12866
12867/*
12868 * Aug 24, 2001 Manuel Novoa III
12869 *
12870 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12871 *
12872 * 1) In arith_apply():
12873 * a) Cached values of *numptr and &(numptr[-1]).
12874 * b) Removed redundant test for zero denominator.
12875 *
12876 * 2) In arith():
12877 * a) Eliminated redundant code for processing operator tokens by moving
12878 * to a table-based implementation. Also folded handling of parens
12879 * into the table.
12880 * b) Combined all 3 loops which called arith_apply to reduce generated
12881 * code size at the cost of speed.
12882 *
12883 * 3) The following expressions were treated as valid by the original code:
12884 * 1() , 0! , 1 ( *3 ) .
12885 * These bugs have been fixed by internally enclosing the expression in
12886 * parens and then checking that all binary ops and right parens are
12887 * preceded by a valid expression (NUM_TOKEN).
12888 *
12889 * Note: It may be desireable to replace Aaron's test for whitespace with
12890 * ctype's isspace() if it is used by another busybox applet or if additional
12891 * whitespace chars should be considered. Look below the "#include"s for a
12892 * precompiler test.
12893 */
12894
12895/*
12896 * Aug 26, 2001 Manuel Novoa III
12897 *
12898 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12899 *
12900 * Merge in Aaron's comments previously posted to the busybox list,
12901 * modified slightly to take account of my changes to the code.
12902 *
12903 */
12904
12905/*
12906 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12907 *
12908 * - allow access to variable,
12909 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12910 * - realize assign syntax (VAR=expr, +=, *= etc)
12911 * - realize exponentiation (** operator)
12912 * - realize comma separated - expr, expr
12913 * - realise ++expr --expr expr++ expr--
12914 * - realise expr ? expr : expr (but, second expr calculate always)
12915 * - allow hexdecimal and octal numbers
12916 * - was restored loses XOR operator
12917 * - remove one goto label, added three ;-)
12918 * - protect $((num num)) as true zero expr (Manuel`s error)
12919 * - always use special isspace(), see comment from bash ;-)
12920 */
12921
12922
12923#define arith_isspace(arithval) \
12924 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12925
12926
12927typedef unsigned char operator;
12928
12929/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12930 * precedence, and 3 high bits are an ID unique accross operators of that
12931 * precedence. The ID portion is so that multiple operators can have the
12932 * same precedence, ensuring that the leftmost one is evaluated first.
12933 * Consider * and /. */
12934
12935#define tok_decl(prec,id) (((id)<<5)|(prec))
12936#define PREC(op) ((op) & 0x1F)
12937
12938#define TOK_LPAREN tok_decl(0,0)
12939
12940#define TOK_COMMA tok_decl(1,0)
12941
12942#define TOK_ASSIGN tok_decl(2,0)
12943#define TOK_AND_ASSIGN tok_decl(2,1)
12944#define TOK_OR_ASSIGN tok_decl(2,2)
12945#define TOK_XOR_ASSIGN tok_decl(2,3)
12946#define TOK_PLUS_ASSIGN tok_decl(2,4)
12947#define TOK_MINUS_ASSIGN tok_decl(2,5)
12948#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12949#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12950
12951#define TOK_MUL_ASSIGN tok_decl(3,0)
12952#define TOK_DIV_ASSIGN tok_decl(3,1)
12953#define TOK_REM_ASSIGN tok_decl(3,2)
12954
12955/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12956#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12957
12958/* conditional is right associativity too */
12959#define TOK_CONDITIONAL tok_decl(4,0)
12960#define TOK_CONDITIONAL_SEP tok_decl(4,1)
12961
12962#define TOK_OR tok_decl(5,0)
12963
12964#define TOK_AND tok_decl(6,0)
12965
12966#define TOK_BOR tok_decl(7,0)
12967
12968#define TOK_BXOR tok_decl(8,0)
12969
12970#define TOK_BAND tok_decl(9,0)
12971
12972#define TOK_EQ tok_decl(10,0)
12973#define TOK_NE tok_decl(10,1)
12974
12975#define TOK_LT tok_decl(11,0)
12976#define TOK_GT tok_decl(11,1)
12977#define TOK_GE tok_decl(11,2)
12978#define TOK_LE tok_decl(11,3)
12979
12980#define TOK_LSHIFT tok_decl(12,0)
12981#define TOK_RSHIFT tok_decl(12,1)
12982
12983#define TOK_ADD tok_decl(13,0)
12984#define TOK_SUB tok_decl(13,1)
12985
12986#define TOK_MUL tok_decl(14,0)
12987#define TOK_DIV tok_decl(14,1)
12988#define TOK_REM tok_decl(14,2)
12989
12990/* exponent is right associativity */
12991#define TOK_EXPONENT tok_decl(15,1)
12992
12993/* For now unary operators. */
12994#define UNARYPREC 16
12995#define TOK_BNOT tok_decl(UNARYPREC,0)
12996#define TOK_NOT tok_decl(UNARYPREC,1)
12997
12998#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12999#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13000
13001#define PREC_PRE (UNARYPREC+2)
13002
13003#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13004#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13005
13006#define PREC_POST (UNARYPREC+3)
13007
13008#define TOK_POST_INC tok_decl(PREC_POST, 0)
13009#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13010
13011#define SPEC_PREC (UNARYPREC+4)
13012
13013#define TOK_NUM tok_decl(SPEC_PREC, 0)
13014#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13015
13016#define NUMPTR (*numstackptr)
13017
13018static inline int tok_have_assign(operator op)
13019{
13020 operator prec = PREC(op);
13021
13022 convert_prec_is_assing(prec);
13023 return (prec == PREC(TOK_ASSIGN) ||
13024 prec == PREC_PRE || prec == PREC_POST);
13025}
13026
13027static inline int is_right_associativity(operator prec)
13028{
13029 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13030 prec == PREC(TOK_CONDITIONAL));
13031}
13032
13033
13034typedef struct ARITCH_VAR_NUM {
13035 long val;
13036 long contidional_second_val;
13037 char contidional_second_val_initialized;
13038 char *var; /* if NULL then is regular number,
13039 else is varable name */
13040} v_n_t;
13041
13042
13043typedef struct CHK_VAR_RECURSIVE_LOOPED {
13044 const char *var;
13045 struct CHK_VAR_RECURSIVE_LOOPED *next;
13046} chk_var_recursive_looped_t;
13047
13048static chk_var_recursive_looped_t *prev_chk_var_recursive;
13049
13050
13051static int arith_lookup_val(v_n_t *t)
13052{
13053 if(t->var) {
13054 const char * p = lookupvar(t->var);
13055
13056 if(p) {
13057 int errcode;
13058
13059 /* recursive try as expression */
13060 chk_var_recursive_looped_t *cur;
13061 chk_var_recursive_looped_t cur_save;
13062
13063 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13064 if(strcmp(cur->var, t->var) == 0) {
13065 /* expression recursion loop detected */
13066 return -5;
13067 }
13068 }
13069 /* save current lookuped var name */
13070 cur = prev_chk_var_recursive;
13071 cur_save.var = t->var;
13072 cur_save.next = cur;
13073 prev_chk_var_recursive = &cur_save;
13074
13075 t->val = arith (p, &errcode);
13076 /* restore previous ptr after recursiving */
13077 prev_chk_var_recursive = cur;
13078 return errcode;
13079 } else {
13080 /* allow undefined var as 0 */
13081 t->val = 0;
13082 }
13083 }
13084 return 0;
13085}
13086
13087/* "applying" a token means performing it on the top elements on the integer
13088 * stack. For a unary operator it will only change the top element, but a
13089 * binary operator will pop two arguments and push a result */
13090static inline int
13091arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13092{
13093 long numptr_val;
13094 v_n_t *numptr_m1;
13095 long rez;
13096 int ret_arith_lookup_val;
13097
13098 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13099 without arguments */
13100 numptr_m1 = NUMPTR - 1;
13101
13102 /* check operand is var with noninteger value */
13103 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13104 if(ret_arith_lookup_val)
13105 return ret_arith_lookup_val;
13106
13107 rez = numptr_m1->val;
13108 if (op == TOK_UMINUS)
13109 rez *= -1;
13110 else if (op == TOK_NOT)
13111 rez = !rez;
13112 else if (op == TOK_BNOT)
13113 rez = ~rez;
13114 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13115 rez++;
13116 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13117 rez--;
13118 else if (op != TOK_UPLUS) {
13119 /* Binary operators */
13120
13121 /* check and binary operators need two arguments */
13122 if (numptr_m1 == numstack) goto err;
13123
13124 /* ... and they pop one */
13125 --NUMPTR;
13126 numptr_val = rez;
13127 if (op == TOK_CONDITIONAL) {
13128 if(! numptr_m1->contidional_second_val_initialized) {
13129 /* protect $((expr1 ? expr2)) without ": expr" */
13130 goto err;
13131 }
13132 rez = numptr_m1->contidional_second_val;
13133 } else if(numptr_m1->contidional_second_val_initialized) {
13134 /* protect $((expr1 : expr2)) without "expr ? " */
13135 goto err;
13136 }
13137 numptr_m1 = NUMPTR - 1;
13138 if(op != TOK_ASSIGN) {
13139 /* check operand is var with noninteger value for not '=' */
13140 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13141 if(ret_arith_lookup_val)
13142 return ret_arith_lookup_val;
13143 }
13144 if (op == TOK_CONDITIONAL) {
13145 numptr_m1->contidional_second_val = rez;
13146 }
13147 rez = numptr_m1->val;
13148 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13149 rez |= numptr_val;
13150 else if (op == TOK_OR)
13151 rez = numptr_val || rez;
13152 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13153 rez &= numptr_val;
13154 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13155 rez ^= numptr_val;
13156 else if (op == TOK_AND)
13157 rez = rez && numptr_val;
13158 else if (op == TOK_EQ)
13159 rez = (rez == numptr_val);
13160 else if (op == TOK_NE)
13161 rez = (rez != numptr_val);
13162 else if (op == TOK_GE)
13163 rez = (rez >= numptr_val);
13164 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13165 rez >>= numptr_val;
13166 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13167 rez <<= numptr_val;
13168 else if (op == TOK_GT)
13169 rez = (rez > numptr_val);
13170 else if (op == TOK_LT)
13171 rez = (rez < numptr_val);
13172 else if (op == TOK_LE)
13173 rez = (rez <= numptr_val);
13174 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13175 rez *= numptr_val;
13176 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13177 rez += numptr_val;
13178 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13179 rez -= numptr_val;
13180 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13181 rez = numptr_val;
13182 else if (op == TOK_CONDITIONAL_SEP) {
13183 if (numptr_m1 == numstack) {
13184 /* protect $((expr : expr)) without "expr ? " */
13185 goto err;
13186 }
13187 numptr_m1->contidional_second_val_initialized = op;
13188 numptr_m1->contidional_second_val = numptr_val;
13189 }
13190 else if (op == TOK_CONDITIONAL) {
13191 rez = rez ?
13192 numptr_val : numptr_m1->contidional_second_val;
13193 }
13194 else if(op == TOK_EXPONENT) {
13195 if(numptr_val < 0)
13196 return -3; /* exponent less than 0 */
13197 else {
13198 long c = 1;
13199
13200 if(numptr_val)
13201 while(numptr_val--)
13202 c *= rez;
13203 rez = c;
13204 }
13205 }
13206 else if(numptr_val==0) /* zero divisor check */
13207 return -2;
13208 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13209 rez /= numptr_val;
13210 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13211 rez %= numptr_val;
13212 }
13213 if(tok_have_assign(op)) {
13214 char buf[32];
13215
13216 if(numptr_m1->var == NULL) {
13217 /* Hmm, 1=2 ? */
13218 goto err;
13219 }
13220 /* save to shell variable */
13221 sprintf(buf, "%ld", rez);
13222 setvar(numptr_m1->var, buf, 0);
13223 /* after saving, make previous value for v++ or v-- */
13224 if(op == TOK_POST_INC)
13225 rez--;
13226 else if(op == TOK_POST_DEC)
13227 rez++;
13228 }
13229 numptr_m1->val = rez;
13230 /* protect geting var value, is number now */
13231 numptr_m1->var = NULL;
13232 return 0;
13233err: return(-1);
13234}
13235
13236/* longest must first */
13237static const char op_tokens[] = {
13238 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13239 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13240 '<','<', 0, TOK_LSHIFT,
13241 '>','>', 0, TOK_RSHIFT,
13242 '|','|', 0, TOK_OR,
13243 '&','&', 0, TOK_AND,
13244 '!','=', 0, TOK_NE,
13245 '<','=', 0, TOK_LE,
13246 '>','=', 0, TOK_GE,
13247 '=','=', 0, TOK_EQ,
13248 '|','=', 0, TOK_OR_ASSIGN,
13249 '&','=', 0, TOK_AND_ASSIGN,
13250 '*','=', 0, TOK_MUL_ASSIGN,
13251 '/','=', 0, TOK_DIV_ASSIGN,
13252 '%','=', 0, TOK_REM_ASSIGN,
13253 '+','=', 0, TOK_PLUS_ASSIGN,
13254 '-','=', 0, TOK_MINUS_ASSIGN,
13255 '-','-', 0, TOK_POST_DEC,
13256 '^','=', 0, TOK_XOR_ASSIGN,
13257 '+','+', 0, TOK_POST_INC,
13258 '*','*', 0, TOK_EXPONENT,
13259 '!', 0, TOK_NOT,
13260 '<', 0, TOK_LT,
13261 '>', 0, TOK_GT,
13262 '=', 0, TOK_ASSIGN,
13263 '|', 0, TOK_BOR,
13264 '&', 0, TOK_BAND,
13265 '*', 0, TOK_MUL,
13266 '/', 0, TOK_DIV,
13267 '%', 0, TOK_REM,
13268 '+', 0, TOK_ADD,
13269 '-', 0, TOK_SUB,
13270 '^', 0, TOK_BXOR,
13271 /* uniq */
13272 '~', 0, TOK_BNOT,
13273 ',', 0, TOK_COMMA,
13274 '?', 0, TOK_CONDITIONAL,
13275 ':', 0, TOK_CONDITIONAL_SEP,
13276 ')', 0, TOK_RPAREN,
13277 '(', 0, TOK_LPAREN,
13278 0
13279};
13280/* ptr to ")" */
13281#define endexpression &op_tokens[sizeof(op_tokens)-7]
13282
13283
13284extern long arith (const char *expr, int *perrcode)
13285{
13286 register char arithval; /* Current character under analysis */
13287 operator lasttok, op;
13288 operator prec;
13289
13290 const char *p = endexpression;
13291 int errcode;
13292
13293 size_t datasizes = strlen(expr) + 2;
13294
13295 /* Stack of integers */
13296 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13297 * in any given correct or incorrect expression is left as an excersize to
13298 * the reader. */
13299 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13300 *numstackptr = numstack;
13301 /* Stack of operator tokens */
13302 operator *stack = alloca((datasizes) * sizeof(operator)),
13303 *stackptr = stack;
13304
13305 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13306 *perrcode = errcode = 0;
13307
13308 while(1) {
13309 if ((arithval = *expr) == 0) {
13310 if (p == endexpression) {
13311 /* Null expression. */
13312 return 0;
13313 }
13314
13315 /* This is only reached after all tokens have been extracted from the
13316 * input stream. If there are still tokens on the operator stack, they
13317 * are to be applied in order. At the end, there should be a final
13318 * result on the integer stack */
13319
13320 if (expr != endexpression + 1) {
13321 /* If we haven't done so already, */
13322 /* append a closing right paren */
13323 expr = endexpression;
13324 /* and let the loop process it. */
13325 continue;
13326 }
13327 /* At this point, we're done with the expression. */
13328 if (numstackptr != numstack+1) {
13329 /* ... but if there isn't, it's bad */
13330 err:
13331 return (*perrcode = -1);
13332 }
13333 if(numstack->var) {
13334 /* expression is $((var)) only, lookup now */
13335 errcode = arith_lookup_val(numstack);
13336 }
13337 ret:
13338 *perrcode = errcode;
13339 return numstack->val;
13340 } else {
13341 /* Continue processing the expression. */
13342 if (arith_isspace(arithval)) {
13343 /* Skip whitespace */
13344 goto prologue;
13345 }
13346 if((p = endofname(expr)) != expr) {
13347 int var_name_size = (p-expr) + 1; /* trailing zero */
13348
13349 numstackptr->var = alloca(var_name_size);
13350 safe_strncpy(numstackptr->var, expr, var_name_size);
13351 expr = p;
13352 num:
13353 numstackptr->contidional_second_val_initialized = 0;
13354 numstackptr++;
13355 lasttok = TOK_NUM;
13356 continue;
13357 } else if (is_digit(arithval)) {
13358 numstackptr->var = NULL;
13359 numstackptr->val = strtol(expr, (char **) &expr, 0);
13360 goto num;
13361 }
13362 for(p = op_tokens; ; p++) {
13363 const char *o;
13364
13365 if(*p == 0) {
13366 /* strange operator not found */
13367 goto err;
13368 }
13369 for(o = expr; *p && *o == *p; p++)
13370 o++;
13371 if(! *p) {
13372 /* found */
13373 expr = o - 1;
13374 break;
13375 }
13376 /* skip tail uncompared token */
13377 while(*p)
13378 p++;
13379 /* skip zero delim */
13380 p++;
13381 }
13382 op = p[1];
13383
13384 /* post grammar: a++ reduce to num */
13385 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13386 lasttok = TOK_NUM;
13387
13388 /* Plus and minus are binary (not unary) _only_ if the last
13389 * token was as number, or a right paren (which pretends to be
13390 * a number, since it evaluates to one). Think about it.
13391 * It makes sense. */
13392 if (lasttok != TOK_NUM) {
13393 switch(op) {
13394 case TOK_ADD:
13395 op = TOK_UPLUS;
13396 break;
13397 case TOK_SUB:
13398 op = TOK_UMINUS;
13399 break;
13400 case TOK_POST_INC:
13401 op = TOK_PRE_INC;
13402 break;
13403 case TOK_POST_DEC:
13404 op = TOK_PRE_DEC;
13405 break;
13406 }
13407 }
13408 /* We don't want a unary operator to cause recursive descent on the
13409 * stack, because there can be many in a row and it could cause an
13410 * operator to be evaluated before its argument is pushed onto the
13411 * integer stack. */
13412 /* But for binary operators, "apply" everything on the operator
13413 * stack until we find an operator with a lesser priority than the
13414 * one we have just extracted. */
13415 /* Left paren is given the lowest priority so it will never be
13416 * "applied" in this way.
13417 * if associativity is right and priority eq, applied also skip
13418 */
13419 prec = PREC(op);
13420 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13421 /* not left paren or unary */
13422 if (lasttok != TOK_NUM) {
13423 /* binary op must be preceded by a num */
13424 goto err;
13425 }
13426 while (stackptr != stack) {
13427 if (op == TOK_RPAREN) {
13428 /* The algorithm employed here is simple: while we don't
13429 * hit an open paren nor the bottom of the stack, pop
13430 * tokens and apply them */
13431 if (stackptr[-1] == TOK_LPAREN) {
13432 --stackptr;
13433 /* Any operator directly after a */
13434 lasttok = TOK_NUM;
13435 /* close paren should consider itself binary */
13436 goto prologue;
13437 }
13438 } else {
13439 operator prev_prec = PREC(stackptr[-1]);
13440
13441 convert_prec_is_assing(prec);
13442 convert_prec_is_assing(prev_prec);
13443 if (prev_prec < prec)
13444 break;
13445 /* check right assoc */
13446 if(prev_prec == prec && is_right_associativity(prec))
13447 break;
13448 }
13449 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13450 if(errcode) goto ret;
13451 }
13452 if (op == TOK_RPAREN) {
13453 goto err;
13454 }
13455 }
13456
13457 /* Push this operator to the stack and remember it. */
13458 *stackptr++ = lasttok = op;
13459
13460 prologue:
13461 ++expr;
13462 }
13463 }
13464}
13465#endif /* CONFIG_ASH_MATH_SUPPORT */
13466
13467
Eric Andersenc470f442003-07-28 09:56:35 +000013468#ifdef DEBUG
13469const char *bb_applet_name = "debug stuff usage";
13470int main(int argc, char **argv)
13471{
13472 return ash_main(argc, argv);
13473}
13474#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013475
Eric Andersendf82f612001-06-28 07:46:40 +000013476/*-
13477 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013478 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013479 *
13480 * This code is derived from software contributed to Berkeley by
13481 * Kenneth Almquist.
13482 *
13483 * Redistribution and use in source and binary forms, with or without
13484 * modification, are permitted provided that the following conditions
13485 * are met:
13486 * 1. Redistributions of source code must retain the above copyright
13487 * notice, this list of conditions and the following disclaimer.
13488 * 2. Redistributions in binary form must reproduce the above copyright
13489 * notice, this list of conditions and the following disclaimer in the
13490 * documentation and/or other materials provided with the distribution.
13491 *
Eric Andersen2870d962001-07-02 17:27:21 +000013492 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13493 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013494 *
13495 * 4. Neither the name of the University nor the names of its contributors
13496 * may be used to endorse or promote products derived from this software
13497 * without specific prior written permission.
13498 *
13499 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13500 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13501 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13502 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13503 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13504 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13505 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13506 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13507 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13508 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13509 * SUCH DAMAGE.
13510 */