blob: 2146349abbbdf992a2c1c1efe17b0990826ab95c [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 */
Eric Andersenc470f442003-07-28 09:56:35 +0000553static struct parsefile basepf; /* top level input file */
554static char basebuf[IBUFSIZ]; /* buffer for top level input file */
555static struct parsefile *parsefile = &basepf; /* current input file */
556
557
558static int tokpushback; /* last token pushed back */
559#define NEOF ((union node *)&tokpushback)
560static int parsebackquote; /* nonzero if we are inside backquotes */
561static int doprompt; /* if set, prompt the user */
562static int needprompt; /* true if interactive and at start of line */
563static int lasttoken; /* last token read */
564static char *wordtext; /* text of last word returned by readtoken */
565static int checkkwd;
566static struct nodelist *backquotelist;
567static union node *redirnode;
568static struct heredoc *heredoc;
569static int quoteflag; /* set if (part of) last token was quoted */
570static int startlinno; /* line # where last token started */
571
572static union node *parsecmd(int);
573static void fixredir(union node *, const char *, int);
574static const char *const *findkwd(const char *);
575static char *endofname(const char *);
576
577/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
578
579typedef void *pointer;
580
581static char nullstr[1]; /* zero length string */
582static const char spcstr[] = " ";
583static const char snlfmt[] = "%s\n";
584static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
585static const char illnum[] = "Illegal number: %s";
586static const char homestr[] = "HOME";
587
588#ifdef DEBUG
589#define TRACE(param) trace param
590#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000591#else
Eric Andersenc470f442003-07-28 09:56:35 +0000592#define TRACE(param)
593#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000594#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000595
Eric Andersenc470f442003-07-28 09:56:35 +0000596#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
597#define __builtin_expect(x, expected_value) (x)
598#endif
599
600#define likely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000601
Eric Andersenc470f442003-07-28 09:56:35 +0000602
603#define TEOF 0
604#define TNL 1
605#define TREDIR 2
606#define TWORD 3
607#define TSEMI 4
608#define TBACKGND 5
609#define TAND 6
610#define TOR 7
611#define TPIPE 8
612#define TLP 9
613#define TRP 10
614#define TENDCASE 11
615#define TENDBQUOTE 12
616#define TNOT 13
617#define TCASE 14
618#define TDO 15
619#define TDONE 16
620#define TELIF 17
621#define TELSE 18
622#define TESAC 19
623#define TFI 20
624#define TFOR 21
625#define TIF 22
626#define TIN 23
627#define TTHEN 24
628#define TUNTIL 25
629#define TWHILE 26
630#define TBEGIN 27
631#define TEND 28
632
633/* first char is indicating which tokens mark the end of a list */
634static const char *const tokname_array[] = {
635 "\1end of file",
636 "\0newline",
637 "\0redirection",
638 "\0word",
639 "\0;",
640 "\0&",
641 "\0&&",
642 "\0||",
643 "\0|",
644 "\0(",
645 "\1)",
646 "\1;;",
647 "\1`",
648#define KWDOFFSET 13
649 /* the following are keywords */
650 "\0!",
651 "\0case",
652 "\1do",
653 "\1done",
654 "\1elif",
655 "\1else",
656 "\1esac",
657 "\1fi",
658 "\0for",
659 "\0if",
660 "\0in",
661 "\1then",
662 "\0until",
663 "\0while",
664 "\0{",
665 "\1}",
666};
667
668static const char *tokname(int tok)
669{
670 static char buf[16];
671
672 if (tok >= TSEMI)
673 buf[0] = '"';
674 sprintf(buf + (tok >= TSEMI), "%s%c",
675 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
676 return buf;
677}
678
679/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
680
681/*
682 * Most machines require the value returned from malloc to be aligned
683 * in some way. The following macro will get this right on many machines.
684 */
685
686#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
687/*
688 * It appears that grabstackstr() will barf with such alignments
689 * because stalloc() will return a string allocated in a new stackblock.
690 */
691#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
692
693/*
694 * This file was generated by the mksyntax program.
695 */
696
697
698/* Syntax classes */
699#define CWORD 0 /* character is nothing special */
700#define CNL 1 /* newline character */
701#define CBACK 2 /* a backslash character */
702#define CSQUOTE 3 /* single quote */
703#define CDQUOTE 4 /* double quote */
704#define CENDQUOTE 5 /* a terminating quote */
705#define CBQUOTE 6 /* backwards single quote */
706#define CVAR 7 /* a dollar sign */
707#define CENDVAR 8 /* a '}' character */
708#define CLP 9 /* a left paren in arithmetic */
709#define CRP 10 /* a right paren in arithmetic */
710#define CENDFILE 11 /* end of file */
711#define CCTL 12 /* like CWORD, except it must be escaped */
712#define CSPCL 13 /* these terminate a word */
713#define CIGN 14 /* character should be ignored */
714
715#ifdef CONFIG_ASH_ALIAS
716#define SYNBASE 130
717#define PEOF -130
718#define PEOA -129
719#define PEOA_OR_PEOF PEOA
720#else
721#define SYNBASE 129
722#define PEOF -129
723#define PEOA_OR_PEOF PEOF
724#endif
725
726#define is_digit(c) ((unsigned)((c) - '0') <= 9)
727#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
728#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
729
730/*
731 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
732 * (assuming ascii char codes, as the original implementation did)
733 */
734#define is_special(c) \
735 ( (((unsigned int)c) - 33 < 32) \
736 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
737
738#define digit_val(c) ((c) - '0')
739
740/*
741 * This file was generated by the mksyntax program.
742 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000743
Eric Andersend35c5df2002-01-09 15:37:36 +0000744#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000745#define USE_SIT_FUNCTION
746#endif
747
748/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000749#define BASESYNTAX 0 /* not in quotes */
750#define DQSYNTAX 1 /* in double quotes */
751#define SQSYNTAX 2 /* in single quotes */
752#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000753
Eric Andersenc470f442003-07-28 09:56:35 +0000754#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000755static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000756#ifdef CONFIG_ASH_ALIAS
757 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
758#endif
759 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
760 {CNL, CNL, CNL, CNL}, /* 2, \n */
761 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
762 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
763 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
764 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
765 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
766 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
767 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
768 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
769 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000770#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000771 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
772 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
773 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000774#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000775};
Eric Andersenc470f442003-07-28 09:56:35 +0000776#else
777static const char S_I_T[][3] = {
778#ifdef CONFIG_ASH_ALIAS
779 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
780#endif
781 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
782 {CNL, CNL, CNL}, /* 2, \n */
783 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
784 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
785 {CVAR, CVAR, CWORD}, /* 5, $ */
786 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
787 {CSPCL, CWORD, CWORD}, /* 7, ( */
788 {CSPCL, CWORD, CWORD}, /* 8, ) */
789 {CBACK, CBACK, CCTL}, /* 9, \ */
790 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
791 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
792#ifndef USE_SIT_FUNCTION
793 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
794 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
795 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
796#endif
797};
798#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000799
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000800#ifdef USE_SIT_FUNCTION
801
802#define U_C(c) ((unsigned char)(c))
803
804static int SIT(int c, int syntax)
805{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000806 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000807#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000808 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000809 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
810 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
811 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
812 11, 3 /* "}~" */
813 };
814#else
815 static const char syntax_index_table[] = {
816 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
817 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
818 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
819 10, 2 /* "}~" */
820 };
821#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000822 const char *s;
823 int indx;
824
Eric Andersenc470f442003-07-28 09:56:35 +0000825 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000826 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000827#ifdef CONFIG_ASH_ALIAS
828 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000829 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000830 else
831#endif
832 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
833 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000834 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000835 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000836 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000837 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000838 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000839 }
840 return S_I_T[indx][syntax];
841}
842
Eric Andersenc470f442003-07-28 09:56:35 +0000843#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000844
845#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
846
Eric Andersenc470f442003-07-28 09:56:35 +0000847#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000848#define CSPCL_CIGN_CIGN_CIGN 0
849#define CSPCL_CWORD_CWORD_CWORD 1
850#define CNL_CNL_CNL_CNL 2
851#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000852#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000853#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000854#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000855#define CSPCL_CWORD_CWORD_CLP 7
856#define CSPCL_CWORD_CWORD_CRP 8
857#define CBACK_CBACK_CCTL_CBACK 9
858#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
859#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
860#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
861#define CWORD_CWORD_CWORD_CWORD 13
862#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000863#else
864#define CSPCL_CWORD_CWORD_CWORD 0
865#define CNL_CNL_CNL_CNL 1
866#define CWORD_CCTL_CCTL_CWORD 2
867#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
868#define CVAR_CVAR_CWORD_CVAR 4
869#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
870#define CSPCL_CWORD_CWORD_CLP 6
871#define CSPCL_CWORD_CWORD_CRP 7
872#define CBACK_CBACK_CCTL_CBACK 8
873#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
874#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
875#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
876#define CWORD_CWORD_CWORD_CWORD 12
877#define CCTL_CCTL_CCTL_CCTL 13
878#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000879
880static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000881 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000882 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
883#ifdef CONFIG_ASH_ALIAS
884 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
885#endif
886 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
887 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
888 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
889 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
890 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
891 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
892 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
893 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
894 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000895 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
896 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
897 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
898 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
899 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
900 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
901 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
902 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
903 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
904 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
905 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
906 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
907 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
908 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
909 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
910 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
911 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
912 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
913 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
914 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
915 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
916 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
917 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
918 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
919 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
920 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
921 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
922 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
923 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
924 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
925 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
926 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
927 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
928 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
929 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
930 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
931 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
932 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
933 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
934 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
935 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
936 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
937 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
938 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
939 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
940 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
941 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
942 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
943 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
944 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
945 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
946 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
947 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
948 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
949 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
950 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
951 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
952 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
953 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
954 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
955 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
956 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
957 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
958 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
959 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
960 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
961 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
962 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
963 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
964 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
965 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
966 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
967 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
968 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
969 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
970 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
971 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
972 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
973 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
974 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
975 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
976 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
977 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
978 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
979 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
980 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
981 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
982 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
983 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
984 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
985 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
986 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
987 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
988 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
989 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
990 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
991 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
992 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
993 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
994 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
995 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
996 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
997 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
998 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
999 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1024 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1025 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1047 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001048 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001049 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1050 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1051 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1052 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001053 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001054 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1055 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1056 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1057 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1058 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1059 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1060 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1061 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1062 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1063 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1064 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1072 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1073 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1075 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1076 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1077 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1078 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1106 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1107 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1108 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1111 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1139 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1140 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1141 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001142};
1143
Eric Andersenc470f442003-07-28 09:56:35 +00001144#endif /* USE_SIT_FUNCTION */
1145
1146/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001147
Eric Andersen2870d962001-07-02 17:27:21 +00001148
Eric Andersenc470f442003-07-28 09:56:35 +00001149#define ATABSIZE 39
1150
1151static int funcblocksize; /* size of structures in function */
1152static int funcstringsize; /* size of strings in node */
1153static pointer funcblock; /* block to allocate function from */
1154static char *funcstring; /* block to allocate strings from */
1155
1156static const short nodesize[26] = {
1157 SHELL_ALIGN(sizeof (struct ncmd)),
1158 SHELL_ALIGN(sizeof (struct npipe)),
1159 SHELL_ALIGN(sizeof (struct nredir)),
1160 SHELL_ALIGN(sizeof (struct nredir)),
1161 SHELL_ALIGN(sizeof (struct nredir)),
1162 SHELL_ALIGN(sizeof (struct nbinary)),
1163 SHELL_ALIGN(sizeof (struct nbinary)),
1164 SHELL_ALIGN(sizeof (struct nbinary)),
1165 SHELL_ALIGN(sizeof (struct nif)),
1166 SHELL_ALIGN(sizeof (struct nbinary)),
1167 SHELL_ALIGN(sizeof (struct nbinary)),
1168 SHELL_ALIGN(sizeof (struct nfor)),
1169 SHELL_ALIGN(sizeof (struct ncase)),
1170 SHELL_ALIGN(sizeof (struct nclist)),
1171 SHELL_ALIGN(sizeof (struct narg)),
1172 SHELL_ALIGN(sizeof (struct narg)),
1173 SHELL_ALIGN(sizeof (struct nfile)),
1174 SHELL_ALIGN(sizeof (struct nfile)),
1175 SHELL_ALIGN(sizeof (struct nfile)),
1176 SHELL_ALIGN(sizeof (struct nfile)),
1177 SHELL_ALIGN(sizeof (struct nfile)),
1178 SHELL_ALIGN(sizeof (struct ndup)),
1179 SHELL_ALIGN(sizeof (struct ndup)),
1180 SHELL_ALIGN(sizeof (struct nhere)),
1181 SHELL_ALIGN(sizeof (struct nhere)),
1182 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001183};
1184
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001185
Eric Andersenc470f442003-07-28 09:56:35 +00001186static void calcsize(union node *);
1187static void sizenodelist(struct nodelist *);
1188static union node *copynode(union node *);
1189static struct nodelist *copynodelist(struct nodelist *);
1190static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001191
1192
Eric Andersen2870d962001-07-02 17:27:21 +00001193
Eric Andersenc470f442003-07-28 09:56:35 +00001194static void evalstring(char *, int);
1195union node; /* BLETCH for ansi C */
1196static void evaltree(union node *, int);
1197static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001198
Eric Andersenc470f442003-07-28 09:56:35 +00001199/* in_function returns nonzero if we are currently evaluating a function */
1200#define in_function() funcnest
1201static int evalskip; /* set if we are skipping commands */
1202static int skipcount; /* number of levels to skip */
1203static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001204
1205/* reasons for skipping commands (see comment on breakcmd routine) */
1206#define SKIPBREAK 1
1207#define SKIPCONT 2
1208#define SKIPFUNC 3
1209#define SKIPFILE 4
1210
Eric Andersenc470f442003-07-28 09:56:35 +00001211/*
1212 * This file was generated by the mkbuiltins program.
1213 */
Eric Andersen2870d962001-07-02 17:27:21 +00001214
Eric Andersenc470f442003-07-28 09:56:35 +00001215#ifdef JOBS
1216static int bgcmd(int, char **);
1217#endif
1218static int breakcmd(int, char **);
1219static int cdcmd(int, char **);
1220#ifdef CONFIG_ASH_CMDCMD
1221static int commandcmd(int, char **);
1222#endif
1223static int dotcmd(int, char **);
1224static int evalcmd(int, char **);
1225static int execcmd(int, char **);
1226static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001227static int exportcmd(int, char **);
1228static int falsecmd(int, char **);
1229#ifdef JOBS
1230static int fgcmd(int, char **);
1231#endif
1232#ifdef CONFIG_ASH_GETOPTS
1233static int getoptscmd(int, char **);
1234#endif
1235static int hashcmd(int, char **);
1236#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1237static int helpcmd(int argc, char **argv);
1238#endif
1239#ifdef JOBS
1240static int jobscmd(int, char **);
1241#endif
Eric Andersen90898442003-08-06 11:20:52 +00001242#ifdef CONFIG_ASH_MATH_SUPPORT
1243static int letcmd(int, char **);
1244#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001245static int localcmd(int, char **);
1246static int pwdcmd(int, char **);
1247static int readcmd(int, char **);
1248static int returncmd(int, char **);
1249static int setcmd(int, char **);
1250static int shiftcmd(int, char **);
1251static int timescmd(int, char **);
1252static int trapcmd(int, char **);
1253static int truecmd(int, char **);
1254static int typecmd(int, char **);
1255static int umaskcmd(int, char **);
1256static int unsetcmd(int, char **);
1257static int waitcmd(int, char **);
1258static int ulimitcmd(int, char **);
1259#ifdef JOBS
1260static int killcmd(int, char **);
1261#endif
1262
1263/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1264
1265#ifdef CONFIG_ASH_MAIL
1266static void chkmail(void);
1267static void changemail(const char *);
1268#endif
1269
1270/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1271
1272/* values of cmdtype */
1273#define CMDUNKNOWN -1 /* no entry in table for command */
1274#define CMDNORMAL 0 /* command is an executable program */
1275#define CMDFUNCTION 1 /* command is a shell function */
1276#define CMDBUILTIN 2 /* command is a shell builtin */
1277
1278struct builtincmd {
1279 const char *name;
1280 int (*builtin)(int, char **);
1281 /* unsigned flags; */
1282};
1283
1284#ifdef CONFIG_ASH_CMDCMD
1285# ifdef JOBS
1286# ifdef CONFIG_ASH_ALIAS
1287# define COMMANDCMD (builtincmd + 7)
1288# define EXECCMD (builtincmd + 10)
1289# else
1290# define COMMANDCMD (builtincmd + 6)
1291# define EXECCMD (builtincmd + 9)
1292# endif
1293# else /* ! JOBS */
1294# ifdef CONFIG_ASH_ALIAS
1295# define COMMANDCMD (builtincmd + 6)
1296# define EXECCMD (builtincmd + 9)
1297# else
1298# define COMMANDCMD (builtincmd + 5)
1299# define EXECCMD (builtincmd + 8)
1300# endif
1301# endif /* JOBS */
1302#else /* ! CONFIG_ASH_CMDCMD */
1303# ifdef JOBS
1304# ifdef CONFIG_ASH_ALIAS
1305# define EXECCMD (builtincmd + 9)
1306# else
1307# define EXECCMD (builtincmd + 8)
1308# endif
1309# else /* ! JOBS */
1310# ifdef CONFIG_ASH_ALIAS
1311# define EXECCMD (builtincmd + 8)
1312# else
1313# define EXECCMD (builtincmd + 7)
1314# endif
1315# endif /* JOBS */
1316#endif /* CONFIG_ASH_CMDCMD */
1317
1318#define BUILTIN_NOSPEC "0"
1319#define BUILTIN_SPECIAL "1"
1320#define BUILTIN_REGULAR "2"
1321#define BUILTIN_SPEC_REG "3"
1322#define BUILTIN_ASSIGN "4"
1323#define BUILTIN_SPEC_ASSG "5"
1324#define BUILTIN_REG_ASSG "6"
1325#define BUILTIN_SPEC_REG_ASSG "7"
1326
1327#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1328#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1329
1330static const struct builtincmd builtincmd[] = {
1331 { BUILTIN_SPEC_REG ".", dotcmd },
1332 { BUILTIN_SPEC_REG ":", truecmd },
1333#ifdef CONFIG_ASH_ALIAS
1334 { BUILTIN_REG_ASSG "alias", aliascmd },
1335#endif
1336#ifdef JOBS
1337 { BUILTIN_REGULAR "bg", bgcmd },
1338#endif
1339 { BUILTIN_SPEC_REG "break", breakcmd },
1340 { BUILTIN_REGULAR "cd", cdcmd },
1341 { BUILTIN_NOSPEC "chdir", cdcmd },
1342#ifdef CONFIG_ASH_CMDCMD
1343 { BUILTIN_REGULAR "command", commandcmd },
1344#endif
1345 { BUILTIN_SPEC_REG "continue", breakcmd },
1346 { BUILTIN_SPEC_REG "eval", evalcmd },
1347 { BUILTIN_SPEC_REG "exec", execcmd },
1348 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001349 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1350 { BUILTIN_REGULAR "false", falsecmd },
1351#ifdef JOBS
1352 { BUILTIN_REGULAR "fg", fgcmd },
1353#endif
1354#ifdef CONFIG_ASH_GETOPTS
1355 { BUILTIN_REGULAR "getopts", getoptscmd },
1356#endif
1357 { BUILTIN_NOSPEC "hash", hashcmd },
1358#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1359 { BUILTIN_NOSPEC "help", helpcmd },
1360#endif
1361#ifdef JOBS
1362 { BUILTIN_REGULAR "jobs", jobscmd },
1363 { BUILTIN_REGULAR "kill", killcmd },
1364#endif
1365#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001366 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001367#endif
1368 { BUILTIN_ASSIGN "local", localcmd },
1369 { BUILTIN_NOSPEC "pwd", pwdcmd },
1370 { BUILTIN_REGULAR "read", readcmd },
1371 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1372 { BUILTIN_SPEC_REG "return", returncmd },
1373 { BUILTIN_SPEC_REG "set", setcmd },
1374 { BUILTIN_SPEC_REG "shift", shiftcmd },
1375 { BUILTIN_SPEC_REG "times", timescmd },
1376 { BUILTIN_SPEC_REG "trap", trapcmd },
1377 { BUILTIN_REGULAR "true", truecmd },
1378 { BUILTIN_NOSPEC "type", typecmd },
1379 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1380 { BUILTIN_REGULAR "umask", umaskcmd },
1381#ifdef CONFIG_ASH_ALIAS
1382 { BUILTIN_REGULAR "unalias", unaliascmd },
1383#endif
1384 { BUILTIN_SPEC_REG "unset", unsetcmd },
1385 { BUILTIN_REGULAR "wait", waitcmd },
1386};
1387
1388#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1389
1390
1391
1392struct cmdentry {
1393 int cmdtype;
1394 union param {
1395 int index;
1396 const struct builtincmd *cmd;
1397 struct funcnode *func;
1398 } u;
1399};
1400
1401
1402/* action to find_command() */
1403#define DO_ERR 0x01 /* prints errors */
1404#define DO_ABS 0x02 /* checks absolute paths */
1405#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1406#define DO_ALTPATH 0x08 /* using alternate path */
1407#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1408
1409static const char *pathopt; /* set by padvance */
1410
1411static void shellexec(char **, const char *, int)
1412 __attribute__((__noreturn__));
1413static char *padvance(const char **, const char *);
1414static void find_command(char *, struct cmdentry *, int, const char *);
1415static struct builtincmd *find_builtin(const char *);
1416static void hashcd(void);
1417static void changepath(const char *);
1418static void defun(char *, union node *);
1419static void unsetfunc(const char *);
1420
1421#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001422static int dash_arith(const char *);
1423#endif
1424
1425/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1426
1427static void reset(void);
1428
1429/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001430
1431/*
1432 * Shell variables.
1433 */
1434
1435/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001436#define VEXPORT 0x01 /* variable is exported */
1437#define VREADONLY 0x02 /* variable cannot be modified */
1438#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1439#define VTEXTFIXED 0x08 /* text is statically allocated */
1440#define VSTACK 0x10 /* text is allocated on the stack */
1441#define VUNSET 0x20 /* the variable is not set */
1442#define VNOFUNC 0x40 /* don't call the callback function */
1443#define VNOSET 0x80 /* do not set variable - just readonly test */
1444#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen2870d962001-07-02 17:27:21 +00001445
1446
1447struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001448 struct var *next; /* next entry in hash list */
1449 int flags; /* flags are defined above */
1450 const char *text; /* name=value */
1451 void (*func)(const char *);
1452 /* function to be called when */
1453 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001454};
1455
1456struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001457 struct localvar *next; /* next local variable in list */
1458 struct var *vp; /* the variable that was made local */
1459 int flags; /* saved flags */
1460 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001461};
1462
1463
Eric Andersen2870d962001-07-02 17:27:21 +00001464static struct localvar *localvars;
1465
Eric Andersenc470f442003-07-28 09:56:35 +00001466/*
1467 * Shell variables.
1468 */
1469
1470#ifdef CONFIG_ASH_GETOPTS
1471static void getoptsreset(const char *);
1472#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001473
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001474#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001475#include <locale.h>
1476static void change_lc_all(const char *value);
1477static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001478#endif
1479
Eric Andersen2870d962001-07-02 17:27:21 +00001480#define VTABSIZE 39
1481
Eric Andersen90898442003-08-06 11:20:52 +00001482static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001483#ifdef IFS_BROKEN
1484static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001485#define defifs (defifsvar + 4)
1486#else
Eric Andersenc470f442003-07-28 09:56:35 +00001487static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001488#endif
1489
Eric Andersenc470f442003-07-28 09:56:35 +00001490
1491static struct var varinit[] = {
1492#ifdef IFS_BROKEN
1493 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1494#else
1495 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1496#endif
1497
1498#ifdef CONFIG_ASH_MAIL
1499 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1500 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1501#endif
1502
1503 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1504 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1505 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1506 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1507#ifdef CONFIG_ASH_GETOPTS
1508 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1509#endif
1510#ifdef CONFIG_LOCALE_SUPPORT
1511 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
1512 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
1513#endif
1514#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1515 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
1516#endif
1517};
1518
1519#define vifs varinit[0]
1520#ifdef CONFIG_ASH_MAIL
1521#define vmail (&vifs)[1]
1522#define vmpath (&vmail)[1]
1523#else
1524#define vmpath vifs
1525#endif
1526#define vpath (&vmpath)[1]
1527#define vps1 (&vpath)[1]
1528#define vps2 (&vps1)[1]
1529#define vps4 (&vps2)[1]
1530#define voptind (&vps4)[1]
1531
1532#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001533
1534/*
1535 * The following macros access the values of the above variables.
1536 * They have to skip over the name. They return the null string
1537 * for unset variables.
1538 */
1539
1540#define ifsval() (vifs.text + 4)
1541#define ifsset() ((vifs.flags & VUNSET) == 0)
1542#define mailval() (vmail.text + 5)
1543#define mpathval() (vmpath.text + 9)
1544#define pathval() (vpath.text + 5)
1545#define ps1val() (vps1.text + 4)
1546#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001547#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001548#define optindval() (voptind.text + 7)
1549
1550#define mpathset() ((vmpath.flags & VUNSET) == 0)
1551
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001552static void setvar(const char *, const char *, int);
1553static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001554static void listsetvar(struct strlist *, int);
1555static char *lookupvar(const char *);
1556static char *bltinlookup(const char *);
1557static char **listvars(int, int, char ***);
1558#define environment() listvars(VEXPORT, VUNSET, 0)
1559static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001560static void poplocalvars(void);
1561static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001562#ifdef CONFIG_ASH_GETOPTS
1563static int setvarsafe(const char *, const char *, int);
1564#endif
1565static int varcmp(const char *, const char *);
1566static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001567
1568
Eric Andersenc470f442003-07-28 09:56:35 +00001569static inline int varequal(const char *a, const char *b) {
1570 return !varcmp(a, b);
1571}
Eric Andersen2870d962001-07-02 17:27:21 +00001572
1573
Eric Andersenc470f442003-07-28 09:56:35 +00001574static int loopnest; /* current loop nesting level */
1575
1576struct strpush {
1577 struct strpush *prev; /* preceding string on stack */
1578 char *prevstring;
1579 int prevnleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00001580#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00001581 struct alias *ap; /* if push was associated with an alias */
1582#endif
1583 char *string; /* remember the string since it may change */
Eric Andersen2870d962001-07-02 17:27:21 +00001584};
1585
Eric Andersenc470f442003-07-28 09:56:35 +00001586struct parsefile {
1587 struct parsefile *prev; /* preceding file on stack */
1588 int linno; /* current line */
1589 int fd; /* file descriptor (or -1 if string) */
1590 int nleft; /* number of chars left in this line */
1591 int lleft; /* number of chars left in this buffer */
1592 char *nextc; /* next char in buffer */
1593 char *buf; /* input buffer */
1594 struct strpush *strpush; /* for pushing strings at this level */
1595 struct strpush basestrpush; /* so pushing one is fast */
1596};
1597
1598/*
1599 * The parsefile structure pointed to by the global variable parsefile
1600 * contains information about the current file being read.
1601 */
1602
1603
1604struct redirtab {
1605 struct redirtab *next;
1606 int renamed[10];
1607 int nullredirs;
1608};
1609
1610static struct redirtab *redirlist;
1611static int nullredirs;
1612
1613extern char **environ;
1614
1615/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1616
1617
1618static void outstr(const char *, FILE *);
1619static void outcslow(int, FILE *);
1620static void flushall(void);
1621static void flushout(FILE *);
1622static int out1fmt(const char *, ...)
1623 __attribute__((__format__(__printf__,1,2)));
1624static int fmtstr(char *, size_t, const char *, ...)
1625 __attribute__((__format__(__printf__,3,4)));
1626static void xwrite(int, const void *, size_t);
1627
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001628static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001629
Eric Andersenc470f442003-07-28 09:56:35 +00001630
1631static void out1str(const char *p)
1632{
1633 outstr(p, stdout);
1634}
1635
1636static void out2str(const char *p)
1637{
1638 outstr(p, stderr);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001639 flushout(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001640}
1641
1642/*
1643 * Initialization code.
1644 */
1645
1646/*
1647 * This routine initializes the builtin variables.
1648 */
1649
1650static inline void
1651initvar(void)
1652{
1653 struct var *vp;
1654 struct var *end;
1655 struct var **vpp;
1656
1657 /*
1658 * PS1 depends on uid
1659 */
1660#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1661 vps1.text = "PS1=\\w \\$ ";
1662#else
1663 if (!geteuid())
1664 vps1.text = "PS1=# ";
1665#endif
1666 vp = varinit;
1667 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1668 do {
1669 vpp = hashvar(vp->text);
1670 vp->next = *vpp;
1671 *vpp = vp;
1672 } while (++vp < end);
1673}
1674
1675static inline void
1676init(void)
1677{
1678
1679 /* from input.c: */
1680 {
1681 basepf.nextc = basepf.buf = basebuf;
1682 }
1683
1684 /* from trap.c: */
1685 {
1686 signal(SIGCHLD, SIG_DFL);
1687 }
1688
1689 /* from var.c: */
1690 {
1691 char **envp;
1692 char ppid[32];
1693
1694 initvar();
1695 for (envp = environ ; *envp ; envp++) {
1696 if (strchr(*envp, '=')) {
1697 setvareq(*envp, VEXPORT|VTEXTFIXED);
1698 }
1699 }
1700
1701 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1702 setvar("PPID", ppid, 0);
1703 setpwd(0, 0);
1704 }
1705}
1706
1707/* PEOF (the end of file marker) */
1708
1709/*
1710 * The input line number. Input.c just defines this variable, and saves
1711 * and restores it when files are pushed and popped. The user of this
1712 * package must set its value.
1713 */
1714
1715static int pgetc(void);
1716static int pgetc2(void);
1717static int preadbuffer(void);
1718static void pungetc(void);
1719static void pushstring(char *, void *);
1720static void popstring(void);
1721static void setinputfile(const char *, int);
1722static void setinputfd(int, int);
1723static void setinputstring(char *);
1724static void popfile(void);
1725static void popallfiles(void);
1726static void closescript(void);
1727
1728
1729/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1730
1731
1732/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1733#define FORK_FG 0
1734#define FORK_BG 1
1735#define FORK_NOJOB 2
1736
1737/* mode flags for showjob(s) */
1738#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1739#define SHOW_PID 0x04 /* include process pid */
1740#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1741
1742
1743/*
1744 * A job structure contains information about a job. A job is either a
1745 * single process or a set of processes contained in a pipeline. In the
1746 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1747 * array of pids.
1748 */
1749
1750struct procstat {
1751 pid_t pid; /* process id */
1752 int status; /* last process status from wait() */
1753 char *cmd; /* text of command being run */
1754};
1755
1756struct job {
1757 struct procstat ps0; /* status of process */
1758 struct procstat *ps; /* status or processes when more than one */
1759#if JOBS
1760 int stopstatus; /* status of a stopped job */
1761#endif
1762 uint32_t
1763 nprocs: 16, /* number of processes */
1764 state: 8,
1765#define JOBRUNNING 0 /* at least one proc running */
1766#define JOBSTOPPED 1 /* all procs are stopped */
1767#define JOBDONE 2 /* all procs are completed */
1768#if JOBS
1769 sigint: 1, /* job was killed by SIGINT */
1770 jobctl: 1, /* job running under job control */
1771#endif
1772 waited: 1, /* true if this entry has been waited for */
1773 used: 1, /* true if this entry is in used */
1774 changed: 1; /* true if status has changed */
1775 struct job *prev_job; /* previous job */
1776};
1777
1778static pid_t backgndpid; /* pid of last background process */
1779static int job_warning; /* user was warned about stopped jobs */
1780#if JOBS
1781static int jobctl; /* true if doing job control */
1782#endif
1783
1784static struct job *makejob(union node *, int);
1785static int forkshell(struct job *, union node *, int);
1786static int waitforjob(struct job *);
1787static int stoppedjobs(void);
1788
1789#if ! JOBS
1790#define setjobctl(on) /* do nothing */
1791#else
1792static void setjobctl(int);
1793static void showjobs(FILE *, int);
1794#endif
1795
1796/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1797
1798
1799/* pid of main shell */
1800static int rootpid;
1801/* true if we aren't a child of the main shell */
1802static int rootshell;
1803
1804static void readcmdfile(char *);
1805static void cmdloop(int);
1806
1807/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1808
1809
1810struct stackmark {
1811 struct stack_block *stackp;
1812 char *stacknxt;
1813 size_t stacknleft;
1814 struct stackmark *marknext;
1815};
1816
1817/* minimum size of a block */
1818#define MINSIZE SHELL_ALIGN(504)
1819
1820struct stack_block {
1821 struct stack_block *prev;
1822 char space[MINSIZE];
1823};
1824
1825static struct stack_block stackbase;
1826static struct stack_block *stackp = &stackbase;
1827static struct stackmark *markp;
1828static char *stacknxt = stackbase.space;
1829static size_t stacknleft = MINSIZE;
1830static char *sstrend = stackbase.space + MINSIZE;
1831static int herefd = -1;
1832
1833
1834static pointer ckmalloc(size_t);
1835static pointer ckrealloc(pointer, size_t);
1836static char *savestr(const char *);
1837static pointer stalloc(size_t);
1838static void stunalloc(pointer);
1839static void setstackmark(struct stackmark *);
1840static void popstackmark(struct stackmark *);
1841static void growstackblock(void);
1842static void *growstackstr(void);
1843static char *makestrspace(size_t, char *);
1844static char *stnputs(const char *, size_t, char *);
1845static char *stputs(const char *, char *);
1846
1847
1848static inline char *_STPUTC(char c, char *p) {
1849 if (p == sstrend)
1850 p = growstackstr();
1851 *p++ = c;
1852 return p;
1853}
1854
1855#define stackblock() ((void *)stacknxt)
1856#define stackblocksize() stacknleft
1857#define STARTSTACKSTR(p) ((p) = stackblock())
1858#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1859#define CHECKSTRSPACE(n, p) \
1860 ({ \
1861 char *q = (p); \
1862 size_t l = (n); \
1863 size_t m = sstrend - q; \
1864 if (l > m) \
1865 (p) = makestrspace(l, q); \
1866 0; \
1867 })
1868#define USTPUTC(c, p) (*p++ = (c))
1869#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1870#define STUNPUTC(p) (--p)
1871#define STTOPC(p) p[-1]
1872#define STADJUST(amount, p) (p += (amount))
1873
1874#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1875#define ungrabstackstr(s, p) stunalloc((s))
1876#define stackstrend() ((void *)sstrend)
1877
1878#define ckfree(p) free((pointer)(p))
1879
1880/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1881
1882
1883#define DOLATSTRLEN 4
1884
1885static char *prefix(const char *, const char *);
1886static int number(const char *);
1887static int is_number(const char *);
1888static char *single_quote(const char *);
1889static char *sstrdup(const char *);
1890
1891#define equal(s1, s2) (strcmp(s1, s2) == 0)
1892#define scopy(s1, s2) ((void)strcpy(s2, s1))
1893
1894/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1895
1896struct shparam {
1897 int nparam; /* # of positional parameters (without $0) */
1898 unsigned char malloc; /* if parameter list dynamically allocated */
1899 char **p; /* parameter list */
1900#ifdef CONFIG_ASH_GETOPTS
1901 int optind; /* next parameter to be processed by getopts */
1902 int optoff; /* used by getopts */
1903#endif
1904};
1905
1906
1907#define eflag optlist[0]
1908#define fflag optlist[1]
1909#define Iflag optlist[2]
1910#define iflag optlist[3]
1911#define mflag optlist[4]
1912#define nflag optlist[5]
1913#define sflag optlist[6]
1914#define xflag optlist[7]
1915#define vflag optlist[8]
1916#define Cflag optlist[9]
1917#define aflag optlist[10]
1918#define bflag optlist[11]
1919#define uflag optlist[12]
1920#define qflag optlist[13]
1921
1922#ifdef DEBUG
1923#define nolog optlist[14]
1924#define debug optlist[15]
1925#define NOPTS 16
1926#else
1927#define NOPTS 14
1928#endif
1929
1930/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1931
1932
1933static const char *const optletters_optnames[NOPTS] = {
1934 "e" "errexit",
1935 "f" "noglob",
1936 "I" "ignoreeof",
1937 "i" "interactive",
1938 "m" "monitor",
1939 "n" "noexec",
1940 "s" "stdin",
1941 "x" "xtrace",
1942 "v" "verbose",
1943 "C" "noclobber",
1944 "a" "allexport",
1945 "b" "notify",
1946 "u" "nounset",
1947 "q" "quietprofile",
1948#ifdef DEBUG
1949 "\0" "nolog",
1950 "\0" "debug",
1951#endif
1952};
1953
1954#define optletters(n) optletters_optnames[(n)][0]
1955#define optnames(n) (&optletters_optnames[(n)][1])
1956
1957
1958static char optlist[NOPTS];
1959
1960
1961static char *arg0; /* value of $0 */
1962static struct shparam shellparam; /* $@ current positional parameters */
1963static char **argptr; /* argument list for builtin commands */
1964static char *optionarg; /* set by nextopt (like getopt) */
1965static char *optptr; /* used by nextopt */
1966
1967static char *minusc; /* argument to -c option */
1968
1969
1970static void procargs(int, char **);
1971static void optschanged(void);
1972static void setparam(char **);
1973static void freeparam(volatile struct shparam *);
1974static int shiftcmd(int, char **);
1975static int setcmd(int, char **);
1976static int nextopt(const char *);
1977
1978/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1979
1980/* flags passed to redirect */
1981#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001982#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00001983
1984union node;
1985static void redirect(union node *, int);
1986static void popredir(int);
1987static void clearredir(int);
1988static int copyfd(int, int);
1989static int redirectsafe(union node *, int);
1990
1991/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
1992
1993
1994#ifdef DEBUG
1995static void showtree(union node *);
1996static void trace(const char *, ...);
1997static void tracev(const char *, va_list);
1998static void trargs(char **);
1999static void trputc(int);
2000static void trputs(const char *);
2001static void opentrace(void);
2002#endif
2003
2004/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2005
2006
2007/* trap handler commands */
2008static char *trap[NSIG];
2009/* current value of signal */
2010static char sigmode[NSIG - 1];
2011/* indicates specified signal received */
2012static char gotsig[NSIG - 1];
2013
2014static void clear_traps(void);
2015static void setsignal(int);
2016static void ignoresig(int);
2017static void onsig(int);
2018static void dotrap(void);
2019static void setinteractive(int);
2020static void exitshell(void) __attribute__((__noreturn__));
2021static int decode_signal(const char *, int);
2022
2023/*
2024 * This routine is called when an error or an interrupt occurs in an
2025 * interactive shell and control is returned to the main command loop.
2026 */
2027
2028static void
2029reset(void)
2030{
2031 /* from eval.c: */
2032 {
2033 evalskip = 0;
2034 loopnest = 0;
2035 funcnest = 0;
2036 }
2037
2038 /* from input.c: */
2039 {
2040 parselleft = parsenleft = 0; /* clear input buffer */
2041 popallfiles();
2042 }
2043
2044 /* from parser.c: */
2045 {
2046 tokpushback = 0;
2047 checkkwd = 0;
2048 }
2049
2050 /* from redir.c: */
2051 {
2052 clearredir(0);
2053 }
2054
2055}
2056
2057#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002058static struct alias *atab[ATABSIZE];
2059
Eric Andersenc470f442003-07-28 09:56:35 +00002060static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002061static struct alias *freealias(struct alias *);
2062static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002063
Eric Andersenc470f442003-07-28 09:56:35 +00002064static void
2065setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002066{
2067 struct alias *ap, **app;
2068
2069 app = __lookupalias(name);
2070 ap = *app;
2071 INTOFF;
2072 if (ap) {
2073 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002074 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002075 }
Eric Andersenc470f442003-07-28 09:56:35 +00002076 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002077 ap->flag &= ~ALIASDEAD;
2078 } else {
2079 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002080 ap = ckmalloc(sizeof (struct alias));
2081 ap->name = savestr(name);
2082 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002083 ap->flag = 0;
2084 ap->next = 0;
2085 *app = ap;
2086 }
2087 INTON;
2088}
2089
Eric Andersenc470f442003-07-28 09:56:35 +00002090static int
2091unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002092{
Eric Andersencb57d552001-06-28 07:25:16 +00002093 struct alias **app;
2094
2095 app = __lookupalias(name);
2096
2097 if (*app) {
2098 INTOFF;
2099 *app = freealias(*app);
2100 INTON;
2101 return (0);
2102 }
2103
2104 return (1);
2105}
2106
Eric Andersenc470f442003-07-28 09:56:35 +00002107static void
2108rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002109{
Eric Andersencb57d552001-06-28 07:25:16 +00002110 struct alias *ap, **app;
2111 int i;
2112
2113 INTOFF;
2114 for (i = 0; i < ATABSIZE; i++) {
2115 app = &atab[i];
2116 for (ap = *app; ap; ap = *app) {
2117 *app = freealias(*app);
2118 if (ap == *app) {
2119 app = &ap->next;
2120 }
2121 }
2122 }
2123 INTON;
2124}
2125
Eric Andersenc470f442003-07-28 09:56:35 +00002126static struct alias *
2127lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002128{
Eric Andersenc470f442003-07-28 09:56:35 +00002129 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002130
Eric Andersenc470f442003-07-28 09:56:35 +00002131 if (check && ap && (ap->flag & ALIASINUSE))
2132 return (NULL);
2133 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002134}
2135
Eric Andersencb57d552001-06-28 07:25:16 +00002136/*
2137 * TODO - sort output
2138 */
Eric Andersenc470f442003-07-28 09:56:35 +00002139static int
2140aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002141{
2142 char *n, *v;
2143 int ret = 0;
2144 struct alias *ap;
2145
2146 if (argc == 1) {
2147 int i;
2148
2149 for (i = 0; i < ATABSIZE; i++)
2150 for (ap = atab[i]; ap; ap = ap->next) {
2151 printalias(ap);
2152 }
2153 return (0);
2154 }
2155 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002156 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002157 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002158 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002159 ret = 1;
2160 } else
2161 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002162 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002163 *v++ = '\0';
2164 setalias(n, v);
2165 }
2166 }
2167
2168 return (ret);
2169}
2170
Eric Andersenc470f442003-07-28 09:56:35 +00002171static int
2172unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002173{
2174 int i;
2175
2176 while ((i = nextopt("a")) != '\0') {
2177 if (i == 'a') {
2178 rmaliases();
2179 return (0);
2180 }
2181 }
2182 for (i = 0; *argptr; argptr++) {
2183 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002184 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002185 i = 1;
2186 }
2187 }
2188
2189 return (i);
2190}
2191
Eric Andersenc470f442003-07-28 09:56:35 +00002192static struct alias *
2193freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002194 struct alias *next;
2195
2196 if (ap->flag & ALIASINUSE) {
2197 ap->flag |= ALIASDEAD;
2198 return ap;
2199 }
2200
2201 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002202 ckfree(ap->name);
2203 ckfree(ap->val);
2204 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002205 return next;
2206}
2207
Eric Andersenc470f442003-07-28 09:56:35 +00002208static void
2209printalias(const struct alias *ap) {
2210 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2211}
Eric Andersencb57d552001-06-28 07:25:16 +00002212
Eric Andersenc470f442003-07-28 09:56:35 +00002213static struct alias **
2214__lookupalias(const char *name) {
2215 unsigned int hashval;
2216 struct alias **app;
2217 const char *p;
2218 unsigned int ch;
2219
2220 p = name;
2221
2222 ch = (unsigned char)*p;
2223 hashval = ch << 4;
2224 while (ch) {
2225 hashval += ch;
2226 ch = (unsigned char)*++p;
2227 }
2228 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002229
2230 for (; *app; app = &(*app)->next) {
2231 if (equal(name, (*app)->name)) {
2232 break;
2233 }
2234 }
2235
2236 return app;
2237}
Eric Andersenc470f442003-07-28 09:56:35 +00002238#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002239
Eric Andersencb57d552001-06-28 07:25:16 +00002240
Eric Andersenc470f442003-07-28 09:56:35 +00002241/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00002242
Eric Andersencb57d552001-06-28 07:25:16 +00002243/*
Eric Andersenc470f442003-07-28 09:56:35 +00002244 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002245 */
2246
Eric Andersenc470f442003-07-28 09:56:35 +00002247#define CD_PHYSICAL 1
2248#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002249
Eric Andersenc470f442003-07-28 09:56:35 +00002250static int docd(const char *, int);
2251static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002252
Eric Andersenc470f442003-07-28 09:56:35 +00002253static char *curdir = nullstr; /* current working directory */
2254static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002255
Eric Andersenc470f442003-07-28 09:56:35 +00002256static int
2257cdopt(void)
2258{
2259 int flags = 0;
2260 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002261
Eric Andersenc470f442003-07-28 09:56:35 +00002262 j = 'L';
2263 while ((i = nextopt("LP"))) {
2264 if (i != j) {
2265 flags ^= CD_PHYSICAL;
2266 j = i;
2267 }
2268 }
Eric Andersencb57d552001-06-28 07:25:16 +00002269
Eric Andersenc470f442003-07-28 09:56:35 +00002270 return flags;
2271}
Eric Andersen2870d962001-07-02 17:27:21 +00002272
Eric Andersenc470f442003-07-28 09:56:35 +00002273static int
2274cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002275{
2276 const char *dest;
2277 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002278 const char *p;
2279 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002280 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002281 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002282
Eric Andersenc470f442003-07-28 09:56:35 +00002283 flags = cdopt();
2284 dest = *argptr;
2285 if (!dest)
2286 dest = bltinlookup(homestr);
2287 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002288 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002289 flags |= CD_PRINT;
2290 goto step7;
Eric Andersencb57d552001-06-28 07:25:16 +00002291 }
Eric Andersenc470f442003-07-28 09:56:35 +00002292 if (!dest)
2293 dest = nullstr;
2294 if (*dest == '/')
2295 goto step7;
2296 if (*dest == '.') {
2297 c = dest[1];
2298dotdot:
2299 switch (c) {
2300 case '\0':
2301 case '/':
2302 goto step6;
2303 case '.':
2304 c = dest[2];
2305 if (c != '.')
2306 goto dotdot;
2307 }
2308 }
2309 if (!*dest)
2310 dest = ".";
2311 if (!(path = bltinlookup("CDPATH"))) {
2312step6:
2313step7:
2314 p = dest;
2315 goto docd;
2316 }
2317 do {
2318 c = *path;
2319 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002320 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002321 if (c && c != ':')
2322 flags |= CD_PRINT;
2323docd:
2324 if (!docd(p, flags))
2325 goto out;
2326 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002327 }
Eric Andersenc470f442003-07-28 09:56:35 +00002328 } while (path);
Eric Andersencb57d552001-06-28 07:25:16 +00002329 error("can't cd to %s", dest);
2330 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002331out:
2332 if (flags & CD_PRINT)
2333 out1fmt(snlfmt, curdir);
2334 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002335}
2336
2337
2338/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002339 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002340 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002341 */
2342
Eric Andersenc470f442003-07-28 09:56:35 +00002343static inline const char *
2344updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002345{
Eric Andersenc470f442003-07-28 09:56:35 +00002346 char *new;
2347 char *p;
2348 char *cdcomppath;
2349 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002350
Eric Andersenc470f442003-07-28 09:56:35 +00002351 cdcomppath = sstrdup(dir);
2352 STARTSTACKSTR(new);
2353 if (*dir != '/') {
2354 if (curdir == nullstr)
2355 return 0;
2356 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002357 }
Eric Andersenc470f442003-07-28 09:56:35 +00002358 new = makestrspace(strlen(dir) + 2, new);
2359 lim = stackblock() + 1;
2360 if (*dir != '/') {
2361 if (new[-1] != '/')
2362 USTPUTC('/', new);
2363 if (new > lim && *lim == '/')
2364 lim++;
2365 } else {
2366 USTPUTC('/', new);
2367 cdcomppath++;
2368 if (dir[1] == '/' && dir[2] != '/') {
2369 USTPUTC('/', new);
2370 cdcomppath++;
2371 lim++;
2372 }
2373 }
2374 p = strtok(cdcomppath, "/");
2375 while (p) {
2376 switch(*p) {
2377 case '.':
2378 if (p[1] == '.' && p[2] == '\0') {
2379 while (new > lim) {
2380 STUNPUTC(new);
2381 if (new[-1] == '/')
2382 break;
2383 }
2384 break;
2385 } else if (p[1] == '\0')
2386 break;
2387 /* fall through */
2388 default:
2389 new = stputs(p, new);
2390 USTPUTC('/', new);
2391 }
2392 p = strtok(0, "/");
2393 }
2394 if (new > lim)
2395 STUNPUTC(new);
2396 *new = 0;
2397 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002398}
2399
2400/*
Eric Andersenc470f442003-07-28 09:56:35 +00002401 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2402 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002403 */
2404
Eric Andersenc470f442003-07-28 09:56:35 +00002405static int
2406docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002407{
Eric Andersenc470f442003-07-28 09:56:35 +00002408 const char *dir = 0;
2409 int err;
2410
2411 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2412
Eric Andersencb57d552001-06-28 07:25:16 +00002413 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002414 if (!(flags & CD_PHYSICAL)) {
2415 dir = updatepwd(dest);
2416 if (dir)
2417 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002418 }
Eric Andersenc470f442003-07-28 09:56:35 +00002419 err = chdir(dest);
2420 if (err)
2421 goto out;
2422 setpwd(dir, 1);
2423 hashcd();
2424out:
Eric Andersencb57d552001-06-28 07:25:16 +00002425 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002426 return err;
2427}
2428
2429/*
2430 * Find out what the current directory is. If we already know the current
2431 * directory, this routine returns immediately.
2432 */
2433static inline char *
2434getpwd(void)
2435{
2436 char *dir = getcwd(0, 0);
2437 return dir ? dir : nullstr;
2438}
2439
2440static int
2441pwdcmd(int argc, char **argv)
2442{
2443 int flags;
2444 const char *dir = curdir;
2445
2446 flags = cdopt();
2447 if (flags) {
2448 if (physdir == nullstr)
2449 setpwd(dir, 0);
2450 dir = physdir;
2451 }
2452 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002453 return 0;
2454}
2455
Eric Andersenc470f442003-07-28 09:56:35 +00002456static void
2457setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002458{
Eric Andersenc470f442003-07-28 09:56:35 +00002459 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002460
Eric Andersenc470f442003-07-28 09:56:35 +00002461 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002462
Eric Andersencb57d552001-06-28 07:25:16 +00002463 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002464 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002465 }
2466 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002467 if (physdir != nullstr) {
2468 if (physdir != oldcur)
2469 free(physdir);
2470 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002471 }
Eric Andersenc470f442003-07-28 09:56:35 +00002472 if (oldcur == val || !val) {
2473 char *s = getpwd();
2474 physdir = s;
2475 if (!val)
2476 dir = s;
2477 } else
2478 dir = savestr(val);
2479 if (oldcur != dir && oldcur != nullstr) {
2480 free(oldcur);
2481 }
2482 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002483 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002484 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002485}
2486
Eric Andersenc470f442003-07-28 09:56:35 +00002487/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2488
Eric Andersencb57d552001-06-28 07:25:16 +00002489/*
2490 * Errors and exceptions.
2491 */
2492
2493/*
2494 * Code to handle exceptions in C.
2495 */
2496
Eric Andersen2870d962001-07-02 17:27:21 +00002497
Eric Andersencb57d552001-06-28 07:25:16 +00002498
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002499static void exverror(int, const char *, va_list)
Eric Andersenc470f442003-07-28 09:56:35 +00002500 __attribute__((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00002501
2502/*
2503 * Called to raise an exception. Since C doesn't include exceptions, we
2504 * just do a longjmp to the exception handler. The type of exception is
2505 * stored in the global variable "exception".
2506 */
2507
Eric Andersenc470f442003-07-28 09:56:35 +00002508static void
2509exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002510{
2511#ifdef DEBUG
2512 if (handler == NULL)
2513 abort();
2514#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002515 INTOFF;
2516
Eric Andersencb57d552001-06-28 07:25:16 +00002517 exception = e;
2518 longjmp(handler->loc, 1);
2519}
2520
2521
2522/*
2523 * Called from trap.c when a SIGINT is received. (If the user specifies
2524 * that SIGINT is to be trapped or ignored using the trap builtin, then
2525 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002526 * are held using the INTOFF macro. (The test for iflag is just
2527 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002528 */
2529
Eric Andersenc470f442003-07-28 09:56:35 +00002530static void
2531onint(void) {
2532 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002533
Eric Andersencb57d552001-06-28 07:25:16 +00002534 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002535 sigsetmask(0);
2536 i = EXSIG;
2537 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2538 if (!(rootshell && iflag)) {
2539 signal(SIGINT, SIG_DFL);
2540 raise(SIGINT);
2541 }
2542 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002543 }
Eric Andersenc470f442003-07-28 09:56:35 +00002544 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002545 /* NOTREACHED */
2546}
2547
Eric Andersenc470f442003-07-28 09:56:35 +00002548static void
2549exvwarning(const char *msg, va_list ap)
2550{
2551 FILE *errs;
2552 const char *name;
2553 const char *fmt;
Eric Andersencb57d552001-06-28 07:25:16 +00002554
Eric Andersenc470f442003-07-28 09:56:35 +00002555 errs = stderr;
2556 name = arg0;
2557 fmt = "%s: ";
2558 if (commandname) {
2559 name = commandname;
2560 fmt = "%s: %d: ";
2561 }
2562 fprintf(errs, fmt, name, startlinno);
2563 vfprintf(errs, msg, ap);
2564 outcslow('\n', errs);
2565}
Eric Andersen2870d962001-07-02 17:27:21 +00002566
Eric Andersencb57d552001-06-28 07:25:16 +00002567/*
Eric Andersenc470f442003-07-28 09:56:35 +00002568 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002569 * is not NULL then error prints an error message using printf style
2570 * formatting. It then raises the error exception.
2571 */
Eric Andersenc470f442003-07-28 09:56:35 +00002572static void
2573exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002574{
Eric Andersencb57d552001-06-28 07:25:16 +00002575#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002576 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002577 TRACE(("exverror(%d, \"", cond));
2578 TRACEV((msg, ap));
2579 TRACE(("\") pid=%d\n", getpid()));
2580 } else
2581 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2582 if (msg)
2583#endif
2584 exvwarning(msg, ap);
2585
2586 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002587 exraise(cond);
2588 /* NOTREACHED */
2589}
2590
2591
Eric Andersenc470f442003-07-28 09:56:35 +00002592static void
2593error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002594{
Eric Andersencb57d552001-06-28 07:25:16 +00002595 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002596
Eric Andersencb57d552001-06-28 07:25:16 +00002597 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002598 exverror(EXERROR, msg, ap);
2599 /* NOTREACHED */
2600 va_end(ap);
2601}
2602
2603
Eric Andersenc470f442003-07-28 09:56:35 +00002604static void
2605exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002606{
Eric Andersencb57d552001-06-28 07:25:16 +00002607 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002608
Eric Andersencb57d552001-06-28 07:25:16 +00002609 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002610 exverror(cond, msg, ap);
2611 /* NOTREACHED */
2612 va_end(ap);
2613}
2614
Eric Andersencb57d552001-06-28 07:25:16 +00002615/*
Eric Andersenc470f442003-07-28 09:56:35 +00002616 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002617 */
2618
Eric Andersenc470f442003-07-28 09:56:35 +00002619static void
2620sh_warnx(const char *fmt, ...)
2621{
2622 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002623
Eric Andersenc470f442003-07-28 09:56:35 +00002624 va_start(ap, fmt);
2625 exvwarning(fmt, ap);
2626 va_end(ap);
2627}
Eric Andersen2870d962001-07-02 17:27:21 +00002628
Eric Andersencb57d552001-06-28 07:25:16 +00002629
2630/*
2631 * Return a string describing an error. The returned string may be a
2632 * pointer to a static buffer that will be overwritten on the next call.
2633 * Action describes the operation that got the error.
2634 */
2635
Eric Andersenc470f442003-07-28 09:56:35 +00002636static const char *
2637errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002638{
Eric Andersenc470f442003-07-28 09:56:35 +00002639 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002640
Eric Andersenc470f442003-07-28 09:56:35 +00002641 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002642 }
Eric Andersenc470f442003-07-28 09:56:35 +00002643 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002644}
2645
2646
Eric Andersenc470f442003-07-28 09:56:35 +00002647/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2648
2649/*
2650 * Evaluate a command.
2651 */
Eric Andersencb57d552001-06-28 07:25:16 +00002652
2653/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002654#define EV_EXIT 01 /* exit after evaluating tree */
2655#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2656#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002657
2658
Eric Andersenc470f442003-07-28 09:56:35 +00002659static void evalloop(union node *, int);
2660static void evalfor(union node *, int);
2661static void evalcase(union node *, int);
2662static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002663static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002664static void evalpipe(union node *, int);
2665static void evalcommand(union node *, int);
2666static int evalbltin(const struct builtincmd *, int, char **);
2667static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002668static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002669static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002670
Eric Andersenc470f442003-07-28 09:56:35 +00002671
2672static const struct builtincmd bltin = {
2673 "\0\0", bltincmd
2674};
2675
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002676
Eric Andersencb57d552001-06-28 07:25:16 +00002677/*
2678 * Called to reset things after an exception.
2679 */
2680
Eric Andersencb57d552001-06-28 07:25:16 +00002681/*
2682 * The eval commmand.
2683 */
2684
Eric Andersenc470f442003-07-28 09:56:35 +00002685static int
2686evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002687{
Eric Andersen2870d962001-07-02 17:27:21 +00002688 char *p;
2689 char *concat;
2690 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002691
Eric Andersen2870d962001-07-02 17:27:21 +00002692 if (argc > 1) {
2693 p = argv[1];
2694 if (argc > 2) {
2695 STARTSTACKSTR(concat);
2696 ap = argv + 2;
2697 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002698 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002699 if ((p = *ap++) == NULL)
2700 break;
2701 STPUTC(' ', concat);
2702 }
2703 STPUTC('\0', concat);
2704 p = grabstackstr(concat);
2705 }
2706 evalstring(p, EV_TESTED);
2707 }
2708 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002709}
2710
Eric Andersenc470f442003-07-28 09:56:35 +00002711
Eric Andersencb57d552001-06-28 07:25:16 +00002712/*
2713 * Execute a command or commands contained in a string.
2714 */
2715
Eric Andersenc470f442003-07-28 09:56:35 +00002716static void
2717evalstring(char *s, int flag)
Eric Andersen2870d962001-07-02 17:27:21 +00002718{
Eric Andersencb57d552001-06-28 07:25:16 +00002719 union node *n;
2720 struct stackmark smark;
2721
2722 setstackmark(&smark);
2723 setinputstring(s);
Eric Andersenc470f442003-07-28 09:56:35 +00002724
Eric Andersencb57d552001-06-28 07:25:16 +00002725 while ((n = parsecmd(0)) != NEOF) {
2726 evaltree(n, flag);
2727 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002728 if (evalskip)
2729 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002730 }
2731 popfile();
2732 popstackmark(&smark);
2733}
2734
Eric Andersenc470f442003-07-28 09:56:35 +00002735
Eric Andersen62483552001-07-10 06:09:16 +00002736
2737/*
Eric Andersenc470f442003-07-28 09:56:35 +00002738 * Evaluate a parse tree. The value is left in the global variable
2739 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002740 */
2741
Eric Andersenc470f442003-07-28 09:56:35 +00002742static void
2743evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002744{
Eric Andersenc470f442003-07-28 09:56:35 +00002745 int checkexit = 0;
2746 void (*evalfn)(union node *, int);
2747 unsigned isor;
2748 int status;
2749 if (n == NULL) {
2750 TRACE(("evaltree(NULL) called\n"));
2751 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002752 }
Eric Andersenc470f442003-07-28 09:56:35 +00002753 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2754 getpid(), n, n->type, flags));
2755 switch (n->type) {
2756 default:
2757#ifdef DEBUG
2758 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002759 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002760 break;
2761#endif
2762 case NNOT:
2763 evaltree(n->nnot.com, EV_TESTED);
2764 status = !exitstatus;
2765 goto setstatus;
2766 case NREDIR:
2767 expredir(n->nredir.redirect);
2768 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2769 if (!status) {
2770 evaltree(n->nredir.n, flags & EV_TESTED);
2771 status = exitstatus;
2772 }
2773 popredir(0);
2774 goto setstatus;
2775 case NCMD:
2776 evalfn = evalcommand;
2777checkexit:
2778 if (eflag && !(flags & EV_TESTED))
2779 checkexit = ~0;
2780 goto calleval;
2781 case NFOR:
2782 evalfn = evalfor;
2783 goto calleval;
2784 case NWHILE:
2785 case NUNTIL:
2786 evalfn = evalloop;
2787 goto calleval;
2788 case NSUBSHELL:
2789 case NBACKGND:
2790 evalfn = evalsubshell;
2791 goto calleval;
2792 case NPIPE:
2793 evalfn = evalpipe;
2794 goto checkexit;
2795 case NCASE:
2796 evalfn = evalcase;
2797 goto calleval;
2798 case NAND:
2799 case NOR:
2800 case NSEMI:
2801#if NAND + 1 != NOR
2802#error NAND + 1 != NOR
2803#endif
2804#if NOR + 1 != NSEMI
2805#error NOR + 1 != NSEMI
2806#endif
2807 isor = n->type - NAND;
2808 evaltree(
2809 n->nbinary.ch1,
2810 (flags | ((isor >> 1) - 1)) & EV_TESTED
2811 );
2812 if (!exitstatus == isor)
2813 break;
2814 if (!evalskip) {
2815 n = n->nbinary.ch2;
2816evaln:
2817 evalfn = evaltree;
2818calleval:
2819 evalfn(n, flags);
2820 break;
2821 }
2822 break;
2823 case NIF:
2824 evaltree(n->nif.test, EV_TESTED);
2825 if (evalskip)
2826 break;
2827 if (exitstatus == 0) {
2828 n = n->nif.ifpart;
2829 goto evaln;
2830 } else if (n->nif.elsepart) {
2831 n = n->nif.elsepart;
2832 goto evaln;
2833 }
2834 goto success;
2835 case NDEFUN:
2836 defun(n->narg.text, n->narg.next);
2837success:
2838 status = 0;
2839setstatus:
2840 exitstatus = status;
2841 break;
2842 }
2843out:
2844 if (pendingsigs)
2845 dotrap();
2846 if (flags & EV_EXIT || checkexit & exitstatus)
2847 exraise(EXEXIT);
Eric Andersen62483552001-07-10 06:09:16 +00002848}
2849
Eric Andersenc470f442003-07-28 09:56:35 +00002850
2851#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2852static
2853#endif
2854void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2855
2856
2857static void
2858evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002859{
2860 int status;
2861
2862 loopnest++;
2863 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002864 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002865 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002866 int i;
2867
Eric Andersencb57d552001-06-28 07:25:16 +00002868 evaltree(n->nbinary.ch1, EV_TESTED);
2869 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002870skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002871 evalskip = 0;
2872 continue;
2873 }
2874 if (evalskip == SKIPBREAK && --skipcount <= 0)
2875 evalskip = 0;
2876 break;
2877 }
Eric Andersenc470f442003-07-28 09:56:35 +00002878 i = exitstatus;
2879 if (n->type != NWHILE)
2880 i = !i;
2881 if (i != 0)
2882 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002883 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002884 status = exitstatus;
2885 if (evalskip)
2886 goto skipping;
2887 }
2888 loopnest--;
2889 exitstatus = status;
2890}
2891
Eric Andersenc470f442003-07-28 09:56:35 +00002892
2893
2894static void
2895evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002896{
2897 struct arglist arglist;
2898 union node *argp;
2899 struct strlist *sp;
2900 struct stackmark smark;
2901
2902 setstackmark(&smark);
2903 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002904 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002905 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002906 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002907 if (evalskip)
2908 goto out;
2909 }
2910 *arglist.lastp = NULL;
2911
2912 exitstatus = 0;
2913 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002914 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002915 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002916 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002917 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002918 if (evalskip) {
2919 if (evalskip == SKIPCONT && --skipcount <= 0) {
2920 evalskip = 0;
2921 continue;
2922 }
2923 if (evalskip == SKIPBREAK && --skipcount <= 0)
2924 evalskip = 0;
2925 break;
2926 }
2927 }
2928 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002929out:
Eric Andersencb57d552001-06-28 07:25:16 +00002930 popstackmark(&smark);
2931}
2932
Eric Andersenc470f442003-07-28 09:56:35 +00002933
2934
2935static void
2936evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002937{
2938 union node *cp;
2939 union node *patp;
2940 struct arglist arglist;
2941 struct stackmark smark;
2942
2943 setstackmark(&smark);
2944 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002945 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002946 exitstatus = 0;
2947 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2948 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002949 if (casematch(patp, arglist.list->text)) {
2950 if (evalskip == 0) {
2951 evaltree(cp->nclist.body, flags);
2952 }
2953 goto out;
2954 }
2955 }
2956 }
Eric Andersenc470f442003-07-28 09:56:35 +00002957out:
Eric Andersencb57d552001-06-28 07:25:16 +00002958 popstackmark(&smark);
2959}
2960
Eric Andersenc470f442003-07-28 09:56:35 +00002961
2962
2963/*
2964 * Kick off a subshell to evaluate a tree.
2965 */
2966
2967static void
2968evalsubshell(union node *n, int flags)
2969{
2970 struct job *jp;
2971 int backgnd = (n->type == NBACKGND);
2972 int status;
2973
2974 expredir(n->nredir.redirect);
2975 if (!backgnd && flags & EV_EXIT && !trap[0])
2976 goto nofork;
2977 INTOFF;
2978 jp = makejob(n, 1);
2979 if (forkshell(jp, n, backgnd) == 0) {
2980 INTON;
2981 flags |= EV_EXIT;
2982 if (backgnd)
2983 flags &=~ EV_TESTED;
2984nofork:
2985 redirect(n->nredir.redirect, 0);
2986 evaltreenr(n->nredir.n, flags);
2987 /* never returns */
2988 }
2989 status = 0;
2990 if (! backgnd)
2991 status = waitforjob(jp);
2992 exitstatus = status;
2993 INTON;
2994}
2995
2996
2997
2998/*
2999 * Compute the names of the files in a redirection list.
3000 */
3001
3002static void
3003expredir(union node *n)
3004{
3005 union node *redir;
3006
3007 for (redir = n ; redir ; redir = redir->nfile.next) {
3008 struct arglist fn;
3009 fn.lastp = &fn.list;
3010 switch (redir->type) {
3011 case NFROMTO:
3012 case NFROM:
3013 case NTO:
3014 case NCLOBBER:
3015 case NAPPEND:
3016 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3017 redir->nfile.expfname = fn.list->text;
3018 break;
3019 case NFROMFD:
3020 case NTOFD:
3021 if (redir->ndup.vname) {
3022 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3023 fixredir(redir, fn.list->text, 1);
3024 }
3025 break;
3026 }
3027 }
3028}
3029
3030
3031
Eric Andersencb57d552001-06-28 07:25:16 +00003032/*
Eric Andersencb57d552001-06-28 07:25:16 +00003033 * Evaluate a pipeline. All the processes in the pipeline are children
3034 * of the process creating the pipeline. (This differs from some versions
3035 * of the shell, which make the last process in a pipeline the parent
3036 * of all the rest.)
3037 */
3038
Eric Andersenc470f442003-07-28 09:56:35 +00003039static void
3040evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003041{
3042 struct job *jp;
3043 struct nodelist *lp;
3044 int pipelen;
3045 int prevfd;
3046 int pip[2];
3047
Eric Andersenc470f442003-07-28 09:56:35 +00003048 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003049 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003050 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003051 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003052 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003053 INTOFF;
3054 jp = makejob(n, pipelen);
3055 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003056 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003057 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003058 pip[1] = -1;
3059 if (lp->next) {
3060 if (pipe(pip) < 0) {
3061 close(prevfd);
3062 error("Pipe call failed");
3063 }
3064 }
3065 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3066 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003067 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003068 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003069 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003070 if (prevfd > 0) {
3071 dup2(prevfd, 0);
3072 close(prevfd);
3073 }
3074 if (pip[1] > 1) {
3075 dup2(pip[1], 1);
3076 close(pip[1]);
3077 }
Eric Andersenc470f442003-07-28 09:56:35 +00003078 evaltreenr(lp->n, flags);
3079 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003080 }
3081 if (prevfd >= 0)
3082 close(prevfd);
3083 prevfd = pip[0];
3084 close(pip[1]);
3085 }
Eric Andersencb57d552001-06-28 07:25:16 +00003086 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003087 exitstatus = waitforjob(jp);
3088 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003089 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003090 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003091}
3092
Eric Andersen62483552001-07-10 06:09:16 +00003093
3094
3095/*
3096 * Execute a command inside back quotes. If it's a builtin command, we
3097 * want to save its output in a block obtained from malloc. Otherwise
3098 * we fork off a subprocess and get the output of the command via a pipe.
3099 * Should be called with interrupts off.
3100 */
3101
Eric Andersenc470f442003-07-28 09:56:35 +00003102static void
3103evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003104{
Eric Andersenc470f442003-07-28 09:56:35 +00003105 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003106
Eric Andersen62483552001-07-10 06:09:16 +00003107 result->fd = -1;
3108 result->buf = NULL;
3109 result->nleft = 0;
3110 result->jp = NULL;
3111 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003112 goto out;
3113 }
Eric Andersenc470f442003-07-28 09:56:35 +00003114
3115 saveherefd = herefd;
3116 herefd = -1;
3117
3118 {
3119 int pip[2];
3120 struct job *jp;
3121
3122 if (pipe(pip) < 0)
3123 error("Pipe call failed");
3124 jp = makejob(n, 1);
3125 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3126 FORCEINTON;
3127 close(pip[0]);
3128 if (pip[1] != 1) {
3129 close(1);
3130 copyfd(pip[1], 1);
3131 close(pip[1]);
3132 }
3133 eflag = 0;
3134 evaltreenr(n, EV_EXIT);
3135 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003136 }
Eric Andersenc470f442003-07-28 09:56:35 +00003137 close(pip[1]);
3138 result->fd = pip[0];
3139 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003140 }
Eric Andersenc470f442003-07-28 09:56:35 +00003141 herefd = saveherefd;
3142out:
Eric Andersen62483552001-07-10 06:09:16 +00003143 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003144 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003145}
3146
Eric Andersenc470f442003-07-28 09:56:35 +00003147#ifdef CONFIG_ASH_CMDCMD
3148static inline char **
3149parse_command_args(char **argv, const char **path)
3150{
3151 char *cp, c;
3152
3153 for (;;) {
3154 cp = *++argv;
3155 if (!cp)
3156 return 0;
3157 if (*cp++ != '-')
3158 break;
3159 if (!(c = *cp++))
3160 break;
3161 if (c == '-' && !*cp) {
3162 argv++;
3163 break;
3164 }
3165 do {
3166 switch (c) {
3167 case 'p':
3168 *path = defpath;
3169 break;
3170 default:
3171 /* run 'typecmd' for other options */
3172 return 0;
3173 }
3174 } while ((c = *cp++));
3175 }
3176 return argv;
3177}
3178#endif
3179
3180
Eric Andersen62483552001-07-10 06:09:16 +00003181
3182/*
3183 * Execute a simple command.
3184 */
Eric Andersencb57d552001-06-28 07:25:16 +00003185
Eric Andersenc470f442003-07-28 09:56:35 +00003186static void
3187evalcommand(union node *cmd, int flags)
3188{
3189 struct stackmark smark;
3190 union node *argp;
3191 struct arglist arglist;
3192 struct arglist varlist;
3193 char **argv;
3194 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003195 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003196 struct cmdentry cmdentry;
3197 struct job *jp;
3198 char *lastarg;
3199 const char *path;
3200 int spclbltin;
3201 int cmd_is_exec;
3202 int status;
3203 char **nargv;
3204
3205 /* First expand the arguments. */
3206 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3207 setstackmark(&smark);
3208 back_exitstatus = 0;
3209
3210 cmdentry.cmdtype = CMDBUILTIN;
3211 cmdentry.u.cmd = &bltin;
3212 varlist.lastp = &varlist.list;
3213 *varlist.lastp = NULL;
3214 arglist.lastp = &arglist.list;
3215 *arglist.lastp = NULL;
3216
3217 argc = 0;
3218 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3219 struct strlist **spp;
3220
3221 spp = arglist.lastp;
3222 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3223 for (sp = *spp; sp; sp = sp->next)
3224 argc++;
3225 }
3226
3227 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3228 for (sp = arglist.list ; sp ; sp = sp->next) {
3229 TRACE(("evalcommand arg: %s\n", sp->text));
3230 *nargv++ = sp->text;
3231 }
3232 *nargv = NULL;
3233
3234 lastarg = NULL;
3235 if (iflag && funcnest == 0 && argc > 0)
3236 lastarg = nargv[-1];
3237
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003238 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003239 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003240 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003241
3242 path = vpath.text;
3243 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3244 struct strlist **spp;
3245 char *p;
3246
3247 spp = varlist.lastp;
3248 expandarg(argp, &varlist, EXP_VARTILDE);
3249
3250 /*
3251 * Modify the command lookup path, if a PATH= assignment
3252 * is present
3253 */
3254 p = (*spp)->text;
3255 if (varequal(p, path))
3256 path = p;
3257 }
3258
3259 /* Print the command if xflag is set. */
3260 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003261 int n;
3262 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003263
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003264 p++;
3265 dprintf(preverrout_fd, p, ps4val());
3266
3267 sp = varlist.list;
3268 for(n = 0; n < 2; n++) {
3269 while (sp) {
3270 dprintf(preverrout_fd, p, sp->text);
3271 sp = sp->next;
3272 if(*p == '%') {
3273 p--;
3274 }
3275 }
3276 sp = arglist.list;
3277 }
3278 xwrite(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003279 }
3280
3281 cmd_is_exec = 0;
3282 spclbltin = -1;
3283
3284 /* Now locate the command. */
3285 if (argc) {
3286 const char *oldpath;
3287 int cmd_flag = DO_ERR;
3288
3289 path += 5;
3290 oldpath = path;
3291 for (;;) {
3292 find_command(argv[0], &cmdentry, cmd_flag, path);
3293 if (cmdentry.cmdtype == CMDUNKNOWN) {
3294 status = 127;
3295 flushout(stderr);
3296 goto bail;
3297 }
3298
3299 /* implement bltin and command here */
3300 if (cmdentry.cmdtype != CMDBUILTIN)
3301 break;
3302 if (spclbltin < 0)
3303 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3304 if (cmdentry.u.cmd == EXECCMD)
3305 cmd_is_exec++;
3306#ifdef CONFIG_ASH_CMDCMD
3307 if (cmdentry.u.cmd == COMMANDCMD) {
3308
3309 path = oldpath;
3310 nargv = parse_command_args(argv, &path);
3311 if (!nargv)
3312 break;
3313 argc -= nargv - argv;
3314 argv = nargv;
3315 cmd_flag |= DO_NOFUNC;
3316 } else
3317#endif
3318 break;
3319 }
3320 }
3321
3322 if (status) {
3323 /* We have a redirection error. */
3324 if (spclbltin > 0)
3325 exraise(EXERROR);
3326bail:
3327 exitstatus = status;
3328 goto out;
3329 }
3330
3331 /* Execute the command. */
3332 switch (cmdentry.cmdtype) {
3333 default:
3334 /* Fork off a child process if necessary. */
3335 if (!(flags & EV_EXIT) || trap[0]) {
3336 INTOFF;
3337 jp = makejob(cmd, 1);
3338 if (forkshell(jp, cmd, FORK_FG) != 0) {
3339 exitstatus = waitforjob(jp);
3340 INTON;
3341 break;
3342 }
3343 FORCEINTON;
3344 }
3345 listsetvar(varlist.list, VEXPORT|VSTACK);
3346 shellexec(argv, path, cmdentry.u.index);
3347 /* NOTREACHED */
3348
3349 case CMDBUILTIN:
3350 cmdenviron = varlist.list;
3351 if (cmdenviron) {
3352 struct strlist *list = cmdenviron;
3353 int i = VNOSET;
3354 if (spclbltin > 0 || argc == 0) {
3355 i = 0;
3356 if (cmd_is_exec && argc > 1)
3357 i = VEXPORT;
3358 }
3359 listsetvar(list, i);
3360 }
3361 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3362 int exit_status;
3363 int i, j;
3364
3365 i = exception;
3366 if (i == EXEXIT)
3367 goto raise;
3368
3369 exit_status = 2;
3370 j = 0;
3371 if (i == EXINT)
3372 j = SIGINT;
3373 if (i == EXSIG)
3374 j = pendingsigs;
3375 if (j)
3376 exit_status = j + 128;
3377 exitstatus = exit_status;
3378
3379 if (i == EXINT || spclbltin > 0) {
3380raise:
3381 longjmp(handler->loc, 1);
3382 }
3383 FORCEINTON;
3384 }
3385 break;
3386
3387 case CMDFUNCTION:
3388 listsetvar(varlist.list, 0);
3389 if (evalfun(cmdentry.u.func, argc, argv, flags))
3390 goto raise;
3391 break;
3392 }
3393
3394out:
3395 popredir(cmd_is_exec);
3396 if (lastarg)
3397 /* dsl: I think this is intended to be used to support
3398 * '_' in 'vi' command mode during line editing...
3399 * However I implemented that within libedit itself.
3400 */
3401 setvar("_", lastarg, 0);
3402 popstackmark(&smark);
3403}
3404
3405static int
3406evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3407 char *volatile savecmdname;
3408 struct jmploc *volatile savehandler;
3409 struct jmploc jmploc;
3410 int i;
3411
3412 savecmdname = commandname;
3413 if ((i = setjmp(jmploc.loc)))
3414 goto cmddone;
3415 savehandler = handler;
3416 handler = &jmploc;
3417 commandname = argv[0];
3418 argptr = argv + 1;
3419 optptr = NULL; /* initialize nextopt */
3420 exitstatus = (*cmd->builtin)(argc, argv);
3421 flushall();
3422cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003423 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003424 commandname = savecmdname;
3425 exsig = 0;
3426 handler = savehandler;
3427
3428 return i;
3429}
3430
3431static int
3432evalfun(struct funcnode *func, int argc, char **argv, int flags)
3433{
3434 volatile struct shparam saveparam;
3435 struct localvar *volatile savelocalvars;
3436 struct jmploc *volatile savehandler;
3437 struct jmploc jmploc;
3438 int e;
3439
3440 saveparam = shellparam;
3441 savelocalvars = localvars;
3442 if ((e = setjmp(jmploc.loc))) {
3443 goto funcdone;
3444 }
3445 INTOFF;
3446 savehandler = handler;
3447 handler = &jmploc;
3448 localvars = NULL;
3449 shellparam.malloc = 0;
3450 func->count++;
3451 INTON;
3452 shellparam.nparam = argc - 1;
3453 shellparam.p = argv + 1;
3454#ifdef CONFIG_ASH_GETOPTS
3455 shellparam.optind = 1;
3456 shellparam.optoff = -1;
3457#endif
3458 funcnest++;
3459 evaltree(&func->n, flags & EV_TESTED);
3460 funcnest--;
3461funcdone:
3462 INTOFF;
3463 freefunc(func);
3464 poplocalvars();
3465 localvars = savelocalvars;
3466 freeparam(&shellparam);
3467 shellparam = saveparam;
3468 handler = savehandler;
3469 INTON;
3470 if (evalskip == SKIPFUNC) {
3471 evalskip = 0;
3472 skipcount = 0;
3473 }
3474 return e;
3475}
3476
3477
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003478/*
3479 * Search for a command. This is called before we fork so that the
3480 * location of the command will be available in the parent as well as
Eric Andersenc470f442003-07-28 09:56:35 +00003481 * the child.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003482 */
3483
Eric Andersenc470f442003-07-28 09:56:35 +00003484static void
3485prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003486{
3487 struct cmdentry entry;
3488
3489 if (n->type == NCMD && n->ncmd.args)
Eric Andersenc470f442003-07-28 09:56:35 +00003490 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003491}
3492
Eric Andersencb57d552001-06-28 07:25:16 +00003493
Eric Andersenc470f442003-07-28 09:56:35 +00003494
Eric Andersencb57d552001-06-28 07:25:16 +00003495/*
3496 * Builtin commands. Builtin commands whose functions are closely
3497 * tied to evaluation are implemented here.
3498 */
3499
3500/*
Eric Andersenc470f442003-07-28 09:56:35 +00003501 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003502 */
3503
Eric Andersenc470f442003-07-28 09:56:35 +00003504static int
3505bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003506{
3507 /*
3508 * Preserve exitstatus of a previous possible redirection
3509 * as POSIX mandates
3510 */
Eric Andersenc470f442003-07-28 09:56:35 +00003511 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003512}
3513
3514
3515/*
3516 * Handle break and continue commands. Break, continue, and return are
3517 * all handled by setting the evalskip flag. The evaluation routines
3518 * above all check this flag, and if it is set they start skipping
3519 * commands rather than executing them. The variable skipcount is
3520 * the number of loops to break/continue, or the number of function
3521 * levels to return. (The latter is always 1.) It should probably
3522 * be an error to break out of more loops than exist, but it isn't
3523 * in the standard shell so we don't make it one here.
3524 */
3525
Eric Andersenc470f442003-07-28 09:56:35 +00003526static int
3527breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003528{
3529 int n = argc > 1 ? number(argv[1]) : 1;
3530
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003531 if (n <= 0)
Eric Andersenc470f442003-07-28 09:56:35 +00003532 error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003533 if (n > loopnest)
3534 n = loopnest;
3535 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003536 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003537 skipcount = n;
3538 }
3539 return 0;
3540}
3541
3542
3543/*
3544 * The return command.
3545 */
3546
Eric Andersenc470f442003-07-28 09:56:35 +00003547static int
3548returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003549{
Eric Andersenc470f442003-07-28 09:56:35 +00003550 int ret = argc > 1 ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003551
3552 if (funcnest) {
3553 evalskip = SKIPFUNC;
3554 skipcount = 1;
3555 return ret;
Eric Andersenc470f442003-07-28 09:56:35 +00003556 }
3557 else {
Eric Andersencb57d552001-06-28 07:25:16 +00003558 /* Do what ksh does; skip the rest of the file */
3559 evalskip = SKIPFILE;
3560 skipcount = 1;
3561 return ret;
3562 }
3563}
3564
3565
Eric Andersenc470f442003-07-28 09:56:35 +00003566static int
3567falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003568{
3569 return 1;
3570}
3571
Eric Andersenc470f442003-07-28 09:56:35 +00003572
3573static int
3574truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003575{
3576 return 0;
3577}
Eric Andersen2870d962001-07-02 17:27:21 +00003578
Eric Andersencb57d552001-06-28 07:25:16 +00003579
Eric Andersenc470f442003-07-28 09:56:35 +00003580static int
3581execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003582{
3583 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003584 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003585 mflag = 0;
3586 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003587 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003588 }
3589 return 0;
3590}
3591
Eric Andersenc470f442003-07-28 09:56:35 +00003592
Eric Andersenc470f442003-07-28 09:56:35 +00003593/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3594
3595/*
3596 * When commands are first encountered, they are entered in a hash table.
3597 * This ensures that a full path search will not have to be done for them
3598 * on each invocation.
3599 *
3600 * We should investigate converting to a linear search, even though that
3601 * would make the command name "hash" a misnomer.
3602 */
3603
3604#define CMDTABLESIZE 31 /* should be prime */
3605#define ARB 1 /* actual size determined at run time */
3606
3607
3608
3609struct tblentry {
3610 struct tblentry *next; /* next entry in hash chain */
3611 union param param; /* definition of builtin function */
3612 short cmdtype; /* index identifying command */
3613 char rehash; /* if set, cd done since entry created */
3614 char cmdname[ARB]; /* name of command */
3615};
3616
3617
3618static struct tblentry *cmdtable[CMDTABLESIZE];
3619static int builtinloc = -1; /* index in path of %builtin, or -1 */
3620
3621
3622static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003623static void clearcmdentry(int);
3624static struct tblentry *cmdlookup(const char *, int);
3625static void delete_cmd_entry(void);
3626
Eric Andersencb57d552001-06-28 07:25:16 +00003627
3628/*
3629 * Exec a program. Never returns. If you change this routine, you may
3630 * have to change the find_command routine as well.
3631 */
3632
Eric Andersenc470f442003-07-28 09:56:35 +00003633static void
3634shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003635{
3636 char *cmdname;
3637 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003638 char **envp;
Eric Andersencb57d552001-06-28 07:25:16 +00003639
Eric Andersenc470f442003-07-28 09:56:35 +00003640 clearredir(1);
3641 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003642 if (strchr(argv[0], '/') != NULL
3643#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3644 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003645#endif
3646 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003647 tryexec(argv[0], argv, envp);
3648 e = errno;
3649 } else {
3650 e = ENOENT;
3651 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3652 if (--idx < 0 && pathopt == NULL) {
3653 tryexec(cmdname, argv, envp);
3654 if (errno != ENOENT && errno != ENOTDIR)
3655 e = errno;
3656 }
3657 stunalloc(cmdname);
3658 }
3659 }
3660
3661 /* Map to POSIX errors */
3662 switch (e) {
3663 case EACCES:
3664 exerrno = 126;
3665 break;
3666 case ENOENT:
3667 exerrno = 127;
3668 break;
3669 default:
3670 exerrno = 2;
3671 break;
3672 }
Eric Andersenc470f442003-07-28 09:56:35 +00003673 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3674 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003675 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3676 /* NOTREACHED */
3677}
3678
Eric Andersen2870d962001-07-02 17:27:21 +00003679
Eric Andersenc470f442003-07-28 09:56:35 +00003680static void
3681tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003682{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003683 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003684#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003685 int flg_bb = 0;
Eric Andersen3102ac42001-07-06 04:26:23 +00003686 char *name = cmd;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003687
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003688#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
Manuel Novoa III cad53642003-03-19 09:13:01 +00003689 name = bb_get_last_path_component(name);
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003690 if(find_applet_by_name(name) != NULL)
3691 flg_bb = 1;
3692#else
3693 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3694 flg_bb = 1;
3695 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003696#endif
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003697 if(flg_bb) {
3698 char **ap;
3699 char **new;
3700
3701 *argv = name;
3702 if(strcmp(name, "busybox")) {
3703 for (ap = argv; *ap; ap++);
3704 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3705 *ap++ = cmd = "/bin/busybox";
3706 while ((*ap++ = *argv++));
3707 argv = new;
3708 repeated++;
3709 } else {
3710 cmd = "/bin/busybox";
3711 }
3712 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003713#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003714
3715repeat:
3716#ifdef SYSV
3717 do {
3718 execve(cmd, argv, envp);
3719 } while (errno == EINTR);
3720#else
Eric Andersencb57d552001-06-28 07:25:16 +00003721 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003722#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003723 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003724 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003725 } else if (errno == ENOEXEC) {
3726 char **ap;
3727 char **new;
3728
Eric Andersenc470f442003-07-28 09:56:35 +00003729 for (ap = argv; *ap; ap++)
3730 ;
3731 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003732 ap[1] = cmd;
3733 *ap = cmd = (char *)DEFAULT_SHELL;
3734 ap += 2;
3735 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003736 while ((*ap++ = *argv++))
3737 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003738 argv = new;
3739 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003740 }
Eric Andersencb57d552001-06-28 07:25:16 +00003741}
3742
Eric Andersenc470f442003-07-28 09:56:35 +00003743
Eric Andersencb57d552001-06-28 07:25:16 +00003744
3745/*
3746 * Do a path search. The variable path (passed by reference) should be
3747 * set to the start of the path before the first call; padvance will update
3748 * this value as it proceeds. Successive calls to padvance will return
3749 * the possible path expansions in sequence. If an option (indicated by
3750 * a percent sign) appears in the path entry then the global variable
3751 * pathopt will be set to point to it; otherwise pathopt will be set to
3752 * NULL.
3753 */
3754
Eric Andersenc470f442003-07-28 09:56:35 +00003755static char *
3756padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003757{
Eric Andersencb57d552001-06-28 07:25:16 +00003758 const char *p;
3759 char *q;
3760 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003761 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003762
3763 if (*path == NULL)
3764 return NULL;
3765 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003766 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3767 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003768 while (stackblocksize() < len)
3769 growstackblock();
3770 q = stackblock();
3771 if (p != start) {
3772 memcpy(q, start, p - start);
3773 q += p - start;
3774 *q++ = '/';
3775 }
3776 strcpy(q, name);
3777 pathopt = NULL;
3778 if (*p == '%') {
3779 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003780 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003781 }
3782 if (*p == ':')
3783 *path = p + 1;
3784 else
3785 *path = NULL;
3786 return stalloc(len);
3787}
3788
3789
Eric Andersencb57d552001-06-28 07:25:16 +00003790/*** Command hashing code ***/
3791
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003792static void
3793printentry(struct tblentry *cmdp)
3794{
3795 int idx;
3796 const char *path;
3797 char *name;
3798
3799 idx = cmdp->param.index;
3800 path = pathval();
3801 do {
3802 name = padvance(&path, cmdp->cmdname);
3803 stunalloc(name);
3804 } while (--idx >= 0);
3805 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3806}
3807
Eric Andersenc470f442003-07-28 09:56:35 +00003808
3809static int
3810hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003811{
3812 struct tblentry **pp;
3813 struct tblentry *cmdp;
3814 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003815 struct cmdentry entry;
3816 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003817
Eric Andersenc470f442003-07-28 09:56:35 +00003818 while ((c = nextopt("r")) != '\0') {
3819 clearcmdentry(0);
3820 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003821 }
3822 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003823 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3824 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3825 if (cmdp->cmdtype == CMDNORMAL)
3826 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003827 }
3828 }
3829 return 0;
3830 }
3831 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003832 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003833 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003834 && (cmdp->cmdtype == CMDNORMAL
3835 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003836 delete_cmd_entry();
3837 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003838 if (entry.cmdtype == CMDUNKNOWN)
3839 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003840 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003841 }
3842 return c;
3843}
3844
Eric Andersenc470f442003-07-28 09:56:35 +00003845
Eric Andersencb57d552001-06-28 07:25:16 +00003846/*
3847 * Resolve a command name. If you change this routine, you may have to
3848 * change the shellexec routine as well.
3849 */
3850
3851static void
Eric Andersenc470f442003-07-28 09:56:35 +00003852find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003853{
3854 struct tblentry *cmdp;
3855 int idx;
3856 int prev;
3857 char *fullname;
3858 struct stat statb;
3859 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003860 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003861 struct builtincmd *bcmd;
3862
Eric Andersenc470f442003-07-28 09:56:35 +00003863 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003864 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003865 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003866 if (act & DO_ABS) {
3867 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003868#ifdef SYSV
3869 if (errno == EINTR)
3870 continue;
3871#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003872 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003873 return;
3874 }
Eric Andersencb57d552001-06-28 07:25:16 +00003875 }
3876 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003877 return;
3878 }
3879
Eric Andersenbf8bf102002-09-17 08:41:08 +00003880#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3881 if (find_applet_by_name(name)) {
3882 entry->cmdtype = CMDNORMAL;
3883 entry->u.index = -1;
3884 return;
3885 }
3886#endif
3887
Eric Andersenc470f442003-07-28 09:56:35 +00003888 updatetbl = (path == pathval());
3889 if (!updatetbl) {
3890 act |= DO_ALTPATH;
3891 if (strstr(path, "%builtin") != NULL)
3892 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003893 }
3894
Eric Andersenc470f442003-07-28 09:56:35 +00003895 /* If name is in the table, check answer will be ok */
3896 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3897 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003898
Eric Andersenc470f442003-07-28 09:56:35 +00003899 switch (cmdp->cmdtype) {
3900 default:
3901#if DEBUG
3902 abort();
3903#endif
3904 case CMDNORMAL:
3905 bit = DO_ALTPATH;
3906 break;
3907 case CMDFUNCTION:
3908 bit = DO_NOFUNC;
3909 break;
3910 case CMDBUILTIN:
3911 bit = DO_ALTBLTIN;
3912 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003913 }
Eric Andersenc470f442003-07-28 09:56:35 +00003914 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003915 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003916 cmdp = NULL;
3917 } else if (cmdp->rehash == 0)
3918 /* if not invalidated by cd, we're done */
3919 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003920 }
3921
3922 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003923 bcmd = find_builtin(name);
3924 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3925 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3926 )))
3927 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003928
3929 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003930 prev = -1; /* where to start */
3931 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003932 if (cmdp->cmdtype == CMDBUILTIN)
3933 prev = builtinloc;
3934 else
3935 prev = cmdp->param.index;
3936 }
3937
3938 e = ENOENT;
3939 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003940loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003941 while ((fullname = padvance(&path, name)) != NULL) {
3942 stunalloc(fullname);
3943 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003944 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003945 if (prefix(pathopt, "builtin")) {
3946 if (bcmd)
3947 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003948 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003949 } else if (!(act & DO_NOFUNC) &&
3950 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003951 /* handled below */
3952 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003953 /* ignore unimplemented options */
3954 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003955 }
3956 }
3957 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003958 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003959 if (idx < prev)
3960 continue;
3961 TRACE(("searchexec \"%s\": no change\n", name));
3962 goto success;
3963 }
3964 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003965#ifdef SYSV
3966 if (errno == EINTR)
3967 continue;
3968#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003969 if (errno != ENOENT && errno != ENOTDIR)
3970 e = errno;
3971 goto loop;
3972 }
Eric Andersenc470f442003-07-28 09:56:35 +00003973 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003974 if (!S_ISREG(statb.st_mode))
3975 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003976 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003977 stalloc(strlen(fullname) + 1);
3978 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00003979 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3980 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00003981 error("%s not defined in %s", name, fullname);
3982 stunalloc(fullname);
3983 goto success;
3984 }
Eric Andersencb57d552001-06-28 07:25:16 +00003985 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00003986 if (!updatetbl) {
3987 entry->cmdtype = CMDNORMAL;
3988 entry->u.index = idx;
3989 return;
3990 }
3991 INTOFF;
3992 cmdp = cmdlookup(name, 1);
3993 cmdp->cmdtype = CMDNORMAL;
3994 cmdp->param.index = idx;
3995 INTON;
3996 goto success;
3997 }
3998
3999 /* We failed. If there was an entry for this command, delete it */
4000 if (cmdp && updatetbl)
4001 delete_cmd_entry();
4002 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004003 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004004 entry->cmdtype = CMDUNKNOWN;
4005 return;
4006
Eric Andersenc470f442003-07-28 09:56:35 +00004007builtin_success:
4008 if (!updatetbl) {
4009 entry->cmdtype = CMDBUILTIN;
4010 entry->u.cmd = bcmd;
4011 return;
4012 }
4013 INTOFF;
4014 cmdp = cmdlookup(name, 1);
4015 cmdp->cmdtype = CMDBUILTIN;
4016 cmdp->param.cmd = bcmd;
4017 INTON;
4018success:
Eric Andersencb57d552001-06-28 07:25:16 +00004019 cmdp->rehash = 0;
4020 entry->cmdtype = cmdp->cmdtype;
4021 entry->u = cmdp->param;
4022}
4023
4024
Eric Andersenc470f442003-07-28 09:56:35 +00004025/*
4026 * Wrapper around strcmp for qsort/bsearch/...
4027 */
4028static int pstrcmp(const void *a, const void *b)
4029{
4030 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4031}
Eric Andersencb57d552001-06-28 07:25:16 +00004032
4033/*
4034 * Search the table of builtin commands.
4035 */
4036
Eric Andersenc470f442003-07-28 09:56:35 +00004037static struct builtincmd *
4038find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004039{
4040 struct builtincmd *bp;
4041
Eric Andersenc470f442003-07-28 09:56:35 +00004042 bp = bsearch(
4043 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4044 pstrcmp
4045 );
Eric Andersencb57d552001-06-28 07:25:16 +00004046 return bp;
4047}
4048
4049
Eric Andersenc470f442003-07-28 09:56:35 +00004050
Eric Andersencb57d552001-06-28 07:25:16 +00004051/*
4052 * Called when a cd is done. Marks all commands so the next time they
4053 * are executed they will be rehashed.
4054 */
4055
Eric Andersenc470f442003-07-28 09:56:35 +00004056static void
4057hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004058{
Eric Andersencb57d552001-06-28 07:25:16 +00004059 struct tblentry **pp;
4060 struct tblentry *cmdp;
4061
Eric Andersenc470f442003-07-28 09:56:35 +00004062 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4063 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4064 if (cmdp->cmdtype == CMDNORMAL || (
4065 cmdp->cmdtype == CMDBUILTIN &&
4066 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4067 builtinloc > 0
4068 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004069 cmdp->rehash = 1;
4070 }
4071 }
4072}
4073
4074
4075
4076/*
Eric Andersenc470f442003-07-28 09:56:35 +00004077 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004078 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004079 * pathval() still returns the old value at this point.
4080 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004081 */
4082
Eric Andersenc470f442003-07-28 09:56:35 +00004083static void
4084changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004085{
Eric Andersenc470f442003-07-28 09:56:35 +00004086 const char *old, *new;
4087 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004088 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004089 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004090
Eric Andersenc470f442003-07-28 09:56:35 +00004091 old = pathval();
4092 new = newval;
4093 firstchange = 9999; /* assume no change */
4094 idx = 0;
4095 idx_bltin = -1;
4096 for (;;) {
4097 if (*old != *new) {
4098 firstchange = idx;
4099 if ((*old == '\0' && *new == ':')
4100 || (*old == ':' && *new == '\0'))
4101 firstchange++;
4102 old = new; /* ignore subsequent differences */
4103 }
4104 if (*new == '\0')
4105 break;
4106 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4107 idx_bltin = idx;
4108 if (*new == ':') {
4109 idx++;
4110 }
4111 new++, old++;
4112 }
4113 if (builtinloc < 0 && idx_bltin >= 0)
4114 builtinloc = idx_bltin; /* zap builtins */
4115 if (builtinloc >= 0 && idx_bltin < 0)
4116 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004117 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004118 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004119}
4120
4121
4122/*
4123 * Clear out command entries. The argument specifies the first entry in
4124 * PATH which has changed.
4125 */
4126
Eric Andersenc470f442003-07-28 09:56:35 +00004127static void
4128clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004129{
4130 struct tblentry **tblp;
4131 struct tblentry **pp;
4132 struct tblentry *cmdp;
4133
4134 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004135 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004136 pp = tblp;
4137 while ((cmdp = *pp) != NULL) {
4138 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004139 cmdp->param.index >= firstchange)
4140 || (cmdp->cmdtype == CMDBUILTIN &&
4141 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004142 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004143 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004144 } else {
4145 pp = &cmdp->next;
4146 }
4147 }
4148 }
4149 INTON;
4150}
4151
4152
Eric Andersenc470f442003-07-28 09:56:35 +00004153
Eric Andersencb57d552001-06-28 07:25:16 +00004154/*
Eric Andersencb57d552001-06-28 07:25:16 +00004155 * Locate a command in the command hash table. If "add" is nonzero,
4156 * add the command to the table if it is not already present. The
4157 * variable "lastcmdentry" is set to point to the address of the link
4158 * pointing to the entry, so that delete_cmd_entry can delete the
4159 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004160 *
4161 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004162 */
4163
Eric Andersen2870d962001-07-02 17:27:21 +00004164static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004165
Eric Andersenc470f442003-07-28 09:56:35 +00004166
4167static struct tblentry *
4168cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004169{
Eric Andersenc470f442003-07-28 09:56:35 +00004170 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004171 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004172 struct tblentry *cmdp;
4173 struct tblentry **pp;
4174
4175 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004176 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004177 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004178 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004179 hashval &= 0x7FFF;
4180 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004181 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004182 if (equal(cmdp->cmdname, name))
4183 break;
4184 pp = &cmdp->next;
4185 }
4186 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004187 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4188 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004189 cmdp->next = NULL;
4190 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004191 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004192 }
4193 lastcmdentry = pp;
4194 return cmdp;
4195}
4196
4197/*
4198 * Delete the command entry returned on the last lookup.
4199 */
4200
Eric Andersenc470f442003-07-28 09:56:35 +00004201static void
4202delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004203{
Eric Andersencb57d552001-06-28 07:25:16 +00004204 struct tblentry *cmdp;
4205
4206 INTOFF;
4207 cmdp = *lastcmdentry;
4208 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004209 if (cmdp->cmdtype == CMDFUNCTION)
4210 freefunc(cmdp->param.func);
4211 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004212 INTON;
4213}
4214
4215
Eric Andersenc470f442003-07-28 09:56:35 +00004216/*
4217 * Add a new command entry, replacing any existing command entry for
4218 * the same name - except special builtins.
4219 */
Eric Andersencb57d552001-06-28 07:25:16 +00004220
Eric Andersenc470f442003-07-28 09:56:35 +00004221static inline void
4222addcmdentry(char *name, struct cmdentry *entry)
4223{
4224 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004225
Eric Andersenc470f442003-07-28 09:56:35 +00004226 cmdp = cmdlookup(name, 1);
4227 if (cmdp->cmdtype == CMDFUNCTION) {
4228 freefunc(cmdp->param.func);
4229 }
4230 cmdp->cmdtype = entry->cmdtype;
4231 cmdp->param = entry->u;
4232 cmdp->rehash = 0;
4233}
Eric Andersencb57d552001-06-28 07:25:16 +00004234
Eric Andersenc470f442003-07-28 09:56:35 +00004235/*
4236 * Make a copy of a parse tree.
4237 */
Eric Andersencb57d552001-06-28 07:25:16 +00004238
Eric Andersenc470f442003-07-28 09:56:35 +00004239static inline struct funcnode *
4240copyfunc(union node *n)
4241{
4242 struct funcnode *f;
4243 size_t blocksize;
4244
4245 funcblocksize = offsetof(struct funcnode, n);
4246 funcstringsize = 0;
4247 calcsize(n);
4248 blocksize = funcblocksize;
4249 f = ckmalloc(blocksize + funcstringsize);
4250 funcblock = (char *) f + offsetof(struct funcnode, n);
4251 funcstring = (char *) f + blocksize;
4252 copynode(n);
4253 f->count = 0;
4254 return f;
4255}
4256
4257/*
4258 * Define a shell function.
4259 */
4260
4261static void
4262defun(char *name, union node *func)
4263{
4264 struct cmdentry entry;
4265
4266 INTOFF;
4267 entry.cmdtype = CMDFUNCTION;
4268 entry.u.func = copyfunc(func);
4269 addcmdentry(name, &entry);
4270 INTON;
4271}
Eric Andersencb57d552001-06-28 07:25:16 +00004272
4273
4274/*
4275 * Delete a function if it exists.
4276 */
4277
Eric Andersenc470f442003-07-28 09:56:35 +00004278static void
4279unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004280{
Eric Andersencb57d552001-06-28 07:25:16 +00004281 struct tblentry *cmdp;
4282
Eric Andersenc470f442003-07-28 09:56:35 +00004283 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4284 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004285 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004286}
4287
Eric Andersen2870d962001-07-02 17:27:21 +00004288/*
Eric Andersencb57d552001-06-28 07:25:16 +00004289 * Locate and print what a word is...
4290 */
4291
Eric Andersenc470f442003-07-28 09:56:35 +00004292
4293#ifdef CONFIG_ASH_CMDCMD
4294static int
4295describe_command(char *command, int describe_command_verbose)
4296#else
4297#define describe_command_verbose 1
4298static int
4299describe_command(char *command)
4300#endif
4301{
4302 struct cmdentry entry;
4303 struct tblentry *cmdp;
4304#ifdef CONFIG_ASH_ALIAS
4305 const struct alias *ap;
4306#endif
4307 const char *path = pathval();
4308
4309 if (describe_command_verbose) {
4310 out1str(command);
4311 }
4312
4313 /* First look at the keywords */
4314 if (findkwd(command)) {
4315 out1str(describe_command_verbose ? " is a shell keyword" : command);
4316 goto out;
4317 }
4318
4319#ifdef CONFIG_ASH_ALIAS
4320 /* Then look at the aliases */
4321 if ((ap = lookupalias(command, 0)) != NULL) {
4322 if (describe_command_verbose) {
4323 out1fmt(" is an alias for %s", ap->val);
4324 } else {
4325 out1str("alias ");
4326 printalias(ap);
4327 return 0;
4328 }
4329 goto out;
4330 }
4331#endif
4332 /* Then check if it is a tracked alias */
4333 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4334 entry.cmdtype = cmdp->cmdtype;
4335 entry.u = cmdp->param;
4336 } else {
4337 /* Finally use brute force */
4338 find_command(command, &entry, DO_ABS, path);
4339 }
4340
4341 switch (entry.cmdtype) {
4342 case CMDNORMAL: {
4343 int j = entry.u.index;
4344 char *p;
4345 if (j == -1) {
4346 p = command;
4347 } else {
4348 do {
4349 p = padvance(&path, command);
4350 stunalloc(p);
4351 } while (--j >= 0);
4352 }
4353 if (describe_command_verbose) {
4354 out1fmt(" is%s %s",
4355 (cmdp ? " a tracked alias for" : nullstr), p
4356 );
4357 } else {
4358 out1str(p);
4359 }
4360 break;
4361 }
4362
4363 case CMDFUNCTION:
4364 if (describe_command_verbose) {
4365 out1str(" is a shell function");
4366 } else {
4367 out1str(command);
4368 }
4369 break;
4370
4371 case CMDBUILTIN:
4372 if (describe_command_verbose) {
4373 out1fmt(" is a %sshell builtin",
4374 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4375 "special " : nullstr
4376 );
4377 } else {
4378 out1str(command);
4379 }
4380 break;
4381
4382 default:
4383 if (describe_command_verbose) {
4384 out1str(": not found\n");
4385 }
4386 return 127;
4387 }
4388
4389out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004390 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004391 return 0;
4392}
4393
4394static int
4395typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004396{
4397 int i;
4398 int err = 0;
4399
4400 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004401#ifdef CONFIG_ASH_CMDCMD
4402 err |= describe_command(argv[i], 1);
4403#else
4404 err |= describe_command(argv[i]);
4405#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004406 }
4407 return err;
4408}
4409
Eric Andersend35c5df2002-01-09 15:37:36 +00004410#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004411static int
4412commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004413{
4414 int c;
4415 int default_path = 0;
4416 int verify_only = 0;
4417 int verbose_verify_only = 0;
4418
4419 while ((c = nextopt("pvV")) != '\0')
4420 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004421 default:
4422#ifdef DEBUG
4423 fprintf(stderr,
4424"command: nextopt returned character code 0%o\n", c);
4425 return EX_SOFTWARE;
4426#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004427 case 'p':
4428 default_path = 1;
4429 break;
4430 case 'v':
4431 verify_only = 1;
4432 break;
4433 case 'V':
4434 verbose_verify_only = 1;
4435 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004436 }
4437
Eric Andersenc470f442003-07-28 09:56:35 +00004438 if (default_path + verify_only + verbose_verify_only > 1 ||
4439 !*argptr) {
4440 fprintf(stderr,
4441 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004442 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004443 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004444 }
4445
Eric Andersencb57d552001-06-28 07:25:16 +00004446 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004447 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004448 }
Eric Andersencb57d552001-06-28 07:25:16 +00004449
4450 return 0;
4451}
Eric Andersen2870d962001-07-02 17:27:21 +00004452#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004453
Eric Andersenc470f442003-07-28 09:56:35 +00004454/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004455
Eric Andersencb57d552001-06-28 07:25:16 +00004456/*
4457 * Routines to expand arguments to commands. We have to deal with
4458 * backquotes, shell variables, and file metacharacters.
4459 */
Eric Andersenc470f442003-07-28 09:56:35 +00004460
Eric Andersencb57d552001-06-28 07:25:16 +00004461/*
4462 * _rmescape() flags
4463 */
Eric Andersenc470f442003-07-28 09:56:35 +00004464#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4465#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4466#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4467#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4468#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004469
4470/*
4471 * Structure specifying which parts of the string should be searched
4472 * for IFS characters.
4473 */
4474
4475struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004476 struct ifsregion *next; /* next region in list */
4477 int begoff; /* offset of start of region */
4478 int endoff; /* offset of end of region */
4479 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004480};
4481
Eric Andersenc470f442003-07-28 09:56:35 +00004482/* output of current string */
4483static char *expdest;
4484/* list of back quote expressions */
4485static struct nodelist *argbackq;
4486/* first struct in list of ifs regions */
4487static struct ifsregion ifsfirst;
4488/* last struct in list */
4489static struct ifsregion *ifslastp;
4490/* holds expanded arg list */
4491static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004492
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004493static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004494static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004495static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004496static const char *subevalvar(char *, char *, int, int, int, int, int);
4497static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004498static int varisset(char *, int);
4499static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004500static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004501static void varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004502static void recordregion(int, int, int);
4503static void removerecordregions(int);
4504static void ifsbreakup(char *, struct arglist *);
4505static void ifsfree(void);
4506static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004507static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004508
Eric Andersenc470f442003-07-28 09:56:35 +00004509static int cvtnum(long);
4510static size_t esclen(const char *, const char *);
4511static char *scanleft(char *, char *, char *, char *, int, int);
4512static char *scanright(char *, char *, char *, char *, int, int);
4513static void varunset(const char *, const char *, const char *, int)
4514 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004515
Eric Andersenc470f442003-07-28 09:56:35 +00004516
4517#define pmatch(a, b) !fnmatch((a), (b), 0)
4518/*
Eric Andersen90898442003-08-06 11:20:52 +00004519 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004520 *
4521 * Returns an stalloced string.
4522 */
4523
4524static inline char *
4525preglob(const char *pattern, int quoted, int flag) {
4526 flag |= RMESCAPE_GLOB;
4527 if (quoted) {
4528 flag |= RMESCAPE_QUOTED;
4529 }
4530 return _rmescapes((char *)pattern, flag);
4531}
4532
4533
4534static size_t
4535esclen(const char *start, const char *p) {
4536 size_t esc = 0;
4537
4538 while (p > start && *--p == CTLESC) {
4539 esc++;
4540 }
4541 return esc;
4542}
4543
Eric Andersencb57d552001-06-28 07:25:16 +00004544
4545/*
4546 * Expand shell variables and backquotes inside a here document.
4547 */
4548
Eric Andersenc470f442003-07-28 09:56:35 +00004549static inline void
4550expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004551{
Eric Andersencb57d552001-06-28 07:25:16 +00004552 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004553 expandarg(arg, (struct arglist *)NULL, 0);
4554 xwrite(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004555}
4556
4557
4558/*
4559 * Perform variable substitution and command substitution on an argument,
4560 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4561 * perform splitting and file name expansion. When arglist is NULL, perform
4562 * here document expansion.
4563 */
4564
Eric Andersenc470f442003-07-28 09:56:35 +00004565void
4566expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004567{
4568 struct strlist *sp;
4569 char *p;
4570
4571 argbackq = arg->narg.backquote;
4572 STARTSTACKSTR(expdest);
4573 ifsfirst.next = NULL;
4574 ifslastp = NULL;
4575 argstr(arg->narg.text, flag);
4576 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004577 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004578 }
4579 STPUTC('\0', expdest);
4580 p = grabstackstr(expdest);
4581 exparg.lastp = &exparg.list;
4582 /*
4583 * TODO - EXP_REDIR
4584 */
4585 if (flag & EXP_FULL) {
4586 ifsbreakup(p, &exparg);
4587 *exparg.lastp = NULL;
4588 exparg.lastp = &exparg.list;
4589 expandmeta(exparg.list, flag);
4590 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004591 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004592 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004593 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004594 sp->text = p;
4595 *exparg.lastp = sp;
4596 exparg.lastp = &sp->next;
4597 }
Eric Andersenc470f442003-07-28 09:56:35 +00004598 if (ifsfirst.next)
4599 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004600 *exparg.lastp = NULL;
4601 if (exparg.list) {
4602 *arglist->lastp = exparg.list;
4603 arglist->lastp = exparg.lastp;
4604 }
4605}
4606
4607
Eric Andersenc470f442003-07-28 09:56:35 +00004608/*
4609 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4610 * characters to allow for further processing. Otherwise treat
4611 * $@ like $* since no splitting will be performed.
4612 */
4613
4614static void
4615argstr(char *p, int flag)
4616{
4617 static const char spclchars[] = {
4618 '=',
4619 ':',
4620 CTLQUOTEMARK,
4621 CTLENDVAR,
4622 CTLESC,
4623 CTLVAR,
4624 CTLBACKQ,
4625 CTLBACKQ | CTLQUOTE,
4626#ifdef CONFIG_ASH_MATH_SUPPORT
4627 CTLENDARI,
4628#endif
4629 0
4630 };
4631 const char *reject = spclchars;
4632 int c;
4633 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4634 int breakall = flag & EXP_WORD;
4635 int inquotes;
4636 size_t length;
4637 int startloc;
4638
4639 if (!(flag & EXP_VARTILDE)) {
4640 reject += 2;
4641 } else if (flag & EXP_VARTILDE2) {
4642 reject++;
4643 }
4644 inquotes = 0;
4645 length = 0;
4646 if (flag & EXP_TILDE) {
4647 char *q;
4648
4649 flag &= ~EXP_TILDE;
4650tilde:
4651 q = p;
4652 if (*q == CTLESC && (flag & EXP_QWORD))
4653 q++;
4654 if (*q == '~')
4655 p = exptilde(p, q, flag);
4656 }
4657start:
4658 startloc = expdest - (char *)stackblock();
4659 for (;;) {
4660 length += strcspn(p + length, reject);
4661 c = p[length];
4662 if (c && (!(c & 0x80)
4663#ifdef CONFIG_ASH_MATH_SUPPORT
4664 || c == CTLENDARI
4665#endif
4666 )) {
4667 /* c == '=' || c == ':' || c == CTLENDARI */
4668 length++;
4669 }
4670 if (length > 0) {
4671 int newloc;
4672 expdest = stnputs(p, length, expdest);
4673 newloc = expdest - (char *)stackblock();
4674 if (breakall && !inquotes && newloc > startloc) {
4675 recordregion(startloc, newloc, 0);
4676 }
4677 startloc = newloc;
4678 }
4679 p += length + 1;
4680 length = 0;
4681
4682 switch (c) {
4683 case '\0':
4684 goto breakloop;
4685 case '=':
4686 if (flag & EXP_VARTILDE2) {
4687 p--;
4688 continue;
4689 }
4690 flag |= EXP_VARTILDE2;
4691 reject++;
4692 /* fall through */
4693 case ':':
4694 /*
4695 * sort of a hack - expand tildes in variable
4696 * assignments (after the first '=' and after ':'s).
4697 */
4698 if (*--p == '~') {
4699 goto tilde;
4700 }
4701 continue;
4702 }
4703
4704 switch (c) {
4705 case CTLENDVAR: /* ??? */
4706 goto breakloop;
4707 case CTLQUOTEMARK:
4708 /* "$@" syntax adherence hack */
4709 if (
4710 !inquotes &&
4711 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4712 (p[4] == CTLQUOTEMARK || (
4713 p[4] == CTLENDVAR &&
4714 p[5] == CTLQUOTEMARK
4715 ))
4716 ) {
4717 p = evalvar(p + 1, flag) + 1;
4718 goto start;
4719 }
4720 inquotes = !inquotes;
4721addquote:
4722 if (quotes) {
4723 p--;
4724 length++;
4725 startloc++;
4726 }
4727 break;
4728 case CTLESC:
4729 startloc++;
4730 length++;
4731 goto addquote;
4732 case CTLVAR:
4733 p = evalvar(p, flag);
4734 goto start;
4735 case CTLBACKQ:
4736 c = 0;
4737 case CTLBACKQ|CTLQUOTE:
4738 expbackq(argbackq->n, c, quotes);
4739 argbackq = argbackq->next;
4740 goto start;
4741#ifdef CONFIG_ASH_MATH_SUPPORT
4742 case CTLENDARI:
4743 p--;
4744 expari(quotes);
4745 goto start;
4746#endif
4747 }
4748 }
4749breakloop:
4750 ;
4751}
4752
4753static char *
4754exptilde(char *startp, char *p, int flag)
4755{
4756 char c;
4757 char *name;
4758 struct passwd *pw;
4759 const char *home;
4760 int quotes = flag & (EXP_FULL | EXP_CASE);
4761 int startloc;
4762
4763 name = p + 1;
4764
4765 while ((c = *++p) != '\0') {
4766 switch(c) {
4767 case CTLESC:
4768 return (startp);
4769 case CTLQUOTEMARK:
4770 return (startp);
4771 case ':':
4772 if (flag & EXP_VARTILDE)
4773 goto done;
4774 break;
4775 case '/':
4776 case CTLENDVAR:
4777 goto done;
4778 }
4779 }
4780done:
4781 *p = '\0';
4782 if (*name == '\0') {
4783 if ((home = lookupvar(homestr)) == NULL)
4784 goto lose;
4785 } else {
4786 if ((pw = getpwnam(name)) == NULL)
4787 goto lose;
4788 home = pw->pw_dir;
4789 }
4790 if (*home == '\0')
4791 goto lose;
4792 *p = c;
4793 startloc = expdest - (char *)stackblock();
4794 strtodest(home, SQSYNTAX, quotes);
4795 recordregion(startloc, expdest - (char *)stackblock(), 0);
4796 return (p);
4797lose:
4798 *p = c;
4799 return (startp);
4800}
4801
4802
4803static void
4804removerecordregions(int endoff)
4805{
4806 if (ifslastp == NULL)
4807 return;
4808
4809 if (ifsfirst.endoff > endoff) {
4810 while (ifsfirst.next != NULL) {
4811 struct ifsregion *ifsp;
4812 INTOFF;
4813 ifsp = ifsfirst.next->next;
4814 ckfree(ifsfirst.next);
4815 ifsfirst.next = ifsp;
4816 INTON;
4817 }
4818 if (ifsfirst.begoff > endoff)
4819 ifslastp = NULL;
4820 else {
4821 ifslastp = &ifsfirst;
4822 ifsfirst.endoff = endoff;
4823 }
4824 return;
4825 }
4826
4827 ifslastp = &ifsfirst;
4828 while (ifslastp->next && ifslastp->next->begoff < endoff)
4829 ifslastp=ifslastp->next;
4830 while (ifslastp->next != NULL) {
4831 struct ifsregion *ifsp;
4832 INTOFF;
4833 ifsp = ifslastp->next->next;
4834 ckfree(ifslastp->next);
4835 ifslastp->next = ifsp;
4836 INTON;
4837 }
4838 if (ifslastp->endoff > endoff)
4839 ifslastp->endoff = endoff;
4840}
4841
4842
4843#ifdef CONFIG_ASH_MATH_SUPPORT
4844/*
4845 * Expand arithmetic expression. Backup to start of expression,
4846 * evaluate, place result in (backed up) result, adjust string position.
4847 */
4848void
4849expari(int quotes)
4850{
4851 char *p, *start;
4852 int begoff;
4853 int flag;
4854 int len;
4855
4856 /* ifsfree(); */
4857
4858 /*
4859 * This routine is slightly over-complicated for
4860 * efficiency. Next we scan backwards looking for the
4861 * start of arithmetic.
4862 */
4863 start = stackblock();
4864 p = expdest - 1;
4865 *p = '\0';
4866 p--;
4867 do {
4868 int esc;
4869
4870 while (*p != CTLARI) {
4871 p--;
4872#ifdef DEBUG
4873 if (p < start) {
4874 error("missing CTLARI (shouldn't happen)");
4875 }
4876#endif
4877 }
4878
4879 esc = esclen(start, p);
4880 if (!(esc % 2)) {
4881 break;
4882 }
4883
4884 p -= esc + 1;
4885 } while (1);
4886
4887 begoff = p - start;
4888
4889 removerecordregions(begoff);
4890
4891 flag = p[1];
4892
4893 expdest = p;
4894
4895 if (quotes)
4896 rmescapes(p + 2);
4897
4898 len = cvtnum(dash_arith(p + 2));
4899
4900 if (flag != '"')
4901 recordregion(begoff, begoff + len, 0);
4902}
4903#endif
4904
4905/*
4906 * Expand stuff in backwards quotes.
4907 */
4908
4909static void
4910expbackq(union node *cmd, int quoted, int quotes)
4911{
4912 struct backcmd in;
4913 int i;
4914 char buf[128];
4915 char *p;
4916 char *dest;
4917 int startloc;
4918 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4919 struct stackmark smark;
4920
4921 INTOFF;
4922 setstackmark(&smark);
4923 dest = expdest;
4924 startloc = dest - (char *)stackblock();
4925 grabstackstr(dest);
4926 evalbackcmd(cmd, (struct backcmd *) &in);
4927 popstackmark(&smark);
4928
4929 p = in.buf;
4930 i = in.nleft;
4931 if (i == 0)
4932 goto read;
4933 for (;;) {
4934 memtodest(p, i, syntax, quotes);
4935read:
4936 if (in.fd < 0)
4937 break;
4938 i = safe_read(in.fd, buf, sizeof buf);
4939 TRACE(("expbackq: read returns %d\n", i));
4940 if (i <= 0)
4941 break;
4942 p = buf;
4943 }
4944
4945 if (in.buf)
4946 ckfree(in.buf);
4947 if (in.fd >= 0) {
4948 close(in.fd);
4949 back_exitstatus = waitforjob(in.jp);
4950 }
4951 INTON;
4952
4953 /* Eat all trailing newlines */
4954 dest = expdest;
4955 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4956 STUNPUTC(dest);
4957 expdest = dest;
4958
4959 if (quoted == 0)
4960 recordregion(startloc, dest - (char *)stackblock(), 0);
4961 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4962 (dest - (char *)stackblock()) - startloc,
4963 (dest - (char *)stackblock()) - startloc,
4964 stackblock() + startloc));
4965}
4966
4967
4968static char *
Eric Andersen90898442003-08-06 11:20:52 +00004969scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4970 int zero)
4971{
Eric Andersenc470f442003-07-28 09:56:35 +00004972 char *loc;
4973 char *loc2;
4974 char c;
4975
4976 loc = startp;
4977 loc2 = rmesc;
4978 do {
4979 int match;
4980 const char *s = loc2;
4981 c = *loc2;
4982 if (zero) {
4983 *loc2 = '\0';
4984 s = rmesc;
4985 }
4986 match = pmatch(str, s);
4987 *loc2 = c;
4988 if (match)
4989 return loc;
4990 if (quotes && *loc == CTLESC)
4991 loc++;
4992 loc++;
4993 loc2++;
4994 } while (c);
4995 return 0;
4996}
4997
4998
4999static char *
Eric Andersen90898442003-08-06 11:20:52 +00005000scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5001 int zero)
5002{
Eric Andersenc470f442003-07-28 09:56:35 +00005003 int esc = 0;
5004 char *loc;
5005 char *loc2;
5006
5007 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5008 int match;
5009 char c = *loc2;
5010 const char *s = loc2;
5011 if (zero) {
5012 *loc2 = '\0';
5013 s = rmesc;
5014 }
5015 match = pmatch(str, s);
5016 *loc2 = c;
5017 if (match)
5018 return loc;
5019 loc--;
5020 if (quotes) {
5021 if (--esc < 0) {
5022 esc = esclen(startp, loc);
5023 }
5024 if (esc % 2) {
5025 esc--;
5026 loc--;
5027 }
5028 }
5029 }
5030 return 0;
5031}
5032
5033static const char *
5034subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5035{
5036 char *startp;
5037 char *loc;
5038 int saveherefd = herefd;
5039 struct nodelist *saveargbackq = argbackq;
5040 int amount;
5041 char *rmesc, *rmescend;
5042 int zero;
5043 char *(*scan)(char *, char *, char *, char *, int , int);
5044
5045 herefd = -1;
5046 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5047 STPUTC('\0', expdest);
5048 herefd = saveherefd;
5049 argbackq = saveargbackq;
5050 startp = stackblock() + startloc;
5051
5052 switch (subtype) {
5053 case VSASSIGN:
5054 setvar(str, startp, 0);
5055 amount = startp - expdest;
5056 STADJUST(amount, expdest);
5057 return startp;
5058
5059 case VSQUESTION:
5060 varunset(p, str, startp, varflags);
5061 /* NOTREACHED */
5062 }
5063
5064 subtype -= VSTRIMRIGHT;
5065#ifdef DEBUG
5066 if (subtype < 0 || subtype > 3)
5067 abort();
5068#endif
5069
5070 rmesc = startp;
5071 rmescend = stackblock() + strloc;
5072 if (quotes) {
5073 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5074 if (rmesc != startp) {
5075 rmescend = expdest;
5076 startp = stackblock() + startloc;
5077 }
5078 }
5079 rmescend--;
5080 str = stackblock() + strloc;
5081 preglob(str, varflags & VSQUOTE, 0);
5082
5083 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5084 zero = subtype >> 1;
5085 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5086 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5087
5088 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5089 if (loc) {
5090 if (zero) {
5091 memmove(startp, loc, str - loc);
5092 loc = startp + (str - loc) - 1;
5093 }
5094 *loc = '\0';
5095 amount = loc - expdest;
5096 STADJUST(amount, expdest);
5097 }
5098 return loc;
5099}
5100
5101
Eric Andersen62483552001-07-10 06:09:16 +00005102/*
5103 * Expand a variable, and return a pointer to the next character in the
5104 * input string.
5105 */
Eric Andersenc470f442003-07-28 09:56:35 +00005106static char *
5107evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005108{
5109 int subtype;
5110 int varflags;
5111 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005112 int patloc;
5113 int c;
5114 int set;
Eric Andersen62483552001-07-10 06:09:16 +00005115 int startloc;
Eric Andersenc470f442003-07-28 09:56:35 +00005116 size_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005117 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005118 int quotes;
5119 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005120
Eric Andersenc470f442003-07-28 09:56:35 +00005121 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005122 varflags = *p++;
5123 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005124 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005125 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005126 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersen62483552001-07-10 06:09:16 +00005127 varlen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00005128 startloc = expdest - (char *)stackblock();
5129 p = strchr(p, '=') + 1;
5130
5131 if (!is_name(*var)) {
5132 set = varisset(var, varflags & VSNUL);
5133 set--;
5134 if (subtype == VSPLUS)
5135 goto vsplus;
5136 if (++set) {
5137 varvalue(var, quoted, flag);
Eric Andersen62483552001-07-10 06:09:16 +00005138 if (subtype == VSLENGTH) {
Eric Andersenc470f442003-07-28 09:56:35 +00005139 varlen =
5140 expdest - (char *)stackblock() -
5141 startloc;
Eric Andersen62483552001-07-10 06:09:16 +00005142 STADJUST(-varlen, expdest);
Eric Andersenc470f442003-07-28 09:56:35 +00005143 goto vslen;
Eric Andersen62483552001-07-10 06:09:16 +00005144 }
Eric Andersenc470f442003-07-28 09:56:35 +00005145 }
5146 } else {
5147 const char *val;
5148again:
5149 /* jump here after setting a variable with ${var=text} */
5150 val = lookupvar(var);
5151 set = !val || ((varflags & VSNUL) && !*val);
5152 if (subtype == VSPLUS)
5153 goto vsplus;
5154 if (--set) {
5155 varlen = strlen(val);
5156 if (subtype == VSLENGTH)
5157 goto vslen;
5158 memtodest(
5159 val, varlen, quoted ? DQSYNTAX : BASESYNTAX,
5160 quotes
5161 );
Eric Andersen62483552001-07-10 06:09:16 +00005162 }
5163 }
5164
Eric Andersen62483552001-07-10 06:09:16 +00005165
Eric Andersenc470f442003-07-28 09:56:35 +00005166 if (subtype == VSMINUS) {
5167vsplus:
Eric Andersen62483552001-07-10 06:09:16 +00005168 if (!set) {
Eric Andersenc470f442003-07-28 09:56:35 +00005169 argstr(
5170 p, flag | EXP_TILDE |
5171 (quoted ? EXP_QWORD : EXP_WORD)
5172 );
5173 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005174 }
5175 if (easy)
5176 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005177 goto end;
5178 }
Eric Andersen62483552001-07-10 06:09:16 +00005179
Eric Andersenc470f442003-07-28 09:56:35 +00005180 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Eric Andersen62483552001-07-10 06:09:16 +00005181 if (!set) {
Eric Andersenc470f442003-07-28 09:56:35 +00005182 if (subevalvar(p, var, 0, subtype, startloc,
5183 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005184 varflags &= ~VSNUL;
5185 /*
5186 * Remove any recorded regions beyond
5187 * start of variable
5188 */
5189 removerecordregions(startloc);
5190 goto again;
5191 }
Eric Andersenc470f442003-07-28 09:56:35 +00005192 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005193 }
5194 if (easy)
5195 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005196 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005197 }
5198
Eric Andersenc470f442003-07-28 09:56:35 +00005199 if (!set && uflag)
5200 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005201
Eric Andersenc470f442003-07-28 09:56:35 +00005202 if (subtype == VSLENGTH) {
5203vslen:
5204 cvtnum(varlen);
5205 goto record;
5206 }
5207
5208 if (subtype == VSNORMAL) {
5209 if (!easy)
5210 goto end;
5211record:
5212 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5213 goto end;
5214 }
5215
5216#ifdef DEBUG
5217 switch (subtype) {
5218 case VSTRIMLEFT:
5219 case VSTRIMLEFTMAX:
5220 case VSTRIMRIGHT:
5221 case VSTRIMRIGHTMAX:
5222 break;
5223 default:
5224 abort();
5225 }
5226#endif
5227
5228 if (set) {
5229 /*
5230 * Terminate the string and start recording the pattern
5231 * right after it
5232 */
5233 STPUTC('\0', expdest);
5234 patloc = expdest - (char *)stackblock();
5235 if (subevalvar(p, NULL, patloc, subtype,
5236 startloc, varflags, quotes) == 0) {
5237 int amount = expdest - (
5238 (char *)stackblock() + patloc - 1
5239 );
5240 STADJUST(-amount, expdest);
5241 }
5242 /* Remove any recorded regions beyond start of variable */
5243 removerecordregions(startloc);
5244 goto record;
5245 }
5246
5247end:
5248 if (subtype != VSNORMAL) { /* skip to end of alternative */
5249 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005250 for (;;) {
5251 if ((c = *p++) == CTLESC)
5252 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005253 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Eric Andersen62483552001-07-10 06:09:16 +00005254 if (set)
5255 argbackq = argbackq->next;
5256 } else if (c == CTLVAR) {
5257 if ((*p++ & VSTYPE) != VSNORMAL)
5258 nesting++;
5259 } else if (c == CTLENDVAR) {
5260 if (--nesting == 0)
5261 break;
5262 }
5263 }
5264 }
5265 return p;
5266}
5267
Eric Andersencb57d552001-06-28 07:25:16 +00005268
Eric Andersencb57d552001-06-28 07:25:16 +00005269
5270/*
Eric Andersencb57d552001-06-28 07:25:16 +00005271 * Test whether a specialized variable is set.
5272 */
5273
Eric Andersenc470f442003-07-28 09:56:35 +00005274static int
5275varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00005276{
5277 if (*name == '!')
Eric Andersenc470f442003-07-28 09:56:35 +00005278 return backgndpid != 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005279 else if (*name == '@' || *name == '*') {
5280 if (*shellparam.p == NULL)
5281 return 0;
5282
5283 if (nulok) {
5284 char **av;
5285
5286 for (av = shellparam.p; *av; av++)
5287 if (**av != '\0')
5288 return 1;
5289 return 0;
5290 }
5291 } else if (is_digit(*name)) {
5292 char *ap;
5293 int num = atoi(name);
5294
5295 if (num > shellparam.nparam)
5296 return 0;
5297
5298 if (num == 0)
5299 ap = arg0;
5300 else
5301 ap = shellparam.p[num - 1];
5302
5303 if (nulok && (ap == NULL || *ap == '\0'))
5304 return 0;
5305 }
5306 return 1;
5307}
5308
Eric Andersenc470f442003-07-28 09:56:35 +00005309
Eric Andersencb57d552001-06-28 07:25:16 +00005310/*
5311 * Put a string on the stack.
5312 */
5313
Eric Andersenc470f442003-07-28 09:56:35 +00005314static void
5315memtodest(const char *p, size_t len, int syntax, int quotes) {
5316 char *q = expdest;
5317
5318 q = makestrspace(len * 2, q);
5319
5320 while (len--) {
5321 int c = *p++;
5322 if (!c)
5323 continue;
5324 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5325 USTPUTC(CTLESC, q);
5326 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005327 }
Eric Andersenc470f442003-07-28 09:56:35 +00005328
5329 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005330}
5331
Eric Andersenc470f442003-07-28 09:56:35 +00005332
5333static void
5334strtodest(const char *p, int syntax, int quotes)
5335{
5336 memtodest(p, strlen(p), syntax, quotes);
5337}
5338
5339
Eric Andersencb57d552001-06-28 07:25:16 +00005340/*
5341 * Add the value of a specialized variable to the stack string.
5342 */
5343
Eric Andersenc470f442003-07-28 09:56:35 +00005344static void
5345varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005346{
5347 int num;
5348 char *p;
5349 int i;
5350 int sep;
5351 int sepq = 0;
5352 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005353 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00005354 int allow_split = flags & EXP_FULL;
5355 int quotes = flags & (EXP_FULL | EXP_CASE);
5356
5357 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5358 switch (*name) {
5359 case '$':
5360 num = rootpid;
5361 goto numvar;
5362 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005363 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005364 goto numvar;
5365 case '#':
5366 num = shellparam.nparam;
5367 goto numvar;
5368 case '!':
5369 num = backgndpid;
Eric Andersenc470f442003-07-28 09:56:35 +00005370numvar:
5371 cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005372 break;
5373 case '-':
Eric Andersenc470f442003-07-28 09:56:35 +00005374 for (i = 0 ; i < NOPTS ; i++) {
5375 if (optlist[i])
5376 STPUTC(optletters(i), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005377 }
5378 break;
5379 case '@':
5380 if (allow_split && quoted) {
5381 sep = 1 << CHAR_BIT;
5382 goto param;
5383 }
5384 /* fall through */
5385 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005386 sep = ifsset() ? ifsval()[0] : ' ';
Eric Andersencb57d552001-06-28 07:25:16 +00005387 if (quotes) {
Eric Andersenc470f442003-07-28 09:56:35 +00005388 sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK);
Eric Andersencb57d552001-06-28 07:25:16 +00005389 }
Eric Andersenc470f442003-07-28 09:56:35 +00005390param:
5391 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005392 strtodest(p, syntax, quotes);
5393 if (*ap && sep) {
Eric Andersenc470f442003-07-28 09:56:35 +00005394 p = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005395 if (sepq)
Eric Andersenc470f442003-07-28 09:56:35 +00005396 STPUTC(CTLESC, p);
5397 STPUTC(sep, p);
5398 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005399 }
5400 }
5401 break;
5402 case '0':
5403 strtodest(arg0, syntax, quotes);
5404 break;
5405 default:
5406 num = atoi(name);
5407 if (num > 0 && num <= shellparam.nparam) {
5408 strtodest(shellparam.p[num - 1], syntax, quotes);
5409 }
5410 break;
5411 }
5412}
5413
5414
Eric Andersencb57d552001-06-28 07:25:16 +00005415/*
5416 * Record the fact that we have to scan this region of the
5417 * string for IFS characters.
5418 */
5419
Eric Andersenc470f442003-07-28 09:56:35 +00005420static void
5421recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005422{
5423 struct ifsregion *ifsp;
5424
5425 if (ifslastp == NULL) {
5426 ifsp = &ifsfirst;
5427 } else {
5428 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005429 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005430 ifsp->next = NULL;
5431 ifslastp->next = ifsp;
5432 INTON;
5433 }
5434 ifslastp = ifsp;
5435 ifslastp->begoff = start;
5436 ifslastp->endoff = end;
5437 ifslastp->nulonly = nulonly;
5438}
5439
5440
Eric Andersencb57d552001-06-28 07:25:16 +00005441/*
5442 * Break the argument string into pieces based upon IFS and add the
5443 * strings to the argument list. The regions of the string to be
5444 * searched for IFS characters have been stored by recordregion.
5445 */
Eric Andersenc470f442003-07-28 09:56:35 +00005446static void
5447ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005448{
Eric Andersencb57d552001-06-28 07:25:16 +00005449 struct ifsregion *ifsp;
5450 struct strlist *sp;
5451 char *start;
5452 char *p;
5453 char *q;
5454 const char *ifs, *realifs;
5455 int ifsspc;
5456 int nulonly;
5457
5458
5459 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005460 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005461 ifsspc = 0;
5462 nulonly = 0;
5463 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005464 ifsp = &ifsfirst;
5465 do {
5466 p = string + ifsp->begoff;
5467 nulonly = ifsp->nulonly;
5468 ifs = nulonly ? nullstr : realifs;
5469 ifsspc = 0;
5470 while (p < string + ifsp->endoff) {
5471 q = p;
5472 if (*p == CTLESC)
5473 p++;
5474 if (strchr(ifs, *p)) {
5475 if (!nulonly)
5476 ifsspc = (strchr(defifs, *p) != NULL);
5477 /* Ignore IFS whitespace at start */
5478 if (q == start && ifsspc) {
5479 p++;
5480 start = p;
5481 continue;
5482 }
5483 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005484 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005485 sp->text = start;
5486 *arglist->lastp = sp;
5487 arglist->lastp = &sp->next;
5488 p++;
5489 if (!nulonly) {
5490 for (;;) {
5491 if (p >= string + ifsp->endoff) {
5492 break;
5493 }
5494 q = p;
5495 if (*p == CTLESC)
5496 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005497 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005498 p = q;
5499 break;
5500 } else if (strchr(defifs, *p) == NULL) {
5501 if (ifsspc) {
5502 p++;
5503 ifsspc = 0;
5504 } else {
5505 p = q;
5506 break;
5507 }
5508 } else
5509 p++;
5510 }
5511 }
5512 start = p;
5513 } else
5514 p++;
5515 }
5516 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005517 if (nulonly)
5518 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005519 }
5520
Eric Andersenc470f442003-07-28 09:56:35 +00005521 if (!*start)
5522 return;
5523
5524add:
5525 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005526 sp->text = start;
5527 *arglist->lastp = sp;
5528 arglist->lastp = &sp->next;
5529}
5530
Eric Andersenc470f442003-07-28 09:56:35 +00005531static void
5532ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005533{
Eric Andersenc470f442003-07-28 09:56:35 +00005534 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005535
Eric Andersenc470f442003-07-28 09:56:35 +00005536 INTOFF;
5537 p = ifsfirst.next;
5538 do {
5539 struct ifsregion *ifsp;
5540 ifsp = p->next;
5541 ckfree(p);
5542 p = ifsp;
5543 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005544 ifslastp = NULL;
5545 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005546 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005547}
5548
Eric Andersen90898442003-08-06 11:20:52 +00005549static void expmeta(char *, char *);
5550static struct strlist *expsort(struct strlist *);
5551static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005552
Eric Andersen90898442003-08-06 11:20:52 +00005553static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005554
Eric Andersencb57d552001-06-28 07:25:16 +00005555
Eric Andersenc470f442003-07-28 09:56:35 +00005556static void
Eric Andersen90898442003-08-06 11:20:52 +00005557expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005558{
Eric Andersen90898442003-08-06 11:20:52 +00005559 static const char metachars[] = {
5560 '*', '?', '[', 0
5561 };
Eric Andersencb57d552001-06-28 07:25:16 +00005562 /* TODO - EXP_REDIR */
5563
5564 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005565 struct strlist **savelastp;
5566 struct strlist *sp;
5567 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005568
Eric Andersencb57d552001-06-28 07:25:16 +00005569 if (fflag)
5570 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005571 if (!strpbrk(str->text, metachars))
5572 goto nometa;
5573 savelastp = exparg.lastp;
5574
Eric Andersencb57d552001-06-28 07:25:16 +00005575 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005576 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005577 {
5578 int i = strlen(str->text);
5579 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5580 }
5581
5582 expmeta(expdir, p);
5583 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005584 if (p != str->text)
5585 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005586 INTON;
5587 if (exparg.lastp == savelastp) {
5588 /*
5589 * no matches
5590 */
Eric Andersenc470f442003-07-28 09:56:35 +00005591nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005592 *exparg.lastp = str;
5593 rmescapes(str->text);
5594 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005595 } else {
5596 *exparg.lastp = NULL;
5597 *savelastp = sp = expsort(*savelastp);
5598 while (sp->next != NULL)
5599 sp = sp->next;
5600 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005601 }
5602 str = str->next;
5603 }
5604}
5605
Eric Andersencb57d552001-06-28 07:25:16 +00005606/*
Eric Andersenc470f442003-07-28 09:56:35 +00005607 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005608 */
5609
Eric Andersenc470f442003-07-28 09:56:35 +00005610static void
Eric Andersen90898442003-08-06 11:20:52 +00005611addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005612{
Eric Andersencb57d552001-06-28 07:25:16 +00005613 struct strlist *sp;
5614
Eric Andersenc470f442003-07-28 09:56:35 +00005615 sp = (struct strlist *)stalloc(sizeof *sp);
5616 sp->text = sstrdup(name);
5617 *exparg.lastp = sp;
5618 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005619}
5620
5621
Eric Andersencb57d552001-06-28 07:25:16 +00005622/*
Eric Andersen90898442003-08-06 11:20:52 +00005623 * Do metacharacter (i.e. *, ?, [...]) expansion.
5624 */
5625
5626static void
5627expmeta(char *enddir, char *name)
5628{
5629 char *p;
5630 const char *cp;
5631 char *start;
5632 char *endname;
5633 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005634 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005635 DIR *dirp;
5636 struct dirent *dp;
5637 int atend;
5638 int matchdot;
5639
5640 metaflag = 0;
5641 start = name;
5642 for (p = name; *p; p++) {
5643 if (*p == '*' || *p == '?')
5644 metaflag = 1;
5645 else if (*p == '[') {
5646 char *q = p + 1;
5647 if (*q == '!')
5648 q++;
5649 for (;;) {
5650 if (*q == '\\')
5651 q++;
5652 if (*q == '/' || *q == '\0')
5653 break;
5654 if (*++q == ']') {
5655 metaflag = 1;
5656 break;
5657 }
5658 }
5659 } else if (*p == '\\')
5660 p++;
5661 else if (*p == '/') {
5662 if (metaflag)
5663 goto out;
5664 start = p + 1;
5665 }
5666 }
5667out:
5668 if (metaflag == 0) { /* we've reached the end of the file name */
5669 if (enddir != expdir)
5670 metaflag++;
5671 p = name;
5672 do {
5673 if (*p == '\\')
5674 p++;
5675 *enddir++ = *p;
5676 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005677 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005678 addfname(expdir);
5679 return;
5680 }
5681 endname = p;
5682 if (name < start) {
5683 p = name;
5684 do {
5685 if (*p == '\\')
5686 p++;
5687 *enddir++ = *p++;
5688 } while (p < start);
5689 }
5690 if (enddir == expdir) {
5691 cp = ".";
5692 } else if (enddir == expdir + 1 && *expdir == '/') {
5693 cp = "/";
5694 } else {
5695 cp = expdir;
5696 enddir[-1] = '\0';
5697 }
5698 if ((dirp = opendir(cp)) == NULL)
5699 return;
5700 if (enddir != expdir)
5701 enddir[-1] = '/';
5702 if (*endname == 0) {
5703 atend = 1;
5704 } else {
5705 atend = 0;
5706 *endname++ = '\0';
5707 }
5708 matchdot = 0;
5709 p = start;
5710 if (*p == '\\')
5711 p++;
5712 if (*p == '.')
5713 matchdot++;
5714 while (! intpending && (dp = readdir(dirp)) != NULL) {
5715 if (dp->d_name[0] == '.' && ! matchdot)
5716 continue;
5717 if (pmatch(start, dp->d_name)) {
5718 if (atend) {
5719 scopy(dp->d_name, enddir);
5720 addfname(expdir);
5721 } else {
5722 for (p = enddir, cp = dp->d_name;
5723 (*p++ = *cp++) != '\0';)
5724 continue;
5725 p[-1] = '/';
5726 expmeta(p, endname);
5727 }
5728 }
5729 }
5730 closedir(dirp);
5731 if (! atend)
5732 endname[-1] = '/';
5733}
5734
5735/*
5736 * Sort the results of file name expansion. It calculates the number of
5737 * strings to sort and then calls msort (short for merge sort) to do the
5738 * work.
5739 */
5740
5741static struct strlist *
5742expsort(struct strlist *str)
5743{
5744 int len;
5745 struct strlist *sp;
5746
5747 len = 0;
5748 for (sp = str ; sp ; sp = sp->next)
5749 len++;
5750 return msort(str, len);
5751}
5752
5753
5754static struct strlist *
5755msort(struct strlist *list, int len)
5756{
5757 struct strlist *p, *q = NULL;
5758 struct strlist **lpp;
5759 int half;
5760 int n;
5761
5762 if (len <= 1)
5763 return list;
5764 half = len >> 1;
5765 p = list;
5766 for (n = half ; --n >= 0 ; ) {
5767 q = p;
5768 p = p->next;
5769 }
5770 q->next = NULL; /* terminate first half of list */
5771 q = msort(list, half); /* sort first half of list */
5772 p = msort(p, len - half); /* sort second half */
5773 lpp = &list;
5774 for (;;) {
5775#ifdef CONFIG_LOCALE_SUPPORT
5776 if (strcoll(p->text, q->text) < 0)
5777#else
5778 if (strcmp(p->text, q->text) < 0)
5779#endif
5780 {
5781 *lpp = p;
5782 lpp = &p->next;
5783 if ((p = *lpp) == NULL) {
5784 *lpp = q;
5785 break;
5786 }
5787 } else {
5788 *lpp = q;
5789 lpp = &q->next;
5790 if ((q = *lpp) == NULL) {
5791 *lpp = p;
5792 break;
5793 }
5794 }
5795 }
5796 return list;
5797}
5798
5799
5800/*
Eric Andersencb57d552001-06-28 07:25:16 +00005801 * Returns true if the pattern matches the string.
5802 */
5803
Eric Andersenc470f442003-07-28 09:56:35 +00005804static inline int
5805patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005806{
Eric Andersenc470f442003-07-28 09:56:35 +00005807 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005808}
5809
5810
Eric Andersencb57d552001-06-28 07:25:16 +00005811/*
5812 * Remove any CTLESC characters from a string.
5813 */
5814
Eric Andersenc470f442003-07-28 09:56:35 +00005815static char *
5816_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005817{
5818 char *p, *q, *r;
5819 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005820 unsigned inquotes;
5821 int notescaped;
5822 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005823
5824 p = strpbrk(str, qchars);
5825 if (!p) {
5826 return str;
5827 }
5828 q = p;
5829 r = str;
5830 if (flag & RMESCAPE_ALLOC) {
5831 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005832 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005833
Eric Andersenc470f442003-07-28 09:56:35 +00005834 if (flag & RMESCAPE_GROW) {
5835 r = makestrspace(fulllen, expdest);
5836 } else if (flag & RMESCAPE_HEAP) {
5837 r = ckmalloc(fulllen);
5838 } else {
5839 r = stalloc(fulllen);
5840 }
5841 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005842 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005843 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005844 }
5845 }
Eric Andersenc470f442003-07-28 09:56:35 +00005846 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5847 globbing = flag & RMESCAPE_GLOB;
5848 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005849 while (*p) {
5850 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005851 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005852 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005853 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005854 continue;
5855 }
Eric Andersenc470f442003-07-28 09:56:35 +00005856 if (*p == '\\') {
5857 /* naked back slash */
5858 notescaped = 0;
5859 goto copy;
5860 }
Eric Andersencb57d552001-06-28 07:25:16 +00005861 if (*p == CTLESC) {
5862 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005863 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005864 *q++ = '\\';
5865 }
5866 }
Eric Andersenc470f442003-07-28 09:56:35 +00005867 notescaped = globbing;
5868copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005869 *q++ = *p++;
5870 }
5871 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005872 if (flag & RMESCAPE_GROW) {
5873 expdest = r;
5874 STADJUST(q - r + 1, expdest);
5875 }
Eric Andersencb57d552001-06-28 07:25:16 +00005876 return r;
5877}
Eric Andersencb57d552001-06-28 07:25:16 +00005878
5879
Eric Andersencb57d552001-06-28 07:25:16 +00005880/*
5881 * See if a pattern matches in a case statement.
5882 */
5883
Eric Andersenc470f442003-07-28 09:56:35 +00005884int
5885casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005886{
Eric Andersencb57d552001-06-28 07:25:16 +00005887 struct stackmark smark;
5888 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005889
5890 setstackmark(&smark);
5891 argbackq = pattern->narg.backquote;
5892 STARTSTACKSTR(expdest);
5893 ifslastp = NULL;
5894 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005895 STACKSTRNUL(expdest);
5896 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005897 popstackmark(&smark);
5898 return result;
5899}
5900
5901/*
5902 * Our own itoa().
5903 */
5904
Eric Andersenc470f442003-07-28 09:56:35 +00005905static int
5906cvtnum(long num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005907{
Eric Andersencb57d552001-06-28 07:25:16 +00005908 int len;
5909
Eric Andersenc470f442003-07-28 09:56:35 +00005910 expdest = makestrspace(32, expdest);
5911 len = fmtstr(expdest, 32, "%ld", num);
5912 STADJUST(len, expdest);
5913 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005914}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005915
Eric Andersenc470f442003-07-28 09:56:35 +00005916static void
5917varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005918{
Eric Andersenc470f442003-07-28 09:56:35 +00005919 const char *msg;
5920 const char *tail;
5921
5922 tail = nullstr;
5923 msg = "parameter not set";
5924 if (umsg) {
5925 if (*end == CTLENDVAR) {
5926 if (varflags & VSNUL)
5927 tail = " or null";
5928 } else
5929 msg = umsg;
5930 }
5931 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005932}
Eric Andersen90898442003-08-06 11:20:52 +00005933
5934
Eric Andersenc470f442003-07-28 09:56:35 +00005935/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005936
Eric Andersencb57d552001-06-28 07:25:16 +00005937/*
Eric Andersen90898442003-08-06 11:20:52 +00005938 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005939 */
5940
Eric Andersenc470f442003-07-28 09:56:35 +00005941#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5942#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005943
Eric Andersenc470f442003-07-28 09:56:35 +00005944static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005945
Eric Andersencb57d552001-06-28 07:25:16 +00005946/*
5947 * Read a line from the script.
5948 */
5949
Eric Andersenc470f442003-07-28 09:56:35 +00005950static inline char *
5951pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005952{
5953 char *p = line;
5954 int nleft = len;
5955 int c;
5956
5957 while (--nleft > 0) {
5958 c = pgetc2();
5959 if (c == PEOF) {
5960 if (p == line)
5961 return NULL;
5962 break;
5963 }
5964 *p++ = c;
5965 if (c == '\n')
5966 break;
5967 }
5968 *p = '\0';
5969 return line;
5970}
5971
Eric Andersenc470f442003-07-28 09:56:35 +00005972
5973/*
5974 * Read a character from the script, returning PEOF on end of file.
5975 * Nul characters in the input are silently discarded.
5976 */
5977
5978#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5979
5980#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5981#define pgetc_macro() pgetc()
5982static int
5983pgetc(void)
5984{
5985 return pgetc_as_macro();
5986}
5987#else
5988#define pgetc_macro() pgetc_as_macro()
5989static int
5990pgetc(void)
5991{
5992 return pgetc_macro();
5993}
5994#endif
5995
5996
5997/*
5998 * Same as pgetc(), but ignores PEOA.
5999 */
6000#ifdef CONFIG_ASH_ALIAS
6001static int pgetc2(void)
6002{
6003 int c;
6004
6005 do {
6006 c = pgetc_macro();
6007 } while (c == PEOA);
6008 return c;
6009}
6010#else
6011static inline int pgetc2(void)
6012{
6013 return pgetc_macro();
6014}
6015#endif
6016
6017
6018#ifdef CONFIG_FEATURE_COMMAND_EDITING
6019static const char *cmdedit_prompt;
6020static inline void putprompt(const char *s)
6021{
6022 cmdedit_prompt = s;
6023}
6024#else
6025static inline void putprompt(const char *s)
6026{
6027 out2str(s);
6028}
6029#endif
6030
6031static inline int
6032preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006033{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006034 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006035 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006036 parsenextc = buf;
6037
Eric Andersenc470f442003-07-28 09:56:35 +00006038retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006039#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006040 if (!iflag || parsefile->fd)
6041 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6042 else {
6043 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6044 if(nr == 0) {
6045 /* Ctrl+C presend */
6046 raise(SIGINT);
6047 goto retry;
6048 }
6049 if(nr < 0) {
6050 /* Ctrl+D presend */
6051 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006052 }
Eric Andersencb57d552001-06-28 07:25:16 +00006053 }
6054#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006055 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006056#endif
6057
6058 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006059 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6060 int flags = fcntl(0, F_GETFL, 0);
6061 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006062 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006063 if (fcntl(0, F_SETFL, flags) >= 0) {
6064 out2str("sh: turning off NDELAY mode\n");
6065 goto retry;
6066 }
6067 }
6068 }
6069 }
6070 return nr;
6071}
6072
6073/*
6074 * Refill the input buffer and return the next input character:
6075 *
6076 * 1) If a string was pushed back on the input, pop it;
6077 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6078 * from a string so we can't refill the buffer, return EOF.
6079 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6080 * 4) Process input up to the next newline, deleting nul characters.
6081 */
6082
Eric Andersenc470f442003-07-28 09:56:35 +00006083int
6084preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006085{
6086 char *p, *q;
6087 int more;
6088 char savec;
6089
6090 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006091#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006092 if (parsenleft == -1 && parsefile->strpush->ap &&
6093 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006094 return PEOA;
6095 }
Eric Andersen2870d962001-07-02 17:27:21 +00006096#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006097 popstring();
6098 if (--parsenleft >= 0)
6099 return (*parsenextc++);
6100 }
6101 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6102 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006103 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006104
Eric Andersenc470f442003-07-28 09:56:35 +00006105again:
Eric Andersencb57d552001-06-28 07:25:16 +00006106 if (parselleft <= 0) {
6107 if ((parselleft = preadfd()) <= 0) {
6108 parselleft = parsenleft = EOF_NLEFT;
6109 return PEOF;
6110 }
6111 }
6112
6113 q = p = parsenextc;
6114
6115 /* delete nul characters */
6116 for (more = 1; more;) {
6117 switch (*p) {
6118 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006119 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006120 goto check;
6121
Eric Andersencb57d552001-06-28 07:25:16 +00006122 case '\n':
6123 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006124 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006125 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006126
Eric Andersencb57d552001-06-28 07:25:16 +00006127 }
6128
6129 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006130check:
Eric Andersencb57d552001-06-28 07:25:16 +00006131 if (--parselleft <= 0 && more) {
6132 parsenleft = q - parsenextc - 1;
6133 if (parsenleft < 0)
6134 goto again;
6135 more = 0;
6136 }
6137 }
6138
6139 savec = *q;
6140 *q = '\0';
6141
6142 if (vflag) {
6143 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006144 }
6145
6146 *q = savec;
6147
6148 return *parsenextc++;
6149}
6150
Eric Andersenc470f442003-07-28 09:56:35 +00006151/*
6152 * Undo the last call to pgetc. Only one character may be pushed back.
6153 * PEOF may be pushed back.
6154 */
6155
6156void
6157pungetc(void)
6158{
6159 parsenleft++;
6160 parsenextc--;
6161}
Eric Andersencb57d552001-06-28 07:25:16 +00006162
6163/*
6164 * Push a string back onto the input at this current parsefile level.
6165 * We handle aliases this way.
6166 */
Eric Andersenc470f442003-07-28 09:56:35 +00006167void
6168pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006169{
Eric Andersencb57d552001-06-28 07:25:16 +00006170 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006171 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006172
Eric Andersenc470f442003-07-28 09:56:35 +00006173 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006174 INTOFF;
6175/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6176 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006177 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006178 sp->prev = parsefile->strpush;
6179 parsefile->strpush = sp;
6180 } else
6181 sp = parsefile->strpush = &(parsefile->basestrpush);
6182 sp->prevstring = parsenextc;
6183 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006184#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006185 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006186 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006187 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006188 sp->string = s;
6189 }
Eric Andersen2870d962001-07-02 17:27:21 +00006190#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006191 parsenextc = s;
6192 parsenleft = len;
6193 INTON;
6194}
6195
Eric Andersenc470f442003-07-28 09:56:35 +00006196void
6197popstring(void)
6198{
6199 struct strpush *sp = parsefile->strpush;
6200
6201 INTOFF;
6202#ifdef CONFIG_ASH_ALIAS
6203 if (sp->ap) {
6204 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6205 checkkwd |= CHKALIAS;
6206 }
6207 if (sp->string != sp->ap->val) {
6208 ckfree(sp->string);
6209 }
6210 sp->ap->flag &= ~ALIASINUSE;
6211 if (sp->ap->flag & ALIASDEAD) {
6212 unalias(sp->ap->name);
6213 }
6214 }
6215#endif
6216 parsenextc = sp->prevstring;
6217 parsenleft = sp->prevnleft;
6218/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6219 parsefile->strpush = sp->prev;
6220 if (sp != &(parsefile->basestrpush))
6221 ckfree(sp);
6222 INTON;
6223}
6224
6225/*
6226 * Set the input to take input from a file. If push is set, push the
6227 * old input onto the stack first.
6228 */
6229
6230void
6231setinputfile(const char *fname, int push)
6232{
6233 int fd;
6234 int fd2;
6235
6236 INTOFF;
6237 if ((fd = open(fname, O_RDONLY)) < 0)
6238 error("Can't open %s", fname);
6239 if (fd < 10) {
6240 fd2 = copyfd(fd, 10);
6241 close(fd);
6242 if (fd2 < 0)
6243 error("Out of file descriptors");
6244 fd = fd2;
6245 }
6246 setinputfd(fd, push);
6247 INTON;
6248}
6249
6250
6251/*
6252 * Like setinputfile, but takes an open file descriptor. Call this with
6253 * interrupts off.
6254 */
6255
6256static void
6257setinputfd(int fd, int push)
6258{
6259 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6260 if (push) {
6261 pushfile();
6262 parsefile->buf = 0;
6263 }
6264 parsefile->fd = fd;
6265 if (parsefile->buf == NULL)
6266 parsefile->buf = ckmalloc(IBUFSIZ);
6267 parselleft = parsenleft = 0;
6268 plinno = 1;
6269}
6270
Eric Andersencb57d552001-06-28 07:25:16 +00006271
Eric Andersencb57d552001-06-28 07:25:16 +00006272/*
6273 * Like setinputfile, but takes input from a string.
6274 */
6275
Eric Andersenc470f442003-07-28 09:56:35 +00006276static void
6277setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006278{
Eric Andersencb57d552001-06-28 07:25:16 +00006279 INTOFF;
6280 pushfile();
6281 parsenextc = string;
6282 parsenleft = strlen(string);
6283 parsefile->buf = NULL;
6284 plinno = 1;
6285 INTON;
6286}
6287
6288
Eric Andersencb57d552001-06-28 07:25:16 +00006289/*
6290 * To handle the "." command, a stack of input files is used. Pushfile
6291 * adds a new entry to the stack and popfile restores the previous level.
6292 */
6293
Eric Andersenc470f442003-07-28 09:56:35 +00006294static void
6295pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006296{
Eric Andersencb57d552001-06-28 07:25:16 +00006297 struct parsefile *pf;
6298
6299 parsefile->nleft = parsenleft;
6300 parsefile->lleft = parselleft;
6301 parsefile->nextc = parsenextc;
6302 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006303 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006304 pf->prev = parsefile;
6305 pf->fd = -1;
6306 pf->strpush = NULL;
6307 pf->basestrpush.prev = NULL;
6308 parsefile = pf;
6309}
6310
Eric Andersenc470f442003-07-28 09:56:35 +00006311
6312static void
6313popfile(void)
6314{
6315 struct parsefile *pf = parsefile;
6316
6317 INTOFF;
6318 if (pf->fd >= 0)
6319 close(pf->fd);
6320 if (pf->buf)
6321 ckfree(pf->buf);
6322 while (pf->strpush)
6323 popstring();
6324 parsefile = pf->prev;
6325 ckfree(pf);
6326 parsenleft = parsefile->nleft;
6327 parselleft = parsefile->lleft;
6328 parsenextc = parsefile->nextc;
6329 plinno = parsefile->linno;
6330 INTON;
6331}
Eric Andersencb57d552001-06-28 07:25:16 +00006332
6333
Eric Andersen2870d962001-07-02 17:27:21 +00006334/*
Eric Andersenc470f442003-07-28 09:56:35 +00006335 * Return to top level.
6336 */
Eric Andersen2870d962001-07-02 17:27:21 +00006337
Eric Andersenc470f442003-07-28 09:56:35 +00006338static void
6339popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006340{
Eric Andersenc470f442003-07-28 09:56:35 +00006341 while (parsefile != &basepf)
6342 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006343}
6344
Eric Andersen2870d962001-07-02 17:27:21 +00006345
Eric Andersenc470f442003-07-28 09:56:35 +00006346/*
6347 * Close the file(s) that the shell is reading commands from. Called
6348 * after a fork is done.
6349 */
6350
6351static void
6352closescript(void)
6353{
6354 popallfiles();
6355 if (parsefile->fd > 0) {
6356 close(parsefile->fd);
6357 parsefile->fd = 0;
6358 }
6359}
Eric Andersenc470f442003-07-28 09:56:35 +00006360
Eric Andersen90898442003-08-06 11:20:52 +00006361/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006362
6363/* mode flags for set_curjob */
6364#define CUR_DELETE 2
6365#define CUR_RUNNING 1
6366#define CUR_STOPPED 0
6367
6368/* mode flags for dowait */
6369#define DOWAIT_NORMAL 0
6370#define DOWAIT_BLOCK 1
6371
6372/* array of jobs */
6373static struct job *jobtab;
6374/* size of array */
6375static unsigned njobs;
6376#if JOBS
6377/* pgrp of shell on invocation */
6378static int initialpgrp;
6379static int ttyfd = -1;
6380#endif
6381/* current job */
6382static struct job *curjob;
6383/* number of presumed living untracked jobs */
6384static int jobless;
6385
6386static void set_curjob(struct job *, unsigned);
6387#if JOBS
6388static int restartjob(struct job *, int);
6389static void xtcsetpgrp(int, pid_t);
6390static char *commandtext(union node *);
6391static void cmdlist(union node *, int);
6392static void cmdtxt(union node *);
6393static void cmdputs(const char *);
6394static void showpipe(struct job *, FILE *);
6395#endif
6396static int sprint_status(char *, int, int);
6397static void freejob(struct job *);
6398static struct job *getjob(const char *, int);
6399static struct job *growjobtab(void);
6400static void forkchild(struct job *, union node *, int);
6401static void forkparent(struct job *, union node *, int, pid_t);
6402static int dowait(int, struct job *);
6403static int getstatus(struct job *);
6404
6405static void
6406set_curjob(struct job *jp, unsigned mode)
6407{
6408 struct job *jp1;
6409 struct job **jpp, **curp;
6410
6411 /* first remove from list */
6412 jpp = curp = &curjob;
6413 do {
6414 jp1 = *jpp;
6415 if (jp1 == jp)
6416 break;
6417 jpp = &jp1->prev_job;
6418 } while (1);
6419 *jpp = jp1->prev_job;
6420
6421 /* Then re-insert in correct position */
6422 jpp = curp;
6423 switch (mode) {
6424 default:
6425#ifdef DEBUG
6426 abort();
6427#endif
6428 case CUR_DELETE:
6429 /* job being deleted */
6430 break;
6431 case CUR_RUNNING:
6432 /* newly created job or backgrounded job,
6433 put after all stopped jobs. */
6434 do {
6435 jp1 = *jpp;
6436#ifdef JOBS
6437 if (!jp1 || jp1->state != JOBSTOPPED)
6438#endif
6439 break;
6440 jpp = &jp1->prev_job;
6441 } while (1);
6442 /* FALLTHROUGH */
6443#ifdef JOBS
6444 case CUR_STOPPED:
6445#endif
6446 /* newly stopped job - becomes curjob */
6447 jp->prev_job = *jpp;
6448 *jpp = jp;
6449 break;
6450 }
6451}
6452
6453#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006454/*
6455 * Turn job control on and off.
6456 *
6457 * Note: This code assumes that the third arg to ioctl is a character
6458 * pointer, which is true on Berkeley systems but not System V. Since
6459 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006460 *
6461 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006462 */
6463
Eric Andersenc470f442003-07-28 09:56:35 +00006464void
6465setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006466{
Eric Andersenc470f442003-07-28 09:56:35 +00006467 int fd;
6468 int pgrp;
6469
6470 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006471 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006472 if (on) {
6473 int ofd;
6474 ofd = fd = open(_PATH_TTY, O_RDWR);
6475 if (fd < 0) {
6476 fd += 3;
6477 while (!isatty(fd) && --fd >= 0)
6478 ;
6479 }
6480 fd = fcntl(fd, F_DUPFD, 10);
6481 close(ofd);
6482 if (fd < 0)
6483 goto out;
6484 fcntl(fd, F_SETFD, FD_CLOEXEC);
6485 do { /* while we are in the background */
6486 if ((pgrp = tcgetpgrp(fd)) < 0) {
6487out:
6488 sh_warnx("can't access tty; job control turned off");
6489 mflag = on = 0;
6490 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006491 }
Eric Andersenc470f442003-07-28 09:56:35 +00006492 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006493 break;
6494 killpg(0, SIGTTIN);
6495 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006496 initialpgrp = pgrp;
6497
Eric Andersencb57d552001-06-28 07:25:16 +00006498 setsignal(SIGTSTP);
6499 setsignal(SIGTTOU);
6500 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006501 pgrp = rootpid;
6502 setpgid(0, pgrp);
6503 xtcsetpgrp(fd, pgrp);
6504 } else {
6505 /* turning job control off */
6506 fd = ttyfd;
6507 pgrp = initialpgrp;
6508 xtcsetpgrp(fd, pgrp);
6509 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006510 setsignal(SIGTSTP);
6511 setsignal(SIGTTOU);
6512 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006513close:
6514 close(fd);
6515 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006516 }
Eric Andersenc470f442003-07-28 09:56:35 +00006517 ttyfd = fd;
6518 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006519}
Eric Andersencb57d552001-06-28 07:25:16 +00006520
Eric Andersenc470f442003-07-28 09:56:35 +00006521static int
Eric Andersen90898442003-08-06 11:20:52 +00006522killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006523{
6524 int signo = -1;
6525 int list = 0;
6526 int i;
6527 pid_t pid;
6528 struct job *jp;
6529
6530 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006531usage:
6532 error(
6533"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6534"kill -l [exitstatus]"
6535 );
Eric Andersencb57d552001-06-28 07:25:16 +00006536 }
6537
Eric Andersenc470f442003-07-28 09:56:35 +00006538 if (**++argv == '-') {
6539 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006540 if (signo < 0) {
6541 int c;
6542
6543 while ((c = nextopt("ls:")) != '\0')
6544 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006545 default:
6546#ifdef DEBUG
6547 abort();
6548#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006549 case 'l':
6550 list = 1;
6551 break;
6552 case 's':
6553 signo = decode_signal(optionarg, 1);
6554 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006555 error(
6556 "invalid signal number or name: %s",
6557 optionarg
6558 );
Eric Andersencb57d552001-06-28 07:25:16 +00006559 }
Eric Andersen2870d962001-07-02 17:27:21 +00006560 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006561 }
Eric Andersenc470f442003-07-28 09:56:35 +00006562 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006563 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006564 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006565 }
6566
6567 if (!list && signo < 0)
6568 signo = SIGTERM;
6569
Eric Andersenc470f442003-07-28 09:56:35 +00006570 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006571 goto usage;
6572 }
6573
6574 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006575 const char *name;
6576
Eric Andersenc470f442003-07-28 09:56:35 +00006577 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006578 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006579 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006580 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006581 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006582 }
6583 return 0;
6584 }
Eric Andersen34506362001-08-02 05:02:46 +00006585 name = u_signal_names(*argptr, &signo, -1);
6586 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006587 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006588 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006589 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006590 return 0;
6591 }
6592
Eric Andersenc470f442003-07-28 09:56:35 +00006593 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006594 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006595 if (**argv == '%') {
6596 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006597 pid = -jp->ps[0].pid;
6598 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006599 pid = number(*argv);
6600 if (kill(pid, signo) != 0) {
6601 sh_warnx("%m\n");
6602 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006603 }
Eric Andersenc470f442003-07-28 09:56:35 +00006604 } while (*++argv);
6605
6606 return i;
6607}
6608#endif /* JOBS */
6609
6610#if defined(JOBS) || defined(DEBUG)
6611static int
6612jobno(const struct job *jp)
6613{
6614 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006615}
6616#endif
6617
Eric Andersenc470f442003-07-28 09:56:35 +00006618#ifdef JOBS
6619static int
6620fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006621{
Eric Andersenc470f442003-07-28 09:56:35 +00006622 struct job *jp;
6623 FILE *out;
6624 int mode;
6625 int retval;
6626
6627 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6628 nextopt(nullstr);
6629 argv = argptr;
6630 out = stdout;
6631 do {
6632 jp = getjob(*argv, 1);
6633 if (mode == FORK_BG) {
6634 set_curjob(jp, CUR_RUNNING);
6635 fprintf(out, "[%d] ", jobno(jp));
6636 }
6637 outstr(jp->ps->cmd, out);
6638 showpipe(jp, out);
6639 retval = restartjob(jp, mode);
6640 } while (*argv && *++argv);
6641 return retval;
6642}
6643
6644static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6645
6646
6647static int
6648restartjob(struct job *jp, int mode)
6649{
6650 struct procstat *ps;
6651 int i;
6652 int status;
6653 pid_t pgid;
6654
6655 INTOFF;
6656 if (jp->state == JOBDONE)
6657 goto out;
6658 jp->state = JOBRUNNING;
6659 pgid = jp->ps->pid;
6660 if (mode == FORK_FG)
6661 xtcsetpgrp(ttyfd, pgid);
6662 killpg(pgid, SIGCONT);
6663 ps = jp->ps;
6664 i = jp->nprocs;
6665 do {
6666 if (WIFSTOPPED(ps->status)) {
6667 ps->status = -1;
6668 }
6669 } while (ps++, --i);
6670out:
6671 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6672 INTON;
6673 return status;
6674}
6675#endif
6676
6677static int
6678sprint_status(char *s, int status, int sigonly)
6679{
6680 int col;
6681 int st;
6682
6683 col = 0;
6684 st = WEXITSTATUS(status);
6685 if (!WIFEXITED(status)) {
6686 st = WSTOPSIG(status);
6687#if JOBS
6688 if (!WIFSTOPPED(status))
6689 st = WTERMSIG(status);
6690#endif
6691 if (sigonly) {
6692 if (st == SIGINT || st == SIGPIPE)
6693 goto out;
6694 if (WIFSTOPPED(status))
6695 goto out;
6696 }
6697 st &= 0x7f;
6698 col = fmtstr(s, 32, u_signal_names(NULL, &st, 0));
6699 if (WCOREDUMP(status)) {
6700 col += fmtstr(s + col, 16, " (core dumped)");
6701 }
6702 } else if (!sigonly) {
6703 if (st)
6704 col = fmtstr(s, 16, "Done(%d)", st);
6705 else
6706 col = fmtstr(s, 16, "Done");
6707 }
6708
6709out:
6710 return col;
6711}
6712
6713#if JOBS
6714static void
6715showjob(FILE *out, struct job *jp, int mode)
6716{
6717 struct procstat *ps;
6718 struct procstat *psend;
6719 int col;
6720 int indent;
6721 char s[80];
6722
6723 ps = jp->ps;
6724
6725 if (mode & SHOW_PGID) {
6726 /* just output process (group) id of pipeline */
6727 fprintf(out, "%d\n", ps->pid);
6728 return;
6729 }
6730
6731 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6732 indent = col;
6733
6734 if (jp == curjob)
6735 s[col - 2] = '+';
6736 else if (curjob && jp == curjob->prev_job)
6737 s[col - 2] = '-';
6738
6739 if (mode & SHOW_PID)
6740 col += fmtstr(s + col, 16, "%d ", ps->pid);
6741
6742 psend = ps + jp->nprocs;
6743
6744 if (jp->state == JOBRUNNING) {
6745 scopy("Running", s + col);
6746 col += strlen("Running");
6747 } else {
6748 int status = psend[-1].status;
6749#if JOBS
6750 if (jp->state == JOBSTOPPED)
6751 status = jp->stopstatus;
6752#endif
6753 col += sprint_status(s + col, status, 0);
6754 }
6755
6756 goto start;
6757
6758 do {
6759 /* for each process */
6760 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6761
6762start:
Eric Andersen90898442003-08-06 11:20:52 +00006763 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006764 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6765 );
6766 if (!(mode & SHOW_PID)) {
6767 showpipe(jp, out);
6768 break;
6769 }
6770 if (++ps == psend) {
6771 outcslow('\n', out);
6772 break;
6773 }
6774 } while (1);
6775
6776 jp->changed = 0;
6777
6778 if (jp->state == JOBDONE) {
6779 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6780 freejob(jp);
6781 }
6782}
6783
6784
6785static int
6786jobscmd(int argc, char **argv)
6787{
6788 int mode, m;
6789 FILE *out;
6790
6791 mode = 0;
6792 while ((m = nextopt("lp")))
6793 if (m == 'l')
6794 mode = SHOW_PID;
6795 else
6796 mode = SHOW_PGID;
6797
6798 out = stdout;
6799 argv = argptr;
6800 if (*argv)
6801 do
6802 showjob(out, getjob(*argv,0), mode);
6803 while (*++argv);
6804 else
6805 showjobs(out, mode);
6806
Eric Andersencb57d552001-06-28 07:25:16 +00006807 return 0;
6808}
6809
6810
6811/*
6812 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6813 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006814 */
6815
Eric Andersenc470f442003-07-28 09:56:35 +00006816static void
6817showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006818{
Eric Andersencb57d552001-06-28 07:25:16 +00006819 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006820
Eric Andersenc470f442003-07-28 09:56:35 +00006821 TRACE(("showjobs(%x) called\n", mode));
6822
6823 /* If not even one one job changed, there is nothing to do */
6824 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6825 continue;
6826
6827 for (jp = curjob; jp; jp = jp->prev_job) {
6828 if (!(mode & SHOW_CHANGED) || jp->changed)
6829 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006830 }
6831}
Eric Andersenc470f442003-07-28 09:56:35 +00006832#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006833
6834/*
6835 * Mark a job structure as unused.
6836 */
6837
Eric Andersenc470f442003-07-28 09:56:35 +00006838static void
6839freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006840{
Eric Andersenc470f442003-07-28 09:56:35 +00006841 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006842 int i;
6843
6844 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006845 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006846 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006847 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006848 }
6849 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006850 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006851 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006852 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006853 INTON;
6854}
6855
6856
Eric Andersenc470f442003-07-28 09:56:35 +00006857static int
6858waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006859{
6860 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006861 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006862 struct job *jp;
6863
Eric Andersenc470f442003-07-28 09:56:35 +00006864 EXSIGON();
6865
6866 nextopt(nullstr);
6867 retval = 0;
6868
6869 argv = argptr;
6870 if (!*argv) {
6871 /* wait for all jobs */
6872 for (;;) {
6873 jp = curjob;
6874 while (1) {
6875 if (!jp) {
6876 /* no running procs */
6877 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006878 }
Eric Andersenc470f442003-07-28 09:56:35 +00006879 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006880 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006881 jp->waited = 1;
6882 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006883 }
Eric Andersenc470f442003-07-28 09:56:35 +00006884 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006885 }
6886 }
Eric Andersenc470f442003-07-28 09:56:35 +00006887
6888 retval = 127;
6889 do {
6890 if (**argv != '%') {
6891 pid_t pid = number(*argv);
6892 job = curjob;
6893 goto start;
6894 do {
6895 if (job->ps[job->nprocs - 1].pid == pid)
6896 break;
6897 job = job->prev_job;
6898start:
6899 if (!job)
6900 goto repeat;
6901 } while (1);
6902 } else
6903 job = getjob(*argv, 0);
6904 /* loop until process terminated or stopped */
6905 while (job->state == JOBRUNNING)
6906 dowait(DOWAIT_BLOCK, 0);
6907 job->waited = 1;
6908 retval = getstatus(job);
6909repeat:
6910 ;
6911 } while (*++argv);
6912
6913out:
6914 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006915}
6916
6917
Eric Andersencb57d552001-06-28 07:25:16 +00006918/*
6919 * Convert a job name to a job structure.
6920 */
6921
Eric Andersenc470f442003-07-28 09:56:35 +00006922static struct job *
6923getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006924{
Eric Andersencb57d552001-06-28 07:25:16 +00006925 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006926 struct job *found;
6927 const char *err_msg = "No such job: %s";
6928 unsigned num;
6929 int c;
6930 const char *p;
6931 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006932
Eric Andersenc470f442003-07-28 09:56:35 +00006933 jp = curjob;
6934 p = name;
6935 if (!p)
6936 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006937
Eric Andersenc470f442003-07-28 09:56:35 +00006938 if (*p != '%')
6939 goto err;
6940
6941 c = *++p;
6942 if (!c)
6943 goto currentjob;
6944
6945 if (!p[1]) {
6946 if (c == '+' || c == '%') {
6947currentjob:
6948 err_msg = "No current job";
6949 goto check;
6950 } else if (c == '-') {
6951 if (jp)
6952 jp = jp->prev_job;
6953 err_msg = "No previous job";
6954check:
6955 if (!jp)
6956 goto err;
6957 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006958 }
6959 }
Eric Andersenc470f442003-07-28 09:56:35 +00006960
6961 if (is_number(p)) {
6962 num = atoi(p);
6963 if (num < njobs) {
6964 jp = jobtab + num - 1;
6965 if (jp->used)
6966 goto gotit;
6967 goto err;
6968 }
6969 }
6970
6971 match = prefix;
6972 if (*p == '?') {
6973 match = strstr;
6974 p++;
6975 }
6976
6977 found = 0;
6978 while (1) {
6979 if (!jp)
6980 goto err;
6981 if (match(jp->ps[0].cmd, p)) {
6982 if (found)
6983 goto err;
6984 found = jp;
6985 err_msg = "%s: ambiguous";
6986 }
6987 jp = jp->prev_job;
6988 }
6989
6990gotit:
6991#if JOBS
6992 err_msg = "job %s not created under job control";
6993 if (getctl && jp->jobctl == 0)
6994 goto err;
6995#endif
6996 return jp;
6997err:
6998 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006999}
7000
7001
Eric Andersencb57d552001-06-28 07:25:16 +00007002/*
Eric Andersenc470f442003-07-28 09:56:35 +00007003 * Return a new job structure.
7004 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007005 */
7006
Eric Andersenc470f442003-07-28 09:56:35 +00007007static struct job *
7008makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007009{
7010 int i;
7011 struct job *jp;
7012
Eric Andersenc470f442003-07-28 09:56:35 +00007013 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007014 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007015 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007016 break;
7017 }
7018 if (jp->used == 0)
7019 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007020 if (jp->state != JOBDONE || !jp->waited)
7021 continue;
7022#if JOBS
7023 if (jobctl)
7024 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007025#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007026 freejob(jp);
7027 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007028 }
Eric Andersenc470f442003-07-28 09:56:35 +00007029 memset(jp, 0, sizeof(*jp));
7030#if JOBS
7031 if (jobctl)
7032 jp->jobctl = 1;
7033#endif
7034 jp->prev_job = curjob;
7035 curjob = jp;
7036 jp->used = 1;
7037 jp->ps = &jp->ps0;
7038 if (nprocs > 1) {
7039 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7040 }
7041 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7042 jobno(jp)));
7043 return jp;
7044}
7045
7046static struct job *
7047growjobtab(void)
7048{
7049 size_t len;
7050 ptrdiff_t offset;
7051 struct job *jp, *jq;
7052
7053 len = njobs * sizeof(*jp);
7054 jq = jobtab;
7055 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7056
7057 offset = (char *)jp - (char *)jq;
7058 if (offset) {
7059 /* Relocate pointers */
7060 size_t l = len;
7061
7062 jq = (struct job *)((char *)jq + l);
7063 while (l) {
7064 l -= sizeof(*jp);
7065 jq--;
7066#define joff(p) ((struct job *)((char *)(p) + l))
7067#define jmove(p) (p) = (void *)((char *)(p) + offset)
7068 if (likely(joff(jp)->ps == &jq->ps0))
7069 jmove(joff(jp)->ps);
7070 if (joff(jp)->prev_job)
7071 jmove(joff(jp)->prev_job);
7072 }
7073 if (curjob)
7074 jmove(curjob);
7075#undef joff
7076#undef jmove
7077 }
7078
7079 njobs += 4;
7080 jobtab = jp;
7081 jp = (struct job *)((char *)jp + len);
7082 jq = jp + 3;
7083 do {
7084 jq->used = 0;
7085 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007086 return jp;
7087}
7088
7089
7090/*
Eric Andersenc470f442003-07-28 09:56:35 +00007091 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007092 * own process group. Jp is a job structure that the job is to be added to.
7093 * N is the command that will be evaluated by the child. Both jp and n may
7094 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007095 * FORK_FG - Fork off a foreground process.
7096 * FORK_BG - Fork off a background process.
7097 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7098 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007099 *
7100 * When job control is turned off, background processes have their standard
7101 * input redirected to /dev/null (except for the second and later processes
7102 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007103 *
7104 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007105 */
7106
Eric Andersenc470f442003-07-28 09:56:35 +00007107static inline void
7108forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007109{
Eric Andersenc470f442003-07-28 09:56:35 +00007110 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007111
Eric Andersenc470f442003-07-28 09:56:35 +00007112 TRACE(("Child shell %d\n", getpid()));
7113 wasroot = rootshell;
7114 rootshell = 0;
7115
7116 closescript();
7117 clear_traps();
7118#if JOBS
7119 /* do job control only in root shell */
7120 jobctl = 0;
7121 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7122 pid_t pgrp;
7123
7124 if (jp->nprocs == 0)
7125 pgrp = getpid();
7126 else
7127 pgrp = jp->ps[0].pid;
7128 /* This can fail because we are doing it in the parent also */
7129 (void)setpgid(0, pgrp);
7130 if (mode == FORK_FG)
7131 xtcsetpgrp(ttyfd, pgrp);
7132 setsignal(SIGTSTP);
7133 setsignal(SIGTTOU);
7134 } else
Eric Andersen62483552001-07-10 06:09:16 +00007135#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007136 if (mode == FORK_BG) {
7137 ignoresig(SIGINT);
7138 ignoresig(SIGQUIT);
7139 if (jp->nprocs == 0) {
7140 close(0);
7141 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7142 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007143 }
Eric Andersencb57d552001-06-28 07:25:16 +00007144 }
Eric Andersenc470f442003-07-28 09:56:35 +00007145 if (wasroot && iflag) {
7146 setsignal(SIGINT);
7147 setsignal(SIGQUIT);
7148 setsignal(SIGTERM);
7149 }
7150 for (jp = curjob; jp; jp = jp->prev_job)
7151 freejob(jp);
7152 jobless = 0;
7153}
7154
7155static inline void
7156forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7157{
7158 TRACE(("In parent shell: child = %d\n", pid));
7159 if (!jp) {
7160 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7161 jobless++;
7162 return;
7163 }
7164#if JOBS
7165 if (mode != FORK_NOJOB && jp->jobctl) {
7166 int pgrp;
7167
7168 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007169 pgrp = pid;
7170 else
7171 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007172 /* This can fail because we are doing it in the child also */
7173 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007174 }
Eric Andersen62483552001-07-10 06:09:16 +00007175#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007176 if (mode == FORK_BG) {
7177 backgndpid = pid; /* set $! */
7178 set_curjob(jp, CUR_RUNNING);
7179 }
Eric Andersencb57d552001-06-28 07:25:16 +00007180 if (jp) {
7181 struct procstat *ps = &jp->ps[jp->nprocs++];
7182 ps->pid = pid;
7183 ps->status = -1;
7184 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007185#if JOBS
7186 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007187 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007188#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007189 }
Eric Andersencb57d552001-06-28 07:25:16 +00007190}
7191
Eric Andersenc470f442003-07-28 09:56:35 +00007192static int
7193forkshell(struct job *jp, union node *n, int mode)
7194{
7195 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007196
Eric Andersenc470f442003-07-28 09:56:35 +00007197 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7198 pid = fork();
7199 if (pid < 0) {
7200 TRACE(("Fork failed, errno=%d", errno));
7201 if (jp)
7202 freejob(jp);
7203 error("Cannot fork");
7204 }
7205 if (pid == 0)
7206 forkchild(jp, n, mode);
7207 else
7208 forkparent(jp, n, mode, pid);
7209 return pid;
7210}
Eric Andersencb57d552001-06-28 07:25:16 +00007211
7212/*
7213 * Wait for job to finish.
7214 *
7215 * Under job control we have the problem that while a child process is
7216 * running interrupts generated by the user are sent to the child but not
7217 * to the shell. This means that an infinite loop started by an inter-
7218 * active user may be hard to kill. With job control turned off, an
7219 * interactive user may place an interactive program inside a loop. If
7220 * the interactive program catches interrupts, the user doesn't want
7221 * these interrupts to also abort the loop. The approach we take here
7222 * is to have the shell ignore interrupt signals while waiting for a
7223 * forground process to terminate, and then send itself an interrupt
7224 * signal if the child process was terminated by an interrupt signal.
7225 * Unfortunately, some programs want to do a bit of cleanup and then
7226 * exit on interrupt; unless these processes terminate themselves by
7227 * sending a signal to themselves (instead of calling exit) they will
7228 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007229 *
7230 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007231 */
7232
Eric Andersenc470f442003-07-28 09:56:35 +00007233int
7234waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007235{
Eric Andersencb57d552001-06-28 07:25:16 +00007236 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007237
Eric Andersenc470f442003-07-28 09:56:35 +00007238 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7239 while (jp->state == JOBRUNNING) {
7240 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007241 }
Eric Andersenc470f442003-07-28 09:56:35 +00007242 st = getstatus(jp);
7243#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007244 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007245 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007246 /*
7247 * This is truly gross.
7248 * If we're doing job control, then we did a TIOCSPGRP which
7249 * caused us (the shell) to no longer be in the controlling
7250 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7251 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007252 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007253 */
Eric Andersenc470f442003-07-28 09:56:35 +00007254 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007255 raise(SIGINT);
7256 }
Eric Andersen2870d962001-07-02 17:27:21 +00007257 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007258#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007259 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007260 return st;
7261}
7262
7263
Eric Andersen62483552001-07-10 06:09:16 +00007264/*
7265 * Do a wait system call. If job control is compiled in, we accept
7266 * stopped processes. If block is zero, we return a value of zero
7267 * rather than blocking.
7268 *
7269 * System V doesn't have a non-blocking wait system call. It does
7270 * have a SIGCLD signal that is sent to a process when one of it's
7271 * children dies. The obvious way to use SIGCLD would be to install
7272 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7273 * was received, and have waitproc bump another counter when it got
7274 * the status of a process. Waitproc would then know that a wait
7275 * system call would not block if the two counters were different.
7276 * This approach doesn't work because if a process has children that
7277 * have not been waited for, System V will send it a SIGCLD when it
7278 * installs a signal handler for SIGCLD. What this means is that when
7279 * a child exits, the shell will be sent SIGCLD signals continuously
7280 * until is runs out of stack space, unless it does a wait call before
7281 * restoring the signal handler. The code below takes advantage of
7282 * this (mis)feature by installing a signal handler for SIGCLD and
7283 * then checking to see whether it was called. If there are any
7284 * children to be waited for, it will be.
7285 *
Eric Andersenc470f442003-07-28 09:56:35 +00007286 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7287 * waits at all. In this case, the user will not be informed when
7288 * a background process until the next time she runs a real program
7289 * (as opposed to running a builtin command or just typing return),
7290 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007291 */
7292
Eric Andersenc470f442003-07-28 09:56:35 +00007293static inline int
7294waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007295{
Eric Andersenc470f442003-07-28 09:56:35 +00007296 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007297
Eric Andersenc470f442003-07-28 09:56:35 +00007298#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007299 if (jobctl)
7300 flags |= WUNTRACED;
7301#endif
7302 if (block == 0)
7303 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007304 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007305}
7306
Eric Andersenc470f442003-07-28 09:56:35 +00007307/*
7308 * Wait for a process to terminate.
7309 */
7310
7311static int
7312dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007313{
7314 int pid;
7315 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007316 struct job *jp;
7317 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007318 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007319
7320 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007321 pid = waitproc(block, &status);
7322 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007323 if (pid <= 0)
7324 return pid;
7325 INTOFF;
7326 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007327 for (jp = curjob; jp; jp = jp->prev_job) {
7328 struct procstat *sp;
7329 struct procstat *spend;
7330 if (jp->state == JOBDONE)
7331 continue;
7332 state = JOBDONE;
7333 spend = jp->ps + jp->nprocs;
7334 sp = jp->ps;
7335 do {
7336 if (sp->pid == pid) {
7337 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7338 sp->status = status;
7339 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007340 }
Eric Andersenc470f442003-07-28 09:56:35 +00007341 if (sp->status == -1)
7342 state = JOBRUNNING;
7343#ifdef JOBS
7344 if (state == JOBRUNNING)
7345 continue;
7346 if (WIFSTOPPED(sp->status)) {
7347 jp->stopstatus = sp->status;
7348 state = JOBSTOPPED;
7349 }
Eric Andersencb57d552001-06-28 07:25:16 +00007350#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007351 } while (++sp < spend);
7352 if (thisjob)
7353 goto gotjob;
7354 }
7355#ifdef JOBS
7356 if (!WIFSTOPPED(status))
7357#endif
7358
7359 jobless--;
7360 goto out;
7361
7362gotjob:
7363 if (state != JOBRUNNING) {
7364 thisjob->changed = 1;
7365
7366 if (thisjob->state != state) {
7367 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7368 thisjob->state = state;
7369#ifdef JOBS
7370 if (state == JOBSTOPPED) {
7371 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007372 }
Eric Andersenc470f442003-07-28 09:56:35 +00007373#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007374 }
7375 }
Eric Andersencb57d552001-06-28 07:25:16 +00007376
Eric Andersenc470f442003-07-28 09:56:35 +00007377out:
7378 INTON;
7379
7380 if (thisjob && thisjob == job) {
7381 char s[48 + 1];
7382 int len;
7383
7384 len = sprint_status(s, status, 1);
7385 if (len) {
7386 s[len] = '\n';
7387 s[len + 1] = 0;
7388 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007389 }
Eric Andersencb57d552001-06-28 07:25:16 +00007390 }
7391 return pid;
7392}
7393
7394
Eric Andersencb57d552001-06-28 07:25:16 +00007395/*
7396 * return 1 if there are stopped jobs, otherwise 0
7397 */
Eric Andersen90898442003-08-06 11:20:52 +00007398
Eric Andersenc470f442003-07-28 09:56:35 +00007399int
7400stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007401{
Eric Andersencb57d552001-06-28 07:25:16 +00007402 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007403 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007404
Eric Andersenc470f442003-07-28 09:56:35 +00007405 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007406 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007407 goto out;
7408 jp = curjob;
7409 if (jp && jp->state == JOBSTOPPED) {
7410 out2str("You have stopped jobs.\n");
7411 job_warning = 2;
7412 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007413 }
7414
Eric Andersenc470f442003-07-28 09:56:35 +00007415out:
7416 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007417}
7418
7419/*
7420 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007421 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007422 */
7423
Eric Andersenc470f442003-07-28 09:56:35 +00007424#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007425static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007426
Eric Andersenc470f442003-07-28 09:56:35 +00007427static char *
7428commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007429{
Eric Andersenc470f442003-07-28 09:56:35 +00007430 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007431
Eric Andersenc470f442003-07-28 09:56:35 +00007432 STARTSTACKSTR(cmdnextc);
7433 cmdtxt(n);
7434 name = stackblock();
7435 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7436 name, cmdnextc, cmdnextc));
7437 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007438}
7439
Eric Andersenc470f442003-07-28 09:56:35 +00007440static void
7441cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007442{
Eric Andersencb57d552001-06-28 07:25:16 +00007443 union node *np;
7444 struct nodelist *lp;
7445 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007446 char s[2];
7447
Eric Andersencb57d552001-06-28 07:25:16 +00007448 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007449 default:
7450#if DEBUG
7451 abort();
7452#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007453 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007454 lp = n->npipe.cmdlist;
7455 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007456 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007457 lp = lp->next;
7458 if (!lp)
7459 break;
7460 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007461 }
7462 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007463 case NSEMI:
7464 p = "; ";
7465 goto binop;
7466 case NAND:
7467 p = " && ";
7468 goto binop;
7469 case NOR:
7470 p = " || ";
7471binop:
7472 cmdtxt(n->nbinary.ch1);
7473 cmdputs(p);
7474 n = n->nbinary.ch2;
7475 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007476 case NREDIR:
7477 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007478 n = n->nredir.n;
7479 goto donode;
7480 case NNOT:
7481 cmdputs("!");
7482 n = n->nnot.com;
7483donode:
7484 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007485 break;
7486 case NIF:
7487 cmdputs("if ");
7488 cmdtxt(n->nif.test);
7489 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007490 n = n->nif.ifpart;
7491 if (n->nif.elsepart) {
7492 cmdtxt(n);
7493 cmdputs("; else ");
7494 n = n->nif.elsepart;
7495 }
7496 p = "; fi";
7497 goto dotail;
7498 case NSUBSHELL:
7499 cmdputs("(");
7500 n = n->nredir.n;
7501 p = ")";
7502 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007503 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007504 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007505 goto until;
7506 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007507 p = "until ";
7508until:
7509 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007510 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007511 n = n->nbinary.ch2;
7512 p = "; done";
7513dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007514 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007515dotail:
7516 cmdtxt(n);
7517 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007518 case NFOR:
7519 cmdputs("for ");
7520 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007521 cmdputs(" in ");
7522 cmdlist(n->nfor.args, 1);
7523 n = n->nfor.body;
7524 p = "; done";
7525 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007526 case NDEFUN:
7527 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007528 p = "() { ... }";
7529 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007530 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007531 cmdlist(n->ncmd.args, 1);
7532 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007533 break;
7534 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007535 p = n->narg.text;
7536dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007537 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007538 break;
7539 case NHERE:
7540 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007541 p = "<<...";
7542 goto dotail2;
7543 case NCASE:
7544 cmdputs("case ");
7545 cmdputs(n->ncase.expr->narg.text);
7546 cmdputs(" in ");
7547 for (np = n->ncase.cases; np; np = np->nclist.next) {
7548 cmdtxt(np->nclist.pattern);
7549 cmdputs(") ");
7550 cmdtxt(np->nclist.body);
7551 cmdputs(";; ");
7552 }
7553 p = "esac";
7554 goto dotail2;
7555 case NTO:
7556 p = ">";
7557 goto redir;
7558 case NCLOBBER:
7559 p = ">|";
7560 goto redir;
7561 case NAPPEND:
7562 p = ">>";
7563 goto redir;
7564 case NTOFD:
7565 p = ">&";
7566 goto redir;
7567 case NFROM:
7568 p = "<";
7569 goto redir;
7570 case NFROMFD:
7571 p = "<&";
7572 goto redir;
7573 case NFROMTO:
7574 p = "<>";
7575redir:
7576 s[0] = n->nfile.fd + '0';
7577 s[1] = '\0';
7578 cmdputs(s);
7579 cmdputs(p);
7580 if (n->type == NTOFD || n->type == NFROMFD) {
7581 s[0] = n->ndup.dupfd + '0';
7582 p = s;
7583 goto dotail2;
7584 } else {
7585 n = n->nfile.fname;
7586 goto donode;
7587 }
Eric Andersencb57d552001-06-28 07:25:16 +00007588 }
7589}
Eric Andersencb57d552001-06-28 07:25:16 +00007590
Eric Andersenc470f442003-07-28 09:56:35 +00007591static void
7592cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007593{
Eric Andersenc470f442003-07-28 09:56:35 +00007594 for (; np; np = np->narg.next) {
7595 if (!sep)
7596 cmdputs(spcstr);
7597 cmdtxt(np);
7598 if (sep && np->narg.next)
7599 cmdputs(spcstr);
7600 }
Eric Andersencb57d552001-06-28 07:25:16 +00007601}
7602
Eric Andersenc470f442003-07-28 09:56:35 +00007603static void
7604cmdputs(const char *s)
7605{
7606 const char *p, *str;
7607 char c, cc[2] = " ";
7608 char *nextc;
7609 int subtype = 0;
7610 int quoted = 0;
7611 static const char *const vstype[16] = {
7612 nullstr, "}", "-", "+", "?", "=",
7613 "#", "##", "%", "%%"
7614 };
7615
7616 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7617 p = s;
7618 while ((c = *p++) != 0) {
7619 str = 0;
7620 switch (c) {
7621 case CTLESC:
7622 c = *p++;
7623 break;
7624 case CTLVAR:
7625 subtype = *p++;
7626 if ((subtype & VSTYPE) == VSLENGTH)
7627 str = "${#";
7628 else
7629 str = "${";
7630 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7631 quoted ^= 1;
7632 c = '"';
7633 } else
7634 goto dostr;
7635 break;
7636 case CTLENDVAR:
7637 quoted >>= 1;
7638 subtype = 0;
7639 if (quoted & 1) {
7640 str = "\"}";
7641 goto dostr;
7642 }
7643 c = '}';
7644 break;
7645 case CTLBACKQ:
7646 str = "$(...)";
7647 goto dostr;
7648 case CTLBACKQ+CTLQUOTE:
7649 str = "\"$(...)\"";
7650 goto dostr;
7651#ifdef CONFIG_ASH_MATH_SUPPORT
7652 case CTLARI:
7653 str = "$((";
7654 goto dostr;
7655 case CTLENDARI:
7656 str = "))";
7657 goto dostr;
7658#endif
7659 case CTLQUOTEMARK:
7660 quoted ^= 1;
7661 c = '"';
7662 break;
7663 case '=':
7664 if (subtype == 0)
7665 break;
7666 str = vstype[subtype & VSTYPE];
7667 if (subtype & VSNUL)
7668 c = ':';
7669 else
7670 c = *str++;
7671 if (c != '}')
7672 quoted <<= 1;
7673 break;
7674 case '\'':
7675 case '\\':
7676 case '"':
7677 case '$':
7678 /* These can only happen inside quotes */
7679 cc[0] = c;
7680 str = cc;
7681 c = '\\';
7682 break;
7683 default:
7684 break;
7685 }
7686 USTPUTC(c, nextc);
7687 if (!str)
7688 continue;
7689dostr:
7690 while ((c = *str++)) {
7691 USTPUTC(c, nextc);
7692 }
7693 }
7694 if (quoted & 1) {
7695 USTPUTC('"', nextc);
7696 }
7697 *nextc = 0;
7698 cmdnextc = nextc;
7699}
7700
7701
7702static void
7703showpipe(struct job *jp, FILE *out)
7704{
7705 struct procstat *sp;
7706 struct procstat *spend;
7707
7708 spend = jp->ps + jp->nprocs;
7709 for (sp = jp->ps + 1; sp < spend; sp++)
7710 fprintf(out, " | %s", sp->cmd);
7711 outcslow('\n', out);
7712 flushall();
7713}
7714
7715static void
7716xtcsetpgrp(int fd, pid_t pgrp)
7717{
7718 if (tcsetpgrp(fd, pgrp))
7719 error("Cannot set tty process group (%m)");
7720}
7721#endif /* JOBS */
7722
7723static int
7724getstatus(struct job *job) {
7725 int status;
7726 int retval;
7727
7728 status = job->ps[job->nprocs - 1].status;
7729 retval = WEXITSTATUS(status);
7730 if (!WIFEXITED(status)) {
7731#if JOBS
7732 retval = WSTOPSIG(status);
7733 if (!WIFSTOPPED(status))
7734#endif
7735 {
7736 /* XXX: limits number of signals */
7737 retval = WTERMSIG(status);
7738#if JOBS
7739 if (retval == SIGINT)
7740 job->sigint = 1;
7741#endif
7742 }
7743 retval += 128;
7744 }
7745 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7746 jobno(job), job->nprocs, status, retval));
7747 return retval;
7748}
7749
Eric Andersend35c5df2002-01-09 15:37:36 +00007750#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007751/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007752
Eric Andersencb57d552001-06-28 07:25:16 +00007753/*
Eric Andersenc470f442003-07-28 09:56:35 +00007754 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007755 */
7756
Eric Andersencb57d552001-06-28 07:25:16 +00007757#define MAXMBOXES 10
7758
Eric Andersenc470f442003-07-28 09:56:35 +00007759/* times of mailboxes */
7760static time_t mailtime[MAXMBOXES];
7761/* Set if MAIL or MAILPATH is changed. */
7762static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007763
7764
7765
7766/*
Eric Andersenc470f442003-07-28 09:56:35 +00007767 * Print appropriate message(s) if mail has arrived.
7768 * If mail_var_path_changed is set,
7769 * then the value of MAIL has mail_var_path_changed,
7770 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007771 */
7772
Eric Andersenc470f442003-07-28 09:56:35 +00007773static void
7774chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007775{
Eric Andersencb57d552001-06-28 07:25:16 +00007776 const char *mpath;
7777 char *p;
7778 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007779 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007780 struct stackmark smark;
7781 struct stat statb;
7782
Eric Andersencb57d552001-06-28 07:25:16 +00007783 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007784 mpath = mpathset() ? mpathval() : mailval();
7785 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007786 p = padvance(&mpath, nullstr);
7787 if (p == NULL)
7788 break;
7789 if (*p == '\0')
7790 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007791 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007792#ifdef DEBUG
7793 if (q[-1] != '/')
7794 abort();
7795#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007796 q[-1] = '\0'; /* delete trailing '/' */
7797 if (stat(p, &statb) < 0) {
7798 *mtp = 0;
7799 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007800 }
Eric Andersenc470f442003-07-28 09:56:35 +00007801 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7802 fprintf(
7803 stderr, snlfmt,
7804 pathopt ? pathopt : "you have mail"
7805 );
7806 }
7807 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007808 }
Eric Andersenc470f442003-07-28 09:56:35 +00007809 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007810 popstackmark(&smark);
7811}
Eric Andersencb57d552001-06-28 07:25:16 +00007812
Eric Andersenec074692001-10-31 11:05:49 +00007813
Eric Andersenc470f442003-07-28 09:56:35 +00007814static void
7815changemail(const char *val)
7816{
7817 mail_var_path_changed++;
7818}
7819
7820#endif /* CONFIG_ASH_MAIL */
7821
7822/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7823
Eric Andersencb57d552001-06-28 07:25:16 +00007824
Eric Andersencb57d552001-06-28 07:25:16 +00007825#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007826static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007827extern int etext();
7828#endif
7829
Eric Andersenc470f442003-07-28 09:56:35 +00007830static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007831
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007832static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007833
Eric Andersencb57d552001-06-28 07:25:16 +00007834/*
7835 * Main routine. We initialize things, parse the arguments, execute
7836 * profiles if we're a login shell, and then call cmdloop to execute
7837 * commands. The setjmp call sets up the location to jump to when an
7838 * exception occurs. When an exception occurs the variable "state"
7839 * is used to figure out how far we had gotten.
7840 */
7841
Eric Andersenc470f442003-07-28 09:56:35 +00007842int
7843ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007844{
Eric Andersenc470f442003-07-28 09:56:35 +00007845 char *shinit;
7846 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007847 struct jmploc jmploc;
7848 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007849
Eric Andersenc470f442003-07-28 09:56:35 +00007850#ifdef __GLIBC__
7851 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007852#endif
7853
Eric Andersencb57d552001-06-28 07:25:16 +00007854#if PROFILE
7855 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7856#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007857 state = 0;
7858 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007859 int status;
7860 int e;
7861
Eric Andersencb57d552001-06-28 07:25:16 +00007862 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007863
7864 e = exception;
7865 switch (exception) {
7866 case EXEXEC:
7867 status = exerrno;
7868 break;
7869
7870 case EXERROR:
7871 status = 2;
7872 break;
7873
7874 default:
7875 status = exitstatus;
7876 break;
7877 }
7878 exitstatus = status;
7879
7880 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7881 exitshell();
7882
Eric Andersen90898442003-08-06 11:20:52 +00007883 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007884 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007885 }
7886 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007887 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007888 if (state == 1)
7889 goto state1;
7890 else if (state == 2)
7891 goto state2;
7892 else if (state == 3)
7893 goto state3;
7894 else
7895 goto state4;
7896 }
7897 handler = &jmploc;
7898#ifdef DEBUG
7899 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007900 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007901#endif
7902 rootpid = getpid();
7903 rootshell = 1;
7904 init();
7905 setstackmark(&smark);
7906 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007907#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7908 if ( iflag ) {
7909 const char *hp = lookupvar("HISTFILE");
7910
7911 if(hp == NULL ) {
7912 hp = lookupvar("HOME");
7913 if(hp != NULL) {
7914 char *defhp = concat_path_file(hp, ".ash_history");
7915 setvar("HISTFILE", defhp, 0);
7916 free(defhp);
7917 }
7918 }
7919 }
7920#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007921 if (argv[0] && argv[0][0] == '-')
7922 isloginsh = 1;
7923 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007924 state = 1;
7925 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007926state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007927 state = 2;
7928 read_profile(".profile");
7929 }
Eric Andersenc470f442003-07-28 09:56:35 +00007930state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007931 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007932 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007933#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007934 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007935#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007936 iflag
7937 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007938 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007939 read_profile(shinit);
7940 }
Eric Andersencb57d552001-06-28 07:25:16 +00007941 }
Eric Andersenc470f442003-07-28 09:56:35 +00007942state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007943 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007944 if (minusc)
7945 evalstring(minusc, 0);
7946
7947 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007948#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007949 if ( iflag ) {
7950 const char *hp = lookupvar("HISTFILE");
7951
7952 if(hp != NULL )
7953 load_history ( hp );
7954 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007955#endif
Eric Andersen90898442003-08-06 11:20:52 +00007956state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007957 cmdloop(1);
7958 }
7959#if PROFILE
7960 monitor(0);
7961#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007962#if GPROF
7963 {
7964 extern void _mcleanup(void);
7965 _mcleanup();
7966 }
7967#endif
7968 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007969 /* NOTREACHED */
7970}
7971
7972
7973/*
7974 * Read and execute commands. "Top" is nonzero for the top level command
7975 * loop; it turns on prompting if the shell is interactive.
7976 */
7977
Eric Andersenc470f442003-07-28 09:56:35 +00007978static void
7979cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007980{
7981 union node *n;
7982 struct stackmark smark;
7983 int inter;
7984 int numeof = 0;
7985
7986 TRACE(("cmdloop(%d) called\n", top));
7987 setstackmark(&smark);
7988 for (;;) {
7989 if (pendingsigs)
7990 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00007991#if JOBS
7992 if (jobctl)
7993 showjobs(stderr, SHOW_CHANGED);
7994#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007995 inter = 0;
7996 if (iflag && top) {
7997 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00007998#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007999 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008000#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008001 }
8002 n = parsecmd(inter);
8003 /* showtree(n); DEBUG */
8004 if (n == NEOF) {
8005 if (!top || numeof >= 50)
8006 break;
8007 if (!stoppedjobs()) {
8008 if (!Iflag)
8009 break;
8010 out2str("\nUse \"exit\" to leave shell.\n");
8011 }
8012 numeof++;
8013 } else if (n != NULL && nflag == 0) {
8014 job_warning = (job_warning == 2) ? 1 : 0;
8015 numeof = 0;
8016 evaltree(n, 0);
8017 }
8018 popstackmark(&smark);
8019 setstackmark(&smark);
8020 if (evalskip == SKIPFILE) {
8021 evalskip = 0;
8022 break;
8023 }
8024 }
8025 popstackmark(&smark);
8026}
8027
8028
Eric Andersencb57d552001-06-28 07:25:16 +00008029/*
8030 * Read /etc/profile or .profile. Return on error.
8031 */
8032
Eric Andersenc470f442003-07-28 09:56:35 +00008033static void
8034read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008035{
8036 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008037 int xflag_set = 0;
8038 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008039
8040 INTOFF;
8041 if ((fd = open(name, O_RDONLY)) >= 0)
8042 setinputfd(fd, 1);
8043 INTON;
8044 if (fd < 0)
8045 return;
8046 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008047 if (qflag) {
8048 if (xflag)
8049 xflag = 0, xflag_set = 1;
8050 if (vflag)
8051 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008052 }
8053 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008054 if (qflag) {
8055 if (xflag_set)
8056 xflag = 1;
8057 if (vflag_set)
8058 vflag = 1;
8059 }
Eric Andersencb57d552001-06-28 07:25:16 +00008060 popfile();
8061}
8062
8063
Eric Andersencb57d552001-06-28 07:25:16 +00008064/*
8065 * Read a file containing shell functions.
8066 */
8067
Eric Andersenc470f442003-07-28 09:56:35 +00008068static void
8069readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008070{
8071 int fd;
8072
8073 INTOFF;
8074 if ((fd = open(name, O_RDONLY)) >= 0)
8075 setinputfd(fd, 1);
8076 else
8077 error("Can't open %s", name);
8078 INTON;
8079 cmdloop(0);
8080 popfile();
8081}
8082
8083
Eric Andersencb57d552001-06-28 07:25:16 +00008084/*
Eric Andersenc470f442003-07-28 09:56:35 +00008085 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008086 * search for the file, which is necessary to find sub-commands.
8087 */
8088
Eric Andersenc470f442003-07-28 09:56:35 +00008089static inline char *
8090find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008091{
8092 char *fullname;
8093 const char *path = pathval();
8094 struct stat statb;
8095
8096 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008097 if (strchr(name, '/'))
8098 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008099
Eric Andersenc470f442003-07-28 09:56:35 +00008100 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008101 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8102 /*
8103 * Don't bother freeing here, since it will
8104 * be freed by the caller.
8105 */
8106 return fullname;
8107 }
8108 stunalloc(fullname);
8109 }
8110
8111 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008112 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008113 /* NOTREACHED */
8114}
8115
Eric Andersenc470f442003-07-28 09:56:35 +00008116int
8117dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008118{
Eric Andersencb57d552001-06-28 07:25:16 +00008119 exitstatus = 0;
8120
Eric Andersenc470f442003-07-28 09:56:35 +00008121 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008122 char *fullname;
8123 struct stackmark smark;
8124
8125 setstackmark(&smark);
8126 fullname = find_dot_file(argv[1]);
8127 setinputfile(fullname, 1);
8128 commandname = fullname;
8129 cmdloop(0);
8130 popfile();
8131 popstackmark(&smark);
8132 }
8133 return exitstatus;
8134}
8135
8136
Eric Andersenc470f442003-07-28 09:56:35 +00008137static int
8138exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008139{
8140 if (stoppedjobs())
8141 return 0;
8142 if (argc > 1)
8143 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008144 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008145 /* NOTREACHED */
8146}
Eric Andersen62483552001-07-10 06:09:16 +00008147
Eric Andersenc470f442003-07-28 09:56:35 +00008148/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8149
8150/*
Eric Andersen90898442003-08-06 11:20:52 +00008151 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008152 */
8153
8154static pointer
8155ckrealloc(pointer p, size_t nbytes)
8156{
8157 p = realloc(p, nbytes);
8158 if (p == NULL)
8159 error(bb_msg_memory_exhausted);
8160 return p;
8161}
8162
Eric Andersen90898442003-08-06 11:20:52 +00008163static pointer
8164ckmalloc(size_t nbytes)
8165{
8166 return ckrealloc(NULL, nbytes);
8167}
Eric Andersenc470f442003-07-28 09:56:35 +00008168
8169/*
8170 * Make a copy of a string in safe storage.
8171 */
8172
8173static char *
8174savestr(const char *s)
8175{
8176 char *p = strdup(s);
8177 if (!p)
8178 error(bb_msg_memory_exhausted);
8179 return p;
8180}
8181
8182
8183/*
8184 * Parse trees for commands are allocated in lifo order, so we use a stack
8185 * to make this more efficient, and also to avoid all sorts of exception
8186 * handling code to handle interrupts in the middle of a parse.
8187 *
8188 * The size 504 was chosen because the Ultrix malloc handles that size
8189 * well.
8190 */
8191
8192
8193static pointer
8194stalloc(size_t nbytes)
8195{
8196 char *p;
8197 size_t aligned;
8198
8199 aligned = SHELL_ALIGN(nbytes);
8200 if (aligned > stacknleft) {
8201 size_t len;
8202 size_t blocksize;
8203 struct stack_block *sp;
8204
8205 blocksize = aligned;
8206 if (blocksize < MINSIZE)
8207 blocksize = MINSIZE;
8208 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8209 if (len < blocksize)
8210 error(bb_msg_memory_exhausted);
8211 INTOFF;
8212 sp = ckmalloc(len);
8213 sp->prev = stackp;
8214 stacknxt = sp->space;
8215 stacknleft = blocksize;
8216 sstrend = stacknxt + blocksize;
8217 stackp = sp;
8218 INTON;
8219 }
8220 p = stacknxt;
8221 stacknxt += aligned;
8222 stacknleft -= aligned;
8223 return p;
8224}
8225
8226
8227void
8228stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008229{
Eric Andersencb57d552001-06-28 07:25:16 +00008230#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008231 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008232 write(2, "stunalloc\n", 10);
8233 abort();
8234 }
8235#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008236 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008237 stacknxt = p;
8238}
8239
8240
Eric Andersenc470f442003-07-28 09:56:35 +00008241void
8242setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008243{
Eric Andersencb57d552001-06-28 07:25:16 +00008244 mark->stackp = stackp;
8245 mark->stacknxt = stacknxt;
8246 mark->stacknleft = stacknleft;
8247 mark->marknext = markp;
8248 markp = mark;
8249}
8250
8251
Eric Andersenc470f442003-07-28 09:56:35 +00008252void
8253popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008254{
Eric Andersencb57d552001-06-28 07:25:16 +00008255 struct stack_block *sp;
8256
8257 INTOFF;
8258 markp = mark->marknext;
8259 while (stackp != mark->stackp) {
8260 sp = stackp;
8261 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008262 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008263 }
8264 stacknxt = mark->stacknxt;
8265 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008266 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008267 INTON;
8268}
8269
8270
8271/*
8272 * When the parser reads in a string, it wants to stick the string on the
8273 * stack and only adjust the stack pointer when it knows how big the
8274 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8275 * of space on top of the stack and stackblocklen returns the length of
8276 * this block. Growstackblock will grow this space by at least one byte,
8277 * possibly moving it (like realloc). Grabstackblock actually allocates the
8278 * part of the block that has been used.
8279 */
8280
Eric Andersenc470f442003-07-28 09:56:35 +00008281void
8282growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008283{
Eric Andersenc470f442003-07-28 09:56:35 +00008284 size_t newlen;
8285
8286 newlen = stacknleft * 2;
8287 if (newlen < stacknleft)
8288 error(bb_msg_memory_exhausted);
8289 if (newlen < 128)
8290 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008291
8292 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008293 struct stack_block *oldstackp;
8294 struct stackmark *xmark;
8295 struct stack_block *sp;
8296 struct stack_block *prevstackp;
8297 size_t grosslen;
8298
Eric Andersencb57d552001-06-28 07:25:16 +00008299 INTOFF;
8300 oldstackp = stackp;
8301 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008302 prevstackp = sp->prev;
8303 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8304 sp = ckrealloc((pointer)sp, grosslen);
8305 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008306 stackp = sp;
8307 stacknxt = sp->space;
8308 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008309 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008310
Eric Andersenc470f442003-07-28 09:56:35 +00008311 /*
8312 * Stack marks pointing to the start of the old block
8313 * must be relocated to point to the new block
8314 */
8315 xmark = markp;
8316 while (xmark != NULL && xmark->stackp == oldstackp) {
8317 xmark->stackp = stackp;
8318 xmark->stacknxt = stacknxt;
8319 xmark->stacknleft = stacknleft;
8320 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008321 }
8322 INTON;
8323 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008324 char *oldspace = stacknxt;
8325 int oldlen = stacknleft;
8326 char *p = stalloc(newlen);
8327
8328 /* free the space we just allocated */
8329 stacknxt = memcpy(p, oldspace, oldlen);
8330 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008331 }
8332}
8333
Eric Andersenc470f442003-07-28 09:56:35 +00008334static inline void
8335grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008336{
Eric Andersenc470f442003-07-28 09:56:35 +00008337 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008338 stacknxt += len;
8339 stacknleft -= len;
8340}
8341
Eric Andersencb57d552001-06-28 07:25:16 +00008342/*
Eric Andersenc470f442003-07-28 09:56:35 +00008343 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008344 * The user declares a variable of type STACKSTR, which may be declared
8345 * to be a register. The macro STARTSTACKSTR initializes things. Then
8346 * the user uses the macro STPUTC to add characters to the string. In
8347 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8348 * grown as necessary. When the user is done, she can just leave the
8349 * string there and refer to it using stackblock(). Or she can allocate
8350 * the space for it using grabstackstr(). If it is necessary to allow
8351 * someone else to use the stack temporarily and then continue to grow
8352 * the string, the user should use grabstack to allocate the space, and
8353 * then call ungrabstr(p) to return to the previous mode of operation.
8354 *
8355 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8356 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8357 * is space for at least one character.
8358 */
8359
Eric Andersenc470f442003-07-28 09:56:35 +00008360void *
8361growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008362{
Eric Andersenc470f442003-07-28 09:56:35 +00008363 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008364 if (herefd >= 0 && len >= 1024) {
8365 xwrite(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008366 return stackblock();
8367 }
8368 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008369 return stackblock() + len;
8370}
8371
Eric Andersencb57d552001-06-28 07:25:16 +00008372/*
8373 * Called from CHECKSTRSPACE.
8374 */
8375
Eric Andersenc470f442003-07-28 09:56:35 +00008376char *
8377makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008378{
Eric Andersenc470f442003-07-28 09:56:35 +00008379 size_t len = p - stacknxt;
8380 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008381
Eric Andersenc470f442003-07-28 09:56:35 +00008382 for (;;) {
8383 size_t nleft;
8384
8385 size = stackblocksize();
8386 nleft = size - len;
8387 if (nleft >= newlen)
8388 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008389 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008390 }
Eric Andersencb57d552001-06-28 07:25:16 +00008391 return stackblock() + len;
8392}
8393
Eric Andersenc470f442003-07-28 09:56:35 +00008394char *
8395stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008396{
Eric Andersenc470f442003-07-28 09:56:35 +00008397 p = makestrspace(n, p);
8398 p = mempcpy(p, s, n);
8399 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008400}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008401
Eric Andersenc470f442003-07-28 09:56:35 +00008402char *
8403stputs(const char *s, char *p)
8404{
8405 return stnputs(s, strlen(s), p);
8406}
8407
8408/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8409
Eric Andersencb57d552001-06-28 07:25:16 +00008410/*
Eric Andersenc470f442003-07-28 09:56:35 +00008411 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008412 *
Eric Andersenc470f442003-07-28 09:56:35 +00008413 * number(s) Convert a string of digits to an integer.
8414 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008415 */
8416
Eric Andersencb57d552001-06-28 07:25:16 +00008417/*
8418 * prefix -- see if pfx is a prefix of string.
8419 */
8420
Eric Andersenc470f442003-07-28 09:56:35 +00008421char *
8422prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008423{
Eric Andersencb57d552001-06-28 07:25:16 +00008424 while (*pfx) {
8425 if (*pfx++ != *string++)
8426 return 0;
8427 }
Eric Andersenc470f442003-07-28 09:56:35 +00008428 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008429}
8430
8431
8432/*
8433 * Convert a string of digits to an integer, printing an error message on
8434 * failure.
8435 */
8436
Eric Andersenc470f442003-07-28 09:56:35 +00008437int
8438number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008439{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008440
Eric Andersenc470f442003-07-28 09:56:35 +00008441 if (! is_number(s))
8442 error(illnum, s);
8443 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008444}
8445
Eric Andersenc470f442003-07-28 09:56:35 +00008446
Eric Andersenc470f442003-07-28 09:56:35 +00008447/*
8448 * Check for a valid number. This should be elsewhere.
8449 */
8450
8451int
8452is_number(const char *p)
8453{
8454 do {
8455 if (! is_digit(*p))
8456 return 0;
8457 } while (*++p != '\0');
8458 return 1;
8459}
8460
8461
Eric Andersencb57d552001-06-28 07:25:16 +00008462/*
8463 * Produce a possibly single quoted string suitable as input to the shell.
8464 * The return string is allocated on the stack.
8465 */
8466
Eric Andersenc470f442003-07-28 09:56:35 +00008467char *
8468single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008469 char *p;
8470
8471 STARTSTACKSTR(p);
8472
8473 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008474 char *q;
8475 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008476
Eric Andersenc470f442003-07-28 09:56:35 +00008477 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008478
Eric Andersenc470f442003-07-28 09:56:35 +00008479 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008480
Eric Andersenc470f442003-07-28 09:56:35 +00008481 *q++ = '\'';
8482 q = mempcpy(q, s, len);
8483 *q++ = '\'';
8484 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008485
Eric Andersenc470f442003-07-28 09:56:35 +00008486 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008487
Eric Andersenc470f442003-07-28 09:56:35 +00008488 len = strspn(s, "'");
8489 if (!len)
8490 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008491
Eric Andersenc470f442003-07-28 09:56:35 +00008492 q = p = makestrspace(len + 3, p);
8493
8494 *q++ = '"';
8495 q = mempcpy(q, s, len);
8496 *q++ = '"';
8497 s += len;
8498
8499 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008500 } while (*s);
8501
8502 USTPUTC(0, p);
8503
Eric Andersenc470f442003-07-28 09:56:35 +00008504 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008505}
8506
8507/*
Eric Andersenc470f442003-07-28 09:56:35 +00008508 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008509 */
8510
Eric Andersenc470f442003-07-28 09:56:35 +00008511char *
8512sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008513{
Eric Andersenc470f442003-07-28 09:56:35 +00008514 size_t len = strlen(p) + 1;
8515 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008516}
Eric Andersenc470f442003-07-28 09:56:35 +00008517
8518
8519static void
8520calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008521{
Eric Andersenc470f442003-07-28 09:56:35 +00008522 if (n == NULL)
8523 return;
8524 funcblocksize += nodesize[n->type];
8525 switch (n->type) {
8526 case NCMD:
8527 calcsize(n->ncmd.redirect);
8528 calcsize(n->ncmd.args);
8529 calcsize(n->ncmd.assign);
8530 break;
8531 case NPIPE:
8532 sizenodelist(n->npipe.cmdlist);
8533 break;
8534 case NREDIR:
8535 case NBACKGND:
8536 case NSUBSHELL:
8537 calcsize(n->nredir.redirect);
8538 calcsize(n->nredir.n);
8539 break;
8540 case NAND:
8541 case NOR:
8542 case NSEMI:
8543 case NWHILE:
8544 case NUNTIL:
8545 calcsize(n->nbinary.ch2);
8546 calcsize(n->nbinary.ch1);
8547 break;
8548 case NIF:
8549 calcsize(n->nif.elsepart);
8550 calcsize(n->nif.ifpart);
8551 calcsize(n->nif.test);
8552 break;
8553 case NFOR:
8554 funcstringsize += strlen(n->nfor.var) + 1;
8555 calcsize(n->nfor.body);
8556 calcsize(n->nfor.args);
8557 break;
8558 case NCASE:
8559 calcsize(n->ncase.cases);
8560 calcsize(n->ncase.expr);
8561 break;
8562 case NCLIST:
8563 calcsize(n->nclist.body);
8564 calcsize(n->nclist.pattern);
8565 calcsize(n->nclist.next);
8566 break;
8567 case NDEFUN:
8568 case NARG:
8569 sizenodelist(n->narg.backquote);
8570 funcstringsize += strlen(n->narg.text) + 1;
8571 calcsize(n->narg.next);
8572 break;
8573 case NTO:
8574 case NCLOBBER:
8575 case NFROM:
8576 case NFROMTO:
8577 case NAPPEND:
8578 calcsize(n->nfile.fname);
8579 calcsize(n->nfile.next);
8580 break;
8581 case NTOFD:
8582 case NFROMFD:
8583 calcsize(n->ndup.vname);
8584 calcsize(n->ndup.next);
8585 break;
8586 case NHERE:
8587 case NXHERE:
8588 calcsize(n->nhere.doc);
8589 calcsize(n->nhere.next);
8590 break;
8591 case NNOT:
8592 calcsize(n->nnot.com);
8593 break;
8594 };
Eric Andersencb57d552001-06-28 07:25:16 +00008595}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008596
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008597
Eric Andersenc470f442003-07-28 09:56:35 +00008598static void
8599sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008600{
8601 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008602 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008603 calcsize(lp->n);
8604 lp = lp->next;
8605 }
8606}
Eric Andersencb57d552001-06-28 07:25:16 +00008607
8608
Eric Andersenc470f442003-07-28 09:56:35 +00008609static union node *
8610copynode(union node *n)
8611{
8612 union node *new;
8613
8614 if (n == NULL)
8615 return NULL;
8616 new = funcblock;
8617 funcblock = (char *) funcblock + nodesize[n->type];
8618 switch (n->type) {
8619 case NCMD:
8620 new->ncmd.redirect = copynode(n->ncmd.redirect);
8621 new->ncmd.args = copynode(n->ncmd.args);
8622 new->ncmd.assign = copynode(n->ncmd.assign);
8623 break;
8624 case NPIPE:
8625 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8626 new->npipe.backgnd = n->npipe.backgnd;
8627 break;
8628 case NREDIR:
8629 case NBACKGND:
8630 case NSUBSHELL:
8631 new->nredir.redirect = copynode(n->nredir.redirect);
8632 new->nredir.n = copynode(n->nredir.n);
8633 break;
8634 case NAND:
8635 case NOR:
8636 case NSEMI:
8637 case NWHILE:
8638 case NUNTIL:
8639 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8640 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8641 break;
8642 case NIF:
8643 new->nif.elsepart = copynode(n->nif.elsepart);
8644 new->nif.ifpart = copynode(n->nif.ifpart);
8645 new->nif.test = copynode(n->nif.test);
8646 break;
8647 case NFOR:
8648 new->nfor.var = nodesavestr(n->nfor.var);
8649 new->nfor.body = copynode(n->nfor.body);
8650 new->nfor.args = copynode(n->nfor.args);
8651 break;
8652 case NCASE:
8653 new->ncase.cases = copynode(n->ncase.cases);
8654 new->ncase.expr = copynode(n->ncase.expr);
8655 break;
8656 case NCLIST:
8657 new->nclist.body = copynode(n->nclist.body);
8658 new->nclist.pattern = copynode(n->nclist.pattern);
8659 new->nclist.next = copynode(n->nclist.next);
8660 break;
8661 case NDEFUN:
8662 case NARG:
8663 new->narg.backquote = copynodelist(n->narg.backquote);
8664 new->narg.text = nodesavestr(n->narg.text);
8665 new->narg.next = copynode(n->narg.next);
8666 break;
8667 case NTO:
8668 case NCLOBBER:
8669 case NFROM:
8670 case NFROMTO:
8671 case NAPPEND:
8672 new->nfile.fname = copynode(n->nfile.fname);
8673 new->nfile.fd = n->nfile.fd;
8674 new->nfile.next = copynode(n->nfile.next);
8675 break;
8676 case NTOFD:
8677 case NFROMFD:
8678 new->ndup.vname = copynode(n->ndup.vname);
8679 new->ndup.dupfd = n->ndup.dupfd;
8680 new->ndup.fd = n->ndup.fd;
8681 new->ndup.next = copynode(n->ndup.next);
8682 break;
8683 case NHERE:
8684 case NXHERE:
8685 new->nhere.doc = copynode(n->nhere.doc);
8686 new->nhere.fd = n->nhere.fd;
8687 new->nhere.next = copynode(n->nhere.next);
8688 break;
8689 case NNOT:
8690 new->nnot.com = copynode(n->nnot.com);
8691 break;
8692 };
8693 new->type = n->type;
8694 return new;
8695}
8696
8697
8698static struct nodelist *
8699copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008700{
8701 struct nodelist *start;
8702 struct nodelist **lpp;
8703
8704 lpp = &start;
8705 while (lp) {
8706 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008707 funcblock = (char *) funcblock +
8708 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008709 (*lpp)->n = copynode(lp->n);
8710 lp = lp->next;
8711 lpp = &(*lpp)->next;
8712 }
8713 *lpp = NULL;
8714 return start;
8715}
8716
8717
Eric Andersenc470f442003-07-28 09:56:35 +00008718static char *
8719nodesavestr(char *s)
8720{
8721 char *rtn = funcstring;
8722
8723 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008724 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008725}
8726
Eric Andersenc470f442003-07-28 09:56:35 +00008727
Eric Andersenc470f442003-07-28 09:56:35 +00008728/*
8729 * Free a parse tree.
8730 */
8731
8732static void
8733freefunc(struct funcnode *f)
8734{
8735 if (f && --f->count < 0)
8736 ckfree(f);
8737}
8738
8739
8740static void options(int);
8741static void setoption(int, int);
8742
Eric Andersencb57d552001-06-28 07:25:16 +00008743
Eric Andersencb57d552001-06-28 07:25:16 +00008744/*
8745 * Process the shell command line arguments.
8746 */
8747
Eric Andersenc470f442003-07-28 09:56:35 +00008748void
8749procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008750{
8751 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008752 const char *xminusc;
8753 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008754
Eric Andersenc470f442003-07-28 09:56:35 +00008755 xargv = argv;
8756 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008757 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008758 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008759 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008760 optlist[i] = 2;
8761 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008762 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008763 xargv = argptr;
8764 xminusc = minusc;
8765 if (*xargv == NULL) {
8766 if (xminusc)
8767 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008768 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008769 }
Eric Andersencb57d552001-06-28 07:25:16 +00008770 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8771 iflag = 1;
8772 if (mflag == 2)
8773 mflag = iflag;
8774 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008775 if (optlist[i] == 2)
8776 optlist[i] = 0;
8777#if DEBUG == 2
8778 debug = 1;
8779#endif
8780 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8781 if (xminusc) {
8782 minusc = *xargv++;
8783 if (*xargv)
8784 goto setarg0;
8785 } else if (!sflag) {
8786 setinputfile(*xargv, 0);
8787setarg0:
8788 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008789 commandname = arg0;
8790 }
Eric Andersencb57d552001-06-28 07:25:16 +00008791
Eric Andersenc470f442003-07-28 09:56:35 +00008792 shellparam.p = xargv;
8793#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008794 shellparam.optind = 1;
8795 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008796#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008797 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008798 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008799 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008800 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008801 }
8802 optschanged();
8803}
8804
8805
Eric Andersenc470f442003-07-28 09:56:35 +00008806void
8807optschanged(void)
8808{
8809#ifdef DEBUG
8810 opentrace();
8811#endif
8812 setinteractive(iflag);
8813 setjobctl(mflag);
8814}
Eric Andersencb57d552001-06-28 07:25:16 +00008815
Eric Andersenc470f442003-07-28 09:56:35 +00008816static inline void
8817minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008818{
8819 int i;
8820
8821 if (name == NULL) {
8822 out1str("Current option settings\n");
8823 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008824 out1fmt("%-16s%s\n", optnames(i),
8825 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008826 } else {
8827 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008828 if (equal(name, optnames(i))) {
8829 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008830 return;
8831 }
8832 error("Illegal option -o %s", name);
8833 }
8834}
8835
Eric Andersenc470f442003-07-28 09:56:35 +00008836/*
8837 * Process shell options. The global variable argptr contains a pointer
8838 * to the argument list; we advance it past the options.
8839 */
Eric Andersen62483552001-07-10 06:09:16 +00008840
Eric Andersenc470f442003-07-28 09:56:35 +00008841static void
8842options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008843{
8844 char *p;
8845 int val;
8846 int c;
8847
8848 if (cmdline)
8849 minusc = NULL;
8850 while ((p = *argptr) != NULL) {
8851 argptr++;
8852 if ((c = *p++) == '-') {
8853 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008854 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8855 if (!cmdline) {
8856 /* "-" means turn off -x and -v */
8857 if (p[0] == '\0')
8858 xflag = vflag = 0;
8859 /* "--" means reset params */
8860 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008861 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008862 }
Eric Andersenc470f442003-07-28 09:56:35 +00008863 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008864 }
8865 } else if (c == '+') {
8866 val = 0;
8867 } else {
8868 argptr--;
8869 break;
8870 }
8871 while ((c = *p++) != '\0') {
8872 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008873 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008874 } else if (c == 'o') {
8875 minus_o(*argptr, val);
8876 if (*argptr)
8877 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008878 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008879 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008880 isloginsh = 1;
8881 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008882 } else {
8883 setoption(c, val);
8884 }
8885 }
8886 }
8887}
8888
Eric Andersencb57d552001-06-28 07:25:16 +00008889
Eric Andersenc470f442003-07-28 09:56:35 +00008890static void
8891setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008892{
Eric Andersencb57d552001-06-28 07:25:16 +00008893 int i;
8894
8895 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008896 if (optletters(i) == flag) {
8897 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008898 return;
8899 }
8900 error("Illegal option -%c", flag);
8901 /* NOTREACHED */
8902}
8903
8904
8905
Eric Andersencb57d552001-06-28 07:25:16 +00008906/*
8907 * Set the shell parameters.
8908 */
8909
Eric Andersenc470f442003-07-28 09:56:35 +00008910void
8911setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008912{
Eric Andersencb57d552001-06-28 07:25:16 +00008913 char **newparam;
8914 char **ap;
8915 int nparam;
8916
Eric Andersenc470f442003-07-28 09:56:35 +00008917 for (nparam = 0 ; argv[nparam] ; nparam++);
8918 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008919 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008920 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008921 }
8922 *ap = NULL;
8923 freeparam(&shellparam);
8924 shellparam.malloc = 1;
8925 shellparam.nparam = nparam;
8926 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008927#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008928 shellparam.optind = 1;
8929 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008930#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008931}
8932
8933
8934/*
8935 * Free the list of positional parameters.
8936 */
8937
Eric Andersenc470f442003-07-28 09:56:35 +00008938void
8939freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008940{
Eric Andersencb57d552001-06-28 07:25:16 +00008941 char **ap;
8942
8943 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008944 for (ap = param->p ; *ap ; ap++)
8945 ckfree(*ap);
8946 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008947 }
8948}
8949
8950
8951
8952/*
8953 * The shift builtin command.
8954 */
8955
Eric Andersenc470f442003-07-28 09:56:35 +00008956int
8957shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008958{
8959 int n;
8960 char **ap1, **ap2;
8961
8962 n = 1;
8963 if (argc > 1)
8964 n = number(argv[1]);
8965 if (n > shellparam.nparam)
8966 error("can't shift that many");
8967 INTOFF;
8968 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008969 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008970 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008971 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008972 }
8973 ap2 = shellparam.p;
8974 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008975#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008976 shellparam.optind = 1;
8977 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008978#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008979 INTON;
8980 return 0;
8981}
8982
8983
8984
8985/*
8986 * The set command builtin.
8987 */
8988
Eric Andersenc470f442003-07-28 09:56:35 +00008989int
8990setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008991{
8992 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00008993 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00008994 INTOFF;
8995 options(0);
8996 optschanged();
8997 if (*argptr != NULL) {
8998 setparam(argptr);
8999 }
9000 INTON;
9001 return 0;
9002}
9003
9004
Eric Andersenc470f442003-07-28 09:56:35 +00009005#ifdef CONFIG_ASH_GETOPTS
9006static void
9007getoptsreset(value)
9008 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009009{
9010 shellparam.optind = number(value);
9011 shellparam.optoff = -1;
9012}
Eric Andersenc470f442003-07-28 09:56:35 +00009013#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009014
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009015#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009016static void change_lc_all(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_ALL, value);
9020}
9021
9022static void change_lc_ctype(const char *value)
9023{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009024 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009025 setlocale(LC_CTYPE, value);
9026}
9027
9028#endif
9029
Eric Andersend35c5df2002-01-09 15:37:36 +00009030#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009031static int
Eric Andersenc470f442003-07-28 09:56:35 +00009032getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009033{
9034 char *p, *q;
9035 char c = '?';
9036 int done = 0;
9037 int err = 0;
9038 char s[10];
Eric Andersenc470f442003-07-28 09:56:35 +00009039 char **optnext = optfirst + *param_optind - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009040
Eric Andersenc470f442003-07-28 09:56:35 +00009041 if (*param_optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9042 strlen(*(optnext - 1)) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009043 p = NULL;
9044 else
9045 p = *(optnext - 1) + *optoff;
9046 if (p == NULL || *p == '\0') {
9047 /* Current word is done, advance */
9048 if (optnext == NULL)
9049 return 1;
9050 p = *optnext;
9051 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009052atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009053 p = NULL;
9054 done = 1;
9055 goto out;
9056 }
9057 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009058 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009059 goto atend;
9060 }
9061
9062 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009063 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009064 if (*q == '\0') {
9065 if (optstr[0] == ':') {
9066 s[0] = c;
9067 s[1] = '\0';
9068 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009069 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009070 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009071 (void) unsetvar("OPTARG");
9072 }
9073 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009074 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009075 }
9076 if (*++q == ':')
9077 q++;
9078 }
9079
9080 if (*++q == ':') {
9081 if (*p == '\0' && (p = *optnext) == NULL) {
9082 if (optstr[0] == ':') {
9083 s[0] = c;
9084 s[1] = '\0';
9085 err |= setvarsafe("OPTARG", s, 0);
9086 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009087 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009088 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009089 (void) unsetvar("OPTARG");
9090 c = '?';
9091 }
Eric Andersenc470f442003-07-28 09:56:35 +00009092 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009093 }
9094
9095 if (p == *optnext)
9096 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009097 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009098 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009099 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009100 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009101
Eric Andersenc470f442003-07-28 09:56:35 +00009102out:
Eric Andersencb57d552001-06-28 07:25:16 +00009103 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009104 *param_optind = optnext - optfirst + 1;
9105 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009106 err |= setvarsafe("OPTIND", s, VNOFUNC);
9107 s[0] = c;
9108 s[1] = '\0';
9109 err |= setvarsafe(optvar, s, 0);
9110 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009111 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009112 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009113 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009114 exraise(EXERROR);
9115 }
9116 return done;
9117}
Eric Andersenc470f442003-07-28 09:56:35 +00009118
9119/*
9120 * The getopts builtin. Shellparam.optnext points to the next argument
9121 * to be processed. Shellparam.optptr points to the next character to
9122 * be processed in the current argument. If shellparam.optnext is NULL,
9123 * then it's the first time getopts has been called.
9124 */
9125
9126int
9127getoptscmd(int argc, char **argv)
9128{
9129 char **optbase;
9130
9131 if (argc < 3)
9132 error("Usage: getopts optstring var [arg]");
9133 else if (argc == 3) {
9134 optbase = shellparam.p;
9135 if (shellparam.optind > shellparam.nparam + 1) {
9136 shellparam.optind = 1;
9137 shellparam.optoff = -1;
9138 }
9139 }
9140 else {
9141 optbase = &argv[3];
9142 if (shellparam.optind > argc - 2) {
9143 shellparam.optind = 1;
9144 shellparam.optoff = -1;
9145 }
9146 }
9147
9148 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9149 &shellparam.optoff);
9150}
9151#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009152
9153/*
9154 * XXX - should get rid of. have all builtins use getopt(3). the
9155 * library getopt must have the BSD extension static variable "optreset"
9156 * otherwise it can't be used within the shell safely.
9157 *
9158 * Standard option processing (a la getopt) for builtin routines. The
9159 * only argument that is passed to nextopt is the option string; the
9160 * other arguments are unnecessary. It return the character, or '\0' on
9161 * end of input.
9162 */
9163
Eric Andersenc470f442003-07-28 09:56:35 +00009164static int
9165nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009166{
Eric Andersencb57d552001-06-28 07:25:16 +00009167 char *p;
9168 const char *q;
9169 char c;
9170
9171 if ((p = optptr) == NULL || *p == '\0') {
9172 p = *argptr;
9173 if (p == NULL || *p != '-' || *++p == '\0')
9174 return '\0';
9175 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009176 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009177 return '\0';
9178 }
9179 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009180 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009181 if (*q == '\0')
9182 error("Illegal option -%c", c);
9183 if (*++q == ':')
9184 q++;
9185 }
9186 if (*++q == ':') {
9187 if (*p == '\0' && (p = *argptr++) == NULL)
9188 error("No arg for -%c option", c);
9189 optionarg = p;
9190 p = NULL;
9191 }
9192 optptr = p;
9193 return c;
9194}
9195
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009196
Eric Andersenc470f442003-07-28 09:56:35 +00009197/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9198
Eric Andersenc470f442003-07-28 09:56:35 +00009199void
9200outstr(const char *p, FILE *file)
9201{
9202 INTOFF;
9203 fputs(p, file);
9204 INTON;
9205}
9206
9207void
9208flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009209{
Eric Andersencb57d552001-06-28 07:25:16 +00009210 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009211 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009212 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009213 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009214}
9215
Eric Andersenc470f442003-07-28 09:56:35 +00009216void
9217flushout(FILE *dest)
9218{
9219 INTOFF;
9220 fflush(dest);
9221 INTON;
9222}
9223
9224static void
9225outcslow(int c, FILE *dest)
9226{
9227 INTOFF;
9228 putc(c, dest);
9229 fflush(dest);
9230 INTON;
9231}
9232
9233
9234static int
9235out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009236{
9237 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009238 int r;
9239
9240 INTOFF;
9241 va_start(ap, fmt);
9242 r = vprintf(fmt, ap);
9243 va_end(ap);
9244 INTON;
9245 return r;
9246}
9247
9248
9249int
9250fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9251{
9252 va_list ap;
9253 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009254
Eric Andersencb57d552001-06-28 07:25:16 +00009255 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009256 INTOFF;
9257 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009258 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009259 INTON;
9260 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009261}
9262
Eric Andersenc470f442003-07-28 09:56:35 +00009263
Eric Andersencb57d552001-06-28 07:25:16 +00009264/*
9265 * Version of write which resumes after a signal is caught.
9266 */
9267
Eric Andersenc470f442003-07-28 09:56:35 +00009268static void
9269xwrite(int fd, const void *p, size_t n)
Eric Andersen2870d962001-07-02 17:27:21 +00009270{
Eric Andersenc470f442003-07-28 09:56:35 +00009271 ssize_t i;
Eric Andersencb57d552001-06-28 07:25:16 +00009272
Eric Andersenc470f442003-07-28 09:56:35 +00009273 do {
9274 i = bb_full_write(fd, p, n);
9275 } while (i < 0 && errno == EINTR);
Eric Andersencb57d552001-06-28 07:25:16 +00009276}
9277
9278
Eric Andersenc470f442003-07-28 09:56:35 +00009279/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9280
9281
Eric Andersencb57d552001-06-28 07:25:16 +00009282/*
9283 * Shell command parser.
9284 */
9285
9286#define EOFMARKLEN 79
9287
9288
Eric Andersencb57d552001-06-28 07:25:16 +00009289struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009290 struct heredoc *next; /* next here document in list */
9291 union node *here; /* redirection node */
9292 char *eofmark; /* string indicating end of input */
9293 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009294};
9295
9296
9297
Eric Andersenc470f442003-07-28 09:56:35 +00009298static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009299
9300
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009301static union node *list(int);
9302static union node *andor(void);
9303static union node *pipeline(void);
9304static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009305static union node *simplecmd(void);
9306static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009307static void parsefname(void);
9308static void parseheredoc(void);
9309static char peektoken(void);
9310static int readtoken(void);
9311static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009312static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009313static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009314static void synexpect(int) __attribute__((__noreturn__));
9315static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009316static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009317
9318
Eric Andersenc470f442003-07-28 09:56:35 +00009319static inline int
9320goodname(const char *p)
9321{
9322 return !*endofname(p);
9323}
9324
9325static inline int
9326isassignment(const char *p)
9327{
9328 const char *q = endofname(p);
9329 if (p == q)
9330 return 0;
9331 return *q == '=';
9332}
9333
9334
Eric Andersencb57d552001-06-28 07:25:16 +00009335/*
9336 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9337 * valid parse tree indicating a blank line.)
9338 */
9339
Eric Andersenc470f442003-07-28 09:56:35 +00009340union node *
9341parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009342{
9343 int t;
9344
9345 tokpushback = 0;
9346 doprompt = interact;
9347 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009348 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009349 needprompt = 0;
9350 t = readtoken();
9351 if (t == TEOF)
9352 return NEOF;
9353 if (t == TNL)
9354 return NULL;
9355 tokpushback++;
9356 return list(1);
9357}
9358
9359
Eric Andersenc470f442003-07-28 09:56:35 +00009360static union node *
9361list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009362{
9363 union node *n1, *n2, *n3;
9364 int tok;
9365
Eric Andersenc470f442003-07-28 09:56:35 +00009366 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9367 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009368 return NULL;
9369 n1 = NULL;
9370 for (;;) {
9371 n2 = andor();
9372 tok = readtoken();
9373 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009374 if (n2->type == NPIPE) {
9375 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009376 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009377 if (n2->type != NREDIR) {
9378 n3 = stalloc(sizeof(struct nredir));
9379 n3->nredir.n = n2;
9380 n3->nredir.redirect = NULL;
9381 n2 = n3;
9382 }
9383 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009384 }
9385 }
9386 if (n1 == NULL) {
9387 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009388 }
9389 else {
9390 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009391 n3->type = NSEMI;
9392 n3->nbinary.ch1 = n1;
9393 n3->nbinary.ch2 = n2;
9394 n1 = n3;
9395 }
9396 switch (tok) {
9397 case TBACKGND:
9398 case TSEMI:
9399 tok = readtoken();
9400 /* fall through */
9401 case TNL:
9402 if (tok == TNL) {
9403 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009404 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009405 return n1;
9406 } else {
9407 tokpushback++;
9408 }
Eric Andersenc470f442003-07-28 09:56:35 +00009409 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009410 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009411 return n1;
9412 break;
9413 case TEOF:
9414 if (heredoclist)
9415 parseheredoc();
9416 else
Eric Andersenc470f442003-07-28 09:56:35 +00009417 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009418 return n1;
9419 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009420 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009421 synexpect(-1);
9422 tokpushback++;
9423 return n1;
9424 }
9425 }
9426}
9427
9428
9429
Eric Andersenc470f442003-07-28 09:56:35 +00009430static union node *
9431andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009432{
Eric Andersencb57d552001-06-28 07:25:16 +00009433 union node *n1, *n2, *n3;
9434 int t;
9435
Eric Andersencb57d552001-06-28 07:25:16 +00009436 n1 = pipeline();
9437 for (;;) {
9438 if ((t = readtoken()) == TAND) {
9439 t = NAND;
9440 } else if (t == TOR) {
9441 t = NOR;
9442 } else {
9443 tokpushback++;
9444 return n1;
9445 }
Eric Andersenc470f442003-07-28 09:56:35 +00009446 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009447 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009448 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009449 n3->type = t;
9450 n3->nbinary.ch1 = n1;
9451 n3->nbinary.ch2 = n2;
9452 n1 = n3;
9453 }
9454}
9455
9456
9457
Eric Andersenc470f442003-07-28 09:56:35 +00009458static union node *
9459pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009460{
Eric Andersencb57d552001-06-28 07:25:16 +00009461 union node *n1, *n2, *pipenode;
9462 struct nodelist *lp, *prev;
9463 int negate;
9464
9465 negate = 0;
9466 TRACE(("pipeline: entered\n"));
9467 if (readtoken() == TNOT) {
9468 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009469 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009470 } else
9471 tokpushback++;
9472 n1 = command();
9473 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009474 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009475 pipenode->type = NPIPE;
9476 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009477 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009478 pipenode->npipe.cmdlist = lp;
9479 lp->n = n1;
9480 do {
9481 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009482 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9483 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009484 lp->n = command();
9485 prev->next = lp;
9486 } while (readtoken() == TPIPE);
9487 lp->next = NULL;
9488 n1 = pipenode;
9489 }
9490 tokpushback++;
9491 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009492 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009493 n2->type = NNOT;
9494 n2->nnot.com = n1;
9495 return n2;
9496 } else
9497 return n1;
9498}
9499
9500
9501
Eric Andersenc470f442003-07-28 09:56:35 +00009502static union node *
9503command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009504{
Eric Andersencb57d552001-06-28 07:25:16 +00009505 union node *n1, *n2;
9506 union node *ap, **app;
9507 union node *cp, **cpp;
9508 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009509 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009510 int t;
9511
9512 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009513 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009514
Eric Andersencb57d552001-06-28 07:25:16 +00009515 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009516 default:
9517 synexpect(-1);
9518 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009519 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009520 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009521 n1->type = NIF;
9522 n1->nif.test = list(0);
9523 if (readtoken() != TTHEN)
9524 synexpect(TTHEN);
9525 n1->nif.ifpart = list(0);
9526 n2 = n1;
9527 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009528 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009529 n2 = n2->nif.elsepart;
9530 n2->type = NIF;
9531 n2->nif.test = list(0);
9532 if (readtoken() != TTHEN)
9533 synexpect(TTHEN);
9534 n2->nif.ifpart = list(0);
9535 }
9536 if (lasttoken == TELSE)
9537 n2->nif.elsepart = list(0);
9538 else {
9539 n2->nif.elsepart = NULL;
9540 tokpushback++;
9541 }
Eric Andersenc470f442003-07-28 09:56:35 +00009542 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009543 break;
9544 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009545 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009546 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009547 n1 = (union node *)stalloc(sizeof (struct nbinary));
9548 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009549 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009550 if ((got=readtoken()) != TDO) {
9551TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009552 synexpect(TDO);
9553 }
9554 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009555 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009556 break;
9557 }
9558 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009559 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009560 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009561 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009562 n1->type = NFOR;
9563 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009564 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009565 if (readtoken() == TIN) {
9566 app = &ap;
9567 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009568 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009569 n2->type = NARG;
9570 n2->narg.text = wordtext;
9571 n2->narg.backquote = backquotelist;
9572 *app = n2;
9573 app = &n2->narg.next;
9574 }
9575 *app = NULL;
9576 n1->nfor.args = ap;
9577 if (lasttoken != TNL && lasttoken != TSEMI)
9578 synexpect(-1);
9579 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009580 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009581 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009582 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009583 n2->narg.backquote = NULL;
9584 n2->narg.next = NULL;
9585 n1->nfor.args = n2;
9586 /*
9587 * Newline or semicolon here is optional (but note
9588 * that the original Bourne shell only allowed NL).
9589 */
9590 if (lasttoken != TNL && lasttoken != TSEMI)
9591 tokpushback++;
9592 }
Eric Andersenc470f442003-07-28 09:56:35 +00009593 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009594 if (readtoken() != TDO)
9595 synexpect(TDO);
9596 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009597 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009598 break;
9599 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009600 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009601 n1->type = NCASE;
9602 if (readtoken() != TWORD)
9603 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009604 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009605 n2->type = NARG;
9606 n2->narg.text = wordtext;
9607 n2->narg.backquote = backquotelist;
9608 n2->narg.next = NULL;
9609 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009610 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009611 } while (readtoken() == TNL);
9612 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009613 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009614 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009615next_case:
9616 checkkwd = CHKNL | CHKKWD;
9617 t = readtoken();
9618 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009619 if (lasttoken == TLP)
9620 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009621 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009622 cp->type = NCLIST;
9623 app = &cp->nclist.pattern;
9624 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009625 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009626 ap->type = NARG;
9627 ap->narg.text = wordtext;
9628 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009629 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009630 break;
9631 app = &ap->narg.next;
9632 readtoken();
9633 }
9634 ap->narg.next = NULL;
9635 if (lasttoken != TRP)
9636 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009637 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009638
Eric Andersenc470f442003-07-28 09:56:35 +00009639 cpp = &cp->nclist.next;
9640
9641 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009642 if ((t = readtoken()) != TESAC) {
9643 if (t != TENDCASE)
9644 synexpect(TENDCASE);
9645 else
Eric Andersenc470f442003-07-28 09:56:35 +00009646 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009647 }
Eric Andersenc470f442003-07-28 09:56:35 +00009648 }
Eric Andersencb57d552001-06-28 07:25:16 +00009649 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009650 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009651 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009652 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009653 n1->type = NSUBSHELL;
9654 n1->nredir.n = list(0);
9655 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009656 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009657 break;
9658 case TBEGIN:
9659 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009660 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009661 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009662 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009663 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009664 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009665 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009666 }
9667
Eric Andersenc470f442003-07-28 09:56:35 +00009668 if (readtoken() != t)
9669 synexpect(t);
9670
9671redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009672 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009673 checkkwd = CHKKWD | CHKALIAS;
9674 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009675 while (readtoken() == TREDIR) {
9676 *rpp = n2 = redirnode;
9677 rpp = &n2->nfile.next;
9678 parsefname();
9679 }
9680 tokpushback++;
9681 *rpp = NULL;
9682 if (redir) {
9683 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009684 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009685 n2->type = NREDIR;
9686 n2->nredir.n = n1;
9687 n1 = n2;
9688 }
9689 n1->nredir.redirect = redir;
9690 }
9691
9692 return n1;
9693}
9694
9695
Eric Andersenc470f442003-07-28 09:56:35 +00009696static union node *
9697simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009698 union node *args, **app;
9699 union node *n = NULL;
9700 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009701 union node **rpp, *redir;
9702 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009703
9704 args = NULL;
9705 app = &args;
9706 vars = NULL;
9707 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009708 redir = NULL;
9709 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009710
Eric Andersenc470f442003-07-28 09:56:35 +00009711 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009712 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009713 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009714 switch (readtoken()) {
9715 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009716 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009717 n->type = NARG;
9718 n->narg.text = wordtext;
9719 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009720 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009721 *vpp = n;
9722 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009723 } else {
9724 *app = n;
9725 app = &n->narg.next;
9726 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009727 }
9728 break;
9729 case TREDIR:
9730 *rpp = n = redirnode;
9731 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009732 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009733 break;
9734 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009735 if (
9736 args && app == &args->narg.next &&
9737 !vars && !redir
9738 ) {
9739 struct builtincmd *bcmd;
9740 const char *name;
9741
Eric Andersencb57d552001-06-28 07:25:16 +00009742 /* We have a function */
9743 if (readtoken() != TRP)
9744 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009745 name = n->narg.text;
9746 if (
9747 !goodname(name) || (
9748 (bcmd = find_builtin(name)) &&
9749 IS_BUILTIN_SPECIAL(bcmd)
9750 )
9751 )
9752 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009753 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009754 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009755 n->narg.next = command();
9756 return n;
9757 }
9758 /* fall through */
9759 default:
9760 tokpushback++;
9761 goto out;
9762 }
9763 }
Eric Andersenc470f442003-07-28 09:56:35 +00009764out:
Eric Andersencb57d552001-06-28 07:25:16 +00009765 *app = NULL;
9766 *vpp = NULL;
9767 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009768 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009769 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009770 n->ncmd.args = args;
9771 n->ncmd.assign = vars;
9772 n->ncmd.redirect = redir;
9773 return n;
9774}
9775
Eric Andersenc470f442003-07-28 09:56:35 +00009776static union node *
9777makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009778{
Eric Andersencb57d552001-06-28 07:25:16 +00009779 union node *n;
9780
Eric Andersenc470f442003-07-28 09:56:35 +00009781 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009782 n->type = NARG;
9783 n->narg.next = NULL;
9784 n->narg.text = wordtext;
9785 n->narg.backquote = backquotelist;
9786 return n;
9787}
9788
Eric Andersenc470f442003-07-28 09:56:35 +00009789void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009790{
Eric Andersencb57d552001-06-28 07:25:16 +00009791 TRACE(("Fix redir %s %d\n", text, err));
9792 if (!err)
9793 n->ndup.vname = NULL;
9794
9795 if (is_digit(text[0]) && text[1] == '\0')
9796 n->ndup.dupfd = digit_val(text[0]);
9797 else if (text[0] == '-' && text[1] == '\0')
9798 n->ndup.dupfd = -1;
9799 else {
9800
9801 if (err)
9802 synerror("Bad fd number");
9803 else
9804 n->ndup.vname = makename();
9805 }
9806}
9807
9808
Eric Andersenc470f442003-07-28 09:56:35 +00009809static void
9810parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009811{
Eric Andersencb57d552001-06-28 07:25:16 +00009812 union node *n = redirnode;
9813
9814 if (readtoken() != TWORD)
9815 synexpect(-1);
9816 if (n->type == NHERE) {
9817 struct heredoc *here = heredoc;
9818 struct heredoc *p;
9819 int i;
9820
9821 if (quoteflag == 0)
9822 n->type = NXHERE;
9823 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009824 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009825 synerror("Illegal eof marker for << redirection");
9826 rmescapes(wordtext);
9827 here->eofmark = wordtext;
9828 here->next = NULL;
9829 if (heredoclist == NULL)
9830 heredoclist = here;
9831 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009832 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009833 p->next = here;
9834 }
9835 } else if (n->type == NTOFD || n->type == NFROMFD) {
9836 fixredir(n, wordtext, 0);
9837 } else {
9838 n->nfile.fname = makename();
9839 }
9840}
9841
9842
9843/*
9844 * Input any here documents.
9845 */
9846
Eric Andersenc470f442003-07-28 09:56:35 +00009847static void
9848parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009849{
Eric Andersencb57d552001-06-28 07:25:16 +00009850 struct heredoc *here;
9851 union node *n;
9852
Eric Andersenc470f442003-07-28 09:56:35 +00009853 here = heredoclist;
9854 heredoclist = 0;
9855
9856 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009857 if (needprompt) {
9858 setprompt(2);
9859 needprompt = 0;
9860 }
Eric Andersenc470f442003-07-28 09:56:35 +00009861 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9862 here->eofmark, here->striptabs);
9863 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009864 n->narg.type = NARG;
9865 n->narg.next = NULL;
9866 n->narg.text = wordtext;
9867 n->narg.backquote = backquotelist;
9868 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009869 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009870 }
9871}
9872
Eric Andersenc470f442003-07-28 09:56:35 +00009873static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009874{
Eric Andersencb57d552001-06-28 07:25:16 +00009875 int t;
9876
9877 t = readtoken();
9878 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009879 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009880}
9881
Eric Andersenc470f442003-07-28 09:56:35 +00009882static int
9883readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009884{
Eric Andersencb57d552001-06-28 07:25:16 +00009885 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009886#ifdef DEBUG
9887 int alreadyseen = tokpushback;
9888#endif
9889
Eric Andersend35c5df2002-01-09 15:37:36 +00009890#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009891top:
Eric Andersen2870d962001-07-02 17:27:21 +00009892#endif
9893
Eric Andersencb57d552001-06-28 07:25:16 +00009894 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009895
Eric Andersenc470f442003-07-28 09:56:35 +00009896 /*
9897 * eat newlines
9898 */
9899 if (checkkwd & CHKNL) {
9900 while (t == TNL) {
9901 parseheredoc();
9902 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009903 }
9904 }
9905
Eric Andersenc470f442003-07-28 09:56:35 +00009906 if (t != TWORD || quoteflag) {
9907 goto out;
9908 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009909
Eric Andersenc470f442003-07-28 09:56:35 +00009910 /*
9911 * check for keywords
9912 */
9913 if (checkkwd & CHKKWD) {
9914 const char *const *pp;
9915
9916 if ((pp = findkwd(wordtext))) {
9917 lasttoken = t = pp - tokname_array;
9918 TRACE(("keyword %s recognized\n", tokname(t)));
9919 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009920 }
Eric Andersenc470f442003-07-28 09:56:35 +00009921 }
9922
9923 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009924#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009925 struct alias *ap;
9926 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009927 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009928 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009929 }
Eric Andersencb57d552001-06-28 07:25:16 +00009930 goto top;
9931 }
Eric Andersen2870d962001-07-02 17:27:21 +00009932#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009933 }
Eric Andersenc470f442003-07-28 09:56:35 +00009934out:
9935 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009936#ifdef DEBUG
9937 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009938 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009939 else
Eric Andersenc470f442003-07-28 09:56:35 +00009940 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009941#endif
9942 return (t);
9943}
9944
9945
9946/*
9947 * Read the next input token.
9948 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009949 * backquotes. We set quoteflag to true if any part of the word was
9950 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009951 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009952 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009953 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009954 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009955 *
9956 * [Change comment: here documents and internal procedures]
9957 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9958 * word parsing code into a separate routine. In this case, readtoken
9959 * doesn't need to have any internal procedures, but parseword does.
9960 * We could also make parseoperator in essence the main routine, and
9961 * have parseword (readtoken1?) handle both words and redirection.]
9962 */
9963
Eric Andersen81fe1232003-07-29 06:38:40 +00009964#define NEW_xxreadtoken
9965#ifdef NEW_xxreadtoken
9966
9967/* singles must be first! */
9968static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9969
9970static const char xxreadtoken_tokens[] = {
9971 TNL, TLP, TRP, /* only single occurrence allowed */
9972 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9973 TEOF, /* corresponds to trailing nul */
9974 TAND, TOR, TENDCASE, /* if double occurrence */
9975};
9976
9977#define xxreadtoken_doubles \
9978 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9979#define xxreadtoken_singles \
9980 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9981
9982static int xxreadtoken()
9983{
9984 int c;
9985
9986 if (tokpushback) {
9987 tokpushback = 0;
9988 return lasttoken;
9989 }
9990 if (needprompt) {
9991 setprompt(2);
9992 needprompt = 0;
9993 }
9994 startlinno = plinno;
9995 for (;;) { /* until token or start of word found */
9996 c = pgetc_macro();
9997
9998 if ((c != ' ') && (c != '\t')
9999#ifdef CONFIG_ASH_ALIAS
10000 && (c != PEOA)
10001#endif
10002 ) {
10003 if (c == '#') {
10004 while ((c = pgetc()) != '\n' && c != PEOF);
10005 pungetc();
10006 } else if (c == '\\') {
10007 if (pgetc() != '\n') {
10008 pungetc();
10009 goto READTOKEN1;
10010 }
10011 startlinno = ++plinno;
10012 if (doprompt)
10013 setprompt(2);
10014 } else {
10015 const char *p
10016 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10017
10018 if (c != PEOF) {
10019 if (c == '\n') {
10020 plinno++;
10021 needprompt = doprompt;
10022 }
10023
10024 p = strchr(xxreadtoken_chars, c);
10025 if (p == NULL) {
10026 READTOKEN1:
10027 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10028 }
10029
10030 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10031 if (pgetc() == *p) { /* double occurrence? */
10032 p += xxreadtoken_doubles + 1;
10033 } else {
10034 pungetc();
10035 }
10036 }
10037 }
10038
10039 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10040 }
10041 }
10042 }
10043}
10044
10045
10046#else
Eric Andersen2870d962001-07-02 17:27:21 +000010047#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010048
Eric Andersenc470f442003-07-28 09:56:35 +000010049static int
10050xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010051{
Eric Andersencb57d552001-06-28 07:25:16 +000010052 int c;
10053
10054 if (tokpushback) {
10055 tokpushback = 0;
10056 return lasttoken;
10057 }
10058 if (needprompt) {
10059 setprompt(2);
10060 needprompt = 0;
10061 }
10062 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010063 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010064 c = pgetc_macro();
10065 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010066 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010067#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010068 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010069#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010070 continue;
10071 case '#':
10072 while ((c = pgetc()) != '\n' && c != PEOF);
10073 pungetc();
10074 continue;
10075 case '\\':
10076 if (pgetc() == '\n') {
10077 startlinno = ++plinno;
10078 if (doprompt)
10079 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010080 continue;
10081 }
10082 pungetc();
10083 goto breakloop;
10084 case '\n':
10085 plinno++;
10086 needprompt = doprompt;
10087 RETURN(TNL);
10088 case PEOF:
10089 RETURN(TEOF);
10090 case '&':
10091 if (pgetc() == '&')
10092 RETURN(TAND);
10093 pungetc();
10094 RETURN(TBACKGND);
10095 case '|':
10096 if (pgetc() == '|')
10097 RETURN(TOR);
10098 pungetc();
10099 RETURN(TPIPE);
10100 case ';':
10101 if (pgetc() == ';')
10102 RETURN(TENDCASE);
10103 pungetc();
10104 RETURN(TSEMI);
10105 case '(':
10106 RETURN(TLP);
10107 case ')':
10108 RETURN(TRP);
10109 default:
10110 goto breakloop;
10111 }
10112 }
Eric Andersenc470f442003-07-28 09:56:35 +000010113breakloop:
10114 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010115#undef RETURN
10116}
Eric Andersen81fe1232003-07-29 06:38:40 +000010117#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010118
Eric Andersencb57d552001-06-28 07:25:16 +000010119
Eric Andersencb57d552001-06-28 07:25:16 +000010120/*
10121 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10122 * is not NULL, read a here document. In the latter case, eofmark is the
10123 * word which marks the end of the document and striptabs is true if
10124 * leading tabs should be stripped from the document. The argument firstc
10125 * is the first character of the input token or document.
10126 *
10127 * Because C does not have internal subroutines, I have simulated them
10128 * using goto's to implement the subroutine linkage. The following macros
10129 * will run code that appears at the end of readtoken1.
10130 */
10131
Eric Andersen2870d962001-07-02 17:27:21 +000010132#define CHECKEND() {goto checkend; checkend_return:;}
10133#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10134#define PARSESUB() {goto parsesub; parsesub_return:;}
10135#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10136#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10137#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010138
10139static int
Eric Andersenc470f442003-07-28 09:56:35 +000010140readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010141{
Eric Andersencb57d552001-06-28 07:25:16 +000010142 int c = firstc;
10143 char *out;
10144 int len;
10145 char line[EOFMARKLEN + 1];
10146 struct nodelist *bqlist;
10147 int quotef;
10148 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010149 int varnest; /* levels of variables expansion */
10150 int arinest; /* levels of arithmetic expansion */
10151 int parenlevel; /* levels of parens in arithmetic */
10152 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010153 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010154 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010155#if __GNUC__
10156 /* Avoid longjmp clobbering */
10157 (void) &out;
10158 (void) &quotef;
10159 (void) &dblquote;
10160 (void) &varnest;
10161 (void) &arinest;
10162 (void) &parenlevel;
10163 (void) &dqvarnest;
10164 (void) &oldstyle;
10165 (void) &prevsyntax;
10166 (void) &syntax;
10167#endif
10168
10169 startlinno = plinno;
10170 dblquote = 0;
10171 if (syntax == DQSYNTAX)
10172 dblquote = 1;
10173 quotef = 0;
10174 bqlist = NULL;
10175 varnest = 0;
10176 arinest = 0;
10177 parenlevel = 0;
10178 dqvarnest = 0;
10179
10180 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010181 loop: { /* for each line, until end of word */
10182 CHECKEND(); /* set c to PEOF if at end of here document */
10183 for (;;) { /* until end of line or end of word */
10184 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10185 switch(SIT(c, syntax)) {
10186 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010187 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010188 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010189 USTPUTC(c, out);
10190 plinno++;
10191 if (doprompt)
10192 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010193 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010194 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010195 case CWORD:
10196 USTPUTC(c, out);
10197 break;
10198 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010199 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010200 USTPUTC(CTLESC, out);
10201 USTPUTC(c, out);
10202 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010203 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010204 c = pgetc2();
10205 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010206 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010207 USTPUTC('\\', out);
10208 pungetc();
10209 } else if (c == '\n') {
10210 if (doprompt)
10211 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010212 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010213 if (
10214 dblquote &&
10215 c != '\\' && c != '`' &&
10216 c != '$' && (
10217 c != '"' ||
10218 eofmark != NULL
10219 )
10220 ) {
10221 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010222 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010223 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010224 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010225 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010226 USTPUTC(c, out);
10227 quotef++;
10228 }
10229 break;
10230 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010231 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010232quotemark:
10233 if (eofmark == NULL) {
10234 USTPUTC(CTLQUOTEMARK, out);
10235 }
Eric Andersencb57d552001-06-28 07:25:16 +000010236 break;
10237 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010238 syntax = DQSYNTAX;
10239 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010240 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010241 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010242 if (eofmark != NULL && arinest == 0 &&
10243 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010244 USTPUTC(c, out);
10245 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010246 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010247 syntax = BASESYNTAX;
10248 dblquote = 0;
10249 }
10250 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010251 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010252 }
10253 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010254 case CVAR: /* '$' */
10255 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010256 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010257 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010258 if (varnest > 0) {
10259 varnest--;
10260 if (dqvarnest > 0) {
10261 dqvarnest--;
10262 }
10263 USTPUTC(CTLENDVAR, out);
10264 } else {
10265 USTPUTC(c, out);
10266 }
10267 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010268#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010269 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010270 parenlevel++;
10271 USTPUTC(c, out);
10272 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010273 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010274 if (parenlevel > 0) {
10275 USTPUTC(c, out);
10276 --parenlevel;
10277 } else {
10278 if (pgetc() == ')') {
10279 if (--arinest == 0) {
10280 USTPUTC(CTLENDARI, out);
10281 syntax = prevsyntax;
10282 if (syntax == DQSYNTAX)
10283 dblquote = 1;
10284 else
10285 dblquote = 0;
10286 } else
10287 USTPUTC(')', out);
10288 } else {
10289 /*
10290 * unbalanced parens
10291 * (don't 2nd guess - no error)
10292 */
10293 pungetc();
10294 USTPUTC(')', out);
10295 }
10296 }
10297 break;
10298#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010299 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010300 PARSEBACKQOLD();
10301 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010302 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010303 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010304 case CIGN:
10305 break;
10306 default:
10307 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010308 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010309#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010310 if (c != PEOA)
10311#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010312 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010313
Eric Andersencb57d552001-06-28 07:25:16 +000010314 }
10315 c = pgetc_macro();
10316 }
10317 }
Eric Andersenc470f442003-07-28 09:56:35 +000010318endword:
10319#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010320 if (syntax == ARISYNTAX)
10321 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010322#endif
10323 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010324 synerror("Unterminated quoted string");
10325 if (varnest != 0) {
10326 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010327 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010328 synerror("Missing '}'");
10329 }
10330 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010331 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010332 out = stackblock();
10333 if (eofmark == NULL) {
10334 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010335 && quotef == 0
10336 && len <= 2
10337 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010338 PARSEREDIR();
10339 return lasttoken = TREDIR;
10340 } else {
10341 pungetc();
10342 }
10343 }
10344 quoteflag = quotef;
10345 backquotelist = bqlist;
10346 grabstackblock(len);
10347 wordtext = out;
10348 return lasttoken = TWORD;
10349/* end of readtoken routine */
10350
10351
10352
10353/*
10354 * Check to see whether we are at the end of the here document. When this
10355 * is called, c is set to the first character of the next input line. If
10356 * we are at the end of the here document, this routine sets the c to PEOF.
10357 */
10358
Eric Andersenc470f442003-07-28 09:56:35 +000010359checkend: {
10360 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010361#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010362 if (c == PEOA) {
10363 c = pgetc2();
10364 }
10365#endif
10366 if (striptabs) {
10367 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010368 c = pgetc2();
10369 }
Eric Andersenc470f442003-07-28 09:56:35 +000010370 }
10371 if (c == *eofmark) {
10372 if (pfgets(line, sizeof line) != NULL) {
10373 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010374
Eric Andersenc470f442003-07-28 09:56:35 +000010375 p = line;
10376 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10377 if (*p == '\n' && *q == '\0') {
10378 c = PEOF;
10379 plinno++;
10380 needprompt = doprompt;
10381 } else {
10382 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010383 }
10384 }
10385 }
10386 }
Eric Andersenc470f442003-07-28 09:56:35 +000010387 goto checkend_return;
10388}
Eric Andersencb57d552001-06-28 07:25:16 +000010389
10390
10391/*
10392 * Parse a redirection operator. The variable "out" points to a string
10393 * specifying the fd to be redirected. The variable "c" contains the
10394 * first character of the redirection operator.
10395 */
10396
Eric Andersenc470f442003-07-28 09:56:35 +000010397parseredir: {
10398 char fd = *out;
10399 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010400
Eric Andersenc470f442003-07-28 09:56:35 +000010401 np = (union node *)stalloc(sizeof (struct nfile));
10402 if (c == '>') {
10403 np->nfile.fd = 1;
10404 c = pgetc();
10405 if (c == '>')
10406 np->type = NAPPEND;
10407 else if (c == '|')
10408 np->type = NCLOBBER;
10409 else if (c == '&')
10410 np->type = NTOFD;
10411 else {
10412 np->type = NTO;
10413 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010414 }
Eric Andersenc470f442003-07-28 09:56:35 +000010415 } else { /* c == '<' */
10416 np->nfile.fd = 0;
10417 switch (c = pgetc()) {
10418 case '<':
10419 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10420 np = (union node *)stalloc(sizeof (struct nhere));
10421 np->nfile.fd = 0;
10422 }
10423 np->type = NHERE;
10424 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10425 heredoc->here = np;
10426 if ((c = pgetc()) == '-') {
10427 heredoc->striptabs = 1;
10428 } else {
10429 heredoc->striptabs = 0;
10430 pungetc();
10431 }
10432 break;
10433
10434 case '&':
10435 np->type = NFROMFD;
10436 break;
10437
10438 case '>':
10439 np->type = NFROMTO;
10440 break;
10441
10442 default:
10443 np->type = NFROM;
10444 pungetc();
10445 break;
10446 }
Eric Andersencb57d552001-06-28 07:25:16 +000010447 }
Eric Andersenc470f442003-07-28 09:56:35 +000010448 if (fd != '\0')
10449 np->nfile.fd = digit_val(fd);
10450 redirnode = np;
10451 goto parseredir_return;
10452}
Eric Andersencb57d552001-06-28 07:25:16 +000010453
10454
10455/*
10456 * Parse a substitution. At this point, we have read the dollar sign
10457 * and nothing else.
10458 */
10459
Eric Andersenc470f442003-07-28 09:56:35 +000010460parsesub: {
10461 int subtype;
10462 int typeloc;
10463 int flags;
10464 char *p;
10465 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010466
Eric Andersenc470f442003-07-28 09:56:35 +000010467 c = pgetc();
10468 if (
10469 c <= PEOA_OR_PEOF ||
10470 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10471 ) {
10472 USTPUTC('$', out);
10473 pungetc();
10474 } else if (c == '(') { /* $(command) or $((arith)) */
10475 if (pgetc() == '(') {
10476#ifdef CONFIG_ASH_MATH_SUPPORT
10477 PARSEARITH();
10478#else
10479 synerror("We unsupport $((arith))");
10480#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010481 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010482 pungetc();
10483 PARSEBACKQNEW();
10484 }
10485 } else {
10486 USTPUTC(CTLVAR, out);
10487 typeloc = out - (char *)stackblock();
10488 USTPUTC(VSNORMAL, out);
10489 subtype = VSNORMAL;
10490 if (c == '{') {
10491 c = pgetc();
10492 if (c == '#') {
10493 if ((c = pgetc()) == '}')
10494 c = '#';
10495 else
10496 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010497 }
Eric Andersenc470f442003-07-28 09:56:35 +000010498 else
10499 subtype = 0;
10500 }
10501 if (c > PEOA_OR_PEOF && is_name(c)) {
10502 do {
10503 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010504 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010505 } while (c > PEOA_OR_PEOF && is_in_name(c));
10506 } else if (is_digit(c)) {
10507 do {
10508 STPUTC(c, out);
10509 c = pgetc();
10510 } while (is_digit(c));
10511 }
10512 else if (is_special(c)) {
10513 USTPUTC(c, out);
10514 c = pgetc();
10515 }
10516 else
10517badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010518
Eric Andersenc470f442003-07-28 09:56:35 +000010519 STPUTC('=', out);
10520 flags = 0;
10521 if (subtype == 0) {
10522 switch (c) {
10523 case ':':
10524 flags = VSNUL;
10525 c = pgetc();
10526 /*FALLTHROUGH*/
10527 default:
10528 p = strchr(types, c);
10529 if (p == NULL)
10530 goto badsub;
10531 subtype = p - types + VSNORMAL;
10532 break;
10533 case '%':
10534 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010535 {
10536 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010537 subtype = c == '#' ? VSTRIMLEFT :
10538 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010539 c = pgetc();
10540 if (c == cc)
10541 subtype++;
10542 else
10543 pungetc();
10544 break;
10545 }
10546 }
Eric Andersenc470f442003-07-28 09:56:35 +000010547 } else {
10548 pungetc();
10549 }
10550 if (dblquote || arinest)
10551 flags |= VSQUOTE;
10552 *((char *)stackblock() + typeloc) = subtype | flags;
10553 if (subtype != VSNORMAL) {
10554 varnest++;
10555 if (dblquote || arinest) {
10556 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010557 }
10558 }
10559 }
Eric Andersenc470f442003-07-28 09:56:35 +000010560 goto parsesub_return;
10561}
Eric Andersencb57d552001-06-28 07:25:16 +000010562
10563
10564/*
10565 * Called to parse command substitutions. Newstyle is set if the command
10566 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10567 * list of commands (passed by reference), and savelen is the number of
10568 * characters on the top of the stack which must be preserved.
10569 */
10570
Eric Andersenc470f442003-07-28 09:56:35 +000010571parsebackq: {
10572 struct nodelist **nlpp;
10573 int savepbq;
10574 union node *n;
10575 char *volatile str;
10576 struct jmploc jmploc;
10577 struct jmploc *volatile savehandler;
10578 size_t savelen;
10579 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010580#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010581 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010582#endif
10583
Eric Andersenc470f442003-07-28 09:56:35 +000010584 savepbq = parsebackquote;
10585 if (setjmp(jmploc.loc)) {
10586 if (str)
10587 ckfree(str);
10588 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010589 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010590 longjmp(handler->loc, 1);
10591 }
10592 INTOFF;
10593 str = NULL;
10594 savelen = out - (char *)stackblock();
10595 if (savelen > 0) {
10596 str = ckmalloc(savelen);
10597 memcpy(str, stackblock(), savelen);
10598 }
10599 savehandler = handler;
10600 handler = &jmploc;
10601 INTON;
10602 if (oldstyle) {
10603 /* We must read until the closing backquote, giving special
10604 treatment to some slashes, and then push the string and
10605 reread it as input, interpreting it normally. */
10606 char *pout;
10607 int pc;
10608 size_t psavelen;
10609 char *pstr;
10610
10611
10612 STARTSTACKSTR(pout);
10613 for (;;) {
10614 if (needprompt) {
10615 setprompt(2);
10616 needprompt = 0;
10617 }
10618 switch (pc = pgetc()) {
10619 case '`':
10620 goto done;
10621
10622 case '\\':
10623 if ((pc = pgetc()) == '\n') {
10624 plinno++;
10625 if (doprompt)
10626 setprompt(2);
10627 /*
10628 * If eating a newline, avoid putting
10629 * the newline into the new character
10630 * stream (via the STPUTC after the
10631 * switch).
10632 */
10633 continue;
10634 }
10635 if (pc != '\\' && pc != '`' && pc != '$'
10636 && (!dblquote || pc != '"'))
10637 STPUTC('\\', pout);
10638 if (pc > PEOA_OR_PEOF) {
10639 break;
10640 }
10641 /* fall through */
10642
10643 case PEOF:
10644#ifdef CONFIG_ASH_ALIAS
10645 case PEOA:
10646#endif
10647 startlinno = plinno;
10648 synerror("EOF in backquote substitution");
10649
10650 case '\n':
10651 plinno++;
10652 needprompt = doprompt;
10653 break;
10654
10655 default:
10656 break;
10657 }
10658 STPUTC(pc, pout);
10659 }
10660done:
10661 STPUTC('\0', pout);
10662 psavelen = pout - (char *)stackblock();
10663 if (psavelen > 0) {
10664 pstr = grabstackstr(pout);
10665 setinputstring(pstr);
10666 }
10667 }
10668 nlpp = &bqlist;
10669 while (*nlpp)
10670 nlpp = &(*nlpp)->next;
10671 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10672 (*nlpp)->next = NULL;
10673 parsebackquote = oldstyle;
10674
10675 if (oldstyle) {
10676 saveprompt = doprompt;
10677 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010678 }
10679
Eric Andersenc470f442003-07-28 09:56:35 +000010680 n = list(2);
10681
10682 if (oldstyle)
10683 doprompt = saveprompt;
10684 else {
10685 if (readtoken() != TRP)
10686 synexpect(TRP);
10687 }
10688
10689 (*nlpp)->n = n;
10690 if (oldstyle) {
10691 /*
10692 * Start reading from old file again, ignoring any pushed back
10693 * tokens left from the backquote parsing
10694 */
10695 popfile();
10696 tokpushback = 0;
10697 }
10698 while (stackblocksize() <= savelen)
10699 growstackblock();
10700 STARTSTACKSTR(out);
10701 if (str) {
10702 memcpy(out, str, savelen);
10703 STADJUST(savelen, out);
10704 INTOFF;
10705 ckfree(str);
10706 str = NULL;
10707 INTON;
10708 }
10709 parsebackquote = savepbq;
10710 handler = savehandler;
10711 if (arinest || dblquote)
10712 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10713 else
10714 USTPUTC(CTLBACKQ, out);
10715 if (oldstyle)
10716 goto parsebackq_oldreturn;
10717 else
10718 goto parsebackq_newreturn;
10719}
10720
10721#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010722/*
10723 * Parse an arithmetic expansion (indicate start of one and set state)
10724 */
Eric Andersenc470f442003-07-28 09:56:35 +000010725parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010726
Eric Andersenc470f442003-07-28 09:56:35 +000010727 if (++arinest == 1) {
10728 prevsyntax = syntax;
10729 syntax = ARISYNTAX;
10730 USTPUTC(CTLARI, out);
10731 if (dblquote)
10732 USTPUTC('"',out);
10733 else
10734 USTPUTC(' ',out);
10735 } else {
10736 /*
10737 * we collapse embedded arithmetic expansion to
10738 * parenthesis, which should be equivalent
10739 */
10740 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010741 }
Eric Andersenc470f442003-07-28 09:56:35 +000010742 goto parsearith_return;
10743}
10744#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010745
Eric Andersenc470f442003-07-28 09:56:35 +000010746} /* end of readtoken */
10747
Eric Andersencb57d552001-06-28 07:25:16 +000010748
10749
Eric Andersencb57d552001-06-28 07:25:16 +000010750/*
10751 * Returns true if the text contains nothing to expand (no dollar signs
10752 * or backquotes).
10753 */
10754
Eric Andersenc470f442003-07-28 09:56:35 +000010755static int
10756noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010757{
Eric Andersencb57d552001-06-28 07:25:16 +000010758 char *p;
10759 char c;
10760
10761 p = text;
10762 while ((c = *p++) != '\0') {
10763 if (c == CTLQUOTEMARK)
10764 continue;
10765 if (c == CTLESC)
10766 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010767 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010768 return 0;
10769 }
10770 return 1;
10771}
10772
10773
10774/*
Eric Andersenc470f442003-07-28 09:56:35 +000010775 * Return of a legal variable name (a letter or underscore followed by zero or
10776 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010777 */
10778
Eric Andersenc470f442003-07-28 09:56:35 +000010779char *
10780endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010781{
Eric Andersenc470f442003-07-28 09:56:35 +000010782 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010783
Eric Andersenc470f442003-07-28 09:56:35 +000010784 p = (char *) name;
10785 if (! is_name(*p))
10786 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010787 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010788 if (! is_in_name(*p))
10789 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010790 }
Eric Andersenc470f442003-07-28 09:56:35 +000010791 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010792}
10793
10794
10795/*
10796 * Called when an unexpected token is read during the parse. The argument
10797 * is the token that is expected, or -1 if more than one type of token can
10798 * occur at this point.
10799 */
10800
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010801static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010802{
10803 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010804 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010805
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010806 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10807 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010808 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010809 synerror(msg);
10810 /* NOTREACHED */
10811}
10812
Eric Andersenc470f442003-07-28 09:56:35 +000010813static void
10814synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010815{
Eric Andersenc470f442003-07-28 09:56:35 +000010816 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010817 /* NOTREACHED */
10818}
10819
Eric Andersencb57d552001-06-28 07:25:16 +000010820
10821/*
10822 * called by editline -- any expansions to the prompt
10823 * should be added here.
10824 */
Eric Andersenc470f442003-07-28 09:56:35 +000010825
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010826static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010827{
Eric Andersenc470f442003-07-28 09:56:35 +000010828 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010829
10830 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010831 case 1:
10832 prompt = ps1val();
10833 break;
10834 case 2:
10835 prompt = ps2val();
10836 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010837 default: /* 0 */
10838 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010839 }
10840 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010841}
10842
Eric Andersencb57d552001-06-28 07:25:16 +000010843
Eric Andersenc470f442003-07-28 09:56:35 +000010844static const char *const *findkwd(const char *s)
10845{
10846 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010847 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010848 sizeof(const char *), pstrcmp);
10849}
10850
10851/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10852
Eric Andersencb57d552001-06-28 07:25:16 +000010853/*
10854 * Code for dealing with input/output redirection.
10855 */
10856
Eric Andersenc470f442003-07-28 09:56:35 +000010857#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010858#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010859# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010860#else
10861# define PIPESIZE PIPE_BUF
10862#endif
10863
Eric Andersen62483552001-07-10 06:09:16 +000010864/*
10865 * Open a file in noclobber mode.
10866 * The code was copied from bash.
10867 */
Eric Andersenc470f442003-07-28 09:56:35 +000010868static inline int
10869noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010870{
10871 int r, fd;
10872 struct stat finfo, finfo2;
10873
10874 /*
10875 * If the file exists and is a regular file, return an error
10876 * immediately.
10877 */
10878 r = stat(fname, &finfo);
10879 if (r == 0 && S_ISREG(finfo.st_mode)) {
10880 errno = EEXIST;
10881 return -1;
10882 }
10883
10884 /*
10885 * If the file was not present (r != 0), make sure we open it
10886 * exclusively so that if it is created before we open it, our open
10887 * will fail. Make sure that we do not truncate an existing file.
10888 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10889 * file was not a regular file, we leave O_EXCL off.
10890 */
10891 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010892 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10893 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010894
10895 /* If the open failed, return the file descriptor right away. */
10896 if (fd < 0)
10897 return fd;
10898
10899 /*
10900 * OK, the open succeeded, but the file may have been changed from a
10901 * non-regular file to a regular file between the stat and the open.
10902 * We are assuming that the O_EXCL open handles the case where FILENAME
10903 * did not exist and is symlinked to an existing file between the stat
10904 * and open.
10905 */
10906
10907 /*
10908 * If we can open it and fstat the file descriptor, and neither check
10909 * revealed that it was a regular file, and the file has not been
10910 * replaced, return the file descriptor.
10911 */
Eric Andersenc470f442003-07-28 09:56:35 +000010912 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10913 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010914 return fd;
10915
10916 /* The file has been replaced. badness. */
10917 close(fd);
10918 errno = EEXIST;
10919 return -1;
10920}
Eric Andersencb57d552001-06-28 07:25:16 +000010921
10922/*
Eric Andersen62483552001-07-10 06:09:16 +000010923 * Handle here documents. Normally we fork off a process to write the
10924 * data to a pipe. If the document is short, we can stuff the data in
10925 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010926 */
10927
Eric Andersenc470f442003-07-28 09:56:35 +000010928static inline int
10929openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010930{
10931 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010932 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010933
Eric Andersen62483552001-07-10 06:09:16 +000010934 if (pipe(pip) < 0)
10935 error("Pipe call failed");
10936 if (redir->type == NHERE) {
10937 len = strlen(redir->nhere.doc->narg.text);
10938 if (len <= PIPESIZE) {
10939 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10940 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010941 }
Eric Andersencb57d552001-06-28 07:25:16 +000010942 }
Eric Andersenc470f442003-07-28 09:56:35 +000010943 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010944 close(pip[0]);
10945 signal(SIGINT, SIG_IGN);
10946 signal(SIGQUIT, SIG_IGN);
10947 signal(SIGHUP, SIG_IGN);
10948#ifdef SIGTSTP
10949 signal(SIGTSTP, SIG_IGN);
10950#endif
10951 signal(SIGPIPE, SIG_DFL);
10952 if (redir->type == NHERE)
10953 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10954 else
10955 expandhere(redir->nhere.doc, pip[1]);
10956 _exit(0);
10957 }
Eric Andersenc470f442003-07-28 09:56:35 +000010958out:
Eric Andersen62483552001-07-10 06:09:16 +000010959 close(pip[1]);
10960 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010961}
10962
Eric Andersenc470f442003-07-28 09:56:35 +000010963static int
10964openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010965{
Eric Andersencb57d552001-06-28 07:25:16 +000010966 char *fname;
10967 int f;
10968
10969 switch (redir->nfile.type) {
10970 case NFROM:
10971 fname = redir->nfile.expfname;
10972 if ((f = open(fname, O_RDONLY)) < 0)
10973 goto eopen;
10974 break;
10975 case NFROMTO:
10976 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010977 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010978 goto ecreate;
10979 break;
10980 case NTO:
10981 /* Take care of noclobber mode. */
10982 if (Cflag) {
10983 fname = redir->nfile.expfname;
10984 if ((f = noclobberopen(fname)) < 0)
10985 goto ecreate;
10986 break;
10987 }
Eric Andersenc470f442003-07-28 09:56:35 +000010988 /* FALLTHROUGH */
10989 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000010990 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010991 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010992 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010993 break;
10994 case NAPPEND:
10995 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010996 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010997 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010998 break;
10999 default:
11000#ifdef DEBUG
11001 abort();
11002#endif
11003 /* Fall through to eliminate warning. */
11004 case NTOFD:
11005 case NFROMFD:
11006 f = -1;
11007 break;
11008 case NHERE:
11009 case NXHERE:
11010 f = openhere(redir);
11011 break;
11012 }
11013
11014 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011015ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011016 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011017eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011018 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11019}
11020
Eric Andersenc470f442003-07-28 09:56:35 +000011021static inline void
11022dupredirect(union node *redir, int f)
11023{
11024 int fd = redir->nfile.fd;
11025
11026 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11027 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11028 copyfd(redir->ndup.dupfd, fd);
11029 }
11030 return;
11031 }
11032
11033 if (f != fd) {
11034 copyfd(f, fd);
11035 close(f);
11036 }
11037 return;
11038}
Eric Andersencb57d552001-06-28 07:25:16 +000011039
Eric Andersen62483552001-07-10 06:09:16 +000011040/*
11041 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11042 * old file descriptors are stashed away so that the redirection can be
11043 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11044 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011045 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011046 */
11047
Eric Andersenc470f442003-07-28 09:56:35 +000011048static void
11049redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011050{
11051 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011052 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011053 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011054 int fd;
11055 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011056 int *p;
11057 nullredirs++;
11058 if (!redir) {
11059 return;
Eric Andersen62483552001-07-10 06:09:16 +000011060 }
Eric Andersenc470f442003-07-28 09:56:35 +000011061 sv = NULL;
11062 INTOFF;
11063 if (flags & REDIR_PUSH) {
11064 struct redirtab *q;
11065 q = ckmalloc(sizeof (struct redirtab));
11066 q->next = redirlist;
11067 redirlist = q;
11068 q->nullredirs = nullredirs - 1;
11069 for (i = 0 ; i < 10 ; i++)
11070 q->renamed[i] = EMPTY;
11071 nullredirs = 0;
11072 sv = q;
11073 }
11074 n = redir;
11075 do {
Eric Andersen62483552001-07-10 06:09:16 +000011076 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011077 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011078 n->ndup.dupfd == fd)
11079 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011080
Eric Andersen62483552001-07-10 06:09:16 +000011081 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011082 if (fd == newfd)
11083 continue;
11084 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11085 i = fcntl(fd, F_DUPFD, 10);
11086
11087 if (i == -1) {
11088 i = errno;
11089 if (i != EBADF) {
11090 close(newfd);
11091 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011092 error("%d: %m", fd);
11093 /* NOTREACHED */
11094 }
Eric Andersenc470f442003-07-28 09:56:35 +000011095 } else {
11096 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011097 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011098 }
Eric Andersenc470f442003-07-28 09:56:35 +000011099 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011100 close(fd);
11101 }
Eric Andersenc470f442003-07-28 09:56:35 +000011102 dupredirect(n, newfd);
11103 } while ((n = n->nfile.next));
11104 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011105 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11106 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011107}
11108
11109
Eric Andersencb57d552001-06-28 07:25:16 +000011110/*
11111 * Undo the effects of the last redirection.
11112 */
11113
Eric Andersenc470f442003-07-28 09:56:35 +000011114void
11115popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011116{
Eric Andersenc470f442003-07-28 09:56:35 +000011117 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011118 int i;
11119
Eric Andersenc470f442003-07-28 09:56:35 +000011120 if (--nullredirs >= 0)
11121 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011122 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011123 rp = redirlist;
11124 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011125 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011126 if (!drop) {
11127 close(i);
11128 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011129 }
Eric Andersenc470f442003-07-28 09:56:35 +000011130 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011131 }
11132 }
11133 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011134 nullredirs = rp->nullredirs;
11135 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011136 INTON;
11137}
11138
11139/*
Eric Andersenc470f442003-07-28 09:56:35 +000011140 * Undo all redirections. Called on error or interrupt.
11141 */
11142
11143/*
Eric Andersencb57d552001-06-28 07:25:16 +000011144 * Discard all saved file descriptors.
11145 */
11146
Eric Andersenc470f442003-07-28 09:56:35 +000011147void
11148clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011149{
Eric Andersenc470f442003-07-28 09:56:35 +000011150 for (;;) {
11151 nullredirs = 0;
11152 if (!redirlist)
11153 break;
11154 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011155 }
Eric Andersencb57d552001-06-28 07:25:16 +000011156}
11157
11158
Eric Andersencb57d552001-06-28 07:25:16 +000011159/*
11160 * Copy a file descriptor to be >= to. Returns -1
11161 * if the source file descriptor is closed, EMPTY if there are no unused
11162 * file descriptors left.
11163 */
11164
Eric Andersenc470f442003-07-28 09:56:35 +000011165int
11166copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011167{
11168 int newfd;
11169
11170 newfd = fcntl(from, F_DUPFD, to);
11171 if (newfd < 0) {
11172 if (errno == EMFILE)
11173 return EMPTY;
11174 else
Eric Andersen2870d962001-07-02 17:27:21 +000011175 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011176 }
11177 return newfd;
11178}
11179
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011180
Eric Andersenc470f442003-07-28 09:56:35 +000011181int
11182redirectsafe(union node *redir, int flags)
11183{
11184 int err;
11185 volatile int saveint;
11186 struct jmploc *volatile savehandler = handler;
11187 struct jmploc jmploc;
11188
11189 SAVEINT(saveint);
11190 if (!(err = setjmp(jmploc.loc) * 2)) {
11191 handler = &jmploc;
11192 redirect(redir, flags);
11193 }
11194 handler = savehandler;
11195 if (err && exception != EXERROR)
11196 longjmp(handler->loc, 1);
11197 RESTOREINT(saveint);
11198 return err;
11199}
11200
11201/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11202
11203#ifdef DEBUG
11204static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011205static void shcmd(union node *, FILE *);
11206static void sharg(union node *, FILE *);
11207static void indent(int, char *, FILE *);
11208static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011209
11210
Eric Andersenc470f442003-07-28 09:56:35 +000011211void
11212showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011213{
11214 trputs("showtree called\n");
11215 shtree(n, 1, NULL, stdout);
11216}
Eric Andersencb57d552001-06-28 07:25:16 +000011217
Eric Andersenc470f442003-07-28 09:56:35 +000011218
11219static void
11220shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011221{
11222 struct nodelist *lp;
11223 const char *s;
11224
11225 if (n == NULL)
11226 return;
11227
11228 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011229 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011230 case NSEMI:
11231 s = "; ";
11232 goto binop;
11233 case NAND:
11234 s = " && ";
11235 goto binop;
11236 case NOR:
11237 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011238binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011239 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011240 /* if (ind < 0) */
11241 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011242 shtree(n->nbinary.ch2, ind, NULL, fp);
11243 break;
11244 case NCMD:
11245 shcmd(n, fp);
11246 if (ind >= 0)
11247 putc('\n', fp);
11248 break;
11249 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011250 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011251 shcmd(lp->n, fp);
11252 if (lp->next)
11253 fputs(" | ", fp);
11254 }
11255 if (n->npipe.backgnd)
11256 fputs(" &", fp);
11257 if (ind >= 0)
11258 putc('\n', fp);
11259 break;
11260 default:
11261 fprintf(fp, "<node type %d>", n->type);
11262 if (ind >= 0)
11263 putc('\n', fp);
11264 break;
11265 }
11266}
11267
11268
Eric Andersenc470f442003-07-28 09:56:35 +000011269static void
11270shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011271{
11272 union node *np;
11273 int first;
11274 const char *s;
11275 int dftfd;
11276
11277 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011278 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11279 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011280 putchar(' ');
11281 sharg(np, fp);
11282 first = 0;
11283 }
Eric Andersenc470f442003-07-28 09:56:35 +000011284 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11285 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011286 putchar(' ');
11287 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011288 case NTO: s = ">"; dftfd = 1; break;
11289 case NCLOBBER: s = ">|"; dftfd = 1; break;
11290 case NAPPEND: s = ">>"; dftfd = 1; break;
11291 case NTOFD: s = ">&"; dftfd = 1; break;
11292 case NFROM: s = "<"; dftfd = 0; break;
11293 case NFROMFD: s = "<&"; dftfd = 0; break;
11294 case NFROMTO: s = "<>"; dftfd = 0; break;
11295 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011296 }
11297 if (np->nfile.fd != dftfd)
11298 fprintf(fp, "%d", np->nfile.fd);
11299 fputs(s, fp);
11300 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11301 fprintf(fp, "%d", np->ndup.dupfd);
11302 } else {
11303 sharg(np->nfile.fname, fp);
11304 }
11305 first = 0;
11306 }
11307}
11308
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011309
Eric Andersenc470f442003-07-28 09:56:35 +000011310
11311static void
11312sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011313{
Eric Andersencb57d552001-06-28 07:25:16 +000011314 char *p;
11315 struct nodelist *bqlist;
11316 int subtype;
11317
11318 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011319 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011320 abort();
11321 }
11322 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011323 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011324 switch (*p) {
11325 case CTLESC:
11326 putc(*++p, fp);
11327 break;
11328 case CTLVAR:
11329 putc('$', fp);
11330 putc('{', fp);
11331 subtype = *++p;
11332 if (subtype == VSLENGTH)
11333 putc('#', fp);
11334
11335 while (*p != '=')
11336 putc(*p++, fp);
11337
11338 if (subtype & VSNUL)
11339 putc(':', fp);
11340
11341 switch (subtype & VSTYPE) {
11342 case VSNORMAL:
11343 putc('}', fp);
11344 break;
11345 case VSMINUS:
11346 putc('-', fp);
11347 break;
11348 case VSPLUS:
11349 putc('+', fp);
11350 break;
11351 case VSQUESTION:
11352 putc('?', fp);
11353 break;
11354 case VSASSIGN:
11355 putc('=', fp);
11356 break;
11357 case VSTRIMLEFT:
11358 putc('#', fp);
11359 break;
11360 case VSTRIMLEFTMAX:
11361 putc('#', fp);
11362 putc('#', fp);
11363 break;
11364 case VSTRIMRIGHT:
11365 putc('%', fp);
11366 break;
11367 case VSTRIMRIGHTMAX:
11368 putc('%', fp);
11369 putc('%', fp);
11370 break;
11371 case VSLENGTH:
11372 break;
11373 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011374 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011375 }
11376 break;
11377 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011378 putc('}', fp);
11379 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011380 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011381 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011382 putc('$', fp);
11383 putc('(', fp);
11384 shtree(bqlist->n, -1, NULL, fp);
11385 putc(')', fp);
11386 break;
11387 default:
11388 putc(*p, fp);
11389 break;
11390 }
11391 }
11392}
11393
11394
Eric Andersenc470f442003-07-28 09:56:35 +000011395static void
11396indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011397{
11398 int i;
11399
Eric Andersenc470f442003-07-28 09:56:35 +000011400 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011401 if (pfx && i == amount - 1)
11402 fputs(pfx, fp);
11403 putc('\t', fp);
11404 }
11405}
Eric Andersencb57d552001-06-28 07:25:16 +000011406
Eric Andersenc470f442003-07-28 09:56:35 +000011407
11408
11409/*
11410 * Debugging stuff.
11411 */
11412
11413
Eric Andersencb57d552001-06-28 07:25:16 +000011414FILE *tracefile;
11415
Eric Andersencb57d552001-06-28 07:25:16 +000011416
Eric Andersenc470f442003-07-28 09:56:35 +000011417void
11418trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011419{
Eric Andersenc470f442003-07-28 09:56:35 +000011420 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011421 return;
11422 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011423}
11424
Eric Andersenc470f442003-07-28 09:56:35 +000011425void
11426trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011427{
11428 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011429
Eric Andersenc470f442003-07-28 09:56:35 +000011430 if (debug != 1)
11431 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011432 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011433 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011434 va_end(va);
11435}
11436
Eric Andersenc470f442003-07-28 09:56:35 +000011437void
11438tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011439{
Eric Andersenc470f442003-07-28 09:56:35 +000011440 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011441 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011442 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011443}
11444
11445
Eric Andersenc470f442003-07-28 09:56:35 +000011446void
11447trputs(const char *s)
11448{
11449 if (debug != 1)
11450 return;
11451 fputs(s, tracefile);
11452}
11453
11454
11455static void
11456trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011457{
11458 char *p;
11459 char c;
11460
Eric Andersenc470f442003-07-28 09:56:35 +000011461 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011462 return;
11463 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011464 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011465 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011466 case '\n': c = 'n'; goto backslash;
11467 case '\t': c = 't'; goto backslash;
11468 case '\r': c = 'r'; goto backslash;
11469 case '"': c = '"'; goto backslash;
11470 case '\\': c = '\\'; goto backslash;
11471 case CTLESC: c = 'e'; goto backslash;
11472 case CTLVAR: c = 'v'; goto backslash;
11473 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11474 case CTLBACKQ: c = 'q'; goto backslash;
11475 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11476backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011477 putc(c, tracefile);
11478 break;
11479 default:
11480 if (*p >= ' ' && *p <= '~')
11481 putc(*p, tracefile);
11482 else {
11483 putc('\\', tracefile);
11484 putc(*p >> 6 & 03, tracefile);
11485 putc(*p >> 3 & 07, tracefile);
11486 putc(*p & 07, tracefile);
11487 }
11488 break;
11489 }
11490 }
11491 putc('"', tracefile);
11492}
11493
11494
Eric Andersenc470f442003-07-28 09:56:35 +000011495void
11496trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011497{
Eric Andersenc470f442003-07-28 09:56:35 +000011498 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011499 return;
11500 while (*ap) {
11501 trstring(*ap++);
11502 if (*ap)
11503 putc(' ', tracefile);
11504 else
11505 putc('\n', tracefile);
11506 }
Eric Andersencb57d552001-06-28 07:25:16 +000011507}
11508
11509
Eric Andersenc470f442003-07-28 09:56:35 +000011510void
11511opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011512{
Eric Andersencb57d552001-06-28 07:25:16 +000011513 char s[100];
11514#ifdef O_APPEND
11515 int flags;
11516#endif
11517
Eric Andersenc470f442003-07-28 09:56:35 +000011518 if (debug != 1) {
11519 if (tracefile)
11520 fflush(tracefile);
11521 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011522 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011523 }
Eric Andersenc470f442003-07-28 09:56:35 +000011524 scopy("./trace", s);
11525 if (tracefile) {
11526 if (!freopen(s, "a", tracefile)) {
11527 fprintf(stderr, "Can't re-open %s\n", s);
11528 debug = 0;
11529 return;
11530 }
11531 } else {
11532 if ((tracefile = fopen(s, "a")) == NULL) {
11533 fprintf(stderr, "Can't open %s\n", s);
11534 debug = 0;
11535 return;
11536 }
11537 }
Eric Andersencb57d552001-06-28 07:25:16 +000011538#ifdef O_APPEND
11539 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11540 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11541#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011542 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011543 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011544}
Eric Andersenc470f442003-07-28 09:56:35 +000011545#endif /* DEBUG */
11546
11547
11548/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11549
11550/*
11551 * Sigmode records the current value of the signal handlers for the various
11552 * modes. A value of zero means that the current handler is not known.
11553 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11554 */
11555
11556#define S_DFL 1 /* default signal handling (SIG_DFL) */
11557#define S_CATCH 2 /* signal is caught */
11558#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11559#define S_HARD_IGN 4 /* signal is ignored permenantly */
11560#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11561
Eric Andersencb57d552001-06-28 07:25:16 +000011562
11563
11564/*
Eric Andersencb57d552001-06-28 07:25:16 +000011565 * The trap builtin.
11566 */
11567
Eric Andersenc470f442003-07-28 09:56:35 +000011568int
11569trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011570{
11571 char *action;
11572 char **ap;
11573 int signo;
11574
Eric Andersenc470f442003-07-28 09:56:35 +000011575 nextopt(nullstr);
11576 ap = argptr;
11577 if (!*ap) {
11578 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011579 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011580 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011581
Eric Andersenc470f442003-07-28 09:56:35 +000011582 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011583 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011584 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011585 out1fmt("trap -- %s %s\n",
11586 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011587 }
11588 }
11589 return 0;
11590 }
Eric Andersenc470f442003-07-28 09:56:35 +000011591 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011592 action = NULL;
11593 else
11594 action = *ap++;
11595 while (*ap) {
11596 if ((signo = decode_signal(*ap, 0)) < 0)
11597 error("%s: bad trap", *ap);
11598 INTOFF;
11599 if (action) {
11600 if (action[0] == '-' && action[1] == '\0')
11601 action = NULL;
11602 else
Eric Andersenc470f442003-07-28 09:56:35 +000011603 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011604 }
Eric Andersenc470f442003-07-28 09:56:35 +000011605 if (trap[signo])
11606 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011607 trap[signo] = action;
11608 if (signo != 0)
11609 setsignal(signo);
11610 INTON;
11611 ap++;
11612 }
11613 return 0;
11614}
11615
11616
Eric Andersenc470f442003-07-28 09:56:35 +000011617/*
11618 * Clear traps on a fork.
11619 */
11620
11621void
11622clear_traps(void)
11623{
11624 char **tp;
11625
11626 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11627 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11628 INTOFF;
11629 ckfree(*tp);
11630 *tp = NULL;
11631 if (tp != &trap[0])
11632 setsignal(tp - trap);
11633 INTON;
11634 }
11635 }
11636}
11637
11638
Eric Andersencb57d552001-06-28 07:25:16 +000011639/*
11640 * Set the signal handler for the specified signal. The routine figures
11641 * out what it should be set to.
11642 */
11643
Eric Andersenc470f442003-07-28 09:56:35 +000011644void
11645setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011646{
11647 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011648 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011649 struct sigaction act;
11650
11651 if ((t = trap[signo]) == NULL)
11652 action = S_DFL;
11653 else if (*t != '\0')
11654 action = S_CATCH;
11655 else
11656 action = S_IGN;
11657 if (rootshell && action == S_DFL) {
11658 switch (signo) {
11659 case SIGINT:
11660 if (iflag || minusc || sflag == 0)
11661 action = S_CATCH;
11662 break;
11663 case SIGQUIT:
11664#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011665 if (debug)
11666 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011667#endif
11668 /* FALLTHROUGH */
11669 case SIGTERM:
11670 if (iflag)
11671 action = S_IGN;
11672 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011673#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011674 case SIGTSTP:
11675 case SIGTTOU:
11676 if (mflag)
11677 action = S_IGN;
11678 break;
11679#endif
11680 }
11681 }
11682
11683 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011684 tsig = *t;
11685 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011686 /*
11687 * current setting unknown
11688 */
11689 if (sigaction(signo, 0, &act) == -1) {
11690 /*
11691 * Pretend it worked; maybe we should give a warning
11692 * here, but other shells don't. We don't alter
11693 * sigmode, so that we retry every time.
11694 */
11695 return;
11696 }
11697 if (act.sa_handler == SIG_IGN) {
11698 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011699 signo == SIGTTIN || signo == SIGTTOU)) {
11700 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011701 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011702 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011703 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011704 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011705 }
11706 }
Eric Andersenc470f442003-07-28 09:56:35 +000011707 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011708 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011709 switch (action) {
11710 case S_CATCH:
11711 act.sa_handler = onsig;
11712 break;
11713 case S_IGN:
11714 act.sa_handler = SIG_IGN;
11715 break;
11716 default:
11717 act.sa_handler = SIG_DFL;
11718 }
Eric Andersencb57d552001-06-28 07:25:16 +000011719 *t = action;
11720 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011721 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011722 sigaction(signo, &act, 0);
11723}
11724
11725/*
11726 * Ignore a signal.
11727 */
11728
Eric Andersenc470f442003-07-28 09:56:35 +000011729void
11730ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011731{
11732 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11733 signal(signo, SIG_IGN);
11734 }
11735 sigmode[signo - 1] = S_HARD_IGN;
11736}
11737
11738
Eric Andersencb57d552001-06-28 07:25:16 +000011739/*
11740 * Signal handler.
11741 */
11742
Eric Andersenc470f442003-07-28 09:56:35 +000011743void
11744onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011745{
Eric Andersencb57d552001-06-28 07:25:16 +000011746 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011747 pendingsigs = signo;
11748
11749 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11750 if (!suppressint)
11751 onint();
11752 intpending = 1;
11753 }
Eric Andersencb57d552001-06-28 07:25:16 +000011754}
11755
11756
Eric Andersencb57d552001-06-28 07:25:16 +000011757/*
11758 * Called to execute a trap. Perhaps we should avoid entering new trap
11759 * handlers while we are executing a trap handler.
11760 */
11761
Eric Andersenc470f442003-07-28 09:56:35 +000011762void
11763dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011764{
Eric Andersenc470f442003-07-28 09:56:35 +000011765 char *p;
11766 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011767 int savestatus;
11768
Eric Andersenc470f442003-07-28 09:56:35 +000011769 savestatus = exitstatus;
11770 q = gotsig;
11771 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11772 *p = 0;
11773 p = trap[p - q + 1];
11774 if (!p)
11775 continue;
11776 evalstring(p, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011777 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011778 }
Eric Andersencb57d552001-06-28 07:25:16 +000011779}
11780
Eric Andersenc470f442003-07-28 09:56:35 +000011781
Eric Andersenc470f442003-07-28 09:56:35 +000011782/*
11783 * Controls whether the shell is interactive or not.
11784 */
11785
Eric Andersenc470f442003-07-28 09:56:35 +000011786void
11787setinteractive(int on)
11788{
11789 static int is_interactive;
11790
11791 if (++on == is_interactive)
11792 return;
11793 is_interactive = on;
11794 setsignal(SIGINT);
11795 setsignal(SIGQUIT);
11796 setsignal(SIGTERM);
11797#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11798 if(is_interactive > 1) {
11799 /* Looks like they want an interactive shell */
11800 static int do_banner;
11801
11802 if(!do_banner) {
11803 out1fmt(
11804 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11805 "Enter 'help' for a list of built-in commands.\n\n");
11806 do_banner++;
11807 }
11808 }
11809#endif
11810}
11811
11812
11813#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11814/*** List the available builtins ***/
11815
11816static int helpcmd(int argc, char **argv)
11817{
11818 int col, i;
11819
11820 out1fmt("\nBuilt-in commands:\n-------------------\n");
11821 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11822 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11823 builtincmd[i].name + 1);
11824 if (col > 60) {
11825 out1fmt("\n");
11826 col = 0;
11827 }
11828 }
11829#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11830 {
11831 extern const struct BB_applet applets[];
11832 extern const size_t NUM_APPLETS;
11833
11834 for (i = 0; i < NUM_APPLETS; i++) {
11835
11836 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11837 if (col > 60) {
11838 out1fmt("\n");
11839 col = 0;
11840 }
11841 }
11842 }
11843#endif
11844 out1fmt("\n\n");
11845 return EXIT_SUCCESS;
11846}
11847#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11848
Eric Andersencb57d552001-06-28 07:25:16 +000011849/*
11850 * Called to exit the shell.
11851 */
11852
Eric Andersenc470f442003-07-28 09:56:35 +000011853void
11854exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011855{
Eric Andersenc470f442003-07-28 09:56:35 +000011856 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011857 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011858 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011859
Eric Andersenc470f442003-07-28 09:56:35 +000011860 status = exitstatus;
11861 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11862 if (setjmp(loc.loc)) {
11863 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011864 }
Eric Andersenc470f442003-07-28 09:56:35 +000011865 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011866 if ((p = trap[0]) != NULL && *p != '\0') {
11867 trap[0] = NULL;
11868 evalstring(p, 0);
11869 }
Eric Andersencb57d552001-06-28 07:25:16 +000011870 flushall();
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011871#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11872 if (iflag && rootshell) {
11873 const char *hp = lookupvar("HISTFILE");
11874
11875 if(hp != NULL )
11876 save_history ( hp );
11877 }
11878#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011879out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011880 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011881 /* NOTREACHED */
11882}
11883
11884static int decode_signal(const char *string, int minsig)
11885{
11886 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011887 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011888
Eric Andersen34506362001-08-02 05:02:46 +000011889 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011890}
Eric Andersen34506362001-08-02 05:02:46 +000011891
Eric Andersenc470f442003-07-28 09:56:35 +000011892/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11893
11894static struct var *vartab[VTABSIZE];
11895
11896static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011897static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011898
11899/*
11900 * Initialize the varable symbol tables and import the environment
11901 */
11902
Eric Andersenc470f442003-07-28 09:56:35 +000011903
11904#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011905/*
Eric Andersenc470f442003-07-28 09:56:35 +000011906 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011907 */
11908
Eric Andersenc470f442003-07-28 09:56:35 +000011909int
11910setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011911{
Eric Andersenc470f442003-07-28 09:56:35 +000011912 int err;
11913 volatile int saveint;
11914 struct jmploc *volatile savehandler = handler;
11915 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011916
Eric Andersenc470f442003-07-28 09:56:35 +000011917 SAVEINT(saveint);
11918 if (setjmp(jmploc.loc))
11919 err = 1;
11920 else {
11921 handler = &jmploc;
11922 setvar(name, val, flags);
11923 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011924 }
Eric Andersenc470f442003-07-28 09:56:35 +000011925 handler = savehandler;
11926 RESTOREINT(saveint);
11927 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011928}
Eric Andersenc470f442003-07-28 09:56:35 +000011929#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011930
11931/*
11932 * Set the value of a variable. The flags argument is ored with the
11933 * flags of the variable. If val is NULL, the variable is unset.
11934 */
11935
Eric Andersenc470f442003-07-28 09:56:35 +000011936static void
11937setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011938{
Eric Andersenc470f442003-07-28 09:56:35 +000011939 char *p, *q;
11940 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011941 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011942 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011943
Eric Andersenc470f442003-07-28 09:56:35 +000011944 q = endofname(name);
11945 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011946 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011947 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011948 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011949 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011950 if (val == NULL) {
11951 flags |= VUNSET;
11952 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011953 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011954 }
11955 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011956 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11957 *p++ = '\0';
11958 if (vallen) {
11959 p[-1] = '=';
11960 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011961 }
Eric Andersenc470f442003-07-28 09:56:35 +000011962 *p = '\0';
11963 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011964 INTON;
11965}
11966
11967
Eric Andersencb57d552001-06-28 07:25:16 +000011968/*
11969 * Same as setvar except that the variable and value are passed in
11970 * the first argument as name=value. Since the first argument will
11971 * be actually stored in the table, it should not be a string that
11972 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000011973 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000011974 */
11975
Eric Andersenc470f442003-07-28 09:56:35 +000011976void
11977setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011978{
11979 struct var *vp, **vpp;
11980
11981 vpp = hashvar(s);
11982 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000011983 vp = *findvar(vpp, s);
11984 if (vp) {
Eric Andersencb57d552001-06-28 07:25:16 +000011985 if (vp->flags & VREADONLY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011986 if (flags & VNOSAVE)
11987 free(s);
11988 error("%.*s: is read only", strchrnul(s, '=') - s, s);
Eric Andersencb57d552001-06-28 07:25:16 +000011989 }
Eric Andersenc470f442003-07-28 09:56:35 +000011990
11991 if (flags & VNOSET)
11992 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011993
11994 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000011995 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000011996
Eric Andersenc470f442003-07-28 09:56:35 +000011997 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11998 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011999
Eric Andersenc470f442003-07-28 09:56:35 +000012000 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12001 } else {
12002 if (flags & VNOSET)
12003 return;
12004 /* not found */
12005 vp = ckmalloc(sizeof (*vp));
12006 vp->next = *vpp;
12007 vp->func = NULL;
12008 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012009 }
Eric Andersenc470f442003-07-28 09:56:35 +000012010 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12011 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012012 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012013 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012014}
12015
12016
Eric Andersencb57d552001-06-28 07:25:16 +000012017/*
12018 * Process a linked list of variable assignments.
12019 */
12020
Eric Andersenc470f442003-07-28 09:56:35 +000012021static void
12022listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012023{
Eric Andersenc470f442003-07-28 09:56:35 +000012024 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012025
Eric Andersenc470f442003-07-28 09:56:35 +000012026 if (!lp)
12027 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012028 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012029 do {
12030 setvareq(lp->text, flags);
12031 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012032 INTON;
12033}
12034
12035
Eric Andersencb57d552001-06-28 07:25:16 +000012036/*
12037 * Find the value of a variable. Returns NULL if not set.
12038 */
12039
Eric Andersenc470f442003-07-28 09:56:35 +000012040static char *
12041lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012042{
Eric Andersencb57d552001-06-28 07:25:16 +000012043 struct var *v;
12044
12045 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
Eric Andersenc470f442003-07-28 09:56:35 +000012046 return strchrnul(v->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012047 }
12048 return NULL;
12049}
12050
12051
Eric Andersencb57d552001-06-28 07:25:16 +000012052/*
12053 * Search the environment of a builtin command.
12054 */
12055
Eric Andersenc470f442003-07-28 09:56:35 +000012056static char *
12057bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012058{
Eric Andersenc470f442003-07-28 09:56:35 +000012059 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012060
Eric Andersenc470f442003-07-28 09:56:35 +000012061 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012062 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012063 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012064 }
12065 return lookupvar(name);
12066}
12067
12068
Eric Andersencb57d552001-06-28 07:25:16 +000012069/*
Eric Andersenc470f442003-07-28 09:56:35 +000012070 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012071 */
12072
Eric Andersenc470f442003-07-28 09:56:35 +000012073static char **
12074listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012075{
Eric Andersencb57d552001-06-28 07:25:16 +000012076 struct var **vpp;
12077 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012078 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012079 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012080
Eric Andersenc470f442003-07-28 09:56:35 +000012081 STARTSTACKSTR(ep);
12082 vpp = vartab;
12083 mask = on | off;
12084 do {
12085 for (vp = *vpp ; vp ; vp = vp->next)
12086 if ((vp->flags & mask) == on) {
12087 if (ep == stackstrend())
12088 ep = growstackstr();
12089 *ep++ = (char *) vp->text;
12090 }
12091 } while (++vpp < vartab + VTABSIZE);
12092 if (ep == stackstrend())
12093 ep = growstackstr();
12094 if (end)
12095 *end = ep;
12096 *ep++ = NULL;
12097 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012098}
12099
12100
12101/*
Eric Andersenc470f442003-07-28 09:56:35 +000012102 * POSIX requires that 'set' (but not export or readonly) output the
12103 * variables in lexicographic order - by the locale's collating order (sigh).
12104 * Maybe we could keep them in an ordered balanced binary tree
12105 * instead of hashed lists.
12106 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012107 */
12108
Eric Andersenc470f442003-07-28 09:56:35 +000012109static int
12110showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012111{
Eric Andersenc470f442003-07-28 09:56:35 +000012112 const char *sep;
12113 char **ep, **epend;
12114
12115 ep = listvars(on, off, &epend);
12116 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12117
12118 sep = *sep_prefix ? spcstr : sep_prefix;
12119
12120 for (; ep < epend; ep++) {
12121 const char *p;
12122 const char *q;
12123
12124 p = strchrnul(*ep, '=');
12125 q = nullstr;
12126 if (*p)
12127 q = single_quote(++p);
12128
12129 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12130 }
12131
Eric Andersencb57d552001-06-28 07:25:16 +000012132 return 0;
12133}
12134
12135
12136
12137/*
12138 * The export and readonly commands.
12139 */
12140
Eric Andersenc470f442003-07-28 09:56:35 +000012141static int
12142exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012143{
12144 struct var *vp;
12145 char *name;
12146 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012147 char **aptr;
12148 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12149 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012150
Eric Andersenc470f442003-07-28 09:56:35 +000012151 notp = nextopt("p") - 'p';
12152 if (notp && ((name = *(aptr = argptr)))) {
12153 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012154 if ((p = strchr(name, '=')) != NULL) {
12155 p++;
12156 } else {
12157 if ((vp = *findvar(hashvar(name), name))) {
12158 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012159 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012160 }
12161 }
12162 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012163 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012164 } else {
12165 showvars(argv[0], flag, 0);
12166 }
12167 return 0;
12168}
12169
Eric Andersen34506362001-08-02 05:02:46 +000012170
Eric Andersencb57d552001-06-28 07:25:16 +000012171/*
Eric Andersencb57d552001-06-28 07:25:16 +000012172 * Make a variable a local variable. When a variable is made local, it's
12173 * value and flags are saved in a localvar structure. The saved values
12174 * will be restored when the shell function returns. We handle the name
12175 * "-" as a special case.
12176 */
12177
Eric Andersenc470f442003-07-28 09:56:35 +000012178static inline void
12179mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012180{
Eric Andersencb57d552001-06-28 07:25:16 +000012181 struct localvar *lvp;
12182 struct var **vpp;
12183 struct var *vp;
12184
12185 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012186 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012187 if (name[0] == '-' && name[1] == '\0') {
12188 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012189 p = ckmalloc(sizeof(optlist));
12190 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012191 vp = NULL;
12192 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012193 char *eq;
12194
Eric Andersencb57d552001-06-28 07:25:16 +000012195 vpp = hashvar(name);
12196 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012197 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012198 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012199 if (eq)
12200 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012201 else
12202 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012203 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012204 lvp->flags = VUNSET;
12205 } else {
12206 lvp->text = vp->text;
12207 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012208 vp->flags |= VSTRFIXED|VTEXTFIXED;
12209 if (eq)
12210 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012211 }
12212 }
12213 lvp->vp = vp;
12214 lvp->next = localvars;
12215 localvars = lvp;
12216 INTON;
12217}
12218
Eric Andersenc470f442003-07-28 09:56:35 +000012219/*
12220 * The "local" command.
12221 */
12222
12223static int
12224localcmd(int argc, char **argv)
12225{
12226 char *name;
12227
12228 argv = argptr;
12229 while ((name = *argv++) != NULL) {
12230 mklocal(name);
12231 }
12232 return 0;
12233}
12234
12235
Eric Andersencb57d552001-06-28 07:25:16 +000012236/*
12237 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012238 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012239 */
12240
Eric Andersenc470f442003-07-28 09:56:35 +000012241static void
12242poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012243{
Eric Andersencb57d552001-06-28 07:25:16 +000012244 struct localvar *lvp;
12245 struct var *vp;
12246
12247 while ((lvp = localvars) != NULL) {
12248 localvars = lvp->next;
12249 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012250 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12251 if (vp == NULL) { /* $- saved */
12252 memcpy(optlist, lvp->text, sizeof(optlist));
12253 ckfree(lvp->text);
12254 optschanged();
12255 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12256 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012257 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012258 if (vp->func)
12259 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12260 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12261 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012262 vp->flags = lvp->flags;
12263 vp->text = lvp->text;
12264 }
Eric Andersenc470f442003-07-28 09:56:35 +000012265 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012266 }
12267}
12268
12269
Eric Andersencb57d552001-06-28 07:25:16 +000012270/*
12271 * The unset builtin command. We unset the function before we unset the
12272 * variable to allow a function to be unset when there is a readonly variable
12273 * with the same name.
12274 */
12275
Eric Andersenc470f442003-07-28 09:56:35 +000012276int
12277unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012278{
12279 char **ap;
12280 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012281 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012282 int ret = 0;
12283
12284 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012285 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012286 }
Eric Andersencb57d552001-06-28 07:25:16 +000012287
Eric Andersenc470f442003-07-28 09:56:35 +000012288 for (ap = argptr; *ap ; ap++) {
12289 if (flag != 'f') {
12290 i = unsetvar(*ap);
12291 ret |= i;
12292 if (!(i & 2))
12293 continue;
12294 }
12295 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012296 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012297 }
Eric Andersenc470f442003-07-28 09:56:35 +000012298 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012299}
12300
12301
12302/*
12303 * Unset the specified variable.
12304 */
12305
Eric Andersenc470f442003-07-28 09:56:35 +000012306int
12307unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012308{
Eric Andersencb57d552001-06-28 07:25:16 +000012309 struct var **vpp;
12310 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012311 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012312
12313 vpp = findvar(hashvar(s), s);
12314 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012315 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012316 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012317 int flags = vp->flags;
12318
12319 retval = 1;
12320 if (flags & VREADONLY)
12321 goto out;
12322 if (flags & VUNSET)
12323 goto ok;
12324 if ((flags & VSTRFIXED) == 0) {
12325 INTOFF;
12326 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12327 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012328 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012329 ckfree(vp);
12330 INTON;
12331 } else {
12332 setvar(s, 0, 0);
12333 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012334 }
Eric Andersenc470f442003-07-28 09:56:35 +000012335ok:
12336 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012337 }
12338
Eric Andersenc470f442003-07-28 09:56:35 +000012339out:
12340 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012341}
12342
12343
12344
12345/*
12346 * Find the appropriate entry in the hash table from the name.
12347 */
12348
Eric Andersenc470f442003-07-28 09:56:35 +000012349static struct var **
12350hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012351{
Eric Andersencb57d552001-06-28 07:25:16 +000012352 unsigned int hashval;
12353
12354 hashval = ((unsigned char) *p) << 4;
12355 while (*p && *p != '=')
12356 hashval += (unsigned char) *p++;
12357 return &vartab[hashval % VTABSIZE];
12358}
12359
12360
12361
12362/*
Eric Andersenc470f442003-07-28 09:56:35 +000012363 * Compares two strings up to the first = or '\0'. The first
12364 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012365 * either '=' or '\0'.
12366 */
12367
Eric Andersenc470f442003-07-28 09:56:35 +000012368int
12369varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012370{
Eric Andersenc470f442003-07-28 09:56:35 +000012371 int c, d;
12372
12373 while ((c = *p) == (d = *q)) {
12374 if (!c || c == '=')
12375 goto out;
12376 p++;
12377 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012378 }
Eric Andersenc470f442003-07-28 09:56:35 +000012379 if (c == '=')
12380 c = 0;
12381 if (d == '=')
12382 d = 0;
12383out:
12384 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012385}
12386
Eric Andersenc470f442003-07-28 09:56:35 +000012387static int
12388vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012389{
Eric Andersenc470f442003-07-28 09:56:35 +000012390 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012391}
12392
Eric Andersenc470f442003-07-28 09:56:35 +000012393static struct var **
12394findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012395{
12396 for (; *vpp; vpp = &(*vpp)->next) {
12397 if (varequal((*vpp)->text, name)) {
12398 break;
12399 }
12400 }
12401 return vpp;
12402}
Eric Andersenc470f442003-07-28 09:56:35 +000012403/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012404
Eric Andersenc470f442003-07-28 09:56:35 +000012405#include <sys/times.h>
12406
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012407static const unsigned char timescmd_str[] = {
12408 ' ', offsetof(struct tms, tms_utime),
12409 '\n', offsetof(struct tms, tms_stime),
12410 ' ', offsetof(struct tms, tms_cutime),
12411 '\n', offsetof(struct tms, tms_cstime),
12412 0
12413};
Eric Andersencb57d552001-06-28 07:25:16 +000012414
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012415static int timescmd(int ac, char **av)
12416{
12417 long int clk_tck, s, t;
12418 const unsigned char *p;
12419 struct tms buf;
12420
12421 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012422 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012423
12424 p = timescmd_str;
12425 do {
12426 t = *(clock_t *)(((char *) &buf) + p[1]);
12427 s = t / clk_tck;
12428 out1fmt("%ldm%ld.%.3lds%c",
12429 s/60, s%60,
12430 ((t - s * clk_tck) * 1000) / clk_tck,
12431 p[0]);
12432 } while (*(p += 2));
12433
Eric Andersencb57d552001-06-28 07:25:16 +000012434 return 0;
12435}
12436
Eric Andersend35c5df2002-01-09 15:37:36 +000012437#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012438static int
12439dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012440{
Eric Andersen90898442003-08-06 11:20:52 +000012441 long result;
Eric Andersenc470f442003-07-28 09:56:35 +000012442 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012443
Eric Andersenc470f442003-07-28 09:56:35 +000012444 INTOFF;
12445 result = arith(s, &errcode);
12446 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012447 if (errcode == -3)
12448 error("exponent less than 0");
12449 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012450 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012451 else if (errcode == -5)
12452 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012453 else
12454 synerror(s);
12455 }
12456 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012457
Eric Andersenc470f442003-07-28 09:56:35 +000012458 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012459}
Eric Andersenc470f442003-07-28 09:56:35 +000012460
12461
12462/*
Eric Andersen90898442003-08-06 11:20:52 +000012463 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12464 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12465 *
12466 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012467 */
Eric Andersen90898442003-08-06 11:20:52 +000012468
Eric Andersenc470f442003-07-28 09:56:35 +000012469static int
Eric Andersen90898442003-08-06 11:20:52 +000012470letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012471{
Eric Andersenc470f442003-07-28 09:56:35 +000012472 char **ap;
12473 long i;
12474
Eric Andersen90898442003-08-06 11:20:52 +000012475 ap = argv + 1;
12476 if(!*ap)
12477 error("expression expected");
12478 for (ap = argv + 1; *ap; ap++) {
12479 i = dash_arith(*ap);
12480 }
Eric Andersenc470f442003-07-28 09:56:35 +000012481
Eric Andersen90898442003-08-06 11:20:52 +000012482 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012483}
12484#endif /* CONFIG_ASH_MATH_SUPPORT */
12485
12486/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12487
12488/*
12489 * Miscelaneous builtins.
12490 */
12491
12492#undef rflag
12493
12494#ifdef __GLIBC__
12495#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12496typedef enum __rlimit_resource rlim_t;
12497#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012498#endif
12499
12500
Eric Andersenc470f442003-07-28 09:56:35 +000012501/*
12502 * The read builtin. The -e option causes backslashes to escape the
12503 * following character.
12504 *
12505 * This uses unbuffered input, which may be avoidable in some cases.
12506 */
12507
12508static int
12509readcmd(int argc, char **argv)
12510{
12511 char **ap;
12512 int backslash;
12513 char c;
12514 int rflag;
12515 char *prompt;
12516 const char *ifs;
12517 char *p;
12518 int startword;
12519 int status;
12520 int i;
12521
12522 rflag = 0;
12523 prompt = NULL;
12524 while ((i = nextopt("p:r")) != '\0') {
12525 if (i == 'p')
12526 prompt = optionarg;
12527 else
12528 rflag = 1;
12529 }
12530 if (prompt && isatty(0)) {
12531 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012532 }
12533 if (*(ap = argptr) == NULL)
12534 error("arg count");
12535 if ((ifs = bltinlookup("IFS")) == NULL)
12536 ifs = defifs;
12537 status = 0;
12538 startword = 1;
12539 backslash = 0;
12540 STARTSTACKSTR(p);
12541 for (;;) {
12542 if (read(0, &c, 1) != 1) {
12543 status = 1;
12544 break;
12545 }
12546 if (c == '\0')
12547 continue;
12548 if (backslash) {
12549 backslash = 0;
12550 if (c != '\n')
12551 goto put;
12552 continue;
12553 }
12554 if (!rflag && c == '\\') {
12555 backslash++;
12556 continue;
12557 }
12558 if (c == '\n')
12559 break;
12560 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12561 continue;
12562 }
12563 startword = 0;
12564 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12565 STACKSTRNUL(p);
12566 setvar(*ap, stackblock(), 0);
12567 ap++;
12568 startword = 1;
12569 STARTSTACKSTR(p);
12570 } else {
12571put:
12572 STPUTC(c, p);
12573 }
12574 }
12575 STACKSTRNUL(p);
12576 /* Remove trailing blanks */
12577 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12578 *p = '\0';
12579 setvar(*ap, stackblock(), 0);
12580 while (*++ap != NULL)
12581 setvar(*ap, nullstr, 0);
12582 return status;
12583}
12584
12585
12586static int umaskcmd(int argc, char **argv)
12587{
12588 static const char permuser[3] = "ugo";
12589 static const char permmode[3] = "rwx";
12590 static const short int permmask[] = {
12591 S_IRUSR, S_IWUSR, S_IXUSR,
12592 S_IRGRP, S_IWGRP, S_IXGRP,
12593 S_IROTH, S_IWOTH, S_IXOTH
12594 };
12595
12596 char *ap;
12597 mode_t mask;
12598 int i;
12599 int symbolic_mode = 0;
12600
12601 while (nextopt("S") != '\0') {
12602 symbolic_mode = 1;
12603 }
12604
12605 INTOFF;
12606 mask = umask(0);
12607 umask(mask);
12608 INTON;
12609
12610 if ((ap = *argptr) == NULL) {
12611 if (symbolic_mode) {
12612 char buf[18];
12613 char *p = buf;
12614
12615 for (i = 0; i < 3; i++) {
12616 int j;
12617
12618 *p++ = permuser[i];
12619 *p++ = '=';
12620 for (j = 0; j < 3; j++) {
12621 if ((mask & permmask[3 * i + j]) == 0) {
12622 *p++ = permmode[j];
12623 }
12624 }
12625 *p++ = ',';
12626 }
12627 *--p = 0;
12628 puts(buf);
12629 } else {
12630 out1fmt("%.4o\n", mask);
12631 }
12632 } else {
12633 if (is_digit((unsigned char) *ap)) {
12634 mask = 0;
12635 do {
12636 if (*ap >= '8' || *ap < '0')
12637 error(illnum, argv[1]);
12638 mask = (mask << 3) + (*ap - '0');
12639 } while (*++ap != '\0');
12640 umask(mask);
12641 } else {
12642 mask = ~mask & 0777;
12643 if (!bb_parse_mode(ap, &mask)) {
12644 error("Illegal mode: %s", ap);
12645 }
12646 umask(~mask & 0777);
12647 }
12648 }
12649 return 0;
12650}
12651
12652/*
12653 * ulimit builtin
12654 *
12655 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12656 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12657 * ash by J.T. Conklin.
12658 *
12659 * Public domain.
12660 */
12661
12662struct limits {
12663 const char *name;
12664 int cmd;
12665 int factor; /* multiply by to get rlim_{cur,max} values */
12666 char option;
12667};
12668
12669static const struct limits limits[] = {
12670#ifdef RLIMIT_CPU
12671 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12672#endif
12673#ifdef RLIMIT_FSIZE
12674 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12675#endif
12676#ifdef RLIMIT_DATA
12677 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12678#endif
12679#ifdef RLIMIT_STACK
12680 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12681#endif
12682#ifdef RLIMIT_CORE
12683 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12684#endif
12685#ifdef RLIMIT_RSS
12686 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12687#endif
12688#ifdef RLIMIT_MEMLOCK
12689 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12690#endif
12691#ifdef RLIMIT_NPROC
12692 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
12693#endif
12694#ifdef RLIMIT_NOFILE
12695 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
12696#endif
12697#ifdef RLIMIT_VMEM
12698 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
12699#endif
12700#ifdef RLIMIT_SWAP
12701 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
12702#endif
12703 { (char *) 0, 0, 0, '\0' }
12704};
12705
12706int
12707ulimitcmd(int argc, char **argv)
12708{
12709 int c;
12710 rlim_t val = 0;
12711 enum { SOFT = 0x1, HARD = 0x2 }
12712 how = SOFT | HARD;
12713 const struct limits *l;
12714 int set, all = 0;
12715 int optc, what;
12716 struct rlimit limit;
12717
12718 what = 'f';
12719 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
12720 switch (optc) {
12721 case 'H':
12722 how = HARD;
12723 break;
12724 case 'S':
12725 how = SOFT;
12726 break;
12727 case 'a':
12728 all = 1;
12729 break;
12730 default:
12731 what = optc;
12732 }
12733
12734 for (l = limits; l->name && l->option != what; l++)
12735 ;
12736 if (!l->name)
12737 error("internal error (%c)", what);
12738
12739 set = *argptr ? 1 : 0;
12740 if (set) {
12741 char *p = *argptr;
12742
12743 if (all || argptr[1])
12744 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012745 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012746 val = RLIM_INFINITY;
12747 else {
12748 val = (rlim_t) 0;
12749
12750 while ((c = *p++) >= '0' && c <= '9')
12751 {
12752 val = (val * 10) + (long)(c - '0');
12753 if (val < (rlim_t) 0)
12754 break;
12755 }
12756 if (c)
12757 error("bad number");
12758 val *= l->factor;
12759 }
12760 }
12761 if (all) {
12762 for (l = limits; l->name; l++) {
12763 getrlimit(l->cmd, &limit);
12764 if (how & SOFT)
12765 val = limit.rlim_cur;
12766 else if (how & HARD)
12767 val = limit.rlim_max;
12768
12769 out1fmt("%-20s ", l->name);
12770 if (val == RLIM_INFINITY)
12771 out1fmt("unlimited\n");
12772 else
12773 {
12774 val /= l->factor;
12775 out1fmt("%lld\n", (long long) val);
12776 }
12777 }
12778 return 0;
12779 }
12780
12781 getrlimit(l->cmd, &limit);
12782 if (set) {
12783 if (how & HARD)
12784 limit.rlim_max = val;
12785 if (how & SOFT)
12786 limit.rlim_cur = val;
12787 if (setrlimit(l->cmd, &limit) < 0)
12788 error("error setting limit (%m)");
12789 } else {
12790 if (how & SOFT)
12791 val = limit.rlim_cur;
12792 else if (how & HARD)
12793 val = limit.rlim_max;
12794
12795 if (val == RLIM_INFINITY)
12796 out1fmt("unlimited\n");
12797 else
12798 {
12799 val /= l->factor;
12800 out1fmt("%lld\n", (long long) val);
12801 }
12802 }
12803 return 0;
12804}
12805
Eric Andersen90898442003-08-06 11:20:52 +000012806
12807#ifdef CONFIG_ASH_MATH_SUPPORT
12808
12809/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12810
12811 Permission is hereby granted, free of charge, to any person obtaining
12812 a copy of this software and associated documentation files (the
12813 "Software"), to deal in the Software without restriction, including
12814 without limitation the rights to use, copy, modify, merge, publish,
12815 distribute, sublicense, and/or sell copies of the Software, and to
12816 permit persons to whom the Software is furnished to do so, subject to
12817 the following conditions:
12818
12819 The above copyright notice and this permission notice shall be
12820 included in all copies or substantial portions of the Software.
12821
12822 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12823 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12824 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12825 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12826 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12827 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12828 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12829*/
12830
12831/* This is my infix parser/evaluator. It is optimized for size, intended
12832 * as a replacement for yacc-based parsers. However, it may well be faster
12833 * than a comparable parser writen in yacc. The supported operators are
12834 * listed in #defines below. Parens, order of operations, and error handling
12835 * are supported. This code is threadsafe. The exact expression format should
12836 * be that which POSIX specifies for shells. */
12837
12838/* The code uses a simple two-stack algorithm. See
12839 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12840 * for a detailed explaination of the infix-to-postfix algorithm on which
12841 * this is based (this code differs in that it applies operators immediately
12842 * to the stack instead of adding them to a queue to end up with an
12843 * expression). */
12844
12845/* To use the routine, call it with an expression string and error return
12846 * pointer */
12847
12848/*
12849 * Aug 24, 2001 Manuel Novoa III
12850 *
12851 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12852 *
12853 * 1) In arith_apply():
12854 * a) Cached values of *numptr and &(numptr[-1]).
12855 * b) Removed redundant test for zero denominator.
12856 *
12857 * 2) In arith():
12858 * a) Eliminated redundant code for processing operator tokens by moving
12859 * to a table-based implementation. Also folded handling of parens
12860 * into the table.
12861 * b) Combined all 3 loops which called arith_apply to reduce generated
12862 * code size at the cost of speed.
12863 *
12864 * 3) The following expressions were treated as valid by the original code:
12865 * 1() , 0! , 1 ( *3 ) .
12866 * These bugs have been fixed by internally enclosing the expression in
12867 * parens and then checking that all binary ops and right parens are
12868 * preceded by a valid expression (NUM_TOKEN).
12869 *
12870 * Note: It may be desireable to replace Aaron's test for whitespace with
12871 * ctype's isspace() if it is used by another busybox applet or if additional
12872 * whitespace chars should be considered. Look below the "#include"s for a
12873 * precompiler test.
12874 */
12875
12876/*
12877 * Aug 26, 2001 Manuel Novoa III
12878 *
12879 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12880 *
12881 * Merge in Aaron's comments previously posted to the busybox list,
12882 * modified slightly to take account of my changes to the code.
12883 *
12884 */
12885
12886/*
12887 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12888 *
12889 * - allow access to variable,
12890 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12891 * - realize assign syntax (VAR=expr, +=, *= etc)
12892 * - realize exponentiation (** operator)
12893 * - realize comma separated - expr, expr
12894 * - realise ++expr --expr expr++ expr--
12895 * - realise expr ? expr : expr (but, second expr calculate always)
12896 * - allow hexdecimal and octal numbers
12897 * - was restored loses XOR operator
12898 * - remove one goto label, added three ;-)
12899 * - protect $((num num)) as true zero expr (Manuel`s error)
12900 * - always use special isspace(), see comment from bash ;-)
12901 */
12902
12903
12904#define arith_isspace(arithval) \
12905 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12906
12907
12908typedef unsigned char operator;
12909
12910/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12911 * precedence, and 3 high bits are an ID unique accross operators of that
12912 * precedence. The ID portion is so that multiple operators can have the
12913 * same precedence, ensuring that the leftmost one is evaluated first.
12914 * Consider * and /. */
12915
12916#define tok_decl(prec,id) (((id)<<5)|(prec))
12917#define PREC(op) ((op) & 0x1F)
12918
12919#define TOK_LPAREN tok_decl(0,0)
12920
12921#define TOK_COMMA tok_decl(1,0)
12922
12923#define TOK_ASSIGN tok_decl(2,0)
12924#define TOK_AND_ASSIGN tok_decl(2,1)
12925#define TOK_OR_ASSIGN tok_decl(2,2)
12926#define TOK_XOR_ASSIGN tok_decl(2,3)
12927#define TOK_PLUS_ASSIGN tok_decl(2,4)
12928#define TOK_MINUS_ASSIGN tok_decl(2,5)
12929#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12930#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12931
12932#define TOK_MUL_ASSIGN tok_decl(3,0)
12933#define TOK_DIV_ASSIGN tok_decl(3,1)
12934#define TOK_REM_ASSIGN tok_decl(3,2)
12935
12936/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12937#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12938
12939/* conditional is right associativity too */
12940#define TOK_CONDITIONAL tok_decl(4,0)
12941#define TOK_CONDITIONAL_SEP tok_decl(4,1)
12942
12943#define TOK_OR tok_decl(5,0)
12944
12945#define TOK_AND tok_decl(6,0)
12946
12947#define TOK_BOR tok_decl(7,0)
12948
12949#define TOK_BXOR tok_decl(8,0)
12950
12951#define TOK_BAND tok_decl(9,0)
12952
12953#define TOK_EQ tok_decl(10,0)
12954#define TOK_NE tok_decl(10,1)
12955
12956#define TOK_LT tok_decl(11,0)
12957#define TOK_GT tok_decl(11,1)
12958#define TOK_GE tok_decl(11,2)
12959#define TOK_LE tok_decl(11,3)
12960
12961#define TOK_LSHIFT tok_decl(12,0)
12962#define TOK_RSHIFT tok_decl(12,1)
12963
12964#define TOK_ADD tok_decl(13,0)
12965#define TOK_SUB tok_decl(13,1)
12966
12967#define TOK_MUL tok_decl(14,0)
12968#define TOK_DIV tok_decl(14,1)
12969#define TOK_REM tok_decl(14,2)
12970
12971/* exponent is right associativity */
12972#define TOK_EXPONENT tok_decl(15,1)
12973
12974/* For now unary operators. */
12975#define UNARYPREC 16
12976#define TOK_BNOT tok_decl(UNARYPREC,0)
12977#define TOK_NOT tok_decl(UNARYPREC,1)
12978
12979#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12980#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12981
12982#define PREC_PRE (UNARYPREC+2)
12983
12984#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12985#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12986
12987#define PREC_POST (UNARYPREC+3)
12988
12989#define TOK_POST_INC tok_decl(PREC_POST, 0)
12990#define TOK_POST_DEC tok_decl(PREC_POST, 1)
12991
12992#define SPEC_PREC (UNARYPREC+4)
12993
12994#define TOK_NUM tok_decl(SPEC_PREC, 0)
12995#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12996
12997#define NUMPTR (*numstackptr)
12998
12999static inline int tok_have_assign(operator op)
13000{
13001 operator prec = PREC(op);
13002
13003 convert_prec_is_assing(prec);
13004 return (prec == PREC(TOK_ASSIGN) ||
13005 prec == PREC_PRE || prec == PREC_POST);
13006}
13007
13008static inline int is_right_associativity(operator prec)
13009{
13010 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13011 prec == PREC(TOK_CONDITIONAL));
13012}
13013
13014
13015typedef struct ARITCH_VAR_NUM {
13016 long val;
13017 long contidional_second_val;
13018 char contidional_second_val_initialized;
13019 char *var; /* if NULL then is regular number,
13020 else is varable name */
13021} v_n_t;
13022
13023
13024typedef struct CHK_VAR_RECURSIVE_LOOPED {
13025 const char *var;
13026 struct CHK_VAR_RECURSIVE_LOOPED *next;
13027} chk_var_recursive_looped_t;
13028
13029static chk_var_recursive_looped_t *prev_chk_var_recursive;
13030
13031
13032static int arith_lookup_val(v_n_t *t)
13033{
13034 if(t->var) {
13035 const char * p = lookupvar(t->var);
13036
13037 if(p) {
13038 int errcode;
13039
13040 /* recursive try as expression */
13041 chk_var_recursive_looped_t *cur;
13042 chk_var_recursive_looped_t cur_save;
13043
13044 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13045 if(strcmp(cur->var, t->var) == 0) {
13046 /* expression recursion loop detected */
13047 return -5;
13048 }
13049 }
13050 /* save current lookuped var name */
13051 cur = prev_chk_var_recursive;
13052 cur_save.var = t->var;
13053 cur_save.next = cur;
13054 prev_chk_var_recursive = &cur_save;
13055
13056 t->val = arith (p, &errcode);
13057 /* restore previous ptr after recursiving */
13058 prev_chk_var_recursive = cur;
13059 return errcode;
13060 } else {
13061 /* allow undefined var as 0 */
13062 t->val = 0;
13063 }
13064 }
13065 return 0;
13066}
13067
13068/* "applying" a token means performing it on the top elements on the integer
13069 * stack. For a unary operator it will only change the top element, but a
13070 * binary operator will pop two arguments and push a result */
13071static inline int
13072arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13073{
13074 long numptr_val;
13075 v_n_t *numptr_m1;
13076 long rez;
13077 int ret_arith_lookup_val;
13078
13079 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13080 without arguments */
13081 numptr_m1 = NUMPTR - 1;
13082
13083 /* check operand is var with noninteger value */
13084 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13085 if(ret_arith_lookup_val)
13086 return ret_arith_lookup_val;
13087
13088 rez = numptr_m1->val;
13089 if (op == TOK_UMINUS)
13090 rez *= -1;
13091 else if (op == TOK_NOT)
13092 rez = !rez;
13093 else if (op == TOK_BNOT)
13094 rez = ~rez;
13095 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13096 rez++;
13097 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13098 rez--;
13099 else if (op != TOK_UPLUS) {
13100 /* Binary operators */
13101
13102 /* check and binary operators need two arguments */
13103 if (numptr_m1 == numstack) goto err;
13104
13105 /* ... and they pop one */
13106 --NUMPTR;
13107 numptr_val = rez;
13108 if (op == TOK_CONDITIONAL) {
13109 if(! numptr_m1->contidional_second_val_initialized) {
13110 /* protect $((expr1 ? expr2)) without ": expr" */
13111 goto err;
13112 }
13113 rez = numptr_m1->contidional_second_val;
13114 } else if(numptr_m1->contidional_second_val_initialized) {
13115 /* protect $((expr1 : expr2)) without "expr ? " */
13116 goto err;
13117 }
13118 numptr_m1 = NUMPTR - 1;
13119 if(op != TOK_ASSIGN) {
13120 /* check operand is var with noninteger value for not '=' */
13121 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13122 if(ret_arith_lookup_val)
13123 return ret_arith_lookup_val;
13124 }
13125 if (op == TOK_CONDITIONAL) {
13126 numptr_m1->contidional_second_val = rez;
13127 }
13128 rez = numptr_m1->val;
13129 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13130 rez |= numptr_val;
13131 else if (op == TOK_OR)
13132 rez = numptr_val || rez;
13133 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13134 rez &= numptr_val;
13135 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13136 rez ^= numptr_val;
13137 else if (op == TOK_AND)
13138 rez = rez && numptr_val;
13139 else if (op == TOK_EQ)
13140 rez = (rez == numptr_val);
13141 else if (op == TOK_NE)
13142 rez = (rez != numptr_val);
13143 else if (op == TOK_GE)
13144 rez = (rez >= numptr_val);
13145 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13146 rez >>= numptr_val;
13147 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13148 rez <<= numptr_val;
13149 else if (op == TOK_GT)
13150 rez = (rez > numptr_val);
13151 else if (op == TOK_LT)
13152 rez = (rez < numptr_val);
13153 else if (op == TOK_LE)
13154 rez = (rez <= numptr_val);
13155 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13156 rez *= numptr_val;
13157 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13158 rez += numptr_val;
13159 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13160 rez -= numptr_val;
13161 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13162 rez = numptr_val;
13163 else if (op == TOK_CONDITIONAL_SEP) {
13164 if (numptr_m1 == numstack) {
13165 /* protect $((expr : expr)) without "expr ? " */
13166 goto err;
13167 }
13168 numptr_m1->contidional_second_val_initialized = op;
13169 numptr_m1->contidional_second_val = numptr_val;
13170 }
13171 else if (op == TOK_CONDITIONAL) {
13172 rez = rez ?
13173 numptr_val : numptr_m1->contidional_second_val;
13174 }
13175 else if(op == TOK_EXPONENT) {
13176 if(numptr_val < 0)
13177 return -3; /* exponent less than 0 */
13178 else {
13179 long c = 1;
13180
13181 if(numptr_val)
13182 while(numptr_val--)
13183 c *= rez;
13184 rez = c;
13185 }
13186 }
13187 else if(numptr_val==0) /* zero divisor check */
13188 return -2;
13189 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13190 rez /= numptr_val;
13191 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13192 rez %= numptr_val;
13193 }
13194 if(tok_have_assign(op)) {
13195 char buf[32];
13196
13197 if(numptr_m1->var == NULL) {
13198 /* Hmm, 1=2 ? */
13199 goto err;
13200 }
13201 /* save to shell variable */
13202 sprintf(buf, "%ld", rez);
13203 setvar(numptr_m1->var, buf, 0);
13204 /* after saving, make previous value for v++ or v-- */
13205 if(op == TOK_POST_INC)
13206 rez--;
13207 else if(op == TOK_POST_DEC)
13208 rez++;
13209 }
13210 numptr_m1->val = rez;
13211 /* protect geting var value, is number now */
13212 numptr_m1->var = NULL;
13213 return 0;
13214err: return(-1);
13215}
13216
13217/* longest must first */
13218static const char op_tokens[] = {
13219 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13220 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13221 '<','<', 0, TOK_LSHIFT,
13222 '>','>', 0, TOK_RSHIFT,
13223 '|','|', 0, TOK_OR,
13224 '&','&', 0, TOK_AND,
13225 '!','=', 0, TOK_NE,
13226 '<','=', 0, TOK_LE,
13227 '>','=', 0, TOK_GE,
13228 '=','=', 0, TOK_EQ,
13229 '|','=', 0, TOK_OR_ASSIGN,
13230 '&','=', 0, TOK_AND_ASSIGN,
13231 '*','=', 0, TOK_MUL_ASSIGN,
13232 '/','=', 0, TOK_DIV_ASSIGN,
13233 '%','=', 0, TOK_REM_ASSIGN,
13234 '+','=', 0, TOK_PLUS_ASSIGN,
13235 '-','=', 0, TOK_MINUS_ASSIGN,
13236 '-','-', 0, TOK_POST_DEC,
13237 '^','=', 0, TOK_XOR_ASSIGN,
13238 '+','+', 0, TOK_POST_INC,
13239 '*','*', 0, TOK_EXPONENT,
13240 '!', 0, TOK_NOT,
13241 '<', 0, TOK_LT,
13242 '>', 0, TOK_GT,
13243 '=', 0, TOK_ASSIGN,
13244 '|', 0, TOK_BOR,
13245 '&', 0, TOK_BAND,
13246 '*', 0, TOK_MUL,
13247 '/', 0, TOK_DIV,
13248 '%', 0, TOK_REM,
13249 '+', 0, TOK_ADD,
13250 '-', 0, TOK_SUB,
13251 '^', 0, TOK_BXOR,
13252 /* uniq */
13253 '~', 0, TOK_BNOT,
13254 ',', 0, TOK_COMMA,
13255 '?', 0, TOK_CONDITIONAL,
13256 ':', 0, TOK_CONDITIONAL_SEP,
13257 ')', 0, TOK_RPAREN,
13258 '(', 0, TOK_LPAREN,
13259 0
13260};
13261/* ptr to ")" */
13262#define endexpression &op_tokens[sizeof(op_tokens)-7]
13263
13264
13265extern long arith (const char *expr, int *perrcode)
13266{
13267 register char arithval; /* Current character under analysis */
13268 operator lasttok, op;
13269 operator prec;
13270
13271 const char *p = endexpression;
13272 int errcode;
13273
13274 size_t datasizes = strlen(expr) + 2;
13275
13276 /* Stack of integers */
13277 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13278 * in any given correct or incorrect expression is left as an excersize to
13279 * the reader. */
13280 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13281 *numstackptr = numstack;
13282 /* Stack of operator tokens */
13283 operator *stack = alloca((datasizes) * sizeof(operator)),
13284 *stackptr = stack;
13285
13286 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13287 *perrcode = errcode = 0;
13288
13289 while(1) {
13290 if ((arithval = *expr) == 0) {
13291 if (p == endexpression) {
13292 /* Null expression. */
13293 return 0;
13294 }
13295
13296 /* This is only reached after all tokens have been extracted from the
13297 * input stream. If there are still tokens on the operator stack, they
13298 * are to be applied in order. At the end, there should be a final
13299 * result on the integer stack */
13300
13301 if (expr != endexpression + 1) {
13302 /* If we haven't done so already, */
13303 /* append a closing right paren */
13304 expr = endexpression;
13305 /* and let the loop process it. */
13306 continue;
13307 }
13308 /* At this point, we're done with the expression. */
13309 if (numstackptr != numstack+1) {
13310 /* ... but if there isn't, it's bad */
13311 err:
13312 return (*perrcode = -1);
13313 }
13314 if(numstack->var) {
13315 /* expression is $((var)) only, lookup now */
13316 errcode = arith_lookup_val(numstack);
13317 }
13318 ret:
13319 *perrcode = errcode;
13320 return numstack->val;
13321 } else {
13322 /* Continue processing the expression. */
13323 if (arith_isspace(arithval)) {
13324 /* Skip whitespace */
13325 goto prologue;
13326 }
13327 if((p = endofname(expr)) != expr) {
13328 int var_name_size = (p-expr) + 1; /* trailing zero */
13329
13330 numstackptr->var = alloca(var_name_size);
13331 safe_strncpy(numstackptr->var, expr, var_name_size);
13332 expr = p;
13333 num:
13334 numstackptr->contidional_second_val_initialized = 0;
13335 numstackptr++;
13336 lasttok = TOK_NUM;
13337 continue;
13338 } else if (is_digit(arithval)) {
13339 numstackptr->var = NULL;
13340 numstackptr->val = strtol(expr, (char **) &expr, 0);
13341 goto num;
13342 }
13343 for(p = op_tokens; ; p++) {
13344 const char *o;
13345
13346 if(*p == 0) {
13347 /* strange operator not found */
13348 goto err;
13349 }
13350 for(o = expr; *p && *o == *p; p++)
13351 o++;
13352 if(! *p) {
13353 /* found */
13354 expr = o - 1;
13355 break;
13356 }
13357 /* skip tail uncompared token */
13358 while(*p)
13359 p++;
13360 /* skip zero delim */
13361 p++;
13362 }
13363 op = p[1];
13364
13365 /* post grammar: a++ reduce to num */
13366 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13367 lasttok = TOK_NUM;
13368
13369 /* Plus and minus are binary (not unary) _only_ if the last
13370 * token was as number, or a right paren (which pretends to be
13371 * a number, since it evaluates to one). Think about it.
13372 * It makes sense. */
13373 if (lasttok != TOK_NUM) {
13374 switch(op) {
13375 case TOK_ADD:
13376 op = TOK_UPLUS;
13377 break;
13378 case TOK_SUB:
13379 op = TOK_UMINUS;
13380 break;
13381 case TOK_POST_INC:
13382 op = TOK_PRE_INC;
13383 break;
13384 case TOK_POST_DEC:
13385 op = TOK_PRE_DEC;
13386 break;
13387 }
13388 }
13389 /* We don't want a unary operator to cause recursive descent on the
13390 * stack, because there can be many in a row and it could cause an
13391 * operator to be evaluated before its argument is pushed onto the
13392 * integer stack. */
13393 /* But for binary operators, "apply" everything on the operator
13394 * stack until we find an operator with a lesser priority than the
13395 * one we have just extracted. */
13396 /* Left paren is given the lowest priority so it will never be
13397 * "applied" in this way.
13398 * if associativity is right and priority eq, applied also skip
13399 */
13400 prec = PREC(op);
13401 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13402 /* not left paren or unary */
13403 if (lasttok != TOK_NUM) {
13404 /* binary op must be preceded by a num */
13405 goto err;
13406 }
13407 while (stackptr != stack) {
13408 if (op == TOK_RPAREN) {
13409 /* The algorithm employed here is simple: while we don't
13410 * hit an open paren nor the bottom of the stack, pop
13411 * tokens and apply them */
13412 if (stackptr[-1] == TOK_LPAREN) {
13413 --stackptr;
13414 /* Any operator directly after a */
13415 lasttok = TOK_NUM;
13416 /* close paren should consider itself binary */
13417 goto prologue;
13418 }
13419 } else {
13420 operator prev_prec = PREC(stackptr[-1]);
13421
13422 convert_prec_is_assing(prec);
13423 convert_prec_is_assing(prev_prec);
13424 if (prev_prec < prec)
13425 break;
13426 /* check right assoc */
13427 if(prev_prec == prec && is_right_associativity(prec))
13428 break;
13429 }
13430 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13431 if(errcode) goto ret;
13432 }
13433 if (op == TOK_RPAREN) {
13434 goto err;
13435 }
13436 }
13437
13438 /* Push this operator to the stack and remember it. */
13439 *stackptr++ = lasttok = op;
13440
13441 prologue:
13442 ++expr;
13443 }
13444 }
13445}
13446#endif /* CONFIG_ASH_MATH_SUPPORT */
13447
13448
Eric Andersenc470f442003-07-28 09:56:35 +000013449#ifdef DEBUG
13450const char *bb_applet_name = "debug stuff usage";
13451int main(int argc, char **argv)
13452{
13453 return ash_main(argc, argv);
13454}
13455#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013456
Eric Andersendf82f612001-06-28 07:46:40 +000013457/*-
13458 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013459 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013460 *
13461 * This code is derived from software contributed to Berkeley by
13462 * Kenneth Almquist.
13463 *
13464 * Redistribution and use in source and binary forms, with or without
13465 * modification, are permitted provided that the following conditions
13466 * are met:
13467 * 1. Redistributions of source code must retain the above copyright
13468 * notice, this list of conditions and the following disclaimer.
13469 * 2. Redistributions in binary form must reproduce the above copyright
13470 * notice, this list of conditions and the following disclaimer in the
13471 * documentation and/or other materials provided with the distribution.
13472 *
Eric Andersen2870d962001-07-02 17:27:21 +000013473 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13474 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013475 *
13476 * 4. Neither the name of the University nor the names of its contributors
13477 * may be used to endorse or promote products derived from this software
13478 * without specific prior written permission.
13479 *
13480 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13481 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13482 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13483 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13484 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13485 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13486 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13487 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13488 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13489 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13490 * SUCH DAMAGE.
13491 */