blob: 59aa336cd63c52f6656e690ee4f5a9bdeb5cefbc [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 McGrathdc4e75e2003-09-02 02:36:18 +00003732 *ap++ = cmd = (char *)DEFAULT_SHELL;
Eric Andersenc470f442003-07-28 09:56:35 +00003733 while ((*ap++ = *argv++))
3734 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003735 argv = new;
3736 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003737 }
Eric Andersencb57d552001-06-28 07:25:16 +00003738}
3739
Eric Andersenc470f442003-07-28 09:56:35 +00003740
Eric Andersencb57d552001-06-28 07:25:16 +00003741
3742/*
3743 * Do a path search. The variable path (passed by reference) should be
3744 * set to the start of the path before the first call; padvance will update
3745 * this value as it proceeds. Successive calls to padvance will return
3746 * the possible path expansions in sequence. If an option (indicated by
3747 * a percent sign) appears in the path entry then the global variable
3748 * pathopt will be set to point to it; otherwise pathopt will be set to
3749 * NULL.
3750 */
3751
Eric Andersenc470f442003-07-28 09:56:35 +00003752static char *
3753padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003754{
Eric Andersencb57d552001-06-28 07:25:16 +00003755 const char *p;
3756 char *q;
3757 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003758 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003759
3760 if (*path == NULL)
3761 return NULL;
3762 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003763 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3764 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003765 while (stackblocksize() < len)
3766 growstackblock();
3767 q = stackblock();
3768 if (p != start) {
3769 memcpy(q, start, p - start);
3770 q += p - start;
3771 *q++ = '/';
3772 }
3773 strcpy(q, name);
3774 pathopt = NULL;
3775 if (*p == '%') {
3776 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003777 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003778 }
3779 if (*p == ':')
3780 *path = p + 1;
3781 else
3782 *path = NULL;
3783 return stalloc(len);
3784}
3785
3786
Eric Andersencb57d552001-06-28 07:25:16 +00003787/*** Command hashing code ***/
3788
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003789static void
3790printentry(struct tblentry *cmdp)
3791{
3792 int idx;
3793 const char *path;
3794 char *name;
3795
3796 idx = cmdp->param.index;
3797 path = pathval();
3798 do {
3799 name = padvance(&path, cmdp->cmdname);
3800 stunalloc(name);
3801 } while (--idx >= 0);
3802 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3803}
3804
Eric Andersenc470f442003-07-28 09:56:35 +00003805
3806static int
3807hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003808{
3809 struct tblentry **pp;
3810 struct tblentry *cmdp;
3811 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003812 struct cmdentry entry;
3813 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003814
Eric Andersenc470f442003-07-28 09:56:35 +00003815 while ((c = nextopt("r")) != '\0') {
3816 clearcmdentry(0);
3817 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003818 }
3819 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003820 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3821 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3822 if (cmdp->cmdtype == CMDNORMAL)
3823 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003824 }
3825 }
3826 return 0;
3827 }
3828 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003829 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003830 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003831 && (cmdp->cmdtype == CMDNORMAL
3832 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003833 delete_cmd_entry();
3834 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003835 if (entry.cmdtype == CMDUNKNOWN)
3836 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003837 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003838 }
3839 return c;
3840}
3841
Eric Andersenc470f442003-07-28 09:56:35 +00003842
Eric Andersencb57d552001-06-28 07:25:16 +00003843/*
3844 * Resolve a command name. If you change this routine, you may have to
3845 * change the shellexec routine as well.
3846 */
3847
3848static void
Eric Andersenc470f442003-07-28 09:56:35 +00003849find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003850{
3851 struct tblentry *cmdp;
3852 int idx;
3853 int prev;
3854 char *fullname;
3855 struct stat statb;
3856 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003857 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003858 struct builtincmd *bcmd;
3859
Eric Andersenc470f442003-07-28 09:56:35 +00003860 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003861 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003862 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003863 if (act & DO_ABS) {
3864 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003865#ifdef SYSV
3866 if (errno == EINTR)
3867 continue;
3868#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003869 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003870 return;
3871 }
Eric Andersencb57d552001-06-28 07:25:16 +00003872 }
3873 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003874 return;
3875 }
3876
Eric Andersenbf8bf102002-09-17 08:41:08 +00003877#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3878 if (find_applet_by_name(name)) {
3879 entry->cmdtype = CMDNORMAL;
3880 entry->u.index = -1;
3881 return;
3882 }
3883#endif
3884
Eric Andersenc470f442003-07-28 09:56:35 +00003885 updatetbl = (path == pathval());
3886 if (!updatetbl) {
3887 act |= DO_ALTPATH;
3888 if (strstr(path, "%builtin") != NULL)
3889 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003890 }
3891
Eric Andersenc470f442003-07-28 09:56:35 +00003892 /* If name is in the table, check answer will be ok */
3893 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3894 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003895
Eric Andersenc470f442003-07-28 09:56:35 +00003896 switch (cmdp->cmdtype) {
3897 default:
3898#if DEBUG
3899 abort();
3900#endif
3901 case CMDNORMAL:
3902 bit = DO_ALTPATH;
3903 break;
3904 case CMDFUNCTION:
3905 bit = DO_NOFUNC;
3906 break;
3907 case CMDBUILTIN:
3908 bit = DO_ALTBLTIN;
3909 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003910 }
Eric Andersenc470f442003-07-28 09:56:35 +00003911 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003912 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003913 cmdp = NULL;
3914 } else if (cmdp->rehash == 0)
3915 /* if not invalidated by cd, we're done */
3916 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003917 }
3918
3919 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003920 bcmd = find_builtin(name);
3921 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3922 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3923 )))
3924 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003925
3926 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003927 prev = -1; /* where to start */
3928 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003929 if (cmdp->cmdtype == CMDBUILTIN)
3930 prev = builtinloc;
3931 else
3932 prev = cmdp->param.index;
3933 }
3934
3935 e = ENOENT;
3936 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003937loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003938 while ((fullname = padvance(&path, name)) != NULL) {
3939 stunalloc(fullname);
3940 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003941 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003942 if (prefix(pathopt, "builtin")) {
3943 if (bcmd)
3944 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003945 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003946 } else if (!(act & DO_NOFUNC) &&
3947 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003948 /* handled below */
3949 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003950 /* ignore unimplemented options */
3951 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003952 }
3953 }
3954 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003955 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003956 if (idx < prev)
3957 continue;
3958 TRACE(("searchexec \"%s\": no change\n", name));
3959 goto success;
3960 }
3961 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003962#ifdef SYSV
3963 if (errno == EINTR)
3964 continue;
3965#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003966 if (errno != ENOENT && errno != ENOTDIR)
3967 e = errno;
3968 goto loop;
3969 }
Eric Andersenc470f442003-07-28 09:56:35 +00003970 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003971 if (!S_ISREG(statb.st_mode))
3972 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003973 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003974 stalloc(strlen(fullname) + 1);
3975 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00003976 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3977 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00003978 error("%s not defined in %s", name, fullname);
3979 stunalloc(fullname);
3980 goto success;
3981 }
Eric Andersencb57d552001-06-28 07:25:16 +00003982 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00003983 if (!updatetbl) {
3984 entry->cmdtype = CMDNORMAL;
3985 entry->u.index = idx;
3986 return;
3987 }
3988 INTOFF;
3989 cmdp = cmdlookup(name, 1);
3990 cmdp->cmdtype = CMDNORMAL;
3991 cmdp->param.index = idx;
3992 INTON;
3993 goto success;
3994 }
3995
3996 /* We failed. If there was an entry for this command, delete it */
3997 if (cmdp && updatetbl)
3998 delete_cmd_entry();
3999 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004000 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004001 entry->cmdtype = CMDUNKNOWN;
4002 return;
4003
Eric Andersenc470f442003-07-28 09:56:35 +00004004builtin_success:
4005 if (!updatetbl) {
4006 entry->cmdtype = CMDBUILTIN;
4007 entry->u.cmd = bcmd;
4008 return;
4009 }
4010 INTOFF;
4011 cmdp = cmdlookup(name, 1);
4012 cmdp->cmdtype = CMDBUILTIN;
4013 cmdp->param.cmd = bcmd;
4014 INTON;
4015success:
Eric Andersencb57d552001-06-28 07:25:16 +00004016 cmdp->rehash = 0;
4017 entry->cmdtype = cmdp->cmdtype;
4018 entry->u = cmdp->param;
4019}
4020
4021
Eric Andersenc470f442003-07-28 09:56:35 +00004022/*
4023 * Wrapper around strcmp for qsort/bsearch/...
4024 */
4025static int pstrcmp(const void *a, const void *b)
4026{
4027 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4028}
Eric Andersencb57d552001-06-28 07:25:16 +00004029
4030/*
4031 * Search the table of builtin commands.
4032 */
4033
Eric Andersenc470f442003-07-28 09:56:35 +00004034static struct builtincmd *
4035find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004036{
4037 struct builtincmd *bp;
4038
Eric Andersenc470f442003-07-28 09:56:35 +00004039 bp = bsearch(
4040 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4041 pstrcmp
4042 );
Eric Andersencb57d552001-06-28 07:25:16 +00004043 return bp;
4044}
4045
4046
Eric Andersenc470f442003-07-28 09:56:35 +00004047
Eric Andersencb57d552001-06-28 07:25:16 +00004048/*
4049 * Called when a cd is done. Marks all commands so the next time they
4050 * are executed they will be rehashed.
4051 */
4052
Eric Andersenc470f442003-07-28 09:56:35 +00004053static void
4054hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004055{
Eric Andersencb57d552001-06-28 07:25:16 +00004056 struct tblentry **pp;
4057 struct tblentry *cmdp;
4058
Eric Andersenc470f442003-07-28 09:56:35 +00004059 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4060 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4061 if (cmdp->cmdtype == CMDNORMAL || (
4062 cmdp->cmdtype == CMDBUILTIN &&
4063 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4064 builtinloc > 0
4065 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004066 cmdp->rehash = 1;
4067 }
4068 }
4069}
4070
4071
4072
4073/*
Eric Andersenc470f442003-07-28 09:56:35 +00004074 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004075 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004076 * pathval() still returns the old value at this point.
4077 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004078 */
4079
Eric Andersenc470f442003-07-28 09:56:35 +00004080static void
4081changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004082{
Eric Andersenc470f442003-07-28 09:56:35 +00004083 const char *old, *new;
4084 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004085 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004086 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004087
Eric Andersenc470f442003-07-28 09:56:35 +00004088 old = pathval();
4089 new = newval;
4090 firstchange = 9999; /* assume no change */
4091 idx = 0;
4092 idx_bltin = -1;
4093 for (;;) {
4094 if (*old != *new) {
4095 firstchange = idx;
4096 if ((*old == '\0' && *new == ':')
4097 || (*old == ':' && *new == '\0'))
4098 firstchange++;
4099 old = new; /* ignore subsequent differences */
4100 }
4101 if (*new == '\0')
4102 break;
4103 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4104 idx_bltin = idx;
4105 if (*new == ':') {
4106 idx++;
4107 }
4108 new++, old++;
4109 }
4110 if (builtinloc < 0 && idx_bltin >= 0)
4111 builtinloc = idx_bltin; /* zap builtins */
4112 if (builtinloc >= 0 && idx_bltin < 0)
4113 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004114 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004115 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004116}
4117
4118
4119/*
4120 * Clear out command entries. The argument specifies the first entry in
4121 * PATH which has changed.
4122 */
4123
Eric Andersenc470f442003-07-28 09:56:35 +00004124static void
4125clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004126{
4127 struct tblentry **tblp;
4128 struct tblentry **pp;
4129 struct tblentry *cmdp;
4130
4131 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004132 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004133 pp = tblp;
4134 while ((cmdp = *pp) != NULL) {
4135 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004136 cmdp->param.index >= firstchange)
4137 || (cmdp->cmdtype == CMDBUILTIN &&
4138 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004139 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004140 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004141 } else {
4142 pp = &cmdp->next;
4143 }
4144 }
4145 }
4146 INTON;
4147}
4148
4149
Eric Andersenc470f442003-07-28 09:56:35 +00004150
Eric Andersencb57d552001-06-28 07:25:16 +00004151/*
Eric Andersencb57d552001-06-28 07:25:16 +00004152 * Locate a command in the command hash table. If "add" is nonzero,
4153 * add the command to the table if it is not already present. The
4154 * variable "lastcmdentry" is set to point to the address of the link
4155 * pointing to the entry, so that delete_cmd_entry can delete the
4156 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004157 *
4158 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004159 */
4160
Eric Andersen2870d962001-07-02 17:27:21 +00004161static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004162
Eric Andersenc470f442003-07-28 09:56:35 +00004163
4164static struct tblentry *
4165cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004166{
Eric Andersenc470f442003-07-28 09:56:35 +00004167 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004168 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004169 struct tblentry *cmdp;
4170 struct tblentry **pp;
4171
4172 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004173 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004174 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004175 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004176 hashval &= 0x7FFF;
4177 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004178 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004179 if (equal(cmdp->cmdname, name))
4180 break;
4181 pp = &cmdp->next;
4182 }
4183 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004184 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4185 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004186 cmdp->next = NULL;
4187 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004188 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004189 }
4190 lastcmdentry = pp;
4191 return cmdp;
4192}
4193
4194/*
4195 * Delete the command entry returned on the last lookup.
4196 */
4197
Eric Andersenc470f442003-07-28 09:56:35 +00004198static void
4199delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004200{
Eric Andersencb57d552001-06-28 07:25:16 +00004201 struct tblentry *cmdp;
4202
4203 INTOFF;
4204 cmdp = *lastcmdentry;
4205 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004206 if (cmdp->cmdtype == CMDFUNCTION)
4207 freefunc(cmdp->param.func);
4208 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004209 INTON;
4210}
4211
4212
Eric Andersenc470f442003-07-28 09:56:35 +00004213/*
4214 * Add a new command entry, replacing any existing command entry for
4215 * the same name - except special builtins.
4216 */
Eric Andersencb57d552001-06-28 07:25:16 +00004217
Eric Andersenc470f442003-07-28 09:56:35 +00004218static inline void
4219addcmdentry(char *name, struct cmdentry *entry)
4220{
4221 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004222
Eric Andersenc470f442003-07-28 09:56:35 +00004223 cmdp = cmdlookup(name, 1);
4224 if (cmdp->cmdtype == CMDFUNCTION) {
4225 freefunc(cmdp->param.func);
4226 }
4227 cmdp->cmdtype = entry->cmdtype;
4228 cmdp->param = entry->u;
4229 cmdp->rehash = 0;
4230}
Eric Andersencb57d552001-06-28 07:25:16 +00004231
Eric Andersenc470f442003-07-28 09:56:35 +00004232/*
4233 * Make a copy of a parse tree.
4234 */
Eric Andersencb57d552001-06-28 07:25:16 +00004235
Eric Andersenc470f442003-07-28 09:56:35 +00004236static inline struct funcnode *
4237copyfunc(union node *n)
4238{
4239 struct funcnode *f;
4240 size_t blocksize;
4241
4242 funcblocksize = offsetof(struct funcnode, n);
4243 funcstringsize = 0;
4244 calcsize(n);
4245 blocksize = funcblocksize;
4246 f = ckmalloc(blocksize + funcstringsize);
4247 funcblock = (char *) f + offsetof(struct funcnode, n);
4248 funcstring = (char *) f + blocksize;
4249 copynode(n);
4250 f->count = 0;
4251 return f;
4252}
4253
4254/*
4255 * Define a shell function.
4256 */
4257
4258static void
4259defun(char *name, union node *func)
4260{
4261 struct cmdentry entry;
4262
4263 INTOFF;
4264 entry.cmdtype = CMDFUNCTION;
4265 entry.u.func = copyfunc(func);
4266 addcmdentry(name, &entry);
4267 INTON;
4268}
Eric Andersencb57d552001-06-28 07:25:16 +00004269
4270
4271/*
4272 * Delete a function if it exists.
4273 */
4274
Eric Andersenc470f442003-07-28 09:56:35 +00004275static void
4276unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004277{
Eric Andersencb57d552001-06-28 07:25:16 +00004278 struct tblentry *cmdp;
4279
Eric Andersenc470f442003-07-28 09:56:35 +00004280 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4281 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004282 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004283}
4284
Eric Andersen2870d962001-07-02 17:27:21 +00004285/*
Eric Andersencb57d552001-06-28 07:25:16 +00004286 * Locate and print what a word is...
4287 */
4288
Eric Andersenc470f442003-07-28 09:56:35 +00004289
4290#ifdef CONFIG_ASH_CMDCMD
4291static int
4292describe_command(char *command, int describe_command_verbose)
4293#else
4294#define describe_command_verbose 1
4295static int
4296describe_command(char *command)
4297#endif
4298{
4299 struct cmdentry entry;
4300 struct tblentry *cmdp;
4301#ifdef CONFIG_ASH_ALIAS
4302 const struct alias *ap;
4303#endif
4304 const char *path = pathval();
4305
4306 if (describe_command_verbose) {
4307 out1str(command);
4308 }
4309
4310 /* First look at the keywords */
4311 if (findkwd(command)) {
4312 out1str(describe_command_verbose ? " is a shell keyword" : command);
4313 goto out;
4314 }
4315
4316#ifdef CONFIG_ASH_ALIAS
4317 /* Then look at the aliases */
4318 if ((ap = lookupalias(command, 0)) != NULL) {
4319 if (describe_command_verbose) {
4320 out1fmt(" is an alias for %s", ap->val);
4321 } else {
4322 out1str("alias ");
4323 printalias(ap);
4324 return 0;
4325 }
4326 goto out;
4327 }
4328#endif
4329 /* Then check if it is a tracked alias */
4330 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4331 entry.cmdtype = cmdp->cmdtype;
4332 entry.u = cmdp->param;
4333 } else {
4334 /* Finally use brute force */
4335 find_command(command, &entry, DO_ABS, path);
4336 }
4337
4338 switch (entry.cmdtype) {
4339 case CMDNORMAL: {
4340 int j = entry.u.index;
4341 char *p;
4342 if (j == -1) {
4343 p = command;
4344 } else {
4345 do {
4346 p = padvance(&path, command);
4347 stunalloc(p);
4348 } while (--j >= 0);
4349 }
4350 if (describe_command_verbose) {
4351 out1fmt(" is%s %s",
4352 (cmdp ? " a tracked alias for" : nullstr), p
4353 );
4354 } else {
4355 out1str(p);
4356 }
4357 break;
4358 }
4359
4360 case CMDFUNCTION:
4361 if (describe_command_verbose) {
4362 out1str(" is a shell function");
4363 } else {
4364 out1str(command);
4365 }
4366 break;
4367
4368 case CMDBUILTIN:
4369 if (describe_command_verbose) {
4370 out1fmt(" is a %sshell builtin",
4371 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4372 "special " : nullstr
4373 );
4374 } else {
4375 out1str(command);
4376 }
4377 break;
4378
4379 default:
4380 if (describe_command_verbose) {
4381 out1str(": not found\n");
4382 }
4383 return 127;
4384 }
4385
4386out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004387 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004388 return 0;
4389}
4390
4391static int
4392typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004393{
4394 int i;
4395 int err = 0;
4396
4397 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004398#ifdef CONFIG_ASH_CMDCMD
4399 err |= describe_command(argv[i], 1);
4400#else
4401 err |= describe_command(argv[i]);
4402#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004403 }
4404 return err;
4405}
4406
Eric Andersend35c5df2002-01-09 15:37:36 +00004407#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004408static int
4409commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004410{
4411 int c;
4412 int default_path = 0;
4413 int verify_only = 0;
4414 int verbose_verify_only = 0;
4415
4416 while ((c = nextopt("pvV")) != '\0')
4417 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004418 default:
4419#ifdef DEBUG
4420 fprintf(stderr,
4421"command: nextopt returned character code 0%o\n", c);
4422 return EX_SOFTWARE;
4423#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004424 case 'p':
4425 default_path = 1;
4426 break;
4427 case 'v':
4428 verify_only = 1;
4429 break;
4430 case 'V':
4431 verbose_verify_only = 1;
4432 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004433 }
4434
Eric Andersenc470f442003-07-28 09:56:35 +00004435 if (default_path + verify_only + verbose_verify_only > 1 ||
4436 !*argptr) {
4437 fprintf(stderr,
4438 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004439 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004440 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004441 }
4442
Eric Andersencb57d552001-06-28 07:25:16 +00004443 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004444 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004445 }
Eric Andersencb57d552001-06-28 07:25:16 +00004446
4447 return 0;
4448}
Eric Andersen2870d962001-07-02 17:27:21 +00004449#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004450
Eric Andersenc470f442003-07-28 09:56:35 +00004451/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004452
Eric Andersencb57d552001-06-28 07:25:16 +00004453/*
4454 * Routines to expand arguments to commands. We have to deal with
4455 * backquotes, shell variables, and file metacharacters.
4456 */
Eric Andersenc470f442003-07-28 09:56:35 +00004457
Eric Andersencb57d552001-06-28 07:25:16 +00004458/*
4459 * _rmescape() flags
4460 */
Eric Andersenc470f442003-07-28 09:56:35 +00004461#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4462#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4463#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4464#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4465#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004466
4467/*
4468 * Structure specifying which parts of the string should be searched
4469 * for IFS characters.
4470 */
4471
4472struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004473 struct ifsregion *next; /* next region in list */
4474 int begoff; /* offset of start of region */
4475 int endoff; /* offset of end of region */
4476 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004477};
4478
Eric Andersenc470f442003-07-28 09:56:35 +00004479/* output of current string */
4480static char *expdest;
4481/* list of back quote expressions */
4482static struct nodelist *argbackq;
4483/* first struct in list of ifs regions */
4484static struct ifsregion ifsfirst;
4485/* last struct in list */
4486static struct ifsregion *ifslastp;
4487/* holds expanded arg list */
4488static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004489
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004490static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004491static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004492static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004493static const char *subevalvar(char *, char *, int, int, int, int, int);
4494static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004495static int varisset(char *, int);
4496static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004497static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00004498static void varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004499static void recordregion(int, int, int);
4500static void removerecordregions(int);
4501static void ifsbreakup(char *, struct arglist *);
4502static void ifsfree(void);
4503static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004504static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004505
Eric Andersenc470f442003-07-28 09:56:35 +00004506static int cvtnum(long);
4507static size_t esclen(const char *, const char *);
4508static char *scanleft(char *, char *, char *, char *, int, int);
4509static char *scanright(char *, char *, char *, char *, int, int);
4510static void varunset(const char *, const char *, const char *, int)
4511 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004512
Eric Andersenc470f442003-07-28 09:56:35 +00004513
4514#define pmatch(a, b) !fnmatch((a), (b), 0)
4515/*
Eric Andersen90898442003-08-06 11:20:52 +00004516 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004517 *
4518 * Returns an stalloced string.
4519 */
4520
4521static inline char *
4522preglob(const char *pattern, int quoted, int flag) {
4523 flag |= RMESCAPE_GLOB;
4524 if (quoted) {
4525 flag |= RMESCAPE_QUOTED;
4526 }
4527 return _rmescapes((char *)pattern, flag);
4528}
4529
4530
4531static size_t
4532esclen(const char *start, const char *p) {
4533 size_t esc = 0;
4534
4535 while (p > start && *--p == CTLESC) {
4536 esc++;
4537 }
4538 return esc;
4539}
4540
Eric Andersencb57d552001-06-28 07:25:16 +00004541
4542/*
4543 * Expand shell variables and backquotes inside a here document.
4544 */
4545
Eric Andersenc470f442003-07-28 09:56:35 +00004546static inline void
4547expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004548{
Eric Andersencb57d552001-06-28 07:25:16 +00004549 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004550 expandarg(arg, (struct arglist *)NULL, 0);
4551 xwrite(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004552}
4553
4554
4555/*
4556 * Perform variable substitution and command substitution on an argument,
4557 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4558 * perform splitting and file name expansion. When arglist is NULL, perform
4559 * here document expansion.
4560 */
4561
Eric Andersenc470f442003-07-28 09:56:35 +00004562void
4563expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004564{
4565 struct strlist *sp;
4566 char *p;
4567
4568 argbackq = arg->narg.backquote;
4569 STARTSTACKSTR(expdest);
4570 ifsfirst.next = NULL;
4571 ifslastp = NULL;
4572 argstr(arg->narg.text, flag);
4573 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004574 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004575 }
4576 STPUTC('\0', expdest);
4577 p = grabstackstr(expdest);
4578 exparg.lastp = &exparg.list;
4579 /*
4580 * TODO - EXP_REDIR
4581 */
4582 if (flag & EXP_FULL) {
4583 ifsbreakup(p, &exparg);
4584 *exparg.lastp = NULL;
4585 exparg.lastp = &exparg.list;
4586 expandmeta(exparg.list, flag);
4587 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004588 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004589 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004590 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004591 sp->text = p;
4592 *exparg.lastp = sp;
4593 exparg.lastp = &sp->next;
4594 }
Eric Andersenc470f442003-07-28 09:56:35 +00004595 if (ifsfirst.next)
4596 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004597 *exparg.lastp = NULL;
4598 if (exparg.list) {
4599 *arglist->lastp = exparg.list;
4600 arglist->lastp = exparg.lastp;
4601 }
4602}
4603
4604
Eric Andersenc470f442003-07-28 09:56:35 +00004605/*
4606 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4607 * characters to allow for further processing. Otherwise treat
4608 * $@ like $* since no splitting will be performed.
4609 */
4610
4611static void
4612argstr(char *p, int flag)
4613{
4614 static const char spclchars[] = {
4615 '=',
4616 ':',
4617 CTLQUOTEMARK,
4618 CTLENDVAR,
4619 CTLESC,
4620 CTLVAR,
4621 CTLBACKQ,
4622 CTLBACKQ | CTLQUOTE,
4623#ifdef CONFIG_ASH_MATH_SUPPORT
4624 CTLENDARI,
4625#endif
4626 0
4627 };
4628 const char *reject = spclchars;
4629 int c;
4630 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4631 int breakall = flag & EXP_WORD;
4632 int inquotes;
4633 size_t length;
4634 int startloc;
4635
4636 if (!(flag & EXP_VARTILDE)) {
4637 reject += 2;
4638 } else if (flag & EXP_VARTILDE2) {
4639 reject++;
4640 }
4641 inquotes = 0;
4642 length = 0;
4643 if (flag & EXP_TILDE) {
4644 char *q;
4645
4646 flag &= ~EXP_TILDE;
4647tilde:
4648 q = p;
4649 if (*q == CTLESC && (flag & EXP_QWORD))
4650 q++;
4651 if (*q == '~')
4652 p = exptilde(p, q, flag);
4653 }
4654start:
4655 startloc = expdest - (char *)stackblock();
4656 for (;;) {
4657 length += strcspn(p + length, reject);
4658 c = p[length];
4659 if (c && (!(c & 0x80)
4660#ifdef CONFIG_ASH_MATH_SUPPORT
4661 || c == CTLENDARI
4662#endif
4663 )) {
4664 /* c == '=' || c == ':' || c == CTLENDARI */
4665 length++;
4666 }
4667 if (length > 0) {
4668 int newloc;
4669 expdest = stnputs(p, length, expdest);
4670 newloc = expdest - (char *)stackblock();
4671 if (breakall && !inquotes && newloc > startloc) {
4672 recordregion(startloc, newloc, 0);
4673 }
4674 startloc = newloc;
4675 }
4676 p += length + 1;
4677 length = 0;
4678
4679 switch (c) {
4680 case '\0':
4681 goto breakloop;
4682 case '=':
4683 if (flag & EXP_VARTILDE2) {
4684 p--;
4685 continue;
4686 }
4687 flag |= EXP_VARTILDE2;
4688 reject++;
4689 /* fall through */
4690 case ':':
4691 /*
4692 * sort of a hack - expand tildes in variable
4693 * assignments (after the first '=' and after ':'s).
4694 */
4695 if (*--p == '~') {
4696 goto tilde;
4697 }
4698 continue;
4699 }
4700
4701 switch (c) {
4702 case CTLENDVAR: /* ??? */
4703 goto breakloop;
4704 case CTLQUOTEMARK:
4705 /* "$@" syntax adherence hack */
4706 if (
4707 !inquotes &&
4708 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4709 (p[4] == CTLQUOTEMARK || (
4710 p[4] == CTLENDVAR &&
4711 p[5] == CTLQUOTEMARK
4712 ))
4713 ) {
4714 p = evalvar(p + 1, flag) + 1;
4715 goto start;
4716 }
4717 inquotes = !inquotes;
4718addquote:
4719 if (quotes) {
4720 p--;
4721 length++;
4722 startloc++;
4723 }
4724 break;
4725 case CTLESC:
4726 startloc++;
4727 length++;
4728 goto addquote;
4729 case CTLVAR:
4730 p = evalvar(p, flag);
4731 goto start;
4732 case CTLBACKQ:
4733 c = 0;
4734 case CTLBACKQ|CTLQUOTE:
4735 expbackq(argbackq->n, c, quotes);
4736 argbackq = argbackq->next;
4737 goto start;
4738#ifdef CONFIG_ASH_MATH_SUPPORT
4739 case CTLENDARI:
4740 p--;
4741 expari(quotes);
4742 goto start;
4743#endif
4744 }
4745 }
4746breakloop:
4747 ;
4748}
4749
4750static char *
4751exptilde(char *startp, char *p, int flag)
4752{
4753 char c;
4754 char *name;
4755 struct passwd *pw;
4756 const char *home;
4757 int quotes = flag & (EXP_FULL | EXP_CASE);
4758 int startloc;
4759
4760 name = p + 1;
4761
4762 while ((c = *++p) != '\0') {
4763 switch(c) {
4764 case CTLESC:
4765 return (startp);
4766 case CTLQUOTEMARK:
4767 return (startp);
4768 case ':':
4769 if (flag & EXP_VARTILDE)
4770 goto done;
4771 break;
4772 case '/':
4773 case CTLENDVAR:
4774 goto done;
4775 }
4776 }
4777done:
4778 *p = '\0';
4779 if (*name == '\0') {
4780 if ((home = lookupvar(homestr)) == NULL)
4781 goto lose;
4782 } else {
4783 if ((pw = getpwnam(name)) == NULL)
4784 goto lose;
4785 home = pw->pw_dir;
4786 }
4787 if (*home == '\0')
4788 goto lose;
4789 *p = c;
4790 startloc = expdest - (char *)stackblock();
4791 strtodest(home, SQSYNTAX, quotes);
4792 recordregion(startloc, expdest - (char *)stackblock(), 0);
4793 return (p);
4794lose:
4795 *p = c;
4796 return (startp);
4797}
4798
4799
4800static void
4801removerecordregions(int endoff)
4802{
4803 if (ifslastp == NULL)
4804 return;
4805
4806 if (ifsfirst.endoff > endoff) {
4807 while (ifsfirst.next != NULL) {
4808 struct ifsregion *ifsp;
4809 INTOFF;
4810 ifsp = ifsfirst.next->next;
4811 ckfree(ifsfirst.next);
4812 ifsfirst.next = ifsp;
4813 INTON;
4814 }
4815 if (ifsfirst.begoff > endoff)
4816 ifslastp = NULL;
4817 else {
4818 ifslastp = &ifsfirst;
4819 ifsfirst.endoff = endoff;
4820 }
4821 return;
4822 }
4823
4824 ifslastp = &ifsfirst;
4825 while (ifslastp->next && ifslastp->next->begoff < endoff)
4826 ifslastp=ifslastp->next;
4827 while (ifslastp->next != NULL) {
4828 struct ifsregion *ifsp;
4829 INTOFF;
4830 ifsp = ifslastp->next->next;
4831 ckfree(ifslastp->next);
4832 ifslastp->next = ifsp;
4833 INTON;
4834 }
4835 if (ifslastp->endoff > endoff)
4836 ifslastp->endoff = endoff;
4837}
4838
4839
4840#ifdef CONFIG_ASH_MATH_SUPPORT
4841/*
4842 * Expand arithmetic expression. Backup to start of expression,
4843 * evaluate, place result in (backed up) result, adjust string position.
4844 */
4845void
4846expari(int quotes)
4847{
4848 char *p, *start;
4849 int begoff;
4850 int flag;
4851 int len;
4852
4853 /* ifsfree(); */
4854
4855 /*
4856 * This routine is slightly over-complicated for
4857 * efficiency. Next we scan backwards looking for the
4858 * start of arithmetic.
4859 */
4860 start = stackblock();
4861 p = expdest - 1;
4862 *p = '\0';
4863 p--;
4864 do {
4865 int esc;
4866
4867 while (*p != CTLARI) {
4868 p--;
4869#ifdef DEBUG
4870 if (p < start) {
4871 error("missing CTLARI (shouldn't happen)");
4872 }
4873#endif
4874 }
4875
4876 esc = esclen(start, p);
4877 if (!(esc % 2)) {
4878 break;
4879 }
4880
4881 p -= esc + 1;
4882 } while (1);
4883
4884 begoff = p - start;
4885
4886 removerecordregions(begoff);
4887
4888 flag = p[1];
4889
4890 expdest = p;
4891
4892 if (quotes)
4893 rmescapes(p + 2);
4894
4895 len = cvtnum(dash_arith(p + 2));
4896
4897 if (flag != '"')
4898 recordregion(begoff, begoff + len, 0);
4899}
4900#endif
4901
4902/*
4903 * Expand stuff in backwards quotes.
4904 */
4905
4906static void
4907expbackq(union node *cmd, int quoted, int quotes)
4908{
4909 struct backcmd in;
4910 int i;
4911 char buf[128];
4912 char *p;
4913 char *dest;
4914 int startloc;
4915 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4916 struct stackmark smark;
4917
4918 INTOFF;
4919 setstackmark(&smark);
4920 dest = expdest;
4921 startloc = dest - (char *)stackblock();
4922 grabstackstr(dest);
4923 evalbackcmd(cmd, (struct backcmd *) &in);
4924 popstackmark(&smark);
4925
4926 p = in.buf;
4927 i = in.nleft;
4928 if (i == 0)
4929 goto read;
4930 for (;;) {
4931 memtodest(p, i, syntax, quotes);
4932read:
4933 if (in.fd < 0)
4934 break;
4935 i = safe_read(in.fd, buf, sizeof buf);
4936 TRACE(("expbackq: read returns %d\n", i));
4937 if (i <= 0)
4938 break;
4939 p = buf;
4940 }
4941
4942 if (in.buf)
4943 ckfree(in.buf);
4944 if (in.fd >= 0) {
4945 close(in.fd);
4946 back_exitstatus = waitforjob(in.jp);
4947 }
4948 INTON;
4949
4950 /* Eat all trailing newlines */
4951 dest = expdest;
4952 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4953 STUNPUTC(dest);
4954 expdest = dest;
4955
4956 if (quoted == 0)
4957 recordregion(startloc, dest - (char *)stackblock(), 0);
4958 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4959 (dest - (char *)stackblock()) - startloc,
4960 (dest - (char *)stackblock()) - startloc,
4961 stackblock() + startloc));
4962}
4963
4964
4965static char *
Eric Andersen90898442003-08-06 11:20:52 +00004966scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4967 int zero)
4968{
Eric Andersenc470f442003-07-28 09:56:35 +00004969 char *loc;
4970 char *loc2;
4971 char c;
4972
4973 loc = startp;
4974 loc2 = rmesc;
4975 do {
4976 int match;
4977 const char *s = loc2;
4978 c = *loc2;
4979 if (zero) {
4980 *loc2 = '\0';
4981 s = rmesc;
4982 }
4983 match = pmatch(str, s);
4984 *loc2 = c;
4985 if (match)
4986 return loc;
4987 if (quotes && *loc == CTLESC)
4988 loc++;
4989 loc++;
4990 loc2++;
4991 } while (c);
4992 return 0;
4993}
4994
4995
4996static char *
Eric Andersen90898442003-08-06 11:20:52 +00004997scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4998 int zero)
4999{
Eric Andersenc470f442003-07-28 09:56:35 +00005000 int esc = 0;
5001 char *loc;
5002 char *loc2;
5003
5004 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5005 int match;
5006 char c = *loc2;
5007 const char *s = loc2;
5008 if (zero) {
5009 *loc2 = '\0';
5010 s = rmesc;
5011 }
5012 match = pmatch(str, s);
5013 *loc2 = c;
5014 if (match)
5015 return loc;
5016 loc--;
5017 if (quotes) {
5018 if (--esc < 0) {
5019 esc = esclen(startp, loc);
5020 }
5021 if (esc % 2) {
5022 esc--;
5023 loc--;
5024 }
5025 }
5026 }
5027 return 0;
5028}
5029
5030static const char *
5031subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5032{
5033 char *startp;
5034 char *loc;
5035 int saveherefd = herefd;
5036 struct nodelist *saveargbackq = argbackq;
5037 int amount;
5038 char *rmesc, *rmescend;
5039 int zero;
5040 char *(*scan)(char *, char *, char *, char *, int , int);
5041
5042 herefd = -1;
5043 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5044 STPUTC('\0', expdest);
5045 herefd = saveherefd;
5046 argbackq = saveargbackq;
5047 startp = stackblock() + startloc;
5048
5049 switch (subtype) {
5050 case VSASSIGN:
5051 setvar(str, startp, 0);
5052 amount = startp - expdest;
5053 STADJUST(amount, expdest);
5054 return startp;
5055
5056 case VSQUESTION:
5057 varunset(p, str, startp, varflags);
5058 /* NOTREACHED */
5059 }
5060
5061 subtype -= VSTRIMRIGHT;
5062#ifdef DEBUG
5063 if (subtype < 0 || subtype > 3)
5064 abort();
5065#endif
5066
5067 rmesc = startp;
5068 rmescend = stackblock() + strloc;
5069 if (quotes) {
5070 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5071 if (rmesc != startp) {
5072 rmescend = expdest;
5073 startp = stackblock() + startloc;
5074 }
5075 }
5076 rmescend--;
5077 str = stackblock() + strloc;
5078 preglob(str, varflags & VSQUOTE, 0);
5079
5080 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5081 zero = subtype >> 1;
5082 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5083 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5084
5085 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5086 if (loc) {
5087 if (zero) {
5088 memmove(startp, loc, str - loc);
5089 loc = startp + (str - loc) - 1;
5090 }
5091 *loc = '\0';
5092 amount = loc - expdest;
5093 STADJUST(amount, expdest);
5094 }
5095 return loc;
5096}
5097
5098
Eric Andersen62483552001-07-10 06:09:16 +00005099/*
5100 * Expand a variable, and return a pointer to the next character in the
5101 * input string.
5102 */
Eric Andersenc470f442003-07-28 09:56:35 +00005103static char *
5104evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005105{
5106 int subtype;
5107 int varflags;
5108 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005109 int patloc;
5110 int c;
5111 int set;
Eric Andersen62483552001-07-10 06:09:16 +00005112 int startloc;
Eric Andersenc470f442003-07-28 09:56:35 +00005113 size_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005114 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005115 int quotes;
5116 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005117
Eric Andersenc470f442003-07-28 09:56:35 +00005118 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005119 varflags = *p++;
5120 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005121 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005122 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005123 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersen62483552001-07-10 06:09:16 +00005124 varlen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00005125 startloc = expdest - (char *)stackblock();
5126 p = strchr(p, '=') + 1;
5127
5128 if (!is_name(*var)) {
5129 set = varisset(var, varflags & VSNUL);
5130 set--;
5131 if (subtype == VSPLUS)
5132 goto vsplus;
5133 if (++set) {
5134 varvalue(var, quoted, flag);
Eric Andersen62483552001-07-10 06:09:16 +00005135 if (subtype == VSLENGTH) {
Eric Andersenc470f442003-07-28 09:56:35 +00005136 varlen =
5137 expdest - (char *)stackblock() -
5138 startloc;
Eric Andersen62483552001-07-10 06:09:16 +00005139 STADJUST(-varlen, expdest);
Eric Andersenc470f442003-07-28 09:56:35 +00005140 goto vslen;
Eric Andersen62483552001-07-10 06:09:16 +00005141 }
Eric Andersenc470f442003-07-28 09:56:35 +00005142 }
5143 } else {
5144 const char *val;
5145again:
5146 /* jump here after setting a variable with ${var=text} */
5147 val = lookupvar(var);
5148 set = !val || ((varflags & VSNUL) && !*val);
5149 if (subtype == VSPLUS)
5150 goto vsplus;
5151 if (--set) {
5152 varlen = strlen(val);
5153 if (subtype == VSLENGTH)
5154 goto vslen;
5155 memtodest(
5156 val, varlen, quoted ? DQSYNTAX : BASESYNTAX,
5157 quotes
5158 );
Eric Andersen62483552001-07-10 06:09:16 +00005159 }
5160 }
5161
Eric Andersen62483552001-07-10 06:09:16 +00005162
Eric Andersenc470f442003-07-28 09:56:35 +00005163 if (subtype == VSMINUS) {
5164vsplus:
Eric Andersen62483552001-07-10 06:09:16 +00005165 if (!set) {
Eric Andersenc470f442003-07-28 09:56:35 +00005166 argstr(
5167 p, flag | EXP_TILDE |
5168 (quoted ? EXP_QWORD : EXP_WORD)
5169 );
5170 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005171 }
5172 if (easy)
5173 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005174 goto end;
5175 }
Eric Andersen62483552001-07-10 06:09:16 +00005176
Eric Andersenc470f442003-07-28 09:56:35 +00005177 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Eric Andersen62483552001-07-10 06:09:16 +00005178 if (!set) {
Eric Andersenc470f442003-07-28 09:56:35 +00005179 if (subevalvar(p, var, 0, subtype, startloc,
5180 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005181 varflags &= ~VSNUL;
5182 /*
5183 * Remove any recorded regions beyond
5184 * start of variable
5185 */
5186 removerecordregions(startloc);
5187 goto again;
5188 }
Eric Andersenc470f442003-07-28 09:56:35 +00005189 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005190 }
5191 if (easy)
5192 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005193 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005194 }
5195
Eric Andersenc470f442003-07-28 09:56:35 +00005196 if (!set && uflag)
5197 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005198
Eric Andersenc470f442003-07-28 09:56:35 +00005199 if (subtype == VSLENGTH) {
5200vslen:
5201 cvtnum(varlen);
5202 goto record;
5203 }
5204
5205 if (subtype == VSNORMAL) {
5206 if (!easy)
5207 goto end;
5208record:
5209 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5210 goto end;
5211 }
5212
5213#ifdef DEBUG
5214 switch (subtype) {
5215 case VSTRIMLEFT:
5216 case VSTRIMLEFTMAX:
5217 case VSTRIMRIGHT:
5218 case VSTRIMRIGHTMAX:
5219 break;
5220 default:
5221 abort();
5222 }
5223#endif
5224
5225 if (set) {
5226 /*
5227 * Terminate the string and start recording the pattern
5228 * right after it
5229 */
5230 STPUTC('\0', expdest);
5231 patloc = expdest - (char *)stackblock();
5232 if (subevalvar(p, NULL, patloc, subtype,
5233 startloc, varflags, quotes) == 0) {
5234 int amount = expdest - (
5235 (char *)stackblock() + patloc - 1
5236 );
5237 STADJUST(-amount, expdest);
5238 }
5239 /* Remove any recorded regions beyond start of variable */
5240 removerecordregions(startloc);
5241 goto record;
5242 }
5243
5244end:
5245 if (subtype != VSNORMAL) { /* skip to end of alternative */
5246 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005247 for (;;) {
5248 if ((c = *p++) == CTLESC)
5249 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005250 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Eric Andersen62483552001-07-10 06:09:16 +00005251 if (set)
5252 argbackq = argbackq->next;
5253 } else if (c == CTLVAR) {
5254 if ((*p++ & VSTYPE) != VSNORMAL)
5255 nesting++;
5256 } else if (c == CTLENDVAR) {
5257 if (--nesting == 0)
5258 break;
5259 }
5260 }
5261 }
5262 return p;
5263}
5264
Eric Andersencb57d552001-06-28 07:25:16 +00005265
Eric Andersencb57d552001-06-28 07:25:16 +00005266
5267/*
Eric Andersencb57d552001-06-28 07:25:16 +00005268 * Test whether a specialized variable is set.
5269 */
5270
Eric Andersenc470f442003-07-28 09:56:35 +00005271static int
5272varisset(char *name, int nulok)
Eric Andersencb57d552001-06-28 07:25:16 +00005273{
5274 if (*name == '!')
Eric Andersenc470f442003-07-28 09:56:35 +00005275 return backgndpid != 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005276 else if (*name == '@' || *name == '*') {
5277 if (*shellparam.p == NULL)
5278 return 0;
5279
5280 if (nulok) {
5281 char **av;
5282
5283 for (av = shellparam.p; *av; av++)
5284 if (**av != '\0')
5285 return 1;
5286 return 0;
5287 }
5288 } else if (is_digit(*name)) {
5289 char *ap;
5290 int num = atoi(name);
5291
5292 if (num > shellparam.nparam)
5293 return 0;
5294
5295 if (num == 0)
5296 ap = arg0;
5297 else
5298 ap = shellparam.p[num - 1];
5299
5300 if (nulok && (ap == NULL || *ap == '\0'))
5301 return 0;
5302 }
5303 return 1;
5304}
5305
Eric Andersenc470f442003-07-28 09:56:35 +00005306
Eric Andersencb57d552001-06-28 07:25:16 +00005307/*
5308 * Put a string on the stack.
5309 */
5310
Eric Andersenc470f442003-07-28 09:56:35 +00005311static void
5312memtodest(const char *p, size_t len, int syntax, int quotes) {
5313 char *q = expdest;
5314
5315 q = makestrspace(len * 2, q);
5316
5317 while (len--) {
5318 int c = *p++;
5319 if (!c)
5320 continue;
5321 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5322 USTPUTC(CTLESC, q);
5323 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005324 }
Eric Andersenc470f442003-07-28 09:56:35 +00005325
5326 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005327}
5328
Eric Andersenc470f442003-07-28 09:56:35 +00005329
5330static void
5331strtodest(const char *p, int syntax, int quotes)
5332{
5333 memtodest(p, strlen(p), syntax, quotes);
5334}
5335
5336
Eric Andersencb57d552001-06-28 07:25:16 +00005337/*
5338 * Add the value of a specialized variable to the stack string.
5339 */
5340
Eric Andersenc470f442003-07-28 09:56:35 +00005341static void
5342varvalue(char *name, int quoted, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005343{
5344 int num;
5345 char *p;
5346 int i;
5347 int sep;
5348 int sepq = 0;
5349 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005350 int syntax;
Eric Andersencb57d552001-06-28 07:25:16 +00005351 int allow_split = flags & EXP_FULL;
5352 int quotes = flags & (EXP_FULL | EXP_CASE);
5353
5354 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5355 switch (*name) {
5356 case '$':
5357 num = rootpid;
5358 goto numvar;
5359 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005360 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005361 goto numvar;
5362 case '#':
5363 num = shellparam.nparam;
5364 goto numvar;
5365 case '!':
5366 num = backgndpid;
Eric Andersenc470f442003-07-28 09:56:35 +00005367numvar:
5368 cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005369 break;
5370 case '-':
Eric Andersenc470f442003-07-28 09:56:35 +00005371 for (i = 0 ; i < NOPTS ; i++) {
5372 if (optlist[i])
5373 STPUTC(optletters(i), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005374 }
5375 break;
5376 case '@':
5377 if (allow_split && quoted) {
5378 sep = 1 << CHAR_BIT;
5379 goto param;
5380 }
5381 /* fall through */
5382 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005383 sep = ifsset() ? ifsval()[0] : ' ';
Eric Andersencb57d552001-06-28 07:25:16 +00005384 if (quotes) {
Eric Andersenc470f442003-07-28 09:56:35 +00005385 sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK);
Eric Andersencb57d552001-06-28 07:25:16 +00005386 }
Eric Andersenc470f442003-07-28 09:56:35 +00005387param:
5388 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005389 strtodest(p, syntax, quotes);
5390 if (*ap && sep) {
Eric Andersenc470f442003-07-28 09:56:35 +00005391 p = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005392 if (sepq)
Eric Andersenc470f442003-07-28 09:56:35 +00005393 STPUTC(CTLESC, p);
5394 STPUTC(sep, p);
5395 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005396 }
5397 }
5398 break;
5399 case '0':
5400 strtodest(arg0, syntax, quotes);
5401 break;
5402 default:
5403 num = atoi(name);
5404 if (num > 0 && num <= shellparam.nparam) {
5405 strtodest(shellparam.p[num - 1], syntax, quotes);
5406 }
5407 break;
5408 }
5409}
5410
5411
Eric Andersencb57d552001-06-28 07:25:16 +00005412/*
5413 * Record the fact that we have to scan this region of the
5414 * string for IFS characters.
5415 */
5416
Eric Andersenc470f442003-07-28 09:56:35 +00005417static void
5418recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005419{
5420 struct ifsregion *ifsp;
5421
5422 if (ifslastp == NULL) {
5423 ifsp = &ifsfirst;
5424 } else {
5425 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005426 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005427 ifsp->next = NULL;
5428 ifslastp->next = ifsp;
5429 INTON;
5430 }
5431 ifslastp = ifsp;
5432 ifslastp->begoff = start;
5433 ifslastp->endoff = end;
5434 ifslastp->nulonly = nulonly;
5435}
5436
5437
Eric Andersencb57d552001-06-28 07:25:16 +00005438/*
5439 * Break the argument string into pieces based upon IFS and add the
5440 * strings to the argument list. The regions of the string to be
5441 * searched for IFS characters have been stored by recordregion.
5442 */
Eric Andersenc470f442003-07-28 09:56:35 +00005443static void
5444ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005445{
Eric Andersencb57d552001-06-28 07:25:16 +00005446 struct ifsregion *ifsp;
5447 struct strlist *sp;
5448 char *start;
5449 char *p;
5450 char *q;
5451 const char *ifs, *realifs;
5452 int ifsspc;
5453 int nulonly;
5454
5455
5456 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005457 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005458 ifsspc = 0;
5459 nulonly = 0;
5460 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005461 ifsp = &ifsfirst;
5462 do {
5463 p = string + ifsp->begoff;
5464 nulonly = ifsp->nulonly;
5465 ifs = nulonly ? nullstr : realifs;
5466 ifsspc = 0;
5467 while (p < string + ifsp->endoff) {
5468 q = p;
5469 if (*p == CTLESC)
5470 p++;
5471 if (strchr(ifs, *p)) {
5472 if (!nulonly)
5473 ifsspc = (strchr(defifs, *p) != NULL);
5474 /* Ignore IFS whitespace at start */
5475 if (q == start && ifsspc) {
5476 p++;
5477 start = p;
5478 continue;
5479 }
5480 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005481 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005482 sp->text = start;
5483 *arglist->lastp = sp;
5484 arglist->lastp = &sp->next;
5485 p++;
5486 if (!nulonly) {
5487 for (;;) {
5488 if (p >= string + ifsp->endoff) {
5489 break;
5490 }
5491 q = p;
5492 if (*p == CTLESC)
5493 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005494 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005495 p = q;
5496 break;
5497 } else if (strchr(defifs, *p) == NULL) {
5498 if (ifsspc) {
5499 p++;
5500 ifsspc = 0;
5501 } else {
5502 p = q;
5503 break;
5504 }
5505 } else
5506 p++;
5507 }
5508 }
5509 start = p;
5510 } else
5511 p++;
5512 }
5513 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005514 if (nulonly)
5515 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005516 }
5517
Eric Andersenc470f442003-07-28 09:56:35 +00005518 if (!*start)
5519 return;
5520
5521add:
5522 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005523 sp->text = start;
5524 *arglist->lastp = sp;
5525 arglist->lastp = &sp->next;
5526}
5527
Eric Andersenc470f442003-07-28 09:56:35 +00005528static void
5529ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005530{
Eric Andersenc470f442003-07-28 09:56:35 +00005531 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005532
Eric Andersenc470f442003-07-28 09:56:35 +00005533 INTOFF;
5534 p = ifsfirst.next;
5535 do {
5536 struct ifsregion *ifsp;
5537 ifsp = p->next;
5538 ckfree(p);
5539 p = ifsp;
5540 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005541 ifslastp = NULL;
5542 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005543 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005544}
5545
Eric Andersen90898442003-08-06 11:20:52 +00005546static void expmeta(char *, char *);
5547static struct strlist *expsort(struct strlist *);
5548static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005549
Eric Andersen90898442003-08-06 11:20:52 +00005550static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005551
Eric Andersencb57d552001-06-28 07:25:16 +00005552
Eric Andersenc470f442003-07-28 09:56:35 +00005553static void
Eric Andersen90898442003-08-06 11:20:52 +00005554expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005555{
Eric Andersen90898442003-08-06 11:20:52 +00005556 static const char metachars[] = {
5557 '*', '?', '[', 0
5558 };
Eric Andersencb57d552001-06-28 07:25:16 +00005559 /* TODO - EXP_REDIR */
5560
5561 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005562 struct strlist **savelastp;
5563 struct strlist *sp;
5564 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005565
Eric Andersencb57d552001-06-28 07:25:16 +00005566 if (fflag)
5567 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005568 if (!strpbrk(str->text, metachars))
5569 goto nometa;
5570 savelastp = exparg.lastp;
5571
Eric Andersencb57d552001-06-28 07:25:16 +00005572 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005573 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005574 {
5575 int i = strlen(str->text);
5576 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5577 }
5578
5579 expmeta(expdir, p);
5580 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005581 if (p != str->text)
5582 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005583 INTON;
5584 if (exparg.lastp == savelastp) {
5585 /*
5586 * no matches
5587 */
Eric Andersenc470f442003-07-28 09:56:35 +00005588nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005589 *exparg.lastp = str;
5590 rmescapes(str->text);
5591 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005592 } else {
5593 *exparg.lastp = NULL;
5594 *savelastp = sp = expsort(*savelastp);
5595 while (sp->next != NULL)
5596 sp = sp->next;
5597 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005598 }
5599 str = str->next;
5600 }
5601}
5602
Eric Andersencb57d552001-06-28 07:25:16 +00005603/*
Eric Andersenc470f442003-07-28 09:56:35 +00005604 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005605 */
5606
Eric Andersenc470f442003-07-28 09:56:35 +00005607static void
Eric Andersen90898442003-08-06 11:20:52 +00005608addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005609{
Eric Andersencb57d552001-06-28 07:25:16 +00005610 struct strlist *sp;
5611
Eric Andersenc470f442003-07-28 09:56:35 +00005612 sp = (struct strlist *)stalloc(sizeof *sp);
5613 sp->text = sstrdup(name);
5614 *exparg.lastp = sp;
5615 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005616}
5617
5618
Eric Andersencb57d552001-06-28 07:25:16 +00005619/*
Eric Andersen90898442003-08-06 11:20:52 +00005620 * Do metacharacter (i.e. *, ?, [...]) expansion.
5621 */
5622
5623static void
5624expmeta(char *enddir, char *name)
5625{
5626 char *p;
5627 const char *cp;
5628 char *start;
5629 char *endname;
5630 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005631 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005632 DIR *dirp;
5633 struct dirent *dp;
5634 int atend;
5635 int matchdot;
5636
5637 metaflag = 0;
5638 start = name;
5639 for (p = name; *p; p++) {
5640 if (*p == '*' || *p == '?')
5641 metaflag = 1;
5642 else if (*p == '[') {
5643 char *q = p + 1;
5644 if (*q == '!')
5645 q++;
5646 for (;;) {
5647 if (*q == '\\')
5648 q++;
5649 if (*q == '/' || *q == '\0')
5650 break;
5651 if (*++q == ']') {
5652 metaflag = 1;
5653 break;
5654 }
5655 }
5656 } else if (*p == '\\')
5657 p++;
5658 else if (*p == '/') {
5659 if (metaflag)
5660 goto out;
5661 start = p + 1;
5662 }
5663 }
5664out:
5665 if (metaflag == 0) { /* we've reached the end of the file name */
5666 if (enddir != expdir)
5667 metaflag++;
5668 p = name;
5669 do {
5670 if (*p == '\\')
5671 p++;
5672 *enddir++ = *p;
5673 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005674 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005675 addfname(expdir);
5676 return;
5677 }
5678 endname = p;
5679 if (name < start) {
5680 p = name;
5681 do {
5682 if (*p == '\\')
5683 p++;
5684 *enddir++ = *p++;
5685 } while (p < start);
5686 }
5687 if (enddir == expdir) {
5688 cp = ".";
5689 } else if (enddir == expdir + 1 && *expdir == '/') {
5690 cp = "/";
5691 } else {
5692 cp = expdir;
5693 enddir[-1] = '\0';
5694 }
5695 if ((dirp = opendir(cp)) == NULL)
5696 return;
5697 if (enddir != expdir)
5698 enddir[-1] = '/';
5699 if (*endname == 0) {
5700 atend = 1;
5701 } else {
5702 atend = 0;
5703 *endname++ = '\0';
5704 }
5705 matchdot = 0;
5706 p = start;
5707 if (*p == '\\')
5708 p++;
5709 if (*p == '.')
5710 matchdot++;
5711 while (! intpending && (dp = readdir(dirp)) != NULL) {
5712 if (dp->d_name[0] == '.' && ! matchdot)
5713 continue;
5714 if (pmatch(start, dp->d_name)) {
5715 if (atend) {
5716 scopy(dp->d_name, enddir);
5717 addfname(expdir);
5718 } else {
5719 for (p = enddir, cp = dp->d_name;
5720 (*p++ = *cp++) != '\0';)
5721 continue;
5722 p[-1] = '/';
5723 expmeta(p, endname);
5724 }
5725 }
5726 }
5727 closedir(dirp);
5728 if (! atend)
5729 endname[-1] = '/';
5730}
5731
5732/*
5733 * Sort the results of file name expansion. It calculates the number of
5734 * strings to sort and then calls msort (short for merge sort) to do the
5735 * work.
5736 */
5737
5738static struct strlist *
5739expsort(struct strlist *str)
5740{
5741 int len;
5742 struct strlist *sp;
5743
5744 len = 0;
5745 for (sp = str ; sp ; sp = sp->next)
5746 len++;
5747 return msort(str, len);
5748}
5749
5750
5751static struct strlist *
5752msort(struct strlist *list, int len)
5753{
5754 struct strlist *p, *q = NULL;
5755 struct strlist **lpp;
5756 int half;
5757 int n;
5758
5759 if (len <= 1)
5760 return list;
5761 half = len >> 1;
5762 p = list;
5763 for (n = half ; --n >= 0 ; ) {
5764 q = p;
5765 p = p->next;
5766 }
5767 q->next = NULL; /* terminate first half of list */
5768 q = msort(list, half); /* sort first half of list */
5769 p = msort(p, len - half); /* sort second half */
5770 lpp = &list;
5771 for (;;) {
5772#ifdef CONFIG_LOCALE_SUPPORT
5773 if (strcoll(p->text, q->text) < 0)
5774#else
5775 if (strcmp(p->text, q->text) < 0)
5776#endif
5777 {
5778 *lpp = p;
5779 lpp = &p->next;
5780 if ((p = *lpp) == NULL) {
5781 *lpp = q;
5782 break;
5783 }
5784 } else {
5785 *lpp = q;
5786 lpp = &q->next;
5787 if ((q = *lpp) == NULL) {
5788 *lpp = p;
5789 break;
5790 }
5791 }
5792 }
5793 return list;
5794}
5795
5796
5797/*
Eric Andersencb57d552001-06-28 07:25:16 +00005798 * Returns true if the pattern matches the string.
5799 */
5800
Eric Andersenc470f442003-07-28 09:56:35 +00005801static inline int
5802patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005803{
Eric Andersenc470f442003-07-28 09:56:35 +00005804 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005805}
5806
5807
Eric Andersencb57d552001-06-28 07:25:16 +00005808/*
5809 * Remove any CTLESC characters from a string.
5810 */
5811
Eric Andersenc470f442003-07-28 09:56:35 +00005812static char *
5813_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005814{
5815 char *p, *q, *r;
5816 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005817 unsigned inquotes;
5818 int notescaped;
5819 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005820
5821 p = strpbrk(str, qchars);
5822 if (!p) {
5823 return str;
5824 }
5825 q = p;
5826 r = str;
5827 if (flag & RMESCAPE_ALLOC) {
5828 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005829 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005830
Eric Andersenc470f442003-07-28 09:56:35 +00005831 if (flag & RMESCAPE_GROW) {
5832 r = makestrspace(fulllen, expdest);
5833 } else if (flag & RMESCAPE_HEAP) {
5834 r = ckmalloc(fulllen);
5835 } else {
5836 r = stalloc(fulllen);
5837 }
5838 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005839 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005840 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005841 }
5842 }
Eric Andersenc470f442003-07-28 09:56:35 +00005843 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5844 globbing = flag & RMESCAPE_GLOB;
5845 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005846 while (*p) {
5847 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005848 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005849 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005850 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005851 continue;
5852 }
Eric Andersenc470f442003-07-28 09:56:35 +00005853 if (*p == '\\') {
5854 /* naked back slash */
5855 notescaped = 0;
5856 goto copy;
5857 }
Eric Andersencb57d552001-06-28 07:25:16 +00005858 if (*p == CTLESC) {
5859 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005860 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005861 *q++ = '\\';
5862 }
5863 }
Eric Andersenc470f442003-07-28 09:56:35 +00005864 notescaped = globbing;
5865copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005866 *q++ = *p++;
5867 }
5868 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005869 if (flag & RMESCAPE_GROW) {
5870 expdest = r;
5871 STADJUST(q - r + 1, expdest);
5872 }
Eric Andersencb57d552001-06-28 07:25:16 +00005873 return r;
5874}
Eric Andersencb57d552001-06-28 07:25:16 +00005875
5876
Eric Andersencb57d552001-06-28 07:25:16 +00005877/*
5878 * See if a pattern matches in a case statement.
5879 */
5880
Eric Andersenc470f442003-07-28 09:56:35 +00005881int
5882casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005883{
Eric Andersencb57d552001-06-28 07:25:16 +00005884 struct stackmark smark;
5885 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005886
5887 setstackmark(&smark);
5888 argbackq = pattern->narg.backquote;
5889 STARTSTACKSTR(expdest);
5890 ifslastp = NULL;
5891 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005892 STACKSTRNUL(expdest);
5893 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005894 popstackmark(&smark);
5895 return result;
5896}
5897
5898/*
5899 * Our own itoa().
5900 */
5901
Eric Andersenc470f442003-07-28 09:56:35 +00005902static int
5903cvtnum(long num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005904{
Eric Andersencb57d552001-06-28 07:25:16 +00005905 int len;
5906
Eric Andersenc470f442003-07-28 09:56:35 +00005907 expdest = makestrspace(32, expdest);
5908 len = fmtstr(expdest, 32, "%ld", num);
5909 STADJUST(len, expdest);
5910 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005911}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005912
Eric Andersenc470f442003-07-28 09:56:35 +00005913static void
5914varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005915{
Eric Andersenc470f442003-07-28 09:56:35 +00005916 const char *msg;
5917 const char *tail;
5918
5919 tail = nullstr;
5920 msg = "parameter not set";
5921 if (umsg) {
5922 if (*end == CTLENDVAR) {
5923 if (varflags & VSNUL)
5924 tail = " or null";
5925 } else
5926 msg = umsg;
5927 }
5928 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005929}
Eric Andersen90898442003-08-06 11:20:52 +00005930
5931
Eric Andersenc470f442003-07-28 09:56:35 +00005932/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005933
Eric Andersencb57d552001-06-28 07:25:16 +00005934/*
Eric Andersen90898442003-08-06 11:20:52 +00005935 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005936 */
5937
Eric Andersenc470f442003-07-28 09:56:35 +00005938#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5939#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005940
Eric Andersenc470f442003-07-28 09:56:35 +00005941static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005942
Eric Andersencb57d552001-06-28 07:25:16 +00005943/*
5944 * Read a line from the script.
5945 */
5946
Eric Andersenc470f442003-07-28 09:56:35 +00005947static inline char *
5948pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00005949{
5950 char *p = line;
5951 int nleft = len;
5952 int c;
5953
5954 while (--nleft > 0) {
5955 c = pgetc2();
5956 if (c == PEOF) {
5957 if (p == line)
5958 return NULL;
5959 break;
5960 }
5961 *p++ = c;
5962 if (c == '\n')
5963 break;
5964 }
5965 *p = '\0';
5966 return line;
5967}
5968
Eric Andersenc470f442003-07-28 09:56:35 +00005969
5970/*
5971 * Read a character from the script, returning PEOF on end of file.
5972 * Nul characters in the input are silently discarded.
5973 */
5974
5975#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5976
5977#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5978#define pgetc_macro() pgetc()
5979static int
5980pgetc(void)
5981{
5982 return pgetc_as_macro();
5983}
5984#else
5985#define pgetc_macro() pgetc_as_macro()
5986static int
5987pgetc(void)
5988{
5989 return pgetc_macro();
5990}
5991#endif
5992
5993
5994/*
5995 * Same as pgetc(), but ignores PEOA.
5996 */
5997#ifdef CONFIG_ASH_ALIAS
5998static int pgetc2(void)
5999{
6000 int c;
6001
6002 do {
6003 c = pgetc_macro();
6004 } while (c == PEOA);
6005 return c;
6006}
6007#else
6008static inline int pgetc2(void)
6009{
6010 return pgetc_macro();
6011}
6012#endif
6013
6014
6015#ifdef CONFIG_FEATURE_COMMAND_EDITING
6016static const char *cmdedit_prompt;
6017static inline void putprompt(const char *s)
6018{
6019 cmdedit_prompt = s;
6020}
6021#else
6022static inline void putprompt(const char *s)
6023{
6024 out2str(s);
6025}
6026#endif
6027
6028static inline int
6029preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006030{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006031 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006032 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006033 parsenextc = buf;
6034
Eric Andersenc470f442003-07-28 09:56:35 +00006035retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006036#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006037 if (!iflag || parsefile->fd)
6038 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6039 else {
6040 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6041 if(nr == 0) {
6042 /* Ctrl+C presend */
6043 raise(SIGINT);
6044 goto retry;
6045 }
6046 if(nr < 0) {
6047 /* Ctrl+D presend */
6048 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006049 }
Eric Andersencb57d552001-06-28 07:25:16 +00006050 }
6051#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006052 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006053#endif
6054
6055 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006056 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6057 int flags = fcntl(0, F_GETFL, 0);
6058 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006059 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006060 if (fcntl(0, F_SETFL, flags) >= 0) {
6061 out2str("sh: turning off NDELAY mode\n");
6062 goto retry;
6063 }
6064 }
6065 }
6066 }
6067 return nr;
6068}
6069
6070/*
6071 * Refill the input buffer and return the next input character:
6072 *
6073 * 1) If a string was pushed back on the input, pop it;
6074 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6075 * from a string so we can't refill the buffer, return EOF.
6076 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6077 * 4) Process input up to the next newline, deleting nul characters.
6078 */
6079
Eric Andersenc470f442003-07-28 09:56:35 +00006080int
6081preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006082{
6083 char *p, *q;
6084 int more;
6085 char savec;
6086
6087 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006088#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006089 if (parsenleft == -1 && parsefile->strpush->ap &&
6090 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006091 return PEOA;
6092 }
Eric Andersen2870d962001-07-02 17:27:21 +00006093#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006094 popstring();
6095 if (--parsenleft >= 0)
6096 return (*parsenextc++);
6097 }
6098 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6099 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006100 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006101
Eric Andersenc470f442003-07-28 09:56:35 +00006102again:
Eric Andersencb57d552001-06-28 07:25:16 +00006103 if (parselleft <= 0) {
6104 if ((parselleft = preadfd()) <= 0) {
6105 parselleft = parsenleft = EOF_NLEFT;
6106 return PEOF;
6107 }
6108 }
6109
6110 q = p = parsenextc;
6111
6112 /* delete nul characters */
6113 for (more = 1; more;) {
6114 switch (*p) {
6115 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006116 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006117 goto check;
6118
Eric Andersencb57d552001-06-28 07:25:16 +00006119 case '\n':
6120 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006121 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006122 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006123
Eric Andersencb57d552001-06-28 07:25:16 +00006124 }
6125
6126 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006127check:
Eric Andersencb57d552001-06-28 07:25:16 +00006128 if (--parselleft <= 0 && more) {
6129 parsenleft = q - parsenextc - 1;
6130 if (parsenleft < 0)
6131 goto again;
6132 more = 0;
6133 }
6134 }
6135
6136 savec = *q;
6137 *q = '\0';
6138
6139 if (vflag) {
6140 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006141 }
6142
6143 *q = savec;
6144
6145 return *parsenextc++;
6146}
6147
Eric Andersenc470f442003-07-28 09:56:35 +00006148/*
6149 * Undo the last call to pgetc. Only one character may be pushed back.
6150 * PEOF may be pushed back.
6151 */
6152
6153void
6154pungetc(void)
6155{
6156 parsenleft++;
6157 parsenextc--;
6158}
Eric Andersencb57d552001-06-28 07:25:16 +00006159
6160/*
6161 * Push a string back onto the input at this current parsefile level.
6162 * We handle aliases this way.
6163 */
Eric Andersenc470f442003-07-28 09:56:35 +00006164void
6165pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006166{
Eric Andersencb57d552001-06-28 07:25:16 +00006167 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006168 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006169
Eric Andersenc470f442003-07-28 09:56:35 +00006170 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006171 INTOFF;
6172/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6173 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006174 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006175 sp->prev = parsefile->strpush;
6176 parsefile->strpush = sp;
6177 } else
6178 sp = parsefile->strpush = &(parsefile->basestrpush);
6179 sp->prevstring = parsenextc;
6180 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006181#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006182 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006183 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006184 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006185 sp->string = s;
6186 }
Eric Andersen2870d962001-07-02 17:27:21 +00006187#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006188 parsenextc = s;
6189 parsenleft = len;
6190 INTON;
6191}
6192
Eric Andersenc470f442003-07-28 09:56:35 +00006193void
6194popstring(void)
6195{
6196 struct strpush *sp = parsefile->strpush;
6197
6198 INTOFF;
6199#ifdef CONFIG_ASH_ALIAS
6200 if (sp->ap) {
6201 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6202 checkkwd |= CHKALIAS;
6203 }
6204 if (sp->string != sp->ap->val) {
6205 ckfree(sp->string);
6206 }
6207 sp->ap->flag &= ~ALIASINUSE;
6208 if (sp->ap->flag & ALIASDEAD) {
6209 unalias(sp->ap->name);
6210 }
6211 }
6212#endif
6213 parsenextc = sp->prevstring;
6214 parsenleft = sp->prevnleft;
6215/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6216 parsefile->strpush = sp->prev;
6217 if (sp != &(parsefile->basestrpush))
6218 ckfree(sp);
6219 INTON;
6220}
6221
6222/*
6223 * Set the input to take input from a file. If push is set, push the
6224 * old input onto the stack first.
6225 */
6226
6227void
6228setinputfile(const char *fname, int push)
6229{
6230 int fd;
6231 int fd2;
6232
6233 INTOFF;
6234 if ((fd = open(fname, O_RDONLY)) < 0)
6235 error("Can't open %s", fname);
6236 if (fd < 10) {
6237 fd2 = copyfd(fd, 10);
6238 close(fd);
6239 if (fd2 < 0)
6240 error("Out of file descriptors");
6241 fd = fd2;
6242 }
6243 setinputfd(fd, push);
6244 INTON;
6245}
6246
6247
6248/*
6249 * Like setinputfile, but takes an open file descriptor. Call this with
6250 * interrupts off.
6251 */
6252
6253static void
6254setinputfd(int fd, int push)
6255{
6256 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6257 if (push) {
6258 pushfile();
6259 parsefile->buf = 0;
6260 }
6261 parsefile->fd = fd;
6262 if (parsefile->buf == NULL)
6263 parsefile->buf = ckmalloc(IBUFSIZ);
6264 parselleft = parsenleft = 0;
6265 plinno = 1;
6266}
6267
Eric Andersencb57d552001-06-28 07:25:16 +00006268
Eric Andersencb57d552001-06-28 07:25:16 +00006269/*
6270 * Like setinputfile, but takes input from a string.
6271 */
6272
Eric Andersenc470f442003-07-28 09:56:35 +00006273static void
6274setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006275{
Eric Andersencb57d552001-06-28 07:25:16 +00006276 INTOFF;
6277 pushfile();
6278 parsenextc = string;
6279 parsenleft = strlen(string);
6280 parsefile->buf = NULL;
6281 plinno = 1;
6282 INTON;
6283}
6284
6285
Eric Andersencb57d552001-06-28 07:25:16 +00006286/*
6287 * To handle the "." command, a stack of input files is used. Pushfile
6288 * adds a new entry to the stack and popfile restores the previous level.
6289 */
6290
Eric Andersenc470f442003-07-28 09:56:35 +00006291static void
6292pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006293{
Eric Andersencb57d552001-06-28 07:25:16 +00006294 struct parsefile *pf;
6295
6296 parsefile->nleft = parsenleft;
6297 parsefile->lleft = parselleft;
6298 parsefile->nextc = parsenextc;
6299 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006300 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006301 pf->prev = parsefile;
6302 pf->fd = -1;
6303 pf->strpush = NULL;
6304 pf->basestrpush.prev = NULL;
6305 parsefile = pf;
6306}
6307
Eric Andersenc470f442003-07-28 09:56:35 +00006308
6309static void
6310popfile(void)
6311{
6312 struct parsefile *pf = parsefile;
6313
6314 INTOFF;
6315 if (pf->fd >= 0)
6316 close(pf->fd);
6317 if (pf->buf)
6318 ckfree(pf->buf);
6319 while (pf->strpush)
6320 popstring();
6321 parsefile = pf->prev;
6322 ckfree(pf);
6323 parsenleft = parsefile->nleft;
6324 parselleft = parsefile->lleft;
6325 parsenextc = parsefile->nextc;
6326 plinno = parsefile->linno;
6327 INTON;
6328}
Eric Andersencb57d552001-06-28 07:25:16 +00006329
6330
Eric Andersen2870d962001-07-02 17:27:21 +00006331/*
Eric Andersenc470f442003-07-28 09:56:35 +00006332 * Return to top level.
6333 */
Eric Andersen2870d962001-07-02 17:27:21 +00006334
Eric Andersenc470f442003-07-28 09:56:35 +00006335static void
6336popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006337{
Eric Andersenc470f442003-07-28 09:56:35 +00006338 while (parsefile != &basepf)
6339 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006340}
6341
Eric Andersen2870d962001-07-02 17:27:21 +00006342
Eric Andersenc470f442003-07-28 09:56:35 +00006343/*
6344 * Close the file(s) that the shell is reading commands from. Called
6345 * after a fork is done.
6346 */
6347
6348static void
6349closescript(void)
6350{
6351 popallfiles();
6352 if (parsefile->fd > 0) {
6353 close(parsefile->fd);
6354 parsefile->fd = 0;
6355 }
6356}
Eric Andersenc470f442003-07-28 09:56:35 +00006357
Eric Andersen90898442003-08-06 11:20:52 +00006358/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006359
6360/* mode flags for set_curjob */
6361#define CUR_DELETE 2
6362#define CUR_RUNNING 1
6363#define CUR_STOPPED 0
6364
6365/* mode flags for dowait */
6366#define DOWAIT_NORMAL 0
6367#define DOWAIT_BLOCK 1
6368
6369/* array of jobs */
6370static struct job *jobtab;
6371/* size of array */
6372static unsigned njobs;
6373#if JOBS
6374/* pgrp of shell on invocation */
6375static int initialpgrp;
6376static int ttyfd = -1;
6377#endif
6378/* current job */
6379static struct job *curjob;
6380/* number of presumed living untracked jobs */
6381static int jobless;
6382
6383static void set_curjob(struct job *, unsigned);
6384#if JOBS
6385static int restartjob(struct job *, int);
6386static void xtcsetpgrp(int, pid_t);
6387static char *commandtext(union node *);
6388static void cmdlist(union node *, int);
6389static void cmdtxt(union node *);
6390static void cmdputs(const char *);
6391static void showpipe(struct job *, FILE *);
6392#endif
6393static int sprint_status(char *, int, int);
6394static void freejob(struct job *);
6395static struct job *getjob(const char *, int);
6396static struct job *growjobtab(void);
6397static void forkchild(struct job *, union node *, int);
6398static void forkparent(struct job *, union node *, int, pid_t);
6399static int dowait(int, struct job *);
6400static int getstatus(struct job *);
6401
6402static void
6403set_curjob(struct job *jp, unsigned mode)
6404{
6405 struct job *jp1;
6406 struct job **jpp, **curp;
6407
6408 /* first remove from list */
6409 jpp = curp = &curjob;
6410 do {
6411 jp1 = *jpp;
6412 if (jp1 == jp)
6413 break;
6414 jpp = &jp1->prev_job;
6415 } while (1);
6416 *jpp = jp1->prev_job;
6417
6418 /* Then re-insert in correct position */
6419 jpp = curp;
6420 switch (mode) {
6421 default:
6422#ifdef DEBUG
6423 abort();
6424#endif
6425 case CUR_DELETE:
6426 /* job being deleted */
6427 break;
6428 case CUR_RUNNING:
6429 /* newly created job or backgrounded job,
6430 put after all stopped jobs. */
6431 do {
6432 jp1 = *jpp;
6433#ifdef JOBS
6434 if (!jp1 || jp1->state != JOBSTOPPED)
6435#endif
6436 break;
6437 jpp = &jp1->prev_job;
6438 } while (1);
6439 /* FALLTHROUGH */
6440#ifdef JOBS
6441 case CUR_STOPPED:
6442#endif
6443 /* newly stopped job - becomes curjob */
6444 jp->prev_job = *jpp;
6445 *jpp = jp;
6446 break;
6447 }
6448}
6449
6450#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006451/*
6452 * Turn job control on and off.
6453 *
6454 * Note: This code assumes that the third arg to ioctl is a character
6455 * pointer, which is true on Berkeley systems but not System V. Since
6456 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006457 *
6458 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006459 */
6460
Eric Andersenc470f442003-07-28 09:56:35 +00006461void
6462setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006463{
Eric Andersenc470f442003-07-28 09:56:35 +00006464 int fd;
6465 int pgrp;
6466
6467 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006468 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006469 if (on) {
6470 int ofd;
6471 ofd = fd = open(_PATH_TTY, O_RDWR);
6472 if (fd < 0) {
6473 fd += 3;
6474 while (!isatty(fd) && --fd >= 0)
6475 ;
6476 }
6477 fd = fcntl(fd, F_DUPFD, 10);
6478 close(ofd);
6479 if (fd < 0)
6480 goto out;
6481 fcntl(fd, F_SETFD, FD_CLOEXEC);
6482 do { /* while we are in the background */
6483 if ((pgrp = tcgetpgrp(fd)) < 0) {
6484out:
6485 sh_warnx("can't access tty; job control turned off");
6486 mflag = on = 0;
6487 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006488 }
Eric Andersenc470f442003-07-28 09:56:35 +00006489 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006490 break;
6491 killpg(0, SIGTTIN);
6492 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006493 initialpgrp = pgrp;
6494
Eric Andersencb57d552001-06-28 07:25:16 +00006495 setsignal(SIGTSTP);
6496 setsignal(SIGTTOU);
6497 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006498 pgrp = rootpid;
6499 setpgid(0, pgrp);
6500 xtcsetpgrp(fd, pgrp);
6501 } else {
6502 /* turning job control off */
6503 fd = ttyfd;
6504 pgrp = initialpgrp;
6505 xtcsetpgrp(fd, pgrp);
6506 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006507 setsignal(SIGTSTP);
6508 setsignal(SIGTTOU);
6509 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006510close:
6511 close(fd);
6512 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006513 }
Eric Andersenc470f442003-07-28 09:56:35 +00006514 ttyfd = fd;
6515 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006516}
Eric Andersencb57d552001-06-28 07:25:16 +00006517
Eric Andersenc470f442003-07-28 09:56:35 +00006518static int
Eric Andersen90898442003-08-06 11:20:52 +00006519killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006520{
6521 int signo = -1;
6522 int list = 0;
6523 int i;
6524 pid_t pid;
6525 struct job *jp;
6526
6527 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006528usage:
6529 error(
6530"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6531"kill -l [exitstatus]"
6532 );
Eric Andersencb57d552001-06-28 07:25:16 +00006533 }
6534
Eric Andersenc470f442003-07-28 09:56:35 +00006535 if (**++argv == '-') {
6536 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006537 if (signo < 0) {
6538 int c;
6539
6540 while ((c = nextopt("ls:")) != '\0')
6541 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006542 default:
6543#ifdef DEBUG
6544 abort();
6545#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006546 case 'l':
6547 list = 1;
6548 break;
6549 case 's':
6550 signo = decode_signal(optionarg, 1);
6551 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006552 error(
6553 "invalid signal number or name: %s",
6554 optionarg
6555 );
Eric Andersencb57d552001-06-28 07:25:16 +00006556 }
Eric Andersen2870d962001-07-02 17:27:21 +00006557 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006558 }
Eric Andersenc470f442003-07-28 09:56:35 +00006559 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006560 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006561 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006562 }
6563
6564 if (!list && signo < 0)
6565 signo = SIGTERM;
6566
Eric Andersenc470f442003-07-28 09:56:35 +00006567 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006568 goto usage;
6569 }
6570
6571 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006572 const char *name;
6573
Eric Andersenc470f442003-07-28 09:56:35 +00006574 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006575 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006576 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006577 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006578 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006579 }
6580 return 0;
6581 }
Eric Andersen34506362001-08-02 05:02:46 +00006582 name = u_signal_names(*argptr, &signo, -1);
6583 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006584 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006585 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006586 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006587 return 0;
6588 }
6589
Eric Andersenc470f442003-07-28 09:56:35 +00006590 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006591 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006592 if (**argv == '%') {
6593 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006594 pid = -jp->ps[0].pid;
6595 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006596 pid = number(*argv);
6597 if (kill(pid, signo) != 0) {
6598 sh_warnx("%m\n");
6599 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006600 }
Eric Andersenc470f442003-07-28 09:56:35 +00006601 } while (*++argv);
6602
6603 return i;
6604}
6605#endif /* JOBS */
6606
6607#if defined(JOBS) || defined(DEBUG)
6608static int
6609jobno(const struct job *jp)
6610{
6611 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006612}
6613#endif
6614
Eric Andersenc470f442003-07-28 09:56:35 +00006615#ifdef JOBS
6616static int
6617fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006618{
Eric Andersenc470f442003-07-28 09:56:35 +00006619 struct job *jp;
6620 FILE *out;
6621 int mode;
6622 int retval;
6623
6624 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6625 nextopt(nullstr);
6626 argv = argptr;
6627 out = stdout;
6628 do {
6629 jp = getjob(*argv, 1);
6630 if (mode == FORK_BG) {
6631 set_curjob(jp, CUR_RUNNING);
6632 fprintf(out, "[%d] ", jobno(jp));
6633 }
6634 outstr(jp->ps->cmd, out);
6635 showpipe(jp, out);
6636 retval = restartjob(jp, mode);
6637 } while (*argv && *++argv);
6638 return retval;
6639}
6640
6641static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6642
6643
6644static int
6645restartjob(struct job *jp, int mode)
6646{
6647 struct procstat *ps;
6648 int i;
6649 int status;
6650 pid_t pgid;
6651
6652 INTOFF;
6653 if (jp->state == JOBDONE)
6654 goto out;
6655 jp->state = JOBRUNNING;
6656 pgid = jp->ps->pid;
6657 if (mode == FORK_FG)
6658 xtcsetpgrp(ttyfd, pgid);
6659 killpg(pgid, SIGCONT);
6660 ps = jp->ps;
6661 i = jp->nprocs;
6662 do {
6663 if (WIFSTOPPED(ps->status)) {
6664 ps->status = -1;
6665 }
6666 } while (ps++, --i);
6667out:
6668 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6669 INTON;
6670 return status;
6671}
6672#endif
6673
6674static int
6675sprint_status(char *s, int status, int sigonly)
6676{
6677 int col;
6678 int st;
6679
6680 col = 0;
6681 st = WEXITSTATUS(status);
6682 if (!WIFEXITED(status)) {
6683 st = WSTOPSIG(status);
6684#if JOBS
6685 if (!WIFSTOPPED(status))
6686 st = WTERMSIG(status);
6687#endif
6688 if (sigonly) {
6689 if (st == SIGINT || st == SIGPIPE)
6690 goto out;
6691 if (WIFSTOPPED(status))
6692 goto out;
6693 }
6694 st &= 0x7f;
6695 col = fmtstr(s, 32, u_signal_names(NULL, &st, 0));
6696 if (WCOREDUMP(status)) {
6697 col += fmtstr(s + col, 16, " (core dumped)");
6698 }
6699 } else if (!sigonly) {
6700 if (st)
6701 col = fmtstr(s, 16, "Done(%d)", st);
6702 else
6703 col = fmtstr(s, 16, "Done");
6704 }
6705
6706out:
6707 return col;
6708}
6709
6710#if JOBS
6711static void
6712showjob(FILE *out, struct job *jp, int mode)
6713{
6714 struct procstat *ps;
6715 struct procstat *psend;
6716 int col;
6717 int indent;
6718 char s[80];
6719
6720 ps = jp->ps;
6721
6722 if (mode & SHOW_PGID) {
6723 /* just output process (group) id of pipeline */
6724 fprintf(out, "%d\n", ps->pid);
6725 return;
6726 }
6727
6728 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6729 indent = col;
6730
6731 if (jp == curjob)
6732 s[col - 2] = '+';
6733 else if (curjob && jp == curjob->prev_job)
6734 s[col - 2] = '-';
6735
6736 if (mode & SHOW_PID)
6737 col += fmtstr(s + col, 16, "%d ", ps->pid);
6738
6739 psend = ps + jp->nprocs;
6740
6741 if (jp->state == JOBRUNNING) {
6742 scopy("Running", s + col);
6743 col += strlen("Running");
6744 } else {
6745 int status = psend[-1].status;
6746#if JOBS
6747 if (jp->state == JOBSTOPPED)
6748 status = jp->stopstatus;
6749#endif
6750 col += sprint_status(s + col, status, 0);
6751 }
6752
6753 goto start;
6754
6755 do {
6756 /* for each process */
6757 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6758
6759start:
Eric Andersen90898442003-08-06 11:20:52 +00006760 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006761 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6762 );
6763 if (!(mode & SHOW_PID)) {
6764 showpipe(jp, out);
6765 break;
6766 }
6767 if (++ps == psend) {
6768 outcslow('\n', out);
6769 break;
6770 }
6771 } while (1);
6772
6773 jp->changed = 0;
6774
6775 if (jp->state == JOBDONE) {
6776 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6777 freejob(jp);
6778 }
6779}
6780
6781
6782static int
6783jobscmd(int argc, char **argv)
6784{
6785 int mode, m;
6786 FILE *out;
6787
6788 mode = 0;
6789 while ((m = nextopt("lp")))
6790 if (m == 'l')
6791 mode = SHOW_PID;
6792 else
6793 mode = SHOW_PGID;
6794
6795 out = stdout;
6796 argv = argptr;
6797 if (*argv)
6798 do
6799 showjob(out, getjob(*argv,0), mode);
6800 while (*++argv);
6801 else
6802 showjobs(out, mode);
6803
Eric Andersencb57d552001-06-28 07:25:16 +00006804 return 0;
6805}
6806
6807
6808/*
6809 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6810 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006811 */
6812
Eric Andersenc470f442003-07-28 09:56:35 +00006813static void
6814showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006815{
Eric Andersencb57d552001-06-28 07:25:16 +00006816 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006817
Eric Andersenc470f442003-07-28 09:56:35 +00006818 TRACE(("showjobs(%x) called\n", mode));
6819
6820 /* If not even one one job changed, there is nothing to do */
6821 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6822 continue;
6823
6824 for (jp = curjob; jp; jp = jp->prev_job) {
6825 if (!(mode & SHOW_CHANGED) || jp->changed)
6826 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006827 }
6828}
Eric Andersenc470f442003-07-28 09:56:35 +00006829#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006830
6831/*
6832 * Mark a job structure as unused.
6833 */
6834
Eric Andersenc470f442003-07-28 09:56:35 +00006835static void
6836freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006837{
Eric Andersenc470f442003-07-28 09:56:35 +00006838 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006839 int i;
6840
6841 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006842 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006843 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006844 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006845 }
6846 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006847 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006848 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006849 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006850 INTON;
6851}
6852
6853
Eric Andersenc470f442003-07-28 09:56:35 +00006854static int
6855waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006856{
6857 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006858 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006859 struct job *jp;
6860
Eric Andersenc470f442003-07-28 09:56:35 +00006861 EXSIGON();
6862
6863 nextopt(nullstr);
6864 retval = 0;
6865
6866 argv = argptr;
6867 if (!*argv) {
6868 /* wait for all jobs */
6869 for (;;) {
6870 jp = curjob;
6871 while (1) {
6872 if (!jp) {
6873 /* no running procs */
6874 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006875 }
Eric Andersenc470f442003-07-28 09:56:35 +00006876 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006877 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006878 jp->waited = 1;
6879 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006880 }
Eric Andersenc470f442003-07-28 09:56:35 +00006881 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006882 }
6883 }
Eric Andersenc470f442003-07-28 09:56:35 +00006884
6885 retval = 127;
6886 do {
6887 if (**argv != '%') {
6888 pid_t pid = number(*argv);
6889 job = curjob;
6890 goto start;
6891 do {
6892 if (job->ps[job->nprocs - 1].pid == pid)
6893 break;
6894 job = job->prev_job;
6895start:
6896 if (!job)
6897 goto repeat;
6898 } while (1);
6899 } else
6900 job = getjob(*argv, 0);
6901 /* loop until process terminated or stopped */
6902 while (job->state == JOBRUNNING)
6903 dowait(DOWAIT_BLOCK, 0);
6904 job->waited = 1;
6905 retval = getstatus(job);
6906repeat:
6907 ;
6908 } while (*++argv);
6909
6910out:
6911 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006912}
6913
6914
Eric Andersencb57d552001-06-28 07:25:16 +00006915/*
6916 * Convert a job name to a job structure.
6917 */
6918
Eric Andersenc470f442003-07-28 09:56:35 +00006919static struct job *
6920getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006921{
Eric Andersencb57d552001-06-28 07:25:16 +00006922 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006923 struct job *found;
6924 const char *err_msg = "No such job: %s";
6925 unsigned num;
6926 int c;
6927 const char *p;
6928 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006929
Eric Andersenc470f442003-07-28 09:56:35 +00006930 jp = curjob;
6931 p = name;
6932 if (!p)
6933 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006934
Eric Andersenc470f442003-07-28 09:56:35 +00006935 if (*p != '%')
6936 goto err;
6937
6938 c = *++p;
6939 if (!c)
6940 goto currentjob;
6941
6942 if (!p[1]) {
6943 if (c == '+' || c == '%') {
6944currentjob:
6945 err_msg = "No current job";
6946 goto check;
6947 } else if (c == '-') {
6948 if (jp)
6949 jp = jp->prev_job;
6950 err_msg = "No previous job";
6951check:
6952 if (!jp)
6953 goto err;
6954 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006955 }
6956 }
Eric Andersenc470f442003-07-28 09:56:35 +00006957
6958 if (is_number(p)) {
6959 num = atoi(p);
6960 if (num < njobs) {
6961 jp = jobtab + num - 1;
6962 if (jp->used)
6963 goto gotit;
6964 goto err;
6965 }
6966 }
6967
6968 match = prefix;
6969 if (*p == '?') {
6970 match = strstr;
6971 p++;
6972 }
6973
6974 found = 0;
6975 while (1) {
6976 if (!jp)
6977 goto err;
6978 if (match(jp->ps[0].cmd, p)) {
6979 if (found)
6980 goto err;
6981 found = jp;
6982 err_msg = "%s: ambiguous";
6983 }
6984 jp = jp->prev_job;
6985 }
6986
6987gotit:
6988#if JOBS
6989 err_msg = "job %s not created under job control";
6990 if (getctl && jp->jobctl == 0)
6991 goto err;
6992#endif
6993 return jp;
6994err:
6995 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006996}
6997
6998
Eric Andersencb57d552001-06-28 07:25:16 +00006999/*
Eric Andersenc470f442003-07-28 09:56:35 +00007000 * Return a new job structure.
7001 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007002 */
7003
Eric Andersenc470f442003-07-28 09:56:35 +00007004static struct job *
7005makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007006{
7007 int i;
7008 struct job *jp;
7009
Eric Andersenc470f442003-07-28 09:56:35 +00007010 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007011 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007012 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007013 break;
7014 }
7015 if (jp->used == 0)
7016 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007017 if (jp->state != JOBDONE || !jp->waited)
7018 continue;
7019#if JOBS
7020 if (jobctl)
7021 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007022#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007023 freejob(jp);
7024 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007025 }
Eric Andersenc470f442003-07-28 09:56:35 +00007026 memset(jp, 0, sizeof(*jp));
7027#if JOBS
7028 if (jobctl)
7029 jp->jobctl = 1;
7030#endif
7031 jp->prev_job = curjob;
7032 curjob = jp;
7033 jp->used = 1;
7034 jp->ps = &jp->ps0;
7035 if (nprocs > 1) {
7036 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7037 }
7038 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7039 jobno(jp)));
7040 return jp;
7041}
7042
7043static struct job *
7044growjobtab(void)
7045{
7046 size_t len;
7047 ptrdiff_t offset;
7048 struct job *jp, *jq;
7049
7050 len = njobs * sizeof(*jp);
7051 jq = jobtab;
7052 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7053
7054 offset = (char *)jp - (char *)jq;
7055 if (offset) {
7056 /* Relocate pointers */
7057 size_t l = len;
7058
7059 jq = (struct job *)((char *)jq + l);
7060 while (l) {
7061 l -= sizeof(*jp);
7062 jq--;
7063#define joff(p) ((struct job *)((char *)(p) + l))
7064#define jmove(p) (p) = (void *)((char *)(p) + offset)
7065 if (likely(joff(jp)->ps == &jq->ps0))
7066 jmove(joff(jp)->ps);
7067 if (joff(jp)->prev_job)
7068 jmove(joff(jp)->prev_job);
7069 }
7070 if (curjob)
7071 jmove(curjob);
7072#undef joff
7073#undef jmove
7074 }
7075
7076 njobs += 4;
7077 jobtab = jp;
7078 jp = (struct job *)((char *)jp + len);
7079 jq = jp + 3;
7080 do {
7081 jq->used = 0;
7082 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007083 return jp;
7084}
7085
7086
7087/*
Eric Andersenc470f442003-07-28 09:56:35 +00007088 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007089 * own process group. Jp is a job structure that the job is to be added to.
7090 * N is the command that will be evaluated by the child. Both jp and n may
7091 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007092 * FORK_FG - Fork off a foreground process.
7093 * FORK_BG - Fork off a background process.
7094 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7095 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007096 *
7097 * When job control is turned off, background processes have their standard
7098 * input redirected to /dev/null (except for the second and later processes
7099 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007100 *
7101 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007102 */
7103
Eric Andersenc470f442003-07-28 09:56:35 +00007104static inline void
7105forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007106{
Eric Andersenc470f442003-07-28 09:56:35 +00007107 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007108
Eric Andersenc470f442003-07-28 09:56:35 +00007109 TRACE(("Child shell %d\n", getpid()));
7110 wasroot = rootshell;
7111 rootshell = 0;
7112
7113 closescript();
7114 clear_traps();
7115#if JOBS
7116 /* do job control only in root shell */
7117 jobctl = 0;
7118 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7119 pid_t pgrp;
7120
7121 if (jp->nprocs == 0)
7122 pgrp = getpid();
7123 else
7124 pgrp = jp->ps[0].pid;
7125 /* This can fail because we are doing it in the parent also */
7126 (void)setpgid(0, pgrp);
7127 if (mode == FORK_FG)
7128 xtcsetpgrp(ttyfd, pgrp);
7129 setsignal(SIGTSTP);
7130 setsignal(SIGTTOU);
7131 } else
Eric Andersen62483552001-07-10 06:09:16 +00007132#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007133 if (mode == FORK_BG) {
7134 ignoresig(SIGINT);
7135 ignoresig(SIGQUIT);
7136 if (jp->nprocs == 0) {
7137 close(0);
7138 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7139 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007140 }
Eric Andersencb57d552001-06-28 07:25:16 +00007141 }
Eric Andersenc470f442003-07-28 09:56:35 +00007142 if (wasroot && iflag) {
7143 setsignal(SIGINT);
7144 setsignal(SIGQUIT);
7145 setsignal(SIGTERM);
7146 }
7147 for (jp = curjob; jp; jp = jp->prev_job)
7148 freejob(jp);
7149 jobless = 0;
7150}
7151
7152static inline void
7153forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7154{
7155 TRACE(("In parent shell: child = %d\n", pid));
7156 if (!jp) {
7157 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7158 jobless++;
7159 return;
7160 }
7161#if JOBS
7162 if (mode != FORK_NOJOB && jp->jobctl) {
7163 int pgrp;
7164
7165 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007166 pgrp = pid;
7167 else
7168 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007169 /* This can fail because we are doing it in the child also */
7170 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007171 }
Eric Andersen62483552001-07-10 06:09:16 +00007172#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007173 if (mode == FORK_BG) {
7174 backgndpid = pid; /* set $! */
7175 set_curjob(jp, CUR_RUNNING);
7176 }
Eric Andersencb57d552001-06-28 07:25:16 +00007177 if (jp) {
7178 struct procstat *ps = &jp->ps[jp->nprocs++];
7179 ps->pid = pid;
7180 ps->status = -1;
7181 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007182#if JOBS
7183 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007184 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007185#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007186 }
Eric Andersencb57d552001-06-28 07:25:16 +00007187}
7188
Eric Andersenc470f442003-07-28 09:56:35 +00007189static int
7190forkshell(struct job *jp, union node *n, int mode)
7191{
7192 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007193
Eric Andersenc470f442003-07-28 09:56:35 +00007194 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7195 pid = fork();
7196 if (pid < 0) {
7197 TRACE(("Fork failed, errno=%d", errno));
7198 if (jp)
7199 freejob(jp);
7200 error("Cannot fork");
7201 }
7202 if (pid == 0)
7203 forkchild(jp, n, mode);
7204 else
7205 forkparent(jp, n, mode, pid);
7206 return pid;
7207}
Eric Andersencb57d552001-06-28 07:25:16 +00007208
7209/*
7210 * Wait for job to finish.
7211 *
7212 * Under job control we have the problem that while a child process is
7213 * running interrupts generated by the user are sent to the child but not
7214 * to the shell. This means that an infinite loop started by an inter-
7215 * active user may be hard to kill. With job control turned off, an
7216 * interactive user may place an interactive program inside a loop. If
7217 * the interactive program catches interrupts, the user doesn't want
7218 * these interrupts to also abort the loop. The approach we take here
7219 * is to have the shell ignore interrupt signals while waiting for a
7220 * forground process to terminate, and then send itself an interrupt
7221 * signal if the child process was terminated by an interrupt signal.
7222 * Unfortunately, some programs want to do a bit of cleanup and then
7223 * exit on interrupt; unless these processes terminate themselves by
7224 * sending a signal to themselves (instead of calling exit) they will
7225 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007226 *
7227 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007228 */
7229
Eric Andersenc470f442003-07-28 09:56:35 +00007230int
7231waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007232{
Eric Andersencb57d552001-06-28 07:25:16 +00007233 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007234
Eric Andersenc470f442003-07-28 09:56:35 +00007235 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7236 while (jp->state == JOBRUNNING) {
7237 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007238 }
Eric Andersenc470f442003-07-28 09:56:35 +00007239 st = getstatus(jp);
7240#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007241 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007242 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007243 /*
7244 * This is truly gross.
7245 * If we're doing job control, then we did a TIOCSPGRP which
7246 * caused us (the shell) to no longer be in the controlling
7247 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7248 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007249 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007250 */
Eric Andersenc470f442003-07-28 09:56:35 +00007251 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007252 raise(SIGINT);
7253 }
Eric Andersen2870d962001-07-02 17:27:21 +00007254 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007255#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007256 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007257 return st;
7258}
7259
7260
Eric Andersen62483552001-07-10 06:09:16 +00007261/*
7262 * Do a wait system call. If job control is compiled in, we accept
7263 * stopped processes. If block is zero, we return a value of zero
7264 * rather than blocking.
7265 *
7266 * System V doesn't have a non-blocking wait system call. It does
7267 * have a SIGCLD signal that is sent to a process when one of it's
7268 * children dies. The obvious way to use SIGCLD would be to install
7269 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7270 * was received, and have waitproc bump another counter when it got
7271 * the status of a process. Waitproc would then know that a wait
7272 * system call would not block if the two counters were different.
7273 * This approach doesn't work because if a process has children that
7274 * have not been waited for, System V will send it a SIGCLD when it
7275 * installs a signal handler for SIGCLD. What this means is that when
7276 * a child exits, the shell will be sent SIGCLD signals continuously
7277 * until is runs out of stack space, unless it does a wait call before
7278 * restoring the signal handler. The code below takes advantage of
7279 * this (mis)feature by installing a signal handler for SIGCLD and
7280 * then checking to see whether it was called. If there are any
7281 * children to be waited for, it will be.
7282 *
Eric Andersenc470f442003-07-28 09:56:35 +00007283 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7284 * waits at all. In this case, the user will not be informed when
7285 * a background process until the next time she runs a real program
7286 * (as opposed to running a builtin command or just typing return),
7287 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007288 */
7289
Eric Andersenc470f442003-07-28 09:56:35 +00007290static inline int
7291waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007292{
Eric Andersenc470f442003-07-28 09:56:35 +00007293 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007294
Eric Andersenc470f442003-07-28 09:56:35 +00007295#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007296 if (jobctl)
7297 flags |= WUNTRACED;
7298#endif
7299 if (block == 0)
7300 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007301 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007302}
7303
Eric Andersenc470f442003-07-28 09:56:35 +00007304/*
7305 * Wait for a process to terminate.
7306 */
7307
7308static int
7309dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007310{
7311 int pid;
7312 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007313 struct job *jp;
7314 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007315 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007316
7317 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007318 pid = waitproc(block, &status);
7319 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007320 if (pid <= 0)
7321 return pid;
7322 INTOFF;
7323 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007324 for (jp = curjob; jp; jp = jp->prev_job) {
7325 struct procstat *sp;
7326 struct procstat *spend;
7327 if (jp->state == JOBDONE)
7328 continue;
7329 state = JOBDONE;
7330 spend = jp->ps + jp->nprocs;
7331 sp = jp->ps;
7332 do {
7333 if (sp->pid == pid) {
7334 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7335 sp->status = status;
7336 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007337 }
Eric Andersenc470f442003-07-28 09:56:35 +00007338 if (sp->status == -1)
7339 state = JOBRUNNING;
7340#ifdef JOBS
7341 if (state == JOBRUNNING)
7342 continue;
7343 if (WIFSTOPPED(sp->status)) {
7344 jp->stopstatus = sp->status;
7345 state = JOBSTOPPED;
7346 }
Eric Andersencb57d552001-06-28 07:25:16 +00007347#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007348 } while (++sp < spend);
7349 if (thisjob)
7350 goto gotjob;
7351 }
7352#ifdef JOBS
7353 if (!WIFSTOPPED(status))
7354#endif
7355
7356 jobless--;
7357 goto out;
7358
7359gotjob:
7360 if (state != JOBRUNNING) {
7361 thisjob->changed = 1;
7362
7363 if (thisjob->state != state) {
7364 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7365 thisjob->state = state;
7366#ifdef JOBS
7367 if (state == JOBSTOPPED) {
7368 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007369 }
Eric Andersenc470f442003-07-28 09:56:35 +00007370#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007371 }
7372 }
Eric Andersencb57d552001-06-28 07:25:16 +00007373
Eric Andersenc470f442003-07-28 09:56:35 +00007374out:
7375 INTON;
7376
7377 if (thisjob && thisjob == job) {
7378 char s[48 + 1];
7379 int len;
7380
7381 len = sprint_status(s, status, 1);
7382 if (len) {
7383 s[len] = '\n';
7384 s[len + 1] = 0;
7385 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007386 }
Eric Andersencb57d552001-06-28 07:25:16 +00007387 }
7388 return pid;
7389}
7390
7391
Eric Andersencb57d552001-06-28 07:25:16 +00007392/*
7393 * return 1 if there are stopped jobs, otherwise 0
7394 */
Eric Andersen90898442003-08-06 11:20:52 +00007395
Eric Andersenc470f442003-07-28 09:56:35 +00007396int
7397stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007398{
Eric Andersencb57d552001-06-28 07:25:16 +00007399 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007400 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007401
Eric Andersenc470f442003-07-28 09:56:35 +00007402 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007403 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007404 goto out;
7405 jp = curjob;
7406 if (jp && jp->state == JOBSTOPPED) {
7407 out2str("You have stopped jobs.\n");
7408 job_warning = 2;
7409 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007410 }
7411
Eric Andersenc470f442003-07-28 09:56:35 +00007412out:
7413 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007414}
7415
7416/*
7417 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007418 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007419 */
7420
Eric Andersenc470f442003-07-28 09:56:35 +00007421#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007422static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007423
Eric Andersenc470f442003-07-28 09:56:35 +00007424static char *
7425commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007426{
Eric Andersenc470f442003-07-28 09:56:35 +00007427 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007428
Eric Andersenc470f442003-07-28 09:56:35 +00007429 STARTSTACKSTR(cmdnextc);
7430 cmdtxt(n);
7431 name = stackblock();
7432 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7433 name, cmdnextc, cmdnextc));
7434 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007435}
7436
Eric Andersenc470f442003-07-28 09:56:35 +00007437static void
7438cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007439{
Eric Andersencb57d552001-06-28 07:25:16 +00007440 union node *np;
7441 struct nodelist *lp;
7442 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007443 char s[2];
7444
Eric Andersencb57d552001-06-28 07:25:16 +00007445 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007446 default:
7447#if DEBUG
7448 abort();
7449#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007450 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007451 lp = n->npipe.cmdlist;
7452 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007453 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007454 lp = lp->next;
7455 if (!lp)
7456 break;
7457 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007458 }
7459 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007460 case NSEMI:
7461 p = "; ";
7462 goto binop;
7463 case NAND:
7464 p = " && ";
7465 goto binop;
7466 case NOR:
7467 p = " || ";
7468binop:
7469 cmdtxt(n->nbinary.ch1);
7470 cmdputs(p);
7471 n = n->nbinary.ch2;
7472 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007473 case NREDIR:
7474 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007475 n = n->nredir.n;
7476 goto donode;
7477 case NNOT:
7478 cmdputs("!");
7479 n = n->nnot.com;
7480donode:
7481 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007482 break;
7483 case NIF:
7484 cmdputs("if ");
7485 cmdtxt(n->nif.test);
7486 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007487 n = n->nif.ifpart;
7488 if (n->nif.elsepart) {
7489 cmdtxt(n);
7490 cmdputs("; else ");
7491 n = n->nif.elsepart;
7492 }
7493 p = "; fi";
7494 goto dotail;
7495 case NSUBSHELL:
7496 cmdputs("(");
7497 n = n->nredir.n;
7498 p = ")";
7499 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007500 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007501 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007502 goto until;
7503 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007504 p = "until ";
7505until:
7506 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007507 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007508 n = n->nbinary.ch2;
7509 p = "; done";
7510dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007511 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007512dotail:
7513 cmdtxt(n);
7514 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007515 case NFOR:
7516 cmdputs("for ");
7517 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007518 cmdputs(" in ");
7519 cmdlist(n->nfor.args, 1);
7520 n = n->nfor.body;
7521 p = "; done";
7522 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007523 case NDEFUN:
7524 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007525 p = "() { ... }";
7526 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007527 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007528 cmdlist(n->ncmd.args, 1);
7529 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007530 break;
7531 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007532 p = n->narg.text;
7533dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007534 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007535 break;
7536 case NHERE:
7537 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007538 p = "<<...";
7539 goto dotail2;
7540 case NCASE:
7541 cmdputs("case ");
7542 cmdputs(n->ncase.expr->narg.text);
7543 cmdputs(" in ");
7544 for (np = n->ncase.cases; np; np = np->nclist.next) {
7545 cmdtxt(np->nclist.pattern);
7546 cmdputs(") ");
7547 cmdtxt(np->nclist.body);
7548 cmdputs(";; ");
7549 }
7550 p = "esac";
7551 goto dotail2;
7552 case NTO:
7553 p = ">";
7554 goto redir;
7555 case NCLOBBER:
7556 p = ">|";
7557 goto redir;
7558 case NAPPEND:
7559 p = ">>";
7560 goto redir;
7561 case NTOFD:
7562 p = ">&";
7563 goto redir;
7564 case NFROM:
7565 p = "<";
7566 goto redir;
7567 case NFROMFD:
7568 p = "<&";
7569 goto redir;
7570 case NFROMTO:
7571 p = "<>";
7572redir:
7573 s[0] = n->nfile.fd + '0';
7574 s[1] = '\0';
7575 cmdputs(s);
7576 cmdputs(p);
7577 if (n->type == NTOFD || n->type == NFROMFD) {
7578 s[0] = n->ndup.dupfd + '0';
7579 p = s;
7580 goto dotail2;
7581 } else {
7582 n = n->nfile.fname;
7583 goto donode;
7584 }
Eric Andersencb57d552001-06-28 07:25:16 +00007585 }
7586}
Eric Andersencb57d552001-06-28 07:25:16 +00007587
Eric Andersenc470f442003-07-28 09:56:35 +00007588static void
7589cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007590{
Eric Andersenc470f442003-07-28 09:56:35 +00007591 for (; np; np = np->narg.next) {
7592 if (!sep)
7593 cmdputs(spcstr);
7594 cmdtxt(np);
7595 if (sep && np->narg.next)
7596 cmdputs(spcstr);
7597 }
Eric Andersencb57d552001-06-28 07:25:16 +00007598}
7599
Eric Andersenc470f442003-07-28 09:56:35 +00007600static void
7601cmdputs(const char *s)
7602{
7603 const char *p, *str;
7604 char c, cc[2] = " ";
7605 char *nextc;
7606 int subtype = 0;
7607 int quoted = 0;
7608 static const char *const vstype[16] = {
7609 nullstr, "}", "-", "+", "?", "=",
7610 "#", "##", "%", "%%"
7611 };
7612
7613 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7614 p = s;
7615 while ((c = *p++) != 0) {
7616 str = 0;
7617 switch (c) {
7618 case CTLESC:
7619 c = *p++;
7620 break;
7621 case CTLVAR:
7622 subtype = *p++;
7623 if ((subtype & VSTYPE) == VSLENGTH)
7624 str = "${#";
7625 else
7626 str = "${";
7627 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7628 quoted ^= 1;
7629 c = '"';
7630 } else
7631 goto dostr;
7632 break;
7633 case CTLENDVAR:
7634 quoted >>= 1;
7635 subtype = 0;
7636 if (quoted & 1) {
7637 str = "\"}";
7638 goto dostr;
7639 }
7640 c = '}';
7641 break;
7642 case CTLBACKQ:
7643 str = "$(...)";
7644 goto dostr;
7645 case CTLBACKQ+CTLQUOTE:
7646 str = "\"$(...)\"";
7647 goto dostr;
7648#ifdef CONFIG_ASH_MATH_SUPPORT
7649 case CTLARI:
7650 str = "$((";
7651 goto dostr;
7652 case CTLENDARI:
7653 str = "))";
7654 goto dostr;
7655#endif
7656 case CTLQUOTEMARK:
7657 quoted ^= 1;
7658 c = '"';
7659 break;
7660 case '=':
7661 if (subtype == 0)
7662 break;
7663 str = vstype[subtype & VSTYPE];
7664 if (subtype & VSNUL)
7665 c = ':';
7666 else
7667 c = *str++;
7668 if (c != '}')
7669 quoted <<= 1;
7670 break;
7671 case '\'':
7672 case '\\':
7673 case '"':
7674 case '$':
7675 /* These can only happen inside quotes */
7676 cc[0] = c;
7677 str = cc;
7678 c = '\\';
7679 break;
7680 default:
7681 break;
7682 }
7683 USTPUTC(c, nextc);
7684 if (!str)
7685 continue;
7686dostr:
7687 while ((c = *str++)) {
7688 USTPUTC(c, nextc);
7689 }
7690 }
7691 if (quoted & 1) {
7692 USTPUTC('"', nextc);
7693 }
7694 *nextc = 0;
7695 cmdnextc = nextc;
7696}
7697
7698
7699static void
7700showpipe(struct job *jp, FILE *out)
7701{
7702 struct procstat *sp;
7703 struct procstat *spend;
7704
7705 spend = jp->ps + jp->nprocs;
7706 for (sp = jp->ps + 1; sp < spend; sp++)
7707 fprintf(out, " | %s", sp->cmd);
7708 outcslow('\n', out);
7709 flushall();
7710}
7711
7712static void
7713xtcsetpgrp(int fd, pid_t pgrp)
7714{
7715 if (tcsetpgrp(fd, pgrp))
7716 error("Cannot set tty process group (%m)");
7717}
7718#endif /* JOBS */
7719
7720static int
7721getstatus(struct job *job) {
7722 int status;
7723 int retval;
7724
7725 status = job->ps[job->nprocs - 1].status;
7726 retval = WEXITSTATUS(status);
7727 if (!WIFEXITED(status)) {
7728#if JOBS
7729 retval = WSTOPSIG(status);
7730 if (!WIFSTOPPED(status))
7731#endif
7732 {
7733 /* XXX: limits number of signals */
7734 retval = WTERMSIG(status);
7735#if JOBS
7736 if (retval == SIGINT)
7737 job->sigint = 1;
7738#endif
7739 }
7740 retval += 128;
7741 }
7742 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7743 jobno(job), job->nprocs, status, retval));
7744 return retval;
7745}
7746
Eric Andersend35c5df2002-01-09 15:37:36 +00007747#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007748/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007749
Eric Andersencb57d552001-06-28 07:25:16 +00007750/*
Eric Andersenc470f442003-07-28 09:56:35 +00007751 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007752 */
7753
Eric Andersencb57d552001-06-28 07:25:16 +00007754#define MAXMBOXES 10
7755
Eric Andersenc470f442003-07-28 09:56:35 +00007756/* times of mailboxes */
7757static time_t mailtime[MAXMBOXES];
7758/* Set if MAIL or MAILPATH is changed. */
7759static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007760
7761
7762
7763/*
Eric Andersenc470f442003-07-28 09:56:35 +00007764 * Print appropriate message(s) if mail has arrived.
7765 * If mail_var_path_changed is set,
7766 * then the value of MAIL has mail_var_path_changed,
7767 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007768 */
7769
Eric Andersenc470f442003-07-28 09:56:35 +00007770static void
7771chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007772{
Eric Andersencb57d552001-06-28 07:25:16 +00007773 const char *mpath;
7774 char *p;
7775 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007776 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007777 struct stackmark smark;
7778 struct stat statb;
7779
Eric Andersencb57d552001-06-28 07:25:16 +00007780 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007781 mpath = mpathset() ? mpathval() : mailval();
7782 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007783 p = padvance(&mpath, nullstr);
7784 if (p == NULL)
7785 break;
7786 if (*p == '\0')
7787 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007788 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007789#ifdef DEBUG
7790 if (q[-1] != '/')
7791 abort();
7792#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007793 q[-1] = '\0'; /* delete trailing '/' */
7794 if (stat(p, &statb) < 0) {
7795 *mtp = 0;
7796 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007797 }
Eric Andersenc470f442003-07-28 09:56:35 +00007798 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7799 fprintf(
7800 stderr, snlfmt,
7801 pathopt ? pathopt : "you have mail"
7802 );
7803 }
7804 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007805 }
Eric Andersenc470f442003-07-28 09:56:35 +00007806 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007807 popstackmark(&smark);
7808}
Eric Andersencb57d552001-06-28 07:25:16 +00007809
Eric Andersenec074692001-10-31 11:05:49 +00007810
Eric Andersenc470f442003-07-28 09:56:35 +00007811static void
7812changemail(const char *val)
7813{
7814 mail_var_path_changed++;
7815}
7816
7817#endif /* CONFIG_ASH_MAIL */
7818
7819/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7820
Eric Andersencb57d552001-06-28 07:25:16 +00007821
Eric Andersencb57d552001-06-28 07:25:16 +00007822#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007823static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007824extern int etext();
7825#endif
7826
Eric Andersenc470f442003-07-28 09:56:35 +00007827static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007828
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007829static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007830
Eric Andersencb57d552001-06-28 07:25:16 +00007831/*
7832 * Main routine. We initialize things, parse the arguments, execute
7833 * profiles if we're a login shell, and then call cmdloop to execute
7834 * commands. The setjmp call sets up the location to jump to when an
7835 * exception occurs. When an exception occurs the variable "state"
7836 * is used to figure out how far we had gotten.
7837 */
7838
Eric Andersenc470f442003-07-28 09:56:35 +00007839int
7840ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007841{
Eric Andersenc470f442003-07-28 09:56:35 +00007842 char *shinit;
7843 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007844 struct jmploc jmploc;
7845 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007846
Eric Andersenc470f442003-07-28 09:56:35 +00007847#ifdef __GLIBC__
7848 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007849#endif
7850
Eric Andersencb57d552001-06-28 07:25:16 +00007851#if PROFILE
7852 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7853#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007854 state = 0;
7855 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007856 int status;
7857 int e;
7858
Eric Andersencb57d552001-06-28 07:25:16 +00007859 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007860
7861 e = exception;
7862 switch (exception) {
7863 case EXEXEC:
7864 status = exerrno;
7865 break;
7866
7867 case EXERROR:
7868 status = 2;
7869 break;
7870
7871 default:
7872 status = exitstatus;
7873 break;
7874 }
7875 exitstatus = status;
7876
7877 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7878 exitshell();
7879
Eric Andersen90898442003-08-06 11:20:52 +00007880 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007881 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007882 }
7883 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007884 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007885 if (state == 1)
7886 goto state1;
7887 else if (state == 2)
7888 goto state2;
7889 else if (state == 3)
7890 goto state3;
7891 else
7892 goto state4;
7893 }
7894 handler = &jmploc;
7895#ifdef DEBUG
7896 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007897 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007898#endif
7899 rootpid = getpid();
7900 rootshell = 1;
7901 init();
7902 setstackmark(&smark);
7903 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007904#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7905 if ( iflag ) {
7906 const char *hp = lookupvar("HISTFILE");
7907
7908 if(hp == NULL ) {
7909 hp = lookupvar("HOME");
7910 if(hp != NULL) {
7911 char *defhp = concat_path_file(hp, ".ash_history");
7912 setvar("HISTFILE", defhp, 0);
7913 free(defhp);
7914 }
7915 }
7916 }
7917#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007918 if (argv[0] && argv[0][0] == '-')
7919 isloginsh = 1;
7920 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007921 state = 1;
7922 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007923state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007924 state = 2;
7925 read_profile(".profile");
7926 }
Eric Andersenc470f442003-07-28 09:56:35 +00007927state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007928 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007929 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007930#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007931 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007932#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007933 iflag
7934 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007935 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007936 read_profile(shinit);
7937 }
Eric Andersencb57d552001-06-28 07:25:16 +00007938 }
Eric Andersenc470f442003-07-28 09:56:35 +00007939state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007940 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007941 if (minusc)
7942 evalstring(minusc, 0);
7943
7944 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007945#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007946 if ( iflag ) {
7947 const char *hp = lookupvar("HISTFILE");
7948
7949 if(hp != NULL )
7950 load_history ( hp );
7951 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007952#endif
Eric Andersen90898442003-08-06 11:20:52 +00007953state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007954 cmdloop(1);
7955 }
7956#if PROFILE
7957 monitor(0);
7958#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007959#if GPROF
7960 {
7961 extern void _mcleanup(void);
7962 _mcleanup();
7963 }
7964#endif
7965 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007966 /* NOTREACHED */
7967}
7968
7969
7970/*
7971 * Read and execute commands. "Top" is nonzero for the top level command
7972 * loop; it turns on prompting if the shell is interactive.
7973 */
7974
Eric Andersenc470f442003-07-28 09:56:35 +00007975static void
7976cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007977{
7978 union node *n;
7979 struct stackmark smark;
7980 int inter;
7981 int numeof = 0;
7982
7983 TRACE(("cmdloop(%d) called\n", top));
7984 setstackmark(&smark);
7985 for (;;) {
7986 if (pendingsigs)
7987 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00007988#if JOBS
7989 if (jobctl)
7990 showjobs(stderr, SHOW_CHANGED);
7991#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007992 inter = 0;
7993 if (iflag && top) {
7994 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00007995#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007996 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00007997#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007998 }
7999 n = parsecmd(inter);
8000 /* showtree(n); DEBUG */
8001 if (n == NEOF) {
8002 if (!top || numeof >= 50)
8003 break;
8004 if (!stoppedjobs()) {
8005 if (!Iflag)
8006 break;
8007 out2str("\nUse \"exit\" to leave shell.\n");
8008 }
8009 numeof++;
8010 } else if (n != NULL && nflag == 0) {
8011 job_warning = (job_warning == 2) ? 1 : 0;
8012 numeof = 0;
8013 evaltree(n, 0);
8014 }
8015 popstackmark(&smark);
8016 setstackmark(&smark);
8017 if (evalskip == SKIPFILE) {
8018 evalskip = 0;
8019 break;
8020 }
8021 }
8022 popstackmark(&smark);
8023}
8024
8025
Eric Andersencb57d552001-06-28 07:25:16 +00008026/*
8027 * Read /etc/profile or .profile. Return on error.
8028 */
8029
Eric Andersenc470f442003-07-28 09:56:35 +00008030static void
8031read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008032{
8033 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008034 int xflag_set = 0;
8035 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008036
8037 INTOFF;
8038 if ((fd = open(name, O_RDONLY)) >= 0)
8039 setinputfd(fd, 1);
8040 INTON;
8041 if (fd < 0)
8042 return;
8043 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008044 if (qflag) {
8045 if (xflag)
8046 xflag = 0, xflag_set = 1;
8047 if (vflag)
8048 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008049 }
8050 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008051 if (qflag) {
8052 if (xflag_set)
8053 xflag = 1;
8054 if (vflag_set)
8055 vflag = 1;
8056 }
Eric Andersencb57d552001-06-28 07:25:16 +00008057 popfile();
8058}
8059
8060
Eric Andersencb57d552001-06-28 07:25:16 +00008061/*
8062 * Read a file containing shell functions.
8063 */
8064
Eric Andersenc470f442003-07-28 09:56:35 +00008065static void
8066readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008067{
8068 int fd;
8069
8070 INTOFF;
8071 if ((fd = open(name, O_RDONLY)) >= 0)
8072 setinputfd(fd, 1);
8073 else
8074 error("Can't open %s", name);
8075 INTON;
8076 cmdloop(0);
8077 popfile();
8078}
8079
8080
Eric Andersencb57d552001-06-28 07:25:16 +00008081/*
Eric Andersenc470f442003-07-28 09:56:35 +00008082 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008083 * search for the file, which is necessary to find sub-commands.
8084 */
8085
Eric Andersenc470f442003-07-28 09:56:35 +00008086static inline char *
8087find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008088{
8089 char *fullname;
8090 const char *path = pathval();
8091 struct stat statb;
8092
8093 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008094 if (strchr(name, '/'))
8095 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008096
Eric Andersenc470f442003-07-28 09:56:35 +00008097 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008098 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8099 /*
8100 * Don't bother freeing here, since it will
8101 * be freed by the caller.
8102 */
8103 return fullname;
8104 }
8105 stunalloc(fullname);
8106 }
8107
8108 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008109 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008110 /* NOTREACHED */
8111}
8112
Eric Andersenc470f442003-07-28 09:56:35 +00008113int
8114dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008115{
Eric Andersencb57d552001-06-28 07:25:16 +00008116 exitstatus = 0;
8117
Eric Andersenc470f442003-07-28 09:56:35 +00008118 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008119 char *fullname;
8120 struct stackmark smark;
8121
8122 setstackmark(&smark);
8123 fullname = find_dot_file(argv[1]);
8124 setinputfile(fullname, 1);
8125 commandname = fullname;
8126 cmdloop(0);
8127 popfile();
8128 popstackmark(&smark);
8129 }
8130 return exitstatus;
8131}
8132
8133
Eric Andersenc470f442003-07-28 09:56:35 +00008134static int
8135exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008136{
8137 if (stoppedjobs())
8138 return 0;
8139 if (argc > 1)
8140 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008141 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008142 /* NOTREACHED */
8143}
Eric Andersen62483552001-07-10 06:09:16 +00008144
Eric Andersenc470f442003-07-28 09:56:35 +00008145/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8146
8147/*
Eric Andersen90898442003-08-06 11:20:52 +00008148 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008149 */
8150
8151static pointer
8152ckrealloc(pointer p, size_t nbytes)
8153{
8154 p = realloc(p, nbytes);
8155 if (p == NULL)
8156 error(bb_msg_memory_exhausted);
8157 return p;
8158}
8159
Eric Andersen90898442003-08-06 11:20:52 +00008160static pointer
8161ckmalloc(size_t nbytes)
8162{
8163 return ckrealloc(NULL, nbytes);
8164}
Eric Andersenc470f442003-07-28 09:56:35 +00008165
8166/*
8167 * Make a copy of a string in safe storage.
8168 */
8169
8170static char *
8171savestr(const char *s)
8172{
8173 char *p = strdup(s);
8174 if (!p)
8175 error(bb_msg_memory_exhausted);
8176 return p;
8177}
8178
8179
8180/*
8181 * Parse trees for commands are allocated in lifo order, so we use a stack
8182 * to make this more efficient, and also to avoid all sorts of exception
8183 * handling code to handle interrupts in the middle of a parse.
8184 *
8185 * The size 504 was chosen because the Ultrix malloc handles that size
8186 * well.
8187 */
8188
8189
8190static pointer
8191stalloc(size_t nbytes)
8192{
8193 char *p;
8194 size_t aligned;
8195
8196 aligned = SHELL_ALIGN(nbytes);
8197 if (aligned > stacknleft) {
8198 size_t len;
8199 size_t blocksize;
8200 struct stack_block *sp;
8201
8202 blocksize = aligned;
8203 if (blocksize < MINSIZE)
8204 blocksize = MINSIZE;
8205 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8206 if (len < blocksize)
8207 error(bb_msg_memory_exhausted);
8208 INTOFF;
8209 sp = ckmalloc(len);
8210 sp->prev = stackp;
8211 stacknxt = sp->space;
8212 stacknleft = blocksize;
8213 sstrend = stacknxt + blocksize;
8214 stackp = sp;
8215 INTON;
8216 }
8217 p = stacknxt;
8218 stacknxt += aligned;
8219 stacknleft -= aligned;
8220 return p;
8221}
8222
8223
8224void
8225stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008226{
Eric Andersencb57d552001-06-28 07:25:16 +00008227#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008228 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008229 write(2, "stunalloc\n", 10);
8230 abort();
8231 }
8232#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008233 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008234 stacknxt = p;
8235}
8236
8237
Eric Andersenc470f442003-07-28 09:56:35 +00008238void
8239setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008240{
Eric Andersencb57d552001-06-28 07:25:16 +00008241 mark->stackp = stackp;
8242 mark->stacknxt = stacknxt;
8243 mark->stacknleft = stacknleft;
8244 mark->marknext = markp;
8245 markp = mark;
8246}
8247
8248
Eric Andersenc470f442003-07-28 09:56:35 +00008249void
8250popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008251{
Eric Andersencb57d552001-06-28 07:25:16 +00008252 struct stack_block *sp;
8253
8254 INTOFF;
8255 markp = mark->marknext;
8256 while (stackp != mark->stackp) {
8257 sp = stackp;
8258 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008259 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008260 }
8261 stacknxt = mark->stacknxt;
8262 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008263 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008264 INTON;
8265}
8266
8267
8268/*
8269 * When the parser reads in a string, it wants to stick the string on the
8270 * stack and only adjust the stack pointer when it knows how big the
8271 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8272 * of space on top of the stack and stackblocklen returns the length of
8273 * this block. Growstackblock will grow this space by at least one byte,
8274 * possibly moving it (like realloc). Grabstackblock actually allocates the
8275 * part of the block that has been used.
8276 */
8277
Eric Andersenc470f442003-07-28 09:56:35 +00008278void
8279growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008280{
Eric Andersenc470f442003-07-28 09:56:35 +00008281 size_t newlen;
8282
8283 newlen = stacknleft * 2;
8284 if (newlen < stacknleft)
8285 error(bb_msg_memory_exhausted);
8286 if (newlen < 128)
8287 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008288
8289 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008290 struct stack_block *oldstackp;
8291 struct stackmark *xmark;
8292 struct stack_block *sp;
8293 struct stack_block *prevstackp;
8294 size_t grosslen;
8295
Eric Andersencb57d552001-06-28 07:25:16 +00008296 INTOFF;
8297 oldstackp = stackp;
8298 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008299 prevstackp = sp->prev;
8300 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8301 sp = ckrealloc((pointer)sp, grosslen);
8302 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008303 stackp = sp;
8304 stacknxt = sp->space;
8305 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008306 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008307
Eric Andersenc470f442003-07-28 09:56:35 +00008308 /*
8309 * Stack marks pointing to the start of the old block
8310 * must be relocated to point to the new block
8311 */
8312 xmark = markp;
8313 while (xmark != NULL && xmark->stackp == oldstackp) {
8314 xmark->stackp = stackp;
8315 xmark->stacknxt = stacknxt;
8316 xmark->stacknleft = stacknleft;
8317 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008318 }
8319 INTON;
8320 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008321 char *oldspace = stacknxt;
8322 int oldlen = stacknleft;
8323 char *p = stalloc(newlen);
8324
8325 /* free the space we just allocated */
8326 stacknxt = memcpy(p, oldspace, oldlen);
8327 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008328 }
8329}
8330
Eric Andersenc470f442003-07-28 09:56:35 +00008331static inline void
8332grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008333{
Eric Andersenc470f442003-07-28 09:56:35 +00008334 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008335 stacknxt += len;
8336 stacknleft -= len;
8337}
8338
Eric Andersencb57d552001-06-28 07:25:16 +00008339/*
Eric Andersenc470f442003-07-28 09:56:35 +00008340 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008341 * The user declares a variable of type STACKSTR, which may be declared
8342 * to be a register. The macro STARTSTACKSTR initializes things. Then
8343 * the user uses the macro STPUTC to add characters to the string. In
8344 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8345 * grown as necessary. When the user is done, she can just leave the
8346 * string there and refer to it using stackblock(). Or she can allocate
8347 * the space for it using grabstackstr(). If it is necessary to allow
8348 * someone else to use the stack temporarily and then continue to grow
8349 * the string, the user should use grabstack to allocate the space, and
8350 * then call ungrabstr(p) to return to the previous mode of operation.
8351 *
8352 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8353 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8354 * is space for at least one character.
8355 */
8356
Eric Andersenc470f442003-07-28 09:56:35 +00008357void *
8358growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008359{
Eric Andersenc470f442003-07-28 09:56:35 +00008360 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008361 if (herefd >= 0 && len >= 1024) {
8362 xwrite(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008363 return stackblock();
8364 }
8365 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008366 return stackblock() + len;
8367}
8368
Eric Andersencb57d552001-06-28 07:25:16 +00008369/*
8370 * Called from CHECKSTRSPACE.
8371 */
8372
Eric Andersenc470f442003-07-28 09:56:35 +00008373char *
8374makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008375{
Eric Andersenc470f442003-07-28 09:56:35 +00008376 size_t len = p - stacknxt;
8377 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008378
Eric Andersenc470f442003-07-28 09:56:35 +00008379 for (;;) {
8380 size_t nleft;
8381
8382 size = stackblocksize();
8383 nleft = size - len;
8384 if (nleft >= newlen)
8385 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008386 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008387 }
Eric Andersencb57d552001-06-28 07:25:16 +00008388 return stackblock() + len;
8389}
8390
Eric Andersenc470f442003-07-28 09:56:35 +00008391char *
8392stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008393{
Eric Andersenc470f442003-07-28 09:56:35 +00008394 p = makestrspace(n, p);
8395 p = mempcpy(p, s, n);
8396 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008397}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008398
Eric Andersenc470f442003-07-28 09:56:35 +00008399char *
8400stputs(const char *s, char *p)
8401{
8402 return stnputs(s, strlen(s), p);
8403}
8404
8405/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8406
Eric Andersencb57d552001-06-28 07:25:16 +00008407/*
Eric Andersenc470f442003-07-28 09:56:35 +00008408 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008409 *
Eric Andersenc470f442003-07-28 09:56:35 +00008410 * number(s) Convert a string of digits to an integer.
8411 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008412 */
8413
Eric Andersencb57d552001-06-28 07:25:16 +00008414/*
8415 * prefix -- see if pfx is a prefix of string.
8416 */
8417
Eric Andersenc470f442003-07-28 09:56:35 +00008418char *
8419prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008420{
Eric Andersencb57d552001-06-28 07:25:16 +00008421 while (*pfx) {
8422 if (*pfx++ != *string++)
8423 return 0;
8424 }
Eric Andersenc470f442003-07-28 09:56:35 +00008425 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008426}
8427
8428
8429/*
8430 * Convert a string of digits to an integer, printing an error message on
8431 * failure.
8432 */
8433
Eric Andersenc470f442003-07-28 09:56:35 +00008434int
8435number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008436{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008437
Eric Andersenc470f442003-07-28 09:56:35 +00008438 if (! is_number(s))
8439 error(illnum, s);
8440 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008441}
8442
Eric Andersenc470f442003-07-28 09:56:35 +00008443
Eric Andersenc470f442003-07-28 09:56:35 +00008444/*
8445 * Check for a valid number. This should be elsewhere.
8446 */
8447
8448int
8449is_number(const char *p)
8450{
8451 do {
8452 if (! is_digit(*p))
8453 return 0;
8454 } while (*++p != '\0');
8455 return 1;
8456}
8457
8458
Eric Andersencb57d552001-06-28 07:25:16 +00008459/*
8460 * Produce a possibly single quoted string suitable as input to the shell.
8461 * The return string is allocated on the stack.
8462 */
8463
Eric Andersenc470f442003-07-28 09:56:35 +00008464char *
8465single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008466 char *p;
8467
8468 STARTSTACKSTR(p);
8469
8470 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008471 char *q;
8472 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008473
Eric Andersenc470f442003-07-28 09:56:35 +00008474 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008475
Eric Andersenc470f442003-07-28 09:56:35 +00008476 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008477
Eric Andersenc470f442003-07-28 09:56:35 +00008478 *q++ = '\'';
8479 q = mempcpy(q, s, len);
8480 *q++ = '\'';
8481 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008482
Eric Andersenc470f442003-07-28 09:56:35 +00008483 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008484
Eric Andersenc470f442003-07-28 09:56:35 +00008485 len = strspn(s, "'");
8486 if (!len)
8487 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008488
Eric Andersenc470f442003-07-28 09:56:35 +00008489 q = p = makestrspace(len + 3, p);
8490
8491 *q++ = '"';
8492 q = mempcpy(q, s, len);
8493 *q++ = '"';
8494 s += len;
8495
8496 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008497 } while (*s);
8498
8499 USTPUTC(0, p);
8500
Eric Andersenc470f442003-07-28 09:56:35 +00008501 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008502}
8503
8504/*
Eric Andersenc470f442003-07-28 09:56:35 +00008505 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008506 */
8507
Eric Andersenc470f442003-07-28 09:56:35 +00008508char *
8509sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008510{
Eric Andersenc470f442003-07-28 09:56:35 +00008511 size_t len = strlen(p) + 1;
8512 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008513}
Eric Andersenc470f442003-07-28 09:56:35 +00008514
8515
8516static void
8517calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008518{
Eric Andersenc470f442003-07-28 09:56:35 +00008519 if (n == NULL)
8520 return;
8521 funcblocksize += nodesize[n->type];
8522 switch (n->type) {
8523 case NCMD:
8524 calcsize(n->ncmd.redirect);
8525 calcsize(n->ncmd.args);
8526 calcsize(n->ncmd.assign);
8527 break;
8528 case NPIPE:
8529 sizenodelist(n->npipe.cmdlist);
8530 break;
8531 case NREDIR:
8532 case NBACKGND:
8533 case NSUBSHELL:
8534 calcsize(n->nredir.redirect);
8535 calcsize(n->nredir.n);
8536 break;
8537 case NAND:
8538 case NOR:
8539 case NSEMI:
8540 case NWHILE:
8541 case NUNTIL:
8542 calcsize(n->nbinary.ch2);
8543 calcsize(n->nbinary.ch1);
8544 break;
8545 case NIF:
8546 calcsize(n->nif.elsepart);
8547 calcsize(n->nif.ifpart);
8548 calcsize(n->nif.test);
8549 break;
8550 case NFOR:
8551 funcstringsize += strlen(n->nfor.var) + 1;
8552 calcsize(n->nfor.body);
8553 calcsize(n->nfor.args);
8554 break;
8555 case NCASE:
8556 calcsize(n->ncase.cases);
8557 calcsize(n->ncase.expr);
8558 break;
8559 case NCLIST:
8560 calcsize(n->nclist.body);
8561 calcsize(n->nclist.pattern);
8562 calcsize(n->nclist.next);
8563 break;
8564 case NDEFUN:
8565 case NARG:
8566 sizenodelist(n->narg.backquote);
8567 funcstringsize += strlen(n->narg.text) + 1;
8568 calcsize(n->narg.next);
8569 break;
8570 case NTO:
8571 case NCLOBBER:
8572 case NFROM:
8573 case NFROMTO:
8574 case NAPPEND:
8575 calcsize(n->nfile.fname);
8576 calcsize(n->nfile.next);
8577 break;
8578 case NTOFD:
8579 case NFROMFD:
8580 calcsize(n->ndup.vname);
8581 calcsize(n->ndup.next);
8582 break;
8583 case NHERE:
8584 case NXHERE:
8585 calcsize(n->nhere.doc);
8586 calcsize(n->nhere.next);
8587 break;
8588 case NNOT:
8589 calcsize(n->nnot.com);
8590 break;
8591 };
Eric Andersencb57d552001-06-28 07:25:16 +00008592}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008593
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008594
Eric Andersenc470f442003-07-28 09:56:35 +00008595static void
8596sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008597{
8598 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008599 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008600 calcsize(lp->n);
8601 lp = lp->next;
8602 }
8603}
Eric Andersencb57d552001-06-28 07:25:16 +00008604
8605
Eric Andersenc470f442003-07-28 09:56:35 +00008606static union node *
8607copynode(union node *n)
8608{
8609 union node *new;
8610
8611 if (n == NULL)
8612 return NULL;
8613 new = funcblock;
8614 funcblock = (char *) funcblock + nodesize[n->type];
8615 switch (n->type) {
8616 case NCMD:
8617 new->ncmd.redirect = copynode(n->ncmd.redirect);
8618 new->ncmd.args = copynode(n->ncmd.args);
8619 new->ncmd.assign = copynode(n->ncmd.assign);
8620 break;
8621 case NPIPE:
8622 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8623 new->npipe.backgnd = n->npipe.backgnd;
8624 break;
8625 case NREDIR:
8626 case NBACKGND:
8627 case NSUBSHELL:
8628 new->nredir.redirect = copynode(n->nredir.redirect);
8629 new->nredir.n = copynode(n->nredir.n);
8630 break;
8631 case NAND:
8632 case NOR:
8633 case NSEMI:
8634 case NWHILE:
8635 case NUNTIL:
8636 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8637 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8638 break;
8639 case NIF:
8640 new->nif.elsepart = copynode(n->nif.elsepart);
8641 new->nif.ifpart = copynode(n->nif.ifpart);
8642 new->nif.test = copynode(n->nif.test);
8643 break;
8644 case NFOR:
8645 new->nfor.var = nodesavestr(n->nfor.var);
8646 new->nfor.body = copynode(n->nfor.body);
8647 new->nfor.args = copynode(n->nfor.args);
8648 break;
8649 case NCASE:
8650 new->ncase.cases = copynode(n->ncase.cases);
8651 new->ncase.expr = copynode(n->ncase.expr);
8652 break;
8653 case NCLIST:
8654 new->nclist.body = copynode(n->nclist.body);
8655 new->nclist.pattern = copynode(n->nclist.pattern);
8656 new->nclist.next = copynode(n->nclist.next);
8657 break;
8658 case NDEFUN:
8659 case NARG:
8660 new->narg.backquote = copynodelist(n->narg.backquote);
8661 new->narg.text = nodesavestr(n->narg.text);
8662 new->narg.next = copynode(n->narg.next);
8663 break;
8664 case NTO:
8665 case NCLOBBER:
8666 case NFROM:
8667 case NFROMTO:
8668 case NAPPEND:
8669 new->nfile.fname = copynode(n->nfile.fname);
8670 new->nfile.fd = n->nfile.fd;
8671 new->nfile.next = copynode(n->nfile.next);
8672 break;
8673 case NTOFD:
8674 case NFROMFD:
8675 new->ndup.vname = copynode(n->ndup.vname);
8676 new->ndup.dupfd = n->ndup.dupfd;
8677 new->ndup.fd = n->ndup.fd;
8678 new->ndup.next = copynode(n->ndup.next);
8679 break;
8680 case NHERE:
8681 case NXHERE:
8682 new->nhere.doc = copynode(n->nhere.doc);
8683 new->nhere.fd = n->nhere.fd;
8684 new->nhere.next = copynode(n->nhere.next);
8685 break;
8686 case NNOT:
8687 new->nnot.com = copynode(n->nnot.com);
8688 break;
8689 };
8690 new->type = n->type;
8691 return new;
8692}
8693
8694
8695static struct nodelist *
8696copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008697{
8698 struct nodelist *start;
8699 struct nodelist **lpp;
8700
8701 lpp = &start;
8702 while (lp) {
8703 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008704 funcblock = (char *) funcblock +
8705 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008706 (*lpp)->n = copynode(lp->n);
8707 lp = lp->next;
8708 lpp = &(*lpp)->next;
8709 }
8710 *lpp = NULL;
8711 return start;
8712}
8713
8714
Eric Andersenc470f442003-07-28 09:56:35 +00008715static char *
8716nodesavestr(char *s)
8717{
8718 char *rtn = funcstring;
8719
8720 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008721 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008722}
8723
Eric Andersenc470f442003-07-28 09:56:35 +00008724
Eric Andersenc470f442003-07-28 09:56:35 +00008725/*
8726 * Free a parse tree.
8727 */
8728
8729static void
8730freefunc(struct funcnode *f)
8731{
8732 if (f && --f->count < 0)
8733 ckfree(f);
8734}
8735
8736
8737static void options(int);
8738static void setoption(int, int);
8739
Eric Andersencb57d552001-06-28 07:25:16 +00008740
Eric Andersencb57d552001-06-28 07:25:16 +00008741/*
8742 * Process the shell command line arguments.
8743 */
8744
Eric Andersenc470f442003-07-28 09:56:35 +00008745void
8746procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008747{
8748 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008749 const char *xminusc;
8750 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008751
Eric Andersenc470f442003-07-28 09:56:35 +00008752 xargv = argv;
8753 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008754 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008755 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008756 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008757 optlist[i] = 2;
8758 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008759 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008760 xargv = argptr;
8761 xminusc = minusc;
8762 if (*xargv == NULL) {
8763 if (xminusc)
8764 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008765 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008766 }
Eric Andersencb57d552001-06-28 07:25:16 +00008767 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8768 iflag = 1;
8769 if (mflag == 2)
8770 mflag = iflag;
8771 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008772 if (optlist[i] == 2)
8773 optlist[i] = 0;
8774#if DEBUG == 2
8775 debug = 1;
8776#endif
8777 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8778 if (xminusc) {
8779 minusc = *xargv++;
8780 if (*xargv)
8781 goto setarg0;
8782 } else if (!sflag) {
8783 setinputfile(*xargv, 0);
8784setarg0:
8785 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008786 commandname = arg0;
8787 }
Eric Andersencb57d552001-06-28 07:25:16 +00008788
Eric Andersenc470f442003-07-28 09:56:35 +00008789 shellparam.p = xargv;
8790#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008791 shellparam.optind = 1;
8792 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008793#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008794 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008795 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008796 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008797 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008798 }
8799 optschanged();
8800}
8801
8802
Eric Andersenc470f442003-07-28 09:56:35 +00008803void
8804optschanged(void)
8805{
8806#ifdef DEBUG
8807 opentrace();
8808#endif
8809 setinteractive(iflag);
8810 setjobctl(mflag);
8811}
Eric Andersencb57d552001-06-28 07:25:16 +00008812
Eric Andersenc470f442003-07-28 09:56:35 +00008813static inline void
8814minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008815{
8816 int i;
8817
8818 if (name == NULL) {
8819 out1str("Current option settings\n");
8820 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008821 out1fmt("%-16s%s\n", optnames(i),
8822 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008823 } else {
8824 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008825 if (equal(name, optnames(i))) {
8826 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008827 return;
8828 }
8829 error("Illegal option -o %s", name);
8830 }
8831}
8832
Eric Andersenc470f442003-07-28 09:56:35 +00008833/*
8834 * Process shell options. The global variable argptr contains a pointer
8835 * to the argument list; we advance it past the options.
8836 */
Eric Andersen62483552001-07-10 06:09:16 +00008837
Eric Andersenc470f442003-07-28 09:56:35 +00008838static void
8839options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008840{
8841 char *p;
8842 int val;
8843 int c;
8844
8845 if (cmdline)
8846 minusc = NULL;
8847 while ((p = *argptr) != NULL) {
8848 argptr++;
8849 if ((c = *p++) == '-') {
8850 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008851 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8852 if (!cmdline) {
8853 /* "-" means turn off -x and -v */
8854 if (p[0] == '\0')
8855 xflag = vflag = 0;
8856 /* "--" means reset params */
8857 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008858 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008859 }
Eric Andersenc470f442003-07-28 09:56:35 +00008860 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008861 }
8862 } else if (c == '+') {
8863 val = 0;
8864 } else {
8865 argptr--;
8866 break;
8867 }
8868 while ((c = *p++) != '\0') {
8869 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008870 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008871 } else if (c == 'o') {
8872 minus_o(*argptr, val);
8873 if (*argptr)
8874 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008875 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008876 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008877 isloginsh = 1;
8878 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008879 } else {
8880 setoption(c, val);
8881 }
8882 }
8883 }
8884}
8885
Eric Andersencb57d552001-06-28 07:25:16 +00008886
Eric Andersenc470f442003-07-28 09:56:35 +00008887static void
8888setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008889{
Eric Andersencb57d552001-06-28 07:25:16 +00008890 int i;
8891
8892 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008893 if (optletters(i) == flag) {
8894 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008895 return;
8896 }
8897 error("Illegal option -%c", flag);
8898 /* NOTREACHED */
8899}
8900
8901
8902
Eric Andersencb57d552001-06-28 07:25:16 +00008903/*
8904 * Set the shell parameters.
8905 */
8906
Eric Andersenc470f442003-07-28 09:56:35 +00008907void
8908setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008909{
Eric Andersencb57d552001-06-28 07:25:16 +00008910 char **newparam;
8911 char **ap;
8912 int nparam;
8913
Eric Andersenc470f442003-07-28 09:56:35 +00008914 for (nparam = 0 ; argv[nparam] ; nparam++);
8915 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008916 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008917 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008918 }
8919 *ap = NULL;
8920 freeparam(&shellparam);
8921 shellparam.malloc = 1;
8922 shellparam.nparam = nparam;
8923 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008924#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008925 shellparam.optind = 1;
8926 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008927#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008928}
8929
8930
8931/*
8932 * Free the list of positional parameters.
8933 */
8934
Eric Andersenc470f442003-07-28 09:56:35 +00008935void
8936freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008937{
Eric Andersencb57d552001-06-28 07:25:16 +00008938 char **ap;
8939
8940 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008941 for (ap = param->p ; *ap ; ap++)
8942 ckfree(*ap);
8943 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008944 }
8945}
8946
8947
8948
8949/*
8950 * The shift builtin command.
8951 */
8952
Eric Andersenc470f442003-07-28 09:56:35 +00008953int
8954shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008955{
8956 int n;
8957 char **ap1, **ap2;
8958
8959 n = 1;
8960 if (argc > 1)
8961 n = number(argv[1]);
8962 if (n > shellparam.nparam)
8963 error("can't shift that many");
8964 INTOFF;
8965 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00008966 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00008967 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00008968 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00008969 }
8970 ap2 = shellparam.p;
8971 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00008972#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008973 shellparam.optind = 1;
8974 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008975#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008976 INTON;
8977 return 0;
8978}
8979
8980
8981
8982/*
8983 * The set command builtin.
8984 */
8985
Eric Andersenc470f442003-07-28 09:56:35 +00008986int
8987setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008988{
8989 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00008990 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00008991 INTOFF;
8992 options(0);
8993 optschanged();
8994 if (*argptr != NULL) {
8995 setparam(argptr);
8996 }
8997 INTON;
8998 return 0;
8999}
9000
9001
Eric Andersenc470f442003-07-28 09:56:35 +00009002#ifdef CONFIG_ASH_GETOPTS
9003static void
9004getoptsreset(value)
9005 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009006{
9007 shellparam.optind = number(value);
9008 shellparam.optoff = -1;
9009}
Eric Andersenc470f442003-07-28 09:56:35 +00009010#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009011
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009012#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009013static void change_lc_all(const char *value)
9014{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009015 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009016 setlocale(LC_ALL, value);
9017}
9018
9019static void change_lc_ctype(const char *value)
9020{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009021 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009022 setlocale(LC_CTYPE, value);
9023}
9024
9025#endif
9026
Eric Andersend35c5df2002-01-09 15:37:36 +00009027#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009028static int
Eric Andersenc470f442003-07-28 09:56:35 +00009029getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009030{
9031 char *p, *q;
9032 char c = '?';
9033 int done = 0;
9034 int err = 0;
9035 char s[10];
Eric Andersenc470f442003-07-28 09:56:35 +00009036 char **optnext = optfirst + *param_optind - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009037
Eric Andersenc470f442003-07-28 09:56:35 +00009038 if (*param_optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9039 strlen(*(optnext - 1)) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009040 p = NULL;
9041 else
9042 p = *(optnext - 1) + *optoff;
9043 if (p == NULL || *p == '\0') {
9044 /* Current word is done, advance */
9045 if (optnext == NULL)
9046 return 1;
9047 p = *optnext;
9048 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009049atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009050 p = NULL;
9051 done = 1;
9052 goto out;
9053 }
9054 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009055 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009056 goto atend;
9057 }
9058
9059 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009060 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009061 if (*q == '\0') {
9062 if (optstr[0] == ':') {
9063 s[0] = c;
9064 s[1] = '\0';
9065 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009066 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009067 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009068 (void) unsetvar("OPTARG");
9069 }
9070 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009071 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009072 }
9073 if (*++q == ':')
9074 q++;
9075 }
9076
9077 if (*++q == ':') {
9078 if (*p == '\0' && (p = *optnext) == NULL) {
9079 if (optstr[0] == ':') {
9080 s[0] = c;
9081 s[1] = '\0';
9082 err |= setvarsafe("OPTARG", s, 0);
9083 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009084 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009085 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009086 (void) unsetvar("OPTARG");
9087 c = '?';
9088 }
Eric Andersenc470f442003-07-28 09:56:35 +00009089 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009090 }
9091
9092 if (p == *optnext)
9093 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009094 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009095 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009096 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009097 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009098
Eric Andersenc470f442003-07-28 09:56:35 +00009099out:
Eric Andersencb57d552001-06-28 07:25:16 +00009100 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009101 *param_optind = optnext - optfirst + 1;
9102 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009103 err |= setvarsafe("OPTIND", s, VNOFUNC);
9104 s[0] = c;
9105 s[1] = '\0';
9106 err |= setvarsafe(optvar, s, 0);
9107 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009108 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009109 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009110 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009111 exraise(EXERROR);
9112 }
9113 return done;
9114}
Eric Andersenc470f442003-07-28 09:56:35 +00009115
9116/*
9117 * The getopts builtin. Shellparam.optnext points to the next argument
9118 * to be processed. Shellparam.optptr points to the next character to
9119 * be processed in the current argument. If shellparam.optnext is NULL,
9120 * then it's the first time getopts has been called.
9121 */
9122
9123int
9124getoptscmd(int argc, char **argv)
9125{
9126 char **optbase;
9127
9128 if (argc < 3)
9129 error("Usage: getopts optstring var [arg]");
9130 else if (argc == 3) {
9131 optbase = shellparam.p;
9132 if (shellparam.optind > shellparam.nparam + 1) {
9133 shellparam.optind = 1;
9134 shellparam.optoff = -1;
9135 }
9136 }
9137 else {
9138 optbase = &argv[3];
9139 if (shellparam.optind > argc - 2) {
9140 shellparam.optind = 1;
9141 shellparam.optoff = -1;
9142 }
9143 }
9144
9145 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9146 &shellparam.optoff);
9147}
9148#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009149
9150/*
9151 * XXX - should get rid of. have all builtins use getopt(3). the
9152 * library getopt must have the BSD extension static variable "optreset"
9153 * otherwise it can't be used within the shell safely.
9154 *
9155 * Standard option processing (a la getopt) for builtin routines. The
9156 * only argument that is passed to nextopt is the option string; the
9157 * other arguments are unnecessary. It return the character, or '\0' on
9158 * end of input.
9159 */
9160
Eric Andersenc470f442003-07-28 09:56:35 +00009161static int
9162nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009163{
Eric Andersencb57d552001-06-28 07:25:16 +00009164 char *p;
9165 const char *q;
9166 char c;
9167
9168 if ((p = optptr) == NULL || *p == '\0') {
9169 p = *argptr;
9170 if (p == NULL || *p != '-' || *++p == '\0')
9171 return '\0';
9172 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009173 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009174 return '\0';
9175 }
9176 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009177 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009178 if (*q == '\0')
9179 error("Illegal option -%c", c);
9180 if (*++q == ':')
9181 q++;
9182 }
9183 if (*++q == ':') {
9184 if (*p == '\0' && (p = *argptr++) == NULL)
9185 error("No arg for -%c option", c);
9186 optionarg = p;
9187 p = NULL;
9188 }
9189 optptr = p;
9190 return c;
9191}
9192
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009193
Eric Andersenc470f442003-07-28 09:56:35 +00009194/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9195
Eric Andersenc470f442003-07-28 09:56:35 +00009196void
9197outstr(const char *p, FILE *file)
9198{
9199 INTOFF;
9200 fputs(p, file);
9201 INTON;
9202}
9203
9204void
9205flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009206{
Eric Andersencb57d552001-06-28 07:25:16 +00009207 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009208 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009209 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009210 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009211}
9212
Eric Andersenc470f442003-07-28 09:56:35 +00009213void
9214flushout(FILE *dest)
9215{
9216 INTOFF;
9217 fflush(dest);
9218 INTON;
9219}
9220
9221static void
9222outcslow(int c, FILE *dest)
9223{
9224 INTOFF;
9225 putc(c, dest);
9226 fflush(dest);
9227 INTON;
9228}
9229
9230
9231static int
9232out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009233{
9234 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009235 int r;
9236
9237 INTOFF;
9238 va_start(ap, fmt);
9239 r = vprintf(fmt, ap);
9240 va_end(ap);
9241 INTON;
9242 return r;
9243}
9244
9245
9246int
9247fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9248{
9249 va_list ap;
9250 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009251
Eric Andersencb57d552001-06-28 07:25:16 +00009252 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009253 INTOFF;
9254 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009255 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009256 INTON;
9257 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009258}
9259
Eric Andersenc470f442003-07-28 09:56:35 +00009260
Eric Andersencb57d552001-06-28 07:25:16 +00009261/*
9262 * Version of write which resumes after a signal is caught.
9263 */
9264
Eric Andersenc470f442003-07-28 09:56:35 +00009265static void
9266xwrite(int fd, const void *p, size_t n)
Eric Andersen2870d962001-07-02 17:27:21 +00009267{
Eric Andersenc470f442003-07-28 09:56:35 +00009268 ssize_t i;
Eric Andersencb57d552001-06-28 07:25:16 +00009269
Eric Andersenc470f442003-07-28 09:56:35 +00009270 do {
9271 i = bb_full_write(fd, p, n);
9272 } while (i < 0 && errno == EINTR);
Eric Andersencb57d552001-06-28 07:25:16 +00009273}
9274
9275
Eric Andersenc470f442003-07-28 09:56:35 +00009276/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9277
9278
Eric Andersencb57d552001-06-28 07:25:16 +00009279/*
9280 * Shell command parser.
9281 */
9282
9283#define EOFMARKLEN 79
9284
9285
Eric Andersencb57d552001-06-28 07:25:16 +00009286struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009287 struct heredoc *next; /* next here document in list */
9288 union node *here; /* redirection node */
9289 char *eofmark; /* string indicating end of input */
9290 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009291};
9292
9293
9294
Eric Andersenc470f442003-07-28 09:56:35 +00009295static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009296
9297
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009298static union node *list(int);
9299static union node *andor(void);
9300static union node *pipeline(void);
9301static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009302static union node *simplecmd(void);
9303static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009304static void parsefname(void);
9305static void parseheredoc(void);
9306static char peektoken(void);
9307static int readtoken(void);
9308static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009309static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009310static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009311static void synexpect(int) __attribute__((__noreturn__));
9312static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009313static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009314
9315
Eric Andersenc470f442003-07-28 09:56:35 +00009316static inline int
9317goodname(const char *p)
9318{
9319 return !*endofname(p);
9320}
9321
9322static inline int
9323isassignment(const char *p)
9324{
9325 const char *q = endofname(p);
9326 if (p == q)
9327 return 0;
9328 return *q == '=';
9329}
9330
9331
Eric Andersencb57d552001-06-28 07:25:16 +00009332/*
9333 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9334 * valid parse tree indicating a blank line.)
9335 */
9336
Eric Andersenc470f442003-07-28 09:56:35 +00009337union node *
9338parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009339{
9340 int t;
9341
9342 tokpushback = 0;
9343 doprompt = interact;
9344 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009345 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009346 needprompt = 0;
9347 t = readtoken();
9348 if (t == TEOF)
9349 return NEOF;
9350 if (t == TNL)
9351 return NULL;
9352 tokpushback++;
9353 return list(1);
9354}
9355
9356
Eric Andersenc470f442003-07-28 09:56:35 +00009357static union node *
9358list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009359{
9360 union node *n1, *n2, *n3;
9361 int tok;
9362
Eric Andersenc470f442003-07-28 09:56:35 +00009363 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9364 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009365 return NULL;
9366 n1 = NULL;
9367 for (;;) {
9368 n2 = andor();
9369 tok = readtoken();
9370 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009371 if (n2->type == NPIPE) {
9372 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009373 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009374 if (n2->type != NREDIR) {
9375 n3 = stalloc(sizeof(struct nredir));
9376 n3->nredir.n = n2;
9377 n3->nredir.redirect = NULL;
9378 n2 = n3;
9379 }
9380 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009381 }
9382 }
9383 if (n1 == NULL) {
9384 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009385 }
9386 else {
9387 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009388 n3->type = NSEMI;
9389 n3->nbinary.ch1 = n1;
9390 n3->nbinary.ch2 = n2;
9391 n1 = n3;
9392 }
9393 switch (tok) {
9394 case TBACKGND:
9395 case TSEMI:
9396 tok = readtoken();
9397 /* fall through */
9398 case TNL:
9399 if (tok == TNL) {
9400 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009401 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009402 return n1;
9403 } else {
9404 tokpushback++;
9405 }
Eric Andersenc470f442003-07-28 09:56:35 +00009406 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009407 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009408 return n1;
9409 break;
9410 case TEOF:
9411 if (heredoclist)
9412 parseheredoc();
9413 else
Eric Andersenc470f442003-07-28 09:56:35 +00009414 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009415 return n1;
9416 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009417 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009418 synexpect(-1);
9419 tokpushback++;
9420 return n1;
9421 }
9422 }
9423}
9424
9425
9426
Eric Andersenc470f442003-07-28 09:56:35 +00009427static union node *
9428andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009429{
Eric Andersencb57d552001-06-28 07:25:16 +00009430 union node *n1, *n2, *n3;
9431 int t;
9432
Eric Andersencb57d552001-06-28 07:25:16 +00009433 n1 = pipeline();
9434 for (;;) {
9435 if ((t = readtoken()) == TAND) {
9436 t = NAND;
9437 } else if (t == TOR) {
9438 t = NOR;
9439 } else {
9440 tokpushback++;
9441 return n1;
9442 }
Eric Andersenc470f442003-07-28 09:56:35 +00009443 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009444 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009445 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009446 n3->type = t;
9447 n3->nbinary.ch1 = n1;
9448 n3->nbinary.ch2 = n2;
9449 n1 = n3;
9450 }
9451}
9452
9453
9454
Eric Andersenc470f442003-07-28 09:56:35 +00009455static union node *
9456pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009457{
Eric Andersencb57d552001-06-28 07:25:16 +00009458 union node *n1, *n2, *pipenode;
9459 struct nodelist *lp, *prev;
9460 int negate;
9461
9462 negate = 0;
9463 TRACE(("pipeline: entered\n"));
9464 if (readtoken() == TNOT) {
9465 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009466 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009467 } else
9468 tokpushback++;
9469 n1 = command();
9470 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009471 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009472 pipenode->type = NPIPE;
9473 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009474 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009475 pipenode->npipe.cmdlist = lp;
9476 lp->n = n1;
9477 do {
9478 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009479 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9480 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009481 lp->n = command();
9482 prev->next = lp;
9483 } while (readtoken() == TPIPE);
9484 lp->next = NULL;
9485 n1 = pipenode;
9486 }
9487 tokpushback++;
9488 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009489 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009490 n2->type = NNOT;
9491 n2->nnot.com = n1;
9492 return n2;
9493 } else
9494 return n1;
9495}
9496
9497
9498
Eric Andersenc470f442003-07-28 09:56:35 +00009499static union node *
9500command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009501{
Eric Andersencb57d552001-06-28 07:25:16 +00009502 union node *n1, *n2;
9503 union node *ap, **app;
9504 union node *cp, **cpp;
9505 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009506 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009507 int t;
9508
9509 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009510 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009511
Eric Andersencb57d552001-06-28 07:25:16 +00009512 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009513 default:
9514 synexpect(-1);
9515 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009516 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009517 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009518 n1->type = NIF;
9519 n1->nif.test = list(0);
9520 if (readtoken() != TTHEN)
9521 synexpect(TTHEN);
9522 n1->nif.ifpart = list(0);
9523 n2 = n1;
9524 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009525 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009526 n2 = n2->nif.elsepart;
9527 n2->type = NIF;
9528 n2->nif.test = list(0);
9529 if (readtoken() != TTHEN)
9530 synexpect(TTHEN);
9531 n2->nif.ifpart = list(0);
9532 }
9533 if (lasttoken == TELSE)
9534 n2->nif.elsepart = list(0);
9535 else {
9536 n2->nif.elsepart = NULL;
9537 tokpushback++;
9538 }
Eric Andersenc470f442003-07-28 09:56:35 +00009539 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009540 break;
9541 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009542 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009543 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009544 n1 = (union node *)stalloc(sizeof (struct nbinary));
9545 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009546 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009547 if ((got=readtoken()) != TDO) {
9548TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009549 synexpect(TDO);
9550 }
9551 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009552 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009553 break;
9554 }
9555 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009556 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009557 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009558 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009559 n1->type = NFOR;
9560 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009561 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009562 if (readtoken() == TIN) {
9563 app = &ap;
9564 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009565 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009566 n2->type = NARG;
9567 n2->narg.text = wordtext;
9568 n2->narg.backquote = backquotelist;
9569 *app = n2;
9570 app = &n2->narg.next;
9571 }
9572 *app = NULL;
9573 n1->nfor.args = ap;
9574 if (lasttoken != TNL && lasttoken != TSEMI)
9575 synexpect(-1);
9576 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009577 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009578 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009579 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009580 n2->narg.backquote = NULL;
9581 n2->narg.next = NULL;
9582 n1->nfor.args = n2;
9583 /*
9584 * Newline or semicolon here is optional (but note
9585 * that the original Bourne shell only allowed NL).
9586 */
9587 if (lasttoken != TNL && lasttoken != TSEMI)
9588 tokpushback++;
9589 }
Eric Andersenc470f442003-07-28 09:56:35 +00009590 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009591 if (readtoken() != TDO)
9592 synexpect(TDO);
9593 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009594 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009595 break;
9596 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009597 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009598 n1->type = NCASE;
9599 if (readtoken() != TWORD)
9600 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009601 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009602 n2->type = NARG;
9603 n2->narg.text = wordtext;
9604 n2->narg.backquote = backquotelist;
9605 n2->narg.next = NULL;
9606 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009607 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009608 } while (readtoken() == TNL);
9609 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009610 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009611 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009612next_case:
9613 checkkwd = CHKNL | CHKKWD;
9614 t = readtoken();
9615 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009616 if (lasttoken == TLP)
9617 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009618 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009619 cp->type = NCLIST;
9620 app = &cp->nclist.pattern;
9621 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009622 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009623 ap->type = NARG;
9624 ap->narg.text = wordtext;
9625 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009626 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009627 break;
9628 app = &ap->narg.next;
9629 readtoken();
9630 }
9631 ap->narg.next = NULL;
9632 if (lasttoken != TRP)
9633 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009634 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009635
Eric Andersenc470f442003-07-28 09:56:35 +00009636 cpp = &cp->nclist.next;
9637
9638 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009639 if ((t = readtoken()) != TESAC) {
9640 if (t != TENDCASE)
9641 synexpect(TENDCASE);
9642 else
Eric Andersenc470f442003-07-28 09:56:35 +00009643 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009644 }
Eric Andersenc470f442003-07-28 09:56:35 +00009645 }
Eric Andersencb57d552001-06-28 07:25:16 +00009646 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009647 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009648 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009649 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009650 n1->type = NSUBSHELL;
9651 n1->nredir.n = list(0);
9652 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009653 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009654 break;
9655 case TBEGIN:
9656 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009657 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009658 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009659 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009660 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009661 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009662 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009663 }
9664
Eric Andersenc470f442003-07-28 09:56:35 +00009665 if (readtoken() != t)
9666 synexpect(t);
9667
9668redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009669 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009670 checkkwd = CHKKWD | CHKALIAS;
9671 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009672 while (readtoken() == TREDIR) {
9673 *rpp = n2 = redirnode;
9674 rpp = &n2->nfile.next;
9675 parsefname();
9676 }
9677 tokpushback++;
9678 *rpp = NULL;
9679 if (redir) {
9680 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009681 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009682 n2->type = NREDIR;
9683 n2->nredir.n = n1;
9684 n1 = n2;
9685 }
9686 n1->nredir.redirect = redir;
9687 }
9688
9689 return n1;
9690}
9691
9692
Eric Andersenc470f442003-07-28 09:56:35 +00009693static union node *
9694simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009695 union node *args, **app;
9696 union node *n = NULL;
9697 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009698 union node **rpp, *redir;
9699 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009700
9701 args = NULL;
9702 app = &args;
9703 vars = NULL;
9704 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009705 redir = NULL;
9706 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009707
Eric Andersenc470f442003-07-28 09:56:35 +00009708 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009709 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009710 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009711 switch (readtoken()) {
9712 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009713 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009714 n->type = NARG;
9715 n->narg.text = wordtext;
9716 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009717 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009718 *vpp = n;
9719 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009720 } else {
9721 *app = n;
9722 app = &n->narg.next;
9723 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009724 }
9725 break;
9726 case TREDIR:
9727 *rpp = n = redirnode;
9728 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009729 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009730 break;
9731 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009732 if (
9733 args && app == &args->narg.next &&
9734 !vars && !redir
9735 ) {
9736 struct builtincmd *bcmd;
9737 const char *name;
9738
Eric Andersencb57d552001-06-28 07:25:16 +00009739 /* We have a function */
9740 if (readtoken() != TRP)
9741 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009742 name = n->narg.text;
9743 if (
9744 !goodname(name) || (
9745 (bcmd = find_builtin(name)) &&
9746 IS_BUILTIN_SPECIAL(bcmd)
9747 )
9748 )
9749 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009750 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009751 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009752 n->narg.next = command();
9753 return n;
9754 }
9755 /* fall through */
9756 default:
9757 tokpushback++;
9758 goto out;
9759 }
9760 }
Eric Andersenc470f442003-07-28 09:56:35 +00009761out:
Eric Andersencb57d552001-06-28 07:25:16 +00009762 *app = NULL;
9763 *vpp = NULL;
9764 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009765 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009766 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009767 n->ncmd.args = args;
9768 n->ncmd.assign = vars;
9769 n->ncmd.redirect = redir;
9770 return n;
9771}
9772
Eric Andersenc470f442003-07-28 09:56:35 +00009773static union node *
9774makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009775{
Eric Andersencb57d552001-06-28 07:25:16 +00009776 union node *n;
9777
Eric Andersenc470f442003-07-28 09:56:35 +00009778 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009779 n->type = NARG;
9780 n->narg.next = NULL;
9781 n->narg.text = wordtext;
9782 n->narg.backquote = backquotelist;
9783 return n;
9784}
9785
Eric Andersenc470f442003-07-28 09:56:35 +00009786void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009787{
Eric Andersencb57d552001-06-28 07:25:16 +00009788 TRACE(("Fix redir %s %d\n", text, err));
9789 if (!err)
9790 n->ndup.vname = NULL;
9791
9792 if (is_digit(text[0]) && text[1] == '\0')
9793 n->ndup.dupfd = digit_val(text[0]);
9794 else if (text[0] == '-' && text[1] == '\0')
9795 n->ndup.dupfd = -1;
9796 else {
9797
9798 if (err)
9799 synerror("Bad fd number");
9800 else
9801 n->ndup.vname = makename();
9802 }
9803}
9804
9805
Eric Andersenc470f442003-07-28 09:56:35 +00009806static void
9807parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009808{
Eric Andersencb57d552001-06-28 07:25:16 +00009809 union node *n = redirnode;
9810
9811 if (readtoken() != TWORD)
9812 synexpect(-1);
9813 if (n->type == NHERE) {
9814 struct heredoc *here = heredoc;
9815 struct heredoc *p;
9816 int i;
9817
9818 if (quoteflag == 0)
9819 n->type = NXHERE;
9820 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009821 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009822 synerror("Illegal eof marker for << redirection");
9823 rmescapes(wordtext);
9824 here->eofmark = wordtext;
9825 here->next = NULL;
9826 if (heredoclist == NULL)
9827 heredoclist = here;
9828 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009829 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009830 p->next = here;
9831 }
9832 } else if (n->type == NTOFD || n->type == NFROMFD) {
9833 fixredir(n, wordtext, 0);
9834 } else {
9835 n->nfile.fname = makename();
9836 }
9837}
9838
9839
9840/*
9841 * Input any here documents.
9842 */
9843
Eric Andersenc470f442003-07-28 09:56:35 +00009844static void
9845parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009846{
Eric Andersencb57d552001-06-28 07:25:16 +00009847 struct heredoc *here;
9848 union node *n;
9849
Eric Andersenc470f442003-07-28 09:56:35 +00009850 here = heredoclist;
9851 heredoclist = 0;
9852
9853 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009854 if (needprompt) {
9855 setprompt(2);
9856 needprompt = 0;
9857 }
Eric Andersenc470f442003-07-28 09:56:35 +00009858 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9859 here->eofmark, here->striptabs);
9860 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009861 n->narg.type = NARG;
9862 n->narg.next = NULL;
9863 n->narg.text = wordtext;
9864 n->narg.backquote = backquotelist;
9865 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009866 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009867 }
9868}
9869
Eric Andersenc470f442003-07-28 09:56:35 +00009870static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009871{
Eric Andersencb57d552001-06-28 07:25:16 +00009872 int t;
9873
9874 t = readtoken();
9875 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009876 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009877}
9878
Eric Andersenc470f442003-07-28 09:56:35 +00009879static int
9880readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009881{
Eric Andersencb57d552001-06-28 07:25:16 +00009882 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009883#ifdef DEBUG
9884 int alreadyseen = tokpushback;
9885#endif
9886
Eric Andersend35c5df2002-01-09 15:37:36 +00009887#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009888top:
Eric Andersen2870d962001-07-02 17:27:21 +00009889#endif
9890
Eric Andersencb57d552001-06-28 07:25:16 +00009891 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009892
Eric Andersenc470f442003-07-28 09:56:35 +00009893 /*
9894 * eat newlines
9895 */
9896 if (checkkwd & CHKNL) {
9897 while (t == TNL) {
9898 parseheredoc();
9899 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009900 }
9901 }
9902
Eric Andersenc470f442003-07-28 09:56:35 +00009903 if (t != TWORD || quoteflag) {
9904 goto out;
9905 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009906
Eric Andersenc470f442003-07-28 09:56:35 +00009907 /*
9908 * check for keywords
9909 */
9910 if (checkkwd & CHKKWD) {
9911 const char *const *pp;
9912
9913 if ((pp = findkwd(wordtext))) {
9914 lasttoken = t = pp - tokname_array;
9915 TRACE(("keyword %s recognized\n", tokname(t)));
9916 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009917 }
Eric Andersenc470f442003-07-28 09:56:35 +00009918 }
9919
9920 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009921#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009922 struct alias *ap;
9923 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009924 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009925 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009926 }
Eric Andersencb57d552001-06-28 07:25:16 +00009927 goto top;
9928 }
Eric Andersen2870d962001-07-02 17:27:21 +00009929#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009930 }
Eric Andersenc470f442003-07-28 09:56:35 +00009931out:
9932 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009933#ifdef DEBUG
9934 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009935 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009936 else
Eric Andersenc470f442003-07-28 09:56:35 +00009937 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009938#endif
9939 return (t);
9940}
9941
9942
9943/*
9944 * Read the next input token.
9945 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009946 * backquotes. We set quoteflag to true if any part of the word was
9947 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009948 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009949 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009950 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009951 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009952 *
9953 * [Change comment: here documents and internal procedures]
9954 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9955 * word parsing code into a separate routine. In this case, readtoken
9956 * doesn't need to have any internal procedures, but parseword does.
9957 * We could also make parseoperator in essence the main routine, and
9958 * have parseword (readtoken1?) handle both words and redirection.]
9959 */
9960
Eric Andersen81fe1232003-07-29 06:38:40 +00009961#define NEW_xxreadtoken
9962#ifdef NEW_xxreadtoken
9963
9964/* singles must be first! */
9965static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9966
9967static const char xxreadtoken_tokens[] = {
9968 TNL, TLP, TRP, /* only single occurrence allowed */
9969 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9970 TEOF, /* corresponds to trailing nul */
9971 TAND, TOR, TENDCASE, /* if double occurrence */
9972};
9973
9974#define xxreadtoken_doubles \
9975 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9976#define xxreadtoken_singles \
9977 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9978
9979static int xxreadtoken()
9980{
9981 int c;
9982
9983 if (tokpushback) {
9984 tokpushback = 0;
9985 return lasttoken;
9986 }
9987 if (needprompt) {
9988 setprompt(2);
9989 needprompt = 0;
9990 }
9991 startlinno = plinno;
9992 for (;;) { /* until token or start of word found */
9993 c = pgetc_macro();
9994
9995 if ((c != ' ') && (c != '\t')
9996#ifdef CONFIG_ASH_ALIAS
9997 && (c != PEOA)
9998#endif
9999 ) {
10000 if (c == '#') {
10001 while ((c = pgetc()) != '\n' && c != PEOF);
10002 pungetc();
10003 } else if (c == '\\') {
10004 if (pgetc() != '\n') {
10005 pungetc();
10006 goto READTOKEN1;
10007 }
10008 startlinno = ++plinno;
10009 if (doprompt)
10010 setprompt(2);
10011 } else {
10012 const char *p
10013 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10014
10015 if (c != PEOF) {
10016 if (c == '\n') {
10017 plinno++;
10018 needprompt = doprompt;
10019 }
10020
10021 p = strchr(xxreadtoken_chars, c);
10022 if (p == NULL) {
10023 READTOKEN1:
10024 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10025 }
10026
10027 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10028 if (pgetc() == *p) { /* double occurrence? */
10029 p += xxreadtoken_doubles + 1;
10030 } else {
10031 pungetc();
10032 }
10033 }
10034 }
10035
10036 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10037 }
10038 }
10039 }
10040}
10041
10042
10043#else
Eric Andersen2870d962001-07-02 17:27:21 +000010044#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010045
Eric Andersenc470f442003-07-28 09:56:35 +000010046static int
10047xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010048{
Eric Andersencb57d552001-06-28 07:25:16 +000010049 int c;
10050
10051 if (tokpushback) {
10052 tokpushback = 0;
10053 return lasttoken;
10054 }
10055 if (needprompt) {
10056 setprompt(2);
10057 needprompt = 0;
10058 }
10059 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010060 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010061 c = pgetc_macro();
10062 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010063 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010064#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010065 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010066#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010067 continue;
10068 case '#':
10069 while ((c = pgetc()) != '\n' && c != PEOF);
10070 pungetc();
10071 continue;
10072 case '\\':
10073 if (pgetc() == '\n') {
10074 startlinno = ++plinno;
10075 if (doprompt)
10076 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010077 continue;
10078 }
10079 pungetc();
10080 goto breakloop;
10081 case '\n':
10082 plinno++;
10083 needprompt = doprompt;
10084 RETURN(TNL);
10085 case PEOF:
10086 RETURN(TEOF);
10087 case '&':
10088 if (pgetc() == '&')
10089 RETURN(TAND);
10090 pungetc();
10091 RETURN(TBACKGND);
10092 case '|':
10093 if (pgetc() == '|')
10094 RETURN(TOR);
10095 pungetc();
10096 RETURN(TPIPE);
10097 case ';':
10098 if (pgetc() == ';')
10099 RETURN(TENDCASE);
10100 pungetc();
10101 RETURN(TSEMI);
10102 case '(':
10103 RETURN(TLP);
10104 case ')':
10105 RETURN(TRP);
10106 default:
10107 goto breakloop;
10108 }
10109 }
Eric Andersenc470f442003-07-28 09:56:35 +000010110breakloop:
10111 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010112#undef RETURN
10113}
Eric Andersen81fe1232003-07-29 06:38:40 +000010114#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010115
Eric Andersencb57d552001-06-28 07:25:16 +000010116
Eric Andersencb57d552001-06-28 07:25:16 +000010117/*
10118 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10119 * is not NULL, read a here document. In the latter case, eofmark is the
10120 * word which marks the end of the document and striptabs is true if
10121 * leading tabs should be stripped from the document. The argument firstc
10122 * is the first character of the input token or document.
10123 *
10124 * Because C does not have internal subroutines, I have simulated them
10125 * using goto's to implement the subroutine linkage. The following macros
10126 * will run code that appears at the end of readtoken1.
10127 */
10128
Eric Andersen2870d962001-07-02 17:27:21 +000010129#define CHECKEND() {goto checkend; checkend_return:;}
10130#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10131#define PARSESUB() {goto parsesub; parsesub_return:;}
10132#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10133#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10134#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010135
10136static int
Eric Andersenc470f442003-07-28 09:56:35 +000010137readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010138{
Eric Andersencb57d552001-06-28 07:25:16 +000010139 int c = firstc;
10140 char *out;
10141 int len;
10142 char line[EOFMARKLEN + 1];
10143 struct nodelist *bqlist;
10144 int quotef;
10145 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010146 int varnest; /* levels of variables expansion */
10147 int arinest; /* levels of arithmetic expansion */
10148 int parenlevel; /* levels of parens in arithmetic */
10149 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010150 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010151 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010152#if __GNUC__
10153 /* Avoid longjmp clobbering */
10154 (void) &out;
10155 (void) &quotef;
10156 (void) &dblquote;
10157 (void) &varnest;
10158 (void) &arinest;
10159 (void) &parenlevel;
10160 (void) &dqvarnest;
10161 (void) &oldstyle;
10162 (void) &prevsyntax;
10163 (void) &syntax;
10164#endif
10165
10166 startlinno = plinno;
10167 dblquote = 0;
10168 if (syntax == DQSYNTAX)
10169 dblquote = 1;
10170 quotef = 0;
10171 bqlist = NULL;
10172 varnest = 0;
10173 arinest = 0;
10174 parenlevel = 0;
10175 dqvarnest = 0;
10176
10177 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010178 loop: { /* for each line, until end of word */
10179 CHECKEND(); /* set c to PEOF if at end of here document */
10180 for (;;) { /* until end of line or end of word */
10181 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10182 switch(SIT(c, syntax)) {
10183 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010184 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010185 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010186 USTPUTC(c, out);
10187 plinno++;
10188 if (doprompt)
10189 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010190 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010191 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010192 case CWORD:
10193 USTPUTC(c, out);
10194 break;
10195 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010196 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010197 USTPUTC(CTLESC, out);
10198 USTPUTC(c, out);
10199 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010200 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010201 c = pgetc2();
10202 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010203 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010204 USTPUTC('\\', out);
10205 pungetc();
10206 } else if (c == '\n') {
10207 if (doprompt)
10208 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010209 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010210 if (
10211 dblquote &&
10212 c != '\\' && c != '`' &&
10213 c != '$' && (
10214 c != '"' ||
10215 eofmark != NULL
10216 )
10217 ) {
10218 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010219 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010220 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010221 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010222 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010223 USTPUTC(c, out);
10224 quotef++;
10225 }
10226 break;
10227 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010228 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010229quotemark:
10230 if (eofmark == NULL) {
10231 USTPUTC(CTLQUOTEMARK, out);
10232 }
Eric Andersencb57d552001-06-28 07:25:16 +000010233 break;
10234 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010235 syntax = DQSYNTAX;
10236 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010237 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010238 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010239 if (eofmark != NULL && arinest == 0 &&
10240 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010241 USTPUTC(c, out);
10242 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010243 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010244 syntax = BASESYNTAX;
10245 dblquote = 0;
10246 }
10247 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010248 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010249 }
10250 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010251 case CVAR: /* '$' */
10252 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010253 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010254 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010255 if (varnest > 0) {
10256 varnest--;
10257 if (dqvarnest > 0) {
10258 dqvarnest--;
10259 }
10260 USTPUTC(CTLENDVAR, out);
10261 } else {
10262 USTPUTC(c, out);
10263 }
10264 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010265#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010266 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010267 parenlevel++;
10268 USTPUTC(c, out);
10269 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010270 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010271 if (parenlevel > 0) {
10272 USTPUTC(c, out);
10273 --parenlevel;
10274 } else {
10275 if (pgetc() == ')') {
10276 if (--arinest == 0) {
10277 USTPUTC(CTLENDARI, out);
10278 syntax = prevsyntax;
10279 if (syntax == DQSYNTAX)
10280 dblquote = 1;
10281 else
10282 dblquote = 0;
10283 } else
10284 USTPUTC(')', out);
10285 } else {
10286 /*
10287 * unbalanced parens
10288 * (don't 2nd guess - no error)
10289 */
10290 pungetc();
10291 USTPUTC(')', out);
10292 }
10293 }
10294 break;
10295#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010296 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010297 PARSEBACKQOLD();
10298 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010299 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010300 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010301 case CIGN:
10302 break;
10303 default:
10304 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010305 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010306#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010307 if (c != PEOA)
10308#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010309 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010310
Eric Andersencb57d552001-06-28 07:25:16 +000010311 }
10312 c = pgetc_macro();
10313 }
10314 }
Eric Andersenc470f442003-07-28 09:56:35 +000010315endword:
10316#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010317 if (syntax == ARISYNTAX)
10318 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010319#endif
10320 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010321 synerror("Unterminated quoted string");
10322 if (varnest != 0) {
10323 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010324 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010325 synerror("Missing '}'");
10326 }
10327 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010328 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010329 out = stackblock();
10330 if (eofmark == NULL) {
10331 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010332 && quotef == 0
10333 && len <= 2
10334 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010335 PARSEREDIR();
10336 return lasttoken = TREDIR;
10337 } else {
10338 pungetc();
10339 }
10340 }
10341 quoteflag = quotef;
10342 backquotelist = bqlist;
10343 grabstackblock(len);
10344 wordtext = out;
10345 return lasttoken = TWORD;
10346/* end of readtoken routine */
10347
10348
10349
10350/*
10351 * Check to see whether we are at the end of the here document. When this
10352 * is called, c is set to the first character of the next input line. If
10353 * we are at the end of the here document, this routine sets the c to PEOF.
10354 */
10355
Eric Andersenc470f442003-07-28 09:56:35 +000010356checkend: {
10357 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010358#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010359 if (c == PEOA) {
10360 c = pgetc2();
10361 }
10362#endif
10363 if (striptabs) {
10364 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010365 c = pgetc2();
10366 }
Eric Andersenc470f442003-07-28 09:56:35 +000010367 }
10368 if (c == *eofmark) {
10369 if (pfgets(line, sizeof line) != NULL) {
10370 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010371
Eric Andersenc470f442003-07-28 09:56:35 +000010372 p = line;
10373 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10374 if (*p == '\n' && *q == '\0') {
10375 c = PEOF;
10376 plinno++;
10377 needprompt = doprompt;
10378 } else {
10379 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010380 }
10381 }
10382 }
10383 }
Eric Andersenc470f442003-07-28 09:56:35 +000010384 goto checkend_return;
10385}
Eric Andersencb57d552001-06-28 07:25:16 +000010386
10387
10388/*
10389 * Parse a redirection operator. The variable "out" points to a string
10390 * specifying the fd to be redirected. The variable "c" contains the
10391 * first character of the redirection operator.
10392 */
10393
Eric Andersenc470f442003-07-28 09:56:35 +000010394parseredir: {
10395 char fd = *out;
10396 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010397
Eric Andersenc470f442003-07-28 09:56:35 +000010398 np = (union node *)stalloc(sizeof (struct nfile));
10399 if (c == '>') {
10400 np->nfile.fd = 1;
10401 c = pgetc();
10402 if (c == '>')
10403 np->type = NAPPEND;
10404 else if (c == '|')
10405 np->type = NCLOBBER;
10406 else if (c == '&')
10407 np->type = NTOFD;
10408 else {
10409 np->type = NTO;
10410 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010411 }
Eric Andersenc470f442003-07-28 09:56:35 +000010412 } else { /* c == '<' */
10413 np->nfile.fd = 0;
10414 switch (c = pgetc()) {
10415 case '<':
10416 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10417 np = (union node *)stalloc(sizeof (struct nhere));
10418 np->nfile.fd = 0;
10419 }
10420 np->type = NHERE;
10421 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10422 heredoc->here = np;
10423 if ((c = pgetc()) == '-') {
10424 heredoc->striptabs = 1;
10425 } else {
10426 heredoc->striptabs = 0;
10427 pungetc();
10428 }
10429 break;
10430
10431 case '&':
10432 np->type = NFROMFD;
10433 break;
10434
10435 case '>':
10436 np->type = NFROMTO;
10437 break;
10438
10439 default:
10440 np->type = NFROM;
10441 pungetc();
10442 break;
10443 }
Eric Andersencb57d552001-06-28 07:25:16 +000010444 }
Eric Andersenc470f442003-07-28 09:56:35 +000010445 if (fd != '\0')
10446 np->nfile.fd = digit_val(fd);
10447 redirnode = np;
10448 goto parseredir_return;
10449}
Eric Andersencb57d552001-06-28 07:25:16 +000010450
10451
10452/*
10453 * Parse a substitution. At this point, we have read the dollar sign
10454 * and nothing else.
10455 */
10456
Eric Andersenc470f442003-07-28 09:56:35 +000010457parsesub: {
10458 int subtype;
10459 int typeloc;
10460 int flags;
10461 char *p;
10462 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010463
Eric Andersenc470f442003-07-28 09:56:35 +000010464 c = pgetc();
10465 if (
10466 c <= PEOA_OR_PEOF ||
10467 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10468 ) {
10469 USTPUTC('$', out);
10470 pungetc();
10471 } else if (c == '(') { /* $(command) or $((arith)) */
10472 if (pgetc() == '(') {
10473#ifdef CONFIG_ASH_MATH_SUPPORT
10474 PARSEARITH();
10475#else
10476 synerror("We unsupport $((arith))");
10477#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010478 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010479 pungetc();
10480 PARSEBACKQNEW();
10481 }
10482 } else {
10483 USTPUTC(CTLVAR, out);
10484 typeloc = out - (char *)stackblock();
10485 USTPUTC(VSNORMAL, out);
10486 subtype = VSNORMAL;
10487 if (c == '{') {
10488 c = pgetc();
10489 if (c == '#') {
10490 if ((c = pgetc()) == '}')
10491 c = '#';
10492 else
10493 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010494 }
Eric Andersenc470f442003-07-28 09:56:35 +000010495 else
10496 subtype = 0;
10497 }
10498 if (c > PEOA_OR_PEOF && is_name(c)) {
10499 do {
10500 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010501 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010502 } while (c > PEOA_OR_PEOF && is_in_name(c));
10503 } else if (is_digit(c)) {
10504 do {
10505 STPUTC(c, out);
10506 c = pgetc();
10507 } while (is_digit(c));
10508 }
10509 else if (is_special(c)) {
10510 USTPUTC(c, out);
10511 c = pgetc();
10512 }
10513 else
10514badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010515
Eric Andersenc470f442003-07-28 09:56:35 +000010516 STPUTC('=', out);
10517 flags = 0;
10518 if (subtype == 0) {
10519 switch (c) {
10520 case ':':
10521 flags = VSNUL;
10522 c = pgetc();
10523 /*FALLTHROUGH*/
10524 default:
10525 p = strchr(types, c);
10526 if (p == NULL)
10527 goto badsub;
10528 subtype = p - types + VSNORMAL;
10529 break;
10530 case '%':
10531 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010532 {
10533 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010534 subtype = c == '#' ? VSTRIMLEFT :
10535 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010536 c = pgetc();
10537 if (c == cc)
10538 subtype++;
10539 else
10540 pungetc();
10541 break;
10542 }
10543 }
Eric Andersenc470f442003-07-28 09:56:35 +000010544 } else {
10545 pungetc();
10546 }
10547 if (dblquote || arinest)
10548 flags |= VSQUOTE;
10549 *((char *)stackblock() + typeloc) = subtype | flags;
10550 if (subtype != VSNORMAL) {
10551 varnest++;
10552 if (dblquote || arinest) {
10553 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010554 }
10555 }
10556 }
Eric Andersenc470f442003-07-28 09:56:35 +000010557 goto parsesub_return;
10558}
Eric Andersencb57d552001-06-28 07:25:16 +000010559
10560
10561/*
10562 * Called to parse command substitutions. Newstyle is set if the command
10563 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10564 * list of commands (passed by reference), and savelen is the number of
10565 * characters on the top of the stack which must be preserved.
10566 */
10567
Eric Andersenc470f442003-07-28 09:56:35 +000010568parsebackq: {
10569 struct nodelist **nlpp;
10570 int savepbq;
10571 union node *n;
10572 char *volatile str;
10573 struct jmploc jmploc;
10574 struct jmploc *volatile savehandler;
10575 size_t savelen;
10576 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010577#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010578 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010579#endif
10580
Eric Andersenc470f442003-07-28 09:56:35 +000010581 savepbq = parsebackquote;
10582 if (setjmp(jmploc.loc)) {
10583 if (str)
10584 ckfree(str);
10585 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010586 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010587 longjmp(handler->loc, 1);
10588 }
10589 INTOFF;
10590 str = NULL;
10591 savelen = out - (char *)stackblock();
10592 if (savelen > 0) {
10593 str = ckmalloc(savelen);
10594 memcpy(str, stackblock(), savelen);
10595 }
10596 savehandler = handler;
10597 handler = &jmploc;
10598 INTON;
10599 if (oldstyle) {
10600 /* We must read until the closing backquote, giving special
10601 treatment to some slashes, and then push the string and
10602 reread it as input, interpreting it normally. */
10603 char *pout;
10604 int pc;
10605 size_t psavelen;
10606 char *pstr;
10607
10608
10609 STARTSTACKSTR(pout);
10610 for (;;) {
10611 if (needprompt) {
10612 setprompt(2);
10613 needprompt = 0;
10614 }
10615 switch (pc = pgetc()) {
10616 case '`':
10617 goto done;
10618
10619 case '\\':
10620 if ((pc = pgetc()) == '\n') {
10621 plinno++;
10622 if (doprompt)
10623 setprompt(2);
10624 /*
10625 * If eating a newline, avoid putting
10626 * the newline into the new character
10627 * stream (via the STPUTC after the
10628 * switch).
10629 */
10630 continue;
10631 }
10632 if (pc != '\\' && pc != '`' && pc != '$'
10633 && (!dblquote || pc != '"'))
10634 STPUTC('\\', pout);
10635 if (pc > PEOA_OR_PEOF) {
10636 break;
10637 }
10638 /* fall through */
10639
10640 case PEOF:
10641#ifdef CONFIG_ASH_ALIAS
10642 case PEOA:
10643#endif
10644 startlinno = plinno;
10645 synerror("EOF in backquote substitution");
10646
10647 case '\n':
10648 plinno++;
10649 needprompt = doprompt;
10650 break;
10651
10652 default:
10653 break;
10654 }
10655 STPUTC(pc, pout);
10656 }
10657done:
10658 STPUTC('\0', pout);
10659 psavelen = pout - (char *)stackblock();
10660 if (psavelen > 0) {
10661 pstr = grabstackstr(pout);
10662 setinputstring(pstr);
10663 }
10664 }
10665 nlpp = &bqlist;
10666 while (*nlpp)
10667 nlpp = &(*nlpp)->next;
10668 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10669 (*nlpp)->next = NULL;
10670 parsebackquote = oldstyle;
10671
10672 if (oldstyle) {
10673 saveprompt = doprompt;
10674 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010675 }
10676
Eric Andersenc470f442003-07-28 09:56:35 +000010677 n = list(2);
10678
10679 if (oldstyle)
10680 doprompt = saveprompt;
10681 else {
10682 if (readtoken() != TRP)
10683 synexpect(TRP);
10684 }
10685
10686 (*nlpp)->n = n;
10687 if (oldstyle) {
10688 /*
10689 * Start reading from old file again, ignoring any pushed back
10690 * tokens left from the backquote parsing
10691 */
10692 popfile();
10693 tokpushback = 0;
10694 }
10695 while (stackblocksize() <= savelen)
10696 growstackblock();
10697 STARTSTACKSTR(out);
10698 if (str) {
10699 memcpy(out, str, savelen);
10700 STADJUST(savelen, out);
10701 INTOFF;
10702 ckfree(str);
10703 str = NULL;
10704 INTON;
10705 }
10706 parsebackquote = savepbq;
10707 handler = savehandler;
10708 if (arinest || dblquote)
10709 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10710 else
10711 USTPUTC(CTLBACKQ, out);
10712 if (oldstyle)
10713 goto parsebackq_oldreturn;
10714 else
10715 goto parsebackq_newreturn;
10716}
10717
10718#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010719/*
10720 * Parse an arithmetic expansion (indicate start of one and set state)
10721 */
Eric Andersenc470f442003-07-28 09:56:35 +000010722parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010723
Eric Andersenc470f442003-07-28 09:56:35 +000010724 if (++arinest == 1) {
10725 prevsyntax = syntax;
10726 syntax = ARISYNTAX;
10727 USTPUTC(CTLARI, out);
10728 if (dblquote)
10729 USTPUTC('"',out);
10730 else
10731 USTPUTC(' ',out);
10732 } else {
10733 /*
10734 * we collapse embedded arithmetic expansion to
10735 * parenthesis, which should be equivalent
10736 */
10737 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010738 }
Eric Andersenc470f442003-07-28 09:56:35 +000010739 goto parsearith_return;
10740}
10741#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010742
Eric Andersenc470f442003-07-28 09:56:35 +000010743} /* end of readtoken */
10744
Eric Andersencb57d552001-06-28 07:25:16 +000010745
10746
Eric Andersencb57d552001-06-28 07:25:16 +000010747/*
10748 * Returns true if the text contains nothing to expand (no dollar signs
10749 * or backquotes).
10750 */
10751
Eric Andersenc470f442003-07-28 09:56:35 +000010752static int
10753noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010754{
Eric Andersencb57d552001-06-28 07:25:16 +000010755 char *p;
10756 char c;
10757
10758 p = text;
10759 while ((c = *p++) != '\0') {
10760 if (c == CTLQUOTEMARK)
10761 continue;
10762 if (c == CTLESC)
10763 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010764 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010765 return 0;
10766 }
10767 return 1;
10768}
10769
10770
10771/*
Eric Andersenc470f442003-07-28 09:56:35 +000010772 * Return of a legal variable name (a letter or underscore followed by zero or
10773 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010774 */
10775
Eric Andersenc470f442003-07-28 09:56:35 +000010776char *
10777endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010778{
Eric Andersenc470f442003-07-28 09:56:35 +000010779 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010780
Eric Andersenc470f442003-07-28 09:56:35 +000010781 p = (char *) name;
10782 if (! is_name(*p))
10783 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010784 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010785 if (! is_in_name(*p))
10786 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010787 }
Eric Andersenc470f442003-07-28 09:56:35 +000010788 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010789}
10790
10791
10792/*
10793 * Called when an unexpected token is read during the parse. The argument
10794 * is the token that is expected, or -1 if more than one type of token can
10795 * occur at this point.
10796 */
10797
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010798static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010799{
10800 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010801 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010802
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010803 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10804 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010805 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010806 synerror(msg);
10807 /* NOTREACHED */
10808}
10809
Eric Andersenc470f442003-07-28 09:56:35 +000010810static void
10811synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010812{
Eric Andersenc470f442003-07-28 09:56:35 +000010813 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010814 /* NOTREACHED */
10815}
10816
Eric Andersencb57d552001-06-28 07:25:16 +000010817
10818/*
10819 * called by editline -- any expansions to the prompt
10820 * should be added here.
10821 */
Eric Andersenc470f442003-07-28 09:56:35 +000010822
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010823static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010824{
Eric Andersenc470f442003-07-28 09:56:35 +000010825 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010826
10827 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010828 case 1:
10829 prompt = ps1val();
10830 break;
10831 case 2:
10832 prompt = ps2val();
10833 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010834 default: /* 0 */
10835 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010836 }
10837 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010838}
10839
Eric Andersencb57d552001-06-28 07:25:16 +000010840
Eric Andersenc470f442003-07-28 09:56:35 +000010841static const char *const *findkwd(const char *s)
10842{
10843 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010844 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010845 sizeof(const char *), pstrcmp);
10846}
10847
10848/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10849
Eric Andersencb57d552001-06-28 07:25:16 +000010850/*
10851 * Code for dealing with input/output redirection.
10852 */
10853
Eric Andersenc470f442003-07-28 09:56:35 +000010854#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010855#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010856# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010857#else
10858# define PIPESIZE PIPE_BUF
10859#endif
10860
Eric Andersen62483552001-07-10 06:09:16 +000010861/*
10862 * Open a file in noclobber mode.
10863 * The code was copied from bash.
10864 */
Eric Andersenc470f442003-07-28 09:56:35 +000010865static inline int
10866noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010867{
10868 int r, fd;
10869 struct stat finfo, finfo2;
10870
10871 /*
10872 * If the file exists and is a regular file, return an error
10873 * immediately.
10874 */
10875 r = stat(fname, &finfo);
10876 if (r == 0 && S_ISREG(finfo.st_mode)) {
10877 errno = EEXIST;
10878 return -1;
10879 }
10880
10881 /*
10882 * If the file was not present (r != 0), make sure we open it
10883 * exclusively so that if it is created before we open it, our open
10884 * will fail. Make sure that we do not truncate an existing file.
10885 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10886 * file was not a regular file, we leave O_EXCL off.
10887 */
10888 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010889 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10890 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010891
10892 /* If the open failed, return the file descriptor right away. */
10893 if (fd < 0)
10894 return fd;
10895
10896 /*
10897 * OK, the open succeeded, but the file may have been changed from a
10898 * non-regular file to a regular file between the stat and the open.
10899 * We are assuming that the O_EXCL open handles the case where FILENAME
10900 * did not exist and is symlinked to an existing file between the stat
10901 * and open.
10902 */
10903
10904 /*
10905 * If we can open it and fstat the file descriptor, and neither check
10906 * revealed that it was a regular file, and the file has not been
10907 * replaced, return the file descriptor.
10908 */
Eric Andersenc470f442003-07-28 09:56:35 +000010909 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10910 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010911 return fd;
10912
10913 /* The file has been replaced. badness. */
10914 close(fd);
10915 errno = EEXIST;
10916 return -1;
10917}
Eric Andersencb57d552001-06-28 07:25:16 +000010918
10919/*
Eric Andersen62483552001-07-10 06:09:16 +000010920 * Handle here documents. Normally we fork off a process to write the
10921 * data to a pipe. If the document is short, we can stuff the data in
10922 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010923 */
10924
Eric Andersenc470f442003-07-28 09:56:35 +000010925static inline int
10926openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010927{
10928 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010929 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010930
Eric Andersen62483552001-07-10 06:09:16 +000010931 if (pipe(pip) < 0)
10932 error("Pipe call failed");
10933 if (redir->type == NHERE) {
10934 len = strlen(redir->nhere.doc->narg.text);
10935 if (len <= PIPESIZE) {
10936 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10937 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010938 }
Eric Andersencb57d552001-06-28 07:25:16 +000010939 }
Eric Andersenc470f442003-07-28 09:56:35 +000010940 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010941 close(pip[0]);
10942 signal(SIGINT, SIG_IGN);
10943 signal(SIGQUIT, SIG_IGN);
10944 signal(SIGHUP, SIG_IGN);
10945#ifdef SIGTSTP
10946 signal(SIGTSTP, SIG_IGN);
10947#endif
10948 signal(SIGPIPE, SIG_DFL);
10949 if (redir->type == NHERE)
10950 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10951 else
10952 expandhere(redir->nhere.doc, pip[1]);
10953 _exit(0);
10954 }
Eric Andersenc470f442003-07-28 09:56:35 +000010955out:
Eric Andersen62483552001-07-10 06:09:16 +000010956 close(pip[1]);
10957 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000010958}
10959
Eric Andersenc470f442003-07-28 09:56:35 +000010960static int
10961openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010962{
Eric Andersencb57d552001-06-28 07:25:16 +000010963 char *fname;
10964 int f;
10965
10966 switch (redir->nfile.type) {
10967 case NFROM:
10968 fname = redir->nfile.expfname;
10969 if ((f = open(fname, O_RDONLY)) < 0)
10970 goto eopen;
10971 break;
10972 case NFROMTO:
10973 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010974 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010975 goto ecreate;
10976 break;
10977 case NTO:
10978 /* Take care of noclobber mode. */
10979 if (Cflag) {
10980 fname = redir->nfile.expfname;
10981 if ((f = noclobberopen(fname)) < 0)
10982 goto ecreate;
10983 break;
10984 }
Eric Andersenc470f442003-07-28 09:56:35 +000010985 /* FALLTHROUGH */
10986 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000010987 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010988 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010989 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010990 break;
10991 case NAPPEND:
10992 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000010993 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010994 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000010995 break;
10996 default:
10997#ifdef DEBUG
10998 abort();
10999#endif
11000 /* Fall through to eliminate warning. */
11001 case NTOFD:
11002 case NFROMFD:
11003 f = -1;
11004 break;
11005 case NHERE:
11006 case NXHERE:
11007 f = openhere(redir);
11008 break;
11009 }
11010
11011 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011012ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011013 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011014eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011015 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11016}
11017
Eric Andersenc470f442003-07-28 09:56:35 +000011018static inline void
11019dupredirect(union node *redir, int f)
11020{
11021 int fd = redir->nfile.fd;
11022
11023 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11024 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11025 copyfd(redir->ndup.dupfd, fd);
11026 }
11027 return;
11028 }
11029
11030 if (f != fd) {
11031 copyfd(f, fd);
11032 close(f);
11033 }
11034 return;
11035}
Eric Andersencb57d552001-06-28 07:25:16 +000011036
Eric Andersen62483552001-07-10 06:09:16 +000011037/*
11038 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11039 * old file descriptors are stashed away so that the redirection can be
11040 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11041 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011042 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011043 */
11044
Eric Andersenc470f442003-07-28 09:56:35 +000011045static void
11046redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011047{
11048 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011049 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011050 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011051 int fd;
11052 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011053 int *p;
11054 nullredirs++;
11055 if (!redir) {
11056 return;
Eric Andersen62483552001-07-10 06:09:16 +000011057 }
Eric Andersenc470f442003-07-28 09:56:35 +000011058 sv = NULL;
11059 INTOFF;
11060 if (flags & REDIR_PUSH) {
11061 struct redirtab *q;
11062 q = ckmalloc(sizeof (struct redirtab));
11063 q->next = redirlist;
11064 redirlist = q;
11065 q->nullredirs = nullredirs - 1;
11066 for (i = 0 ; i < 10 ; i++)
11067 q->renamed[i] = EMPTY;
11068 nullredirs = 0;
11069 sv = q;
11070 }
11071 n = redir;
11072 do {
Eric Andersen62483552001-07-10 06:09:16 +000011073 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011074 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011075 n->ndup.dupfd == fd)
11076 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011077
Eric Andersen62483552001-07-10 06:09:16 +000011078 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011079 if (fd == newfd)
11080 continue;
11081 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11082 i = fcntl(fd, F_DUPFD, 10);
11083
11084 if (i == -1) {
11085 i = errno;
11086 if (i != EBADF) {
11087 close(newfd);
11088 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011089 error("%d: %m", fd);
11090 /* NOTREACHED */
11091 }
Eric Andersenc470f442003-07-28 09:56:35 +000011092 } else {
11093 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011094 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011095 }
Eric Andersenc470f442003-07-28 09:56:35 +000011096 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011097 close(fd);
11098 }
Eric Andersenc470f442003-07-28 09:56:35 +000011099 dupredirect(n, newfd);
11100 } while ((n = n->nfile.next));
11101 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011102 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11103 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011104}
11105
11106
Eric Andersencb57d552001-06-28 07:25:16 +000011107/*
11108 * Undo the effects of the last redirection.
11109 */
11110
Eric Andersenc470f442003-07-28 09:56:35 +000011111void
11112popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011113{
Eric Andersenc470f442003-07-28 09:56:35 +000011114 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011115 int i;
11116
Eric Andersenc470f442003-07-28 09:56:35 +000011117 if (--nullredirs >= 0)
11118 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011119 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011120 rp = redirlist;
11121 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011122 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011123 if (!drop) {
11124 close(i);
11125 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011126 }
Eric Andersenc470f442003-07-28 09:56:35 +000011127 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011128 }
11129 }
11130 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011131 nullredirs = rp->nullredirs;
11132 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011133 INTON;
11134}
11135
11136/*
Eric Andersenc470f442003-07-28 09:56:35 +000011137 * Undo all redirections. Called on error or interrupt.
11138 */
11139
11140/*
Eric Andersencb57d552001-06-28 07:25:16 +000011141 * Discard all saved file descriptors.
11142 */
11143
Eric Andersenc470f442003-07-28 09:56:35 +000011144void
11145clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011146{
Eric Andersenc470f442003-07-28 09:56:35 +000011147 for (;;) {
11148 nullredirs = 0;
11149 if (!redirlist)
11150 break;
11151 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011152 }
Eric Andersencb57d552001-06-28 07:25:16 +000011153}
11154
11155
Eric Andersencb57d552001-06-28 07:25:16 +000011156/*
11157 * Copy a file descriptor to be >= to. Returns -1
11158 * if the source file descriptor is closed, EMPTY if there are no unused
11159 * file descriptors left.
11160 */
11161
Eric Andersenc470f442003-07-28 09:56:35 +000011162int
11163copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011164{
11165 int newfd;
11166
11167 newfd = fcntl(from, F_DUPFD, to);
11168 if (newfd < 0) {
11169 if (errno == EMFILE)
11170 return EMPTY;
11171 else
Eric Andersen2870d962001-07-02 17:27:21 +000011172 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011173 }
11174 return newfd;
11175}
11176
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011177
Eric Andersenc470f442003-07-28 09:56:35 +000011178int
11179redirectsafe(union node *redir, int flags)
11180{
11181 int err;
11182 volatile int saveint;
11183 struct jmploc *volatile savehandler = handler;
11184 struct jmploc jmploc;
11185
11186 SAVEINT(saveint);
11187 if (!(err = setjmp(jmploc.loc) * 2)) {
11188 handler = &jmploc;
11189 redirect(redir, flags);
11190 }
11191 handler = savehandler;
11192 if (err && exception != EXERROR)
11193 longjmp(handler->loc, 1);
11194 RESTOREINT(saveint);
11195 return err;
11196}
11197
11198/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11199
11200#ifdef DEBUG
11201static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011202static void shcmd(union node *, FILE *);
11203static void sharg(union node *, FILE *);
11204static void indent(int, char *, FILE *);
11205static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011206
11207
Eric Andersenc470f442003-07-28 09:56:35 +000011208void
11209showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011210{
11211 trputs("showtree called\n");
11212 shtree(n, 1, NULL, stdout);
11213}
Eric Andersencb57d552001-06-28 07:25:16 +000011214
Eric Andersenc470f442003-07-28 09:56:35 +000011215
11216static void
11217shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011218{
11219 struct nodelist *lp;
11220 const char *s;
11221
11222 if (n == NULL)
11223 return;
11224
11225 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011226 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011227 case NSEMI:
11228 s = "; ";
11229 goto binop;
11230 case NAND:
11231 s = " && ";
11232 goto binop;
11233 case NOR:
11234 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011235binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011236 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011237 /* if (ind < 0) */
11238 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011239 shtree(n->nbinary.ch2, ind, NULL, fp);
11240 break;
11241 case NCMD:
11242 shcmd(n, fp);
11243 if (ind >= 0)
11244 putc('\n', fp);
11245 break;
11246 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011247 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011248 shcmd(lp->n, fp);
11249 if (lp->next)
11250 fputs(" | ", fp);
11251 }
11252 if (n->npipe.backgnd)
11253 fputs(" &", fp);
11254 if (ind >= 0)
11255 putc('\n', fp);
11256 break;
11257 default:
11258 fprintf(fp, "<node type %d>", n->type);
11259 if (ind >= 0)
11260 putc('\n', fp);
11261 break;
11262 }
11263}
11264
11265
Eric Andersenc470f442003-07-28 09:56:35 +000011266static void
11267shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011268{
11269 union node *np;
11270 int first;
11271 const char *s;
11272 int dftfd;
11273
11274 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011275 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11276 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011277 putchar(' ');
11278 sharg(np, fp);
11279 first = 0;
11280 }
Eric Andersenc470f442003-07-28 09:56:35 +000011281 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11282 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011283 putchar(' ');
11284 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011285 case NTO: s = ">"; dftfd = 1; break;
11286 case NCLOBBER: s = ">|"; dftfd = 1; break;
11287 case NAPPEND: s = ">>"; dftfd = 1; break;
11288 case NTOFD: s = ">&"; dftfd = 1; break;
11289 case NFROM: s = "<"; dftfd = 0; break;
11290 case NFROMFD: s = "<&"; dftfd = 0; break;
11291 case NFROMTO: s = "<>"; dftfd = 0; break;
11292 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011293 }
11294 if (np->nfile.fd != dftfd)
11295 fprintf(fp, "%d", np->nfile.fd);
11296 fputs(s, fp);
11297 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11298 fprintf(fp, "%d", np->ndup.dupfd);
11299 } else {
11300 sharg(np->nfile.fname, fp);
11301 }
11302 first = 0;
11303 }
11304}
11305
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011306
Eric Andersenc470f442003-07-28 09:56:35 +000011307
11308static void
11309sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011310{
Eric Andersencb57d552001-06-28 07:25:16 +000011311 char *p;
11312 struct nodelist *bqlist;
11313 int subtype;
11314
11315 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011316 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011317 abort();
11318 }
11319 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011320 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011321 switch (*p) {
11322 case CTLESC:
11323 putc(*++p, fp);
11324 break;
11325 case CTLVAR:
11326 putc('$', fp);
11327 putc('{', fp);
11328 subtype = *++p;
11329 if (subtype == VSLENGTH)
11330 putc('#', fp);
11331
11332 while (*p != '=')
11333 putc(*p++, fp);
11334
11335 if (subtype & VSNUL)
11336 putc(':', fp);
11337
11338 switch (subtype & VSTYPE) {
11339 case VSNORMAL:
11340 putc('}', fp);
11341 break;
11342 case VSMINUS:
11343 putc('-', fp);
11344 break;
11345 case VSPLUS:
11346 putc('+', fp);
11347 break;
11348 case VSQUESTION:
11349 putc('?', fp);
11350 break;
11351 case VSASSIGN:
11352 putc('=', fp);
11353 break;
11354 case VSTRIMLEFT:
11355 putc('#', fp);
11356 break;
11357 case VSTRIMLEFTMAX:
11358 putc('#', fp);
11359 putc('#', fp);
11360 break;
11361 case VSTRIMRIGHT:
11362 putc('%', fp);
11363 break;
11364 case VSTRIMRIGHTMAX:
11365 putc('%', fp);
11366 putc('%', fp);
11367 break;
11368 case VSLENGTH:
11369 break;
11370 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011371 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011372 }
11373 break;
11374 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011375 putc('}', fp);
11376 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011377 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011378 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011379 putc('$', fp);
11380 putc('(', fp);
11381 shtree(bqlist->n, -1, NULL, fp);
11382 putc(')', fp);
11383 break;
11384 default:
11385 putc(*p, fp);
11386 break;
11387 }
11388 }
11389}
11390
11391
Eric Andersenc470f442003-07-28 09:56:35 +000011392static void
11393indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011394{
11395 int i;
11396
Eric Andersenc470f442003-07-28 09:56:35 +000011397 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011398 if (pfx && i == amount - 1)
11399 fputs(pfx, fp);
11400 putc('\t', fp);
11401 }
11402}
Eric Andersencb57d552001-06-28 07:25:16 +000011403
Eric Andersenc470f442003-07-28 09:56:35 +000011404
11405
11406/*
11407 * Debugging stuff.
11408 */
11409
11410
Eric Andersencb57d552001-06-28 07:25:16 +000011411FILE *tracefile;
11412
Eric Andersencb57d552001-06-28 07:25:16 +000011413
Eric Andersenc470f442003-07-28 09:56:35 +000011414void
11415trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011416{
Eric Andersenc470f442003-07-28 09:56:35 +000011417 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011418 return;
11419 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011420}
11421
Eric Andersenc470f442003-07-28 09:56:35 +000011422void
11423trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011424{
11425 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011426
Eric Andersenc470f442003-07-28 09:56:35 +000011427 if (debug != 1)
11428 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011429 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011430 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011431 va_end(va);
11432}
11433
Eric Andersenc470f442003-07-28 09:56:35 +000011434void
11435tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011436{
Eric Andersenc470f442003-07-28 09:56:35 +000011437 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011438 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011439 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011440}
11441
11442
Eric Andersenc470f442003-07-28 09:56:35 +000011443void
11444trputs(const char *s)
11445{
11446 if (debug != 1)
11447 return;
11448 fputs(s, tracefile);
11449}
11450
11451
11452static void
11453trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011454{
11455 char *p;
11456 char c;
11457
Eric Andersenc470f442003-07-28 09:56:35 +000011458 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011459 return;
11460 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011461 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011462 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011463 case '\n': c = 'n'; goto backslash;
11464 case '\t': c = 't'; goto backslash;
11465 case '\r': c = 'r'; goto backslash;
11466 case '"': c = '"'; goto backslash;
11467 case '\\': c = '\\'; goto backslash;
11468 case CTLESC: c = 'e'; goto backslash;
11469 case CTLVAR: c = 'v'; goto backslash;
11470 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11471 case CTLBACKQ: c = 'q'; goto backslash;
11472 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11473backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011474 putc(c, tracefile);
11475 break;
11476 default:
11477 if (*p >= ' ' && *p <= '~')
11478 putc(*p, tracefile);
11479 else {
11480 putc('\\', tracefile);
11481 putc(*p >> 6 & 03, tracefile);
11482 putc(*p >> 3 & 07, tracefile);
11483 putc(*p & 07, tracefile);
11484 }
11485 break;
11486 }
11487 }
11488 putc('"', tracefile);
11489}
11490
11491
Eric Andersenc470f442003-07-28 09:56:35 +000011492void
11493trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011494{
Eric Andersenc470f442003-07-28 09:56:35 +000011495 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011496 return;
11497 while (*ap) {
11498 trstring(*ap++);
11499 if (*ap)
11500 putc(' ', tracefile);
11501 else
11502 putc('\n', tracefile);
11503 }
Eric Andersencb57d552001-06-28 07:25:16 +000011504}
11505
11506
Eric Andersenc470f442003-07-28 09:56:35 +000011507void
11508opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011509{
Eric Andersencb57d552001-06-28 07:25:16 +000011510 char s[100];
11511#ifdef O_APPEND
11512 int flags;
11513#endif
11514
Eric Andersenc470f442003-07-28 09:56:35 +000011515 if (debug != 1) {
11516 if (tracefile)
11517 fflush(tracefile);
11518 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011519 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011520 }
Eric Andersenc470f442003-07-28 09:56:35 +000011521 scopy("./trace", s);
11522 if (tracefile) {
11523 if (!freopen(s, "a", tracefile)) {
11524 fprintf(stderr, "Can't re-open %s\n", s);
11525 debug = 0;
11526 return;
11527 }
11528 } else {
11529 if ((tracefile = fopen(s, "a")) == NULL) {
11530 fprintf(stderr, "Can't open %s\n", s);
11531 debug = 0;
11532 return;
11533 }
11534 }
Eric Andersencb57d552001-06-28 07:25:16 +000011535#ifdef O_APPEND
11536 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11537 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11538#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011539 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011540 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011541}
Eric Andersenc470f442003-07-28 09:56:35 +000011542#endif /* DEBUG */
11543
11544
11545/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11546
11547/*
11548 * Sigmode records the current value of the signal handlers for the various
11549 * modes. A value of zero means that the current handler is not known.
11550 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11551 */
11552
11553#define S_DFL 1 /* default signal handling (SIG_DFL) */
11554#define S_CATCH 2 /* signal is caught */
11555#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11556#define S_HARD_IGN 4 /* signal is ignored permenantly */
11557#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11558
Eric Andersencb57d552001-06-28 07:25:16 +000011559
11560
11561/*
Eric Andersencb57d552001-06-28 07:25:16 +000011562 * The trap builtin.
11563 */
11564
Eric Andersenc470f442003-07-28 09:56:35 +000011565int
11566trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011567{
11568 char *action;
11569 char **ap;
11570 int signo;
11571
Eric Andersenc470f442003-07-28 09:56:35 +000011572 nextopt(nullstr);
11573 ap = argptr;
11574 if (!*ap) {
11575 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011576 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011577 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011578
Eric Andersenc470f442003-07-28 09:56:35 +000011579 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011580 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011581 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011582 out1fmt("trap -- %s %s\n",
11583 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011584 }
11585 }
11586 return 0;
11587 }
Eric Andersenc470f442003-07-28 09:56:35 +000011588 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011589 action = NULL;
11590 else
11591 action = *ap++;
11592 while (*ap) {
11593 if ((signo = decode_signal(*ap, 0)) < 0)
11594 error("%s: bad trap", *ap);
11595 INTOFF;
11596 if (action) {
11597 if (action[0] == '-' && action[1] == '\0')
11598 action = NULL;
11599 else
Eric Andersenc470f442003-07-28 09:56:35 +000011600 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011601 }
Eric Andersenc470f442003-07-28 09:56:35 +000011602 if (trap[signo])
11603 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011604 trap[signo] = action;
11605 if (signo != 0)
11606 setsignal(signo);
11607 INTON;
11608 ap++;
11609 }
11610 return 0;
11611}
11612
11613
Eric Andersenc470f442003-07-28 09:56:35 +000011614/*
11615 * Clear traps on a fork.
11616 */
11617
11618void
11619clear_traps(void)
11620{
11621 char **tp;
11622
11623 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11624 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11625 INTOFF;
11626 ckfree(*tp);
11627 *tp = NULL;
11628 if (tp != &trap[0])
11629 setsignal(tp - trap);
11630 INTON;
11631 }
11632 }
11633}
11634
11635
Eric Andersencb57d552001-06-28 07:25:16 +000011636/*
11637 * Set the signal handler for the specified signal. The routine figures
11638 * out what it should be set to.
11639 */
11640
Eric Andersenc470f442003-07-28 09:56:35 +000011641void
11642setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011643{
11644 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011645 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011646 struct sigaction act;
11647
11648 if ((t = trap[signo]) == NULL)
11649 action = S_DFL;
11650 else if (*t != '\0')
11651 action = S_CATCH;
11652 else
11653 action = S_IGN;
11654 if (rootshell && action == S_DFL) {
11655 switch (signo) {
11656 case SIGINT:
11657 if (iflag || minusc || sflag == 0)
11658 action = S_CATCH;
11659 break;
11660 case SIGQUIT:
11661#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011662 if (debug)
11663 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011664#endif
11665 /* FALLTHROUGH */
11666 case SIGTERM:
11667 if (iflag)
11668 action = S_IGN;
11669 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011670#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011671 case SIGTSTP:
11672 case SIGTTOU:
11673 if (mflag)
11674 action = S_IGN;
11675 break;
11676#endif
11677 }
11678 }
11679
11680 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011681 tsig = *t;
11682 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011683 /*
11684 * current setting unknown
11685 */
11686 if (sigaction(signo, 0, &act) == -1) {
11687 /*
11688 * Pretend it worked; maybe we should give a warning
11689 * here, but other shells don't. We don't alter
11690 * sigmode, so that we retry every time.
11691 */
11692 return;
11693 }
11694 if (act.sa_handler == SIG_IGN) {
11695 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011696 signo == SIGTTIN || signo == SIGTTOU)) {
11697 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011698 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011699 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011700 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011701 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011702 }
11703 }
Eric Andersenc470f442003-07-28 09:56:35 +000011704 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011705 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011706 switch (action) {
11707 case S_CATCH:
11708 act.sa_handler = onsig;
11709 break;
11710 case S_IGN:
11711 act.sa_handler = SIG_IGN;
11712 break;
11713 default:
11714 act.sa_handler = SIG_DFL;
11715 }
Eric Andersencb57d552001-06-28 07:25:16 +000011716 *t = action;
11717 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011718 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011719 sigaction(signo, &act, 0);
11720}
11721
11722/*
11723 * Ignore a signal.
11724 */
11725
Eric Andersenc470f442003-07-28 09:56:35 +000011726void
11727ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011728{
11729 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11730 signal(signo, SIG_IGN);
11731 }
11732 sigmode[signo - 1] = S_HARD_IGN;
11733}
11734
11735
Eric Andersencb57d552001-06-28 07:25:16 +000011736/*
11737 * Signal handler.
11738 */
11739
Eric Andersenc470f442003-07-28 09:56:35 +000011740void
11741onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011742{
Eric Andersencb57d552001-06-28 07:25:16 +000011743 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011744 pendingsigs = signo;
11745
11746 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11747 if (!suppressint)
11748 onint();
11749 intpending = 1;
11750 }
Eric Andersencb57d552001-06-28 07:25:16 +000011751}
11752
11753
Eric Andersencb57d552001-06-28 07:25:16 +000011754/*
11755 * Called to execute a trap. Perhaps we should avoid entering new trap
11756 * handlers while we are executing a trap handler.
11757 */
11758
Eric Andersenc470f442003-07-28 09:56:35 +000011759void
11760dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011761{
Eric Andersenc470f442003-07-28 09:56:35 +000011762 char *p;
11763 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011764 int savestatus;
11765
Eric Andersenc470f442003-07-28 09:56:35 +000011766 savestatus = exitstatus;
11767 q = gotsig;
11768 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11769 *p = 0;
11770 p = trap[p - q + 1];
11771 if (!p)
11772 continue;
11773 evalstring(p, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011774 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011775 }
Eric Andersencb57d552001-06-28 07:25:16 +000011776}
11777
Eric Andersenc470f442003-07-28 09:56:35 +000011778
Eric Andersenc470f442003-07-28 09:56:35 +000011779/*
11780 * Controls whether the shell is interactive or not.
11781 */
11782
Eric Andersenc470f442003-07-28 09:56:35 +000011783void
11784setinteractive(int on)
11785{
11786 static int is_interactive;
11787
11788 if (++on == is_interactive)
11789 return;
11790 is_interactive = on;
11791 setsignal(SIGINT);
11792 setsignal(SIGQUIT);
11793 setsignal(SIGTERM);
11794#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11795 if(is_interactive > 1) {
11796 /* Looks like they want an interactive shell */
11797 static int do_banner;
11798
11799 if(!do_banner) {
11800 out1fmt(
11801 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11802 "Enter 'help' for a list of built-in commands.\n\n");
11803 do_banner++;
11804 }
11805 }
11806#endif
11807}
11808
11809
11810#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11811/*** List the available builtins ***/
11812
11813static int helpcmd(int argc, char **argv)
11814{
11815 int col, i;
11816
11817 out1fmt("\nBuilt-in commands:\n-------------------\n");
11818 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11819 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11820 builtincmd[i].name + 1);
11821 if (col > 60) {
11822 out1fmt("\n");
11823 col = 0;
11824 }
11825 }
11826#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11827 {
11828 extern const struct BB_applet applets[];
11829 extern const size_t NUM_APPLETS;
11830
11831 for (i = 0; i < NUM_APPLETS; i++) {
11832
11833 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11834 if (col > 60) {
11835 out1fmt("\n");
11836 col = 0;
11837 }
11838 }
11839 }
11840#endif
11841 out1fmt("\n\n");
11842 return EXIT_SUCCESS;
11843}
11844#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11845
Eric Andersencb57d552001-06-28 07:25:16 +000011846/*
11847 * Called to exit the shell.
11848 */
11849
Eric Andersenc470f442003-07-28 09:56:35 +000011850void
11851exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011852{
Eric Andersenc470f442003-07-28 09:56:35 +000011853 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011854 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011855 int status;
Eric Andersencb57d552001-06-28 07:25:16 +000011856
Eric Andersenc470f442003-07-28 09:56:35 +000011857 status = exitstatus;
11858 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11859 if (setjmp(loc.loc)) {
11860 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011861 }
Eric Andersenc470f442003-07-28 09:56:35 +000011862 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011863 if ((p = trap[0]) != NULL && *p != '\0') {
11864 trap[0] = NULL;
11865 evalstring(p, 0);
11866 }
Eric Andersencb57d552001-06-28 07:25:16 +000011867 flushall();
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011868#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11869 if (iflag && rootshell) {
11870 const char *hp = lookupvar("HISTFILE");
11871
11872 if(hp != NULL )
11873 save_history ( hp );
11874 }
11875#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011876out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011877 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011878 /* NOTREACHED */
11879}
11880
11881static int decode_signal(const char *string, int minsig)
11882{
11883 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011884 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011885
Eric Andersen34506362001-08-02 05:02:46 +000011886 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011887}
Eric Andersen34506362001-08-02 05:02:46 +000011888
Eric Andersenc470f442003-07-28 09:56:35 +000011889/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11890
11891static struct var *vartab[VTABSIZE];
11892
11893static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011894static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011895
11896/*
11897 * Initialize the varable symbol tables and import the environment
11898 */
11899
Eric Andersenc470f442003-07-28 09:56:35 +000011900
11901#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011902/*
Eric Andersenc470f442003-07-28 09:56:35 +000011903 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011904 */
11905
Eric Andersenc470f442003-07-28 09:56:35 +000011906int
11907setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011908{
Eric Andersenc470f442003-07-28 09:56:35 +000011909 int err;
11910 volatile int saveint;
11911 struct jmploc *volatile savehandler = handler;
11912 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011913
Eric Andersenc470f442003-07-28 09:56:35 +000011914 SAVEINT(saveint);
11915 if (setjmp(jmploc.loc))
11916 err = 1;
11917 else {
11918 handler = &jmploc;
11919 setvar(name, val, flags);
11920 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011921 }
Eric Andersenc470f442003-07-28 09:56:35 +000011922 handler = savehandler;
11923 RESTOREINT(saveint);
11924 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011925}
Eric Andersenc470f442003-07-28 09:56:35 +000011926#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011927
11928/*
11929 * Set the value of a variable. The flags argument is ored with the
11930 * flags of the variable. If val is NULL, the variable is unset.
11931 */
11932
Eric Andersenc470f442003-07-28 09:56:35 +000011933static void
11934setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011935{
Eric Andersenc470f442003-07-28 09:56:35 +000011936 char *p, *q;
11937 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011938 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011939 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011940
Eric Andersenc470f442003-07-28 09:56:35 +000011941 q = endofname(name);
11942 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011943 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011944 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011945 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011946 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011947 if (val == NULL) {
11948 flags |= VUNSET;
11949 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011950 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000011951 }
11952 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011953 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11954 *p++ = '\0';
11955 if (vallen) {
11956 p[-1] = '=';
11957 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000011958 }
Eric Andersenc470f442003-07-28 09:56:35 +000011959 *p = '\0';
11960 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000011961 INTON;
11962}
11963
11964
Eric Andersencb57d552001-06-28 07:25:16 +000011965/*
11966 * Same as setvar except that the variable and value are passed in
11967 * the first argument as name=value. Since the first argument will
11968 * be actually stored in the table, it should not be a string that
11969 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000011970 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000011971 */
11972
Eric Andersenc470f442003-07-28 09:56:35 +000011973void
11974setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011975{
11976 struct var *vp, **vpp;
11977
11978 vpp = hashvar(s);
11979 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000011980 vp = *findvar(vpp, s);
11981 if (vp) {
Eric Andersencb57d552001-06-28 07:25:16 +000011982 if (vp->flags & VREADONLY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011983 if (flags & VNOSAVE)
11984 free(s);
11985 error("%.*s: is read only", strchrnul(s, '=') - s, s);
Eric Andersencb57d552001-06-28 07:25:16 +000011986 }
Eric Andersenc470f442003-07-28 09:56:35 +000011987
11988 if (flags & VNOSET)
11989 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011990
11991 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000011992 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000011993
Eric Andersenc470f442003-07-28 09:56:35 +000011994 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11995 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000011996
Eric Andersenc470f442003-07-28 09:56:35 +000011997 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11998 } else {
11999 if (flags & VNOSET)
12000 return;
12001 /* not found */
12002 vp = ckmalloc(sizeof (*vp));
12003 vp->next = *vpp;
12004 vp->func = NULL;
12005 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012006 }
Eric Andersenc470f442003-07-28 09:56:35 +000012007 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12008 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012009 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012010 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012011}
12012
12013
Eric Andersencb57d552001-06-28 07:25:16 +000012014/*
12015 * Process a linked list of variable assignments.
12016 */
12017
Eric Andersenc470f442003-07-28 09:56:35 +000012018static void
12019listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012020{
Eric Andersenc470f442003-07-28 09:56:35 +000012021 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012022
Eric Andersenc470f442003-07-28 09:56:35 +000012023 if (!lp)
12024 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012025 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012026 do {
12027 setvareq(lp->text, flags);
12028 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012029 INTON;
12030}
12031
12032
Eric Andersencb57d552001-06-28 07:25:16 +000012033/*
12034 * Find the value of a variable. Returns NULL if not set.
12035 */
12036
Eric Andersenc470f442003-07-28 09:56:35 +000012037static char *
12038lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012039{
Eric Andersencb57d552001-06-28 07:25:16 +000012040 struct var *v;
12041
12042 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
Eric Andersenc470f442003-07-28 09:56:35 +000012043 return strchrnul(v->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012044 }
12045 return NULL;
12046}
12047
12048
Eric Andersencb57d552001-06-28 07:25:16 +000012049/*
12050 * Search the environment of a builtin command.
12051 */
12052
Eric Andersenc470f442003-07-28 09:56:35 +000012053static char *
12054bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012055{
Eric Andersenc470f442003-07-28 09:56:35 +000012056 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012057
Eric Andersenc470f442003-07-28 09:56:35 +000012058 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012059 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012060 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012061 }
12062 return lookupvar(name);
12063}
12064
12065
Eric Andersencb57d552001-06-28 07:25:16 +000012066/*
Eric Andersenc470f442003-07-28 09:56:35 +000012067 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012068 */
12069
Eric Andersenc470f442003-07-28 09:56:35 +000012070static char **
12071listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012072{
Eric Andersencb57d552001-06-28 07:25:16 +000012073 struct var **vpp;
12074 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012075 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012076 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012077
Eric Andersenc470f442003-07-28 09:56:35 +000012078 STARTSTACKSTR(ep);
12079 vpp = vartab;
12080 mask = on | off;
12081 do {
12082 for (vp = *vpp ; vp ; vp = vp->next)
12083 if ((vp->flags & mask) == on) {
12084 if (ep == stackstrend())
12085 ep = growstackstr();
12086 *ep++ = (char *) vp->text;
12087 }
12088 } while (++vpp < vartab + VTABSIZE);
12089 if (ep == stackstrend())
12090 ep = growstackstr();
12091 if (end)
12092 *end = ep;
12093 *ep++ = NULL;
12094 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012095}
12096
12097
12098/*
Eric Andersenc470f442003-07-28 09:56:35 +000012099 * POSIX requires that 'set' (but not export or readonly) output the
12100 * variables in lexicographic order - by the locale's collating order (sigh).
12101 * Maybe we could keep them in an ordered balanced binary tree
12102 * instead of hashed lists.
12103 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012104 */
12105
Eric Andersenc470f442003-07-28 09:56:35 +000012106static int
12107showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012108{
Eric Andersenc470f442003-07-28 09:56:35 +000012109 const char *sep;
12110 char **ep, **epend;
12111
12112 ep = listvars(on, off, &epend);
12113 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12114
12115 sep = *sep_prefix ? spcstr : sep_prefix;
12116
12117 for (; ep < epend; ep++) {
12118 const char *p;
12119 const char *q;
12120
12121 p = strchrnul(*ep, '=');
12122 q = nullstr;
12123 if (*p)
12124 q = single_quote(++p);
12125
12126 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12127 }
12128
Eric Andersencb57d552001-06-28 07:25:16 +000012129 return 0;
12130}
12131
12132
12133
12134/*
12135 * The export and readonly commands.
12136 */
12137
Eric Andersenc470f442003-07-28 09:56:35 +000012138static int
12139exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012140{
12141 struct var *vp;
12142 char *name;
12143 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012144 char **aptr;
12145 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12146 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012147
Eric Andersenc470f442003-07-28 09:56:35 +000012148 notp = nextopt("p") - 'p';
12149 if (notp && ((name = *(aptr = argptr)))) {
12150 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012151 if ((p = strchr(name, '=')) != NULL) {
12152 p++;
12153 } else {
12154 if ((vp = *findvar(hashvar(name), name))) {
12155 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012156 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012157 }
12158 }
12159 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012160 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012161 } else {
12162 showvars(argv[0], flag, 0);
12163 }
12164 return 0;
12165}
12166
Eric Andersen34506362001-08-02 05:02:46 +000012167
Eric Andersencb57d552001-06-28 07:25:16 +000012168/*
Eric Andersencb57d552001-06-28 07:25:16 +000012169 * Make a variable a local variable. When a variable is made local, it's
12170 * value and flags are saved in a localvar structure. The saved values
12171 * will be restored when the shell function returns. We handle the name
12172 * "-" as a special case.
12173 */
12174
Eric Andersenc470f442003-07-28 09:56:35 +000012175static inline void
12176mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012177{
Eric Andersencb57d552001-06-28 07:25:16 +000012178 struct localvar *lvp;
12179 struct var **vpp;
12180 struct var *vp;
12181
12182 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012183 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012184 if (name[0] == '-' && name[1] == '\0') {
12185 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012186 p = ckmalloc(sizeof(optlist));
12187 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012188 vp = NULL;
12189 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012190 char *eq;
12191
Eric Andersencb57d552001-06-28 07:25:16 +000012192 vpp = hashvar(name);
12193 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012194 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012195 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012196 if (eq)
12197 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012198 else
12199 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012200 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012201 lvp->flags = VUNSET;
12202 } else {
12203 lvp->text = vp->text;
12204 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012205 vp->flags |= VSTRFIXED|VTEXTFIXED;
12206 if (eq)
12207 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012208 }
12209 }
12210 lvp->vp = vp;
12211 lvp->next = localvars;
12212 localvars = lvp;
12213 INTON;
12214}
12215
Eric Andersenc470f442003-07-28 09:56:35 +000012216/*
12217 * The "local" command.
12218 */
12219
12220static int
12221localcmd(int argc, char **argv)
12222{
12223 char *name;
12224
12225 argv = argptr;
12226 while ((name = *argv++) != NULL) {
12227 mklocal(name);
12228 }
12229 return 0;
12230}
12231
12232
Eric Andersencb57d552001-06-28 07:25:16 +000012233/*
12234 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012235 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012236 */
12237
Eric Andersenc470f442003-07-28 09:56:35 +000012238static void
12239poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012240{
Eric Andersencb57d552001-06-28 07:25:16 +000012241 struct localvar *lvp;
12242 struct var *vp;
12243
12244 while ((lvp = localvars) != NULL) {
12245 localvars = lvp->next;
12246 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012247 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12248 if (vp == NULL) { /* $- saved */
12249 memcpy(optlist, lvp->text, sizeof(optlist));
12250 ckfree(lvp->text);
12251 optschanged();
12252 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12253 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012254 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012255 if (vp->func)
12256 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12257 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12258 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012259 vp->flags = lvp->flags;
12260 vp->text = lvp->text;
12261 }
Eric Andersenc470f442003-07-28 09:56:35 +000012262 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012263 }
12264}
12265
12266
Eric Andersencb57d552001-06-28 07:25:16 +000012267/*
12268 * The unset builtin command. We unset the function before we unset the
12269 * variable to allow a function to be unset when there is a readonly variable
12270 * with the same name.
12271 */
12272
Eric Andersenc470f442003-07-28 09:56:35 +000012273int
12274unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012275{
12276 char **ap;
12277 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012278 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012279 int ret = 0;
12280
12281 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012282 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012283 }
Eric Andersencb57d552001-06-28 07:25:16 +000012284
Eric Andersenc470f442003-07-28 09:56:35 +000012285 for (ap = argptr; *ap ; ap++) {
12286 if (flag != 'f') {
12287 i = unsetvar(*ap);
12288 ret |= i;
12289 if (!(i & 2))
12290 continue;
12291 }
12292 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012293 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012294 }
Eric Andersenc470f442003-07-28 09:56:35 +000012295 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012296}
12297
12298
12299/*
12300 * Unset the specified variable.
12301 */
12302
Eric Andersenc470f442003-07-28 09:56:35 +000012303int
12304unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012305{
Eric Andersencb57d552001-06-28 07:25:16 +000012306 struct var **vpp;
12307 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012308 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012309
12310 vpp = findvar(hashvar(s), s);
12311 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012312 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012313 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012314 int flags = vp->flags;
12315
12316 retval = 1;
12317 if (flags & VREADONLY)
12318 goto out;
12319 if (flags & VUNSET)
12320 goto ok;
12321 if ((flags & VSTRFIXED) == 0) {
12322 INTOFF;
12323 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12324 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012325 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012326 ckfree(vp);
12327 INTON;
12328 } else {
12329 setvar(s, 0, 0);
12330 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012331 }
Eric Andersenc470f442003-07-28 09:56:35 +000012332ok:
12333 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012334 }
12335
Eric Andersenc470f442003-07-28 09:56:35 +000012336out:
12337 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012338}
12339
12340
12341
12342/*
12343 * Find the appropriate entry in the hash table from the name.
12344 */
12345
Eric Andersenc470f442003-07-28 09:56:35 +000012346static struct var **
12347hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012348{
Eric Andersencb57d552001-06-28 07:25:16 +000012349 unsigned int hashval;
12350
12351 hashval = ((unsigned char) *p) << 4;
12352 while (*p && *p != '=')
12353 hashval += (unsigned char) *p++;
12354 return &vartab[hashval % VTABSIZE];
12355}
12356
12357
12358
12359/*
Eric Andersenc470f442003-07-28 09:56:35 +000012360 * Compares two strings up to the first = or '\0'. The first
12361 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012362 * either '=' or '\0'.
12363 */
12364
Eric Andersenc470f442003-07-28 09:56:35 +000012365int
12366varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012367{
Eric Andersenc470f442003-07-28 09:56:35 +000012368 int c, d;
12369
12370 while ((c = *p) == (d = *q)) {
12371 if (!c || c == '=')
12372 goto out;
12373 p++;
12374 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012375 }
Eric Andersenc470f442003-07-28 09:56:35 +000012376 if (c == '=')
12377 c = 0;
12378 if (d == '=')
12379 d = 0;
12380out:
12381 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012382}
12383
Eric Andersenc470f442003-07-28 09:56:35 +000012384static int
12385vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012386{
Eric Andersenc470f442003-07-28 09:56:35 +000012387 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012388}
12389
Eric Andersenc470f442003-07-28 09:56:35 +000012390static struct var **
12391findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012392{
12393 for (; *vpp; vpp = &(*vpp)->next) {
12394 if (varequal((*vpp)->text, name)) {
12395 break;
12396 }
12397 }
12398 return vpp;
12399}
Eric Andersenc470f442003-07-28 09:56:35 +000012400/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012401
Eric Andersenc470f442003-07-28 09:56:35 +000012402#include <sys/times.h>
12403
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012404static const unsigned char timescmd_str[] = {
12405 ' ', offsetof(struct tms, tms_utime),
12406 '\n', offsetof(struct tms, tms_stime),
12407 ' ', offsetof(struct tms, tms_cutime),
12408 '\n', offsetof(struct tms, tms_cstime),
12409 0
12410};
Eric Andersencb57d552001-06-28 07:25:16 +000012411
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012412static int timescmd(int ac, char **av)
12413{
12414 long int clk_tck, s, t;
12415 const unsigned char *p;
12416 struct tms buf;
12417
12418 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012419 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012420
12421 p = timescmd_str;
12422 do {
12423 t = *(clock_t *)(((char *) &buf) + p[1]);
12424 s = t / clk_tck;
12425 out1fmt("%ldm%ld.%.3lds%c",
12426 s/60, s%60,
12427 ((t - s * clk_tck) * 1000) / clk_tck,
12428 p[0]);
12429 } while (*(p += 2));
12430
Eric Andersencb57d552001-06-28 07:25:16 +000012431 return 0;
12432}
12433
Eric Andersend35c5df2002-01-09 15:37:36 +000012434#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012435static int
12436dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012437{
Eric Andersen90898442003-08-06 11:20:52 +000012438 long result;
Eric Andersenc470f442003-07-28 09:56:35 +000012439 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012440
Eric Andersenc470f442003-07-28 09:56:35 +000012441 INTOFF;
12442 result = arith(s, &errcode);
12443 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012444 if (errcode == -3)
12445 error("exponent less than 0");
12446 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012447 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012448 else if (errcode == -5)
12449 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012450 else
12451 synerror(s);
12452 }
12453 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012454
Eric Andersenc470f442003-07-28 09:56:35 +000012455 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012456}
Eric Andersenc470f442003-07-28 09:56:35 +000012457
12458
12459/*
Eric Andersen90898442003-08-06 11:20:52 +000012460 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12461 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12462 *
12463 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012464 */
Eric Andersen90898442003-08-06 11:20:52 +000012465
Eric Andersenc470f442003-07-28 09:56:35 +000012466static int
Eric Andersen90898442003-08-06 11:20:52 +000012467letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012468{
Eric Andersenc470f442003-07-28 09:56:35 +000012469 char **ap;
12470 long i;
12471
Eric Andersen90898442003-08-06 11:20:52 +000012472 ap = argv + 1;
12473 if(!*ap)
12474 error("expression expected");
12475 for (ap = argv + 1; *ap; ap++) {
12476 i = dash_arith(*ap);
12477 }
Eric Andersenc470f442003-07-28 09:56:35 +000012478
Eric Andersen90898442003-08-06 11:20:52 +000012479 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012480}
12481#endif /* CONFIG_ASH_MATH_SUPPORT */
12482
12483/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12484
12485/*
12486 * Miscelaneous builtins.
12487 */
12488
12489#undef rflag
12490
12491#ifdef __GLIBC__
12492#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12493typedef enum __rlimit_resource rlim_t;
12494#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012495#endif
12496
12497
Eric Andersenc470f442003-07-28 09:56:35 +000012498/*
12499 * The read builtin. The -e option causes backslashes to escape the
12500 * following character.
12501 *
12502 * This uses unbuffered input, which may be avoidable in some cases.
12503 */
12504
12505static int
12506readcmd(int argc, char **argv)
12507{
12508 char **ap;
12509 int backslash;
12510 char c;
12511 int rflag;
12512 char *prompt;
12513 const char *ifs;
12514 char *p;
12515 int startword;
12516 int status;
12517 int i;
12518
12519 rflag = 0;
12520 prompt = NULL;
12521 while ((i = nextopt("p:r")) != '\0') {
12522 if (i == 'p')
12523 prompt = optionarg;
12524 else
12525 rflag = 1;
12526 }
12527 if (prompt && isatty(0)) {
12528 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012529 }
12530 if (*(ap = argptr) == NULL)
12531 error("arg count");
12532 if ((ifs = bltinlookup("IFS")) == NULL)
12533 ifs = defifs;
12534 status = 0;
12535 startword = 1;
12536 backslash = 0;
12537 STARTSTACKSTR(p);
12538 for (;;) {
12539 if (read(0, &c, 1) != 1) {
12540 status = 1;
12541 break;
12542 }
12543 if (c == '\0')
12544 continue;
12545 if (backslash) {
12546 backslash = 0;
12547 if (c != '\n')
12548 goto put;
12549 continue;
12550 }
12551 if (!rflag && c == '\\') {
12552 backslash++;
12553 continue;
12554 }
12555 if (c == '\n')
12556 break;
12557 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12558 continue;
12559 }
12560 startword = 0;
12561 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12562 STACKSTRNUL(p);
12563 setvar(*ap, stackblock(), 0);
12564 ap++;
12565 startword = 1;
12566 STARTSTACKSTR(p);
12567 } else {
12568put:
12569 STPUTC(c, p);
12570 }
12571 }
12572 STACKSTRNUL(p);
12573 /* Remove trailing blanks */
12574 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12575 *p = '\0';
12576 setvar(*ap, stackblock(), 0);
12577 while (*++ap != NULL)
12578 setvar(*ap, nullstr, 0);
12579 return status;
12580}
12581
12582
12583static int umaskcmd(int argc, char **argv)
12584{
12585 static const char permuser[3] = "ugo";
12586 static const char permmode[3] = "rwx";
12587 static const short int permmask[] = {
12588 S_IRUSR, S_IWUSR, S_IXUSR,
12589 S_IRGRP, S_IWGRP, S_IXGRP,
12590 S_IROTH, S_IWOTH, S_IXOTH
12591 };
12592
12593 char *ap;
12594 mode_t mask;
12595 int i;
12596 int symbolic_mode = 0;
12597
12598 while (nextopt("S") != '\0') {
12599 symbolic_mode = 1;
12600 }
12601
12602 INTOFF;
12603 mask = umask(0);
12604 umask(mask);
12605 INTON;
12606
12607 if ((ap = *argptr) == NULL) {
12608 if (symbolic_mode) {
12609 char buf[18];
12610 char *p = buf;
12611
12612 for (i = 0; i < 3; i++) {
12613 int j;
12614
12615 *p++ = permuser[i];
12616 *p++ = '=';
12617 for (j = 0; j < 3; j++) {
12618 if ((mask & permmask[3 * i + j]) == 0) {
12619 *p++ = permmode[j];
12620 }
12621 }
12622 *p++ = ',';
12623 }
12624 *--p = 0;
12625 puts(buf);
12626 } else {
12627 out1fmt("%.4o\n", mask);
12628 }
12629 } else {
12630 if (is_digit((unsigned char) *ap)) {
12631 mask = 0;
12632 do {
12633 if (*ap >= '8' || *ap < '0')
12634 error(illnum, argv[1]);
12635 mask = (mask << 3) + (*ap - '0');
12636 } while (*++ap != '\0');
12637 umask(mask);
12638 } else {
12639 mask = ~mask & 0777;
12640 if (!bb_parse_mode(ap, &mask)) {
12641 error("Illegal mode: %s", ap);
12642 }
12643 umask(~mask & 0777);
12644 }
12645 }
12646 return 0;
12647}
12648
12649/*
12650 * ulimit builtin
12651 *
12652 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12653 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12654 * ash by J.T. Conklin.
12655 *
12656 * Public domain.
12657 */
12658
12659struct limits {
12660 const char *name;
12661 int cmd;
12662 int factor; /* multiply by to get rlim_{cur,max} values */
12663 char option;
12664};
12665
12666static const struct limits limits[] = {
12667#ifdef RLIMIT_CPU
12668 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12669#endif
12670#ifdef RLIMIT_FSIZE
12671 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12672#endif
12673#ifdef RLIMIT_DATA
12674 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12675#endif
12676#ifdef RLIMIT_STACK
12677 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12678#endif
12679#ifdef RLIMIT_CORE
12680 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12681#endif
12682#ifdef RLIMIT_RSS
12683 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12684#endif
12685#ifdef RLIMIT_MEMLOCK
12686 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12687#endif
12688#ifdef RLIMIT_NPROC
12689 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
12690#endif
12691#ifdef RLIMIT_NOFILE
12692 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
12693#endif
12694#ifdef RLIMIT_VMEM
12695 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
12696#endif
12697#ifdef RLIMIT_SWAP
12698 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
12699#endif
12700 { (char *) 0, 0, 0, '\0' }
12701};
12702
12703int
12704ulimitcmd(int argc, char **argv)
12705{
12706 int c;
12707 rlim_t val = 0;
12708 enum { SOFT = 0x1, HARD = 0x2 }
12709 how = SOFT | HARD;
12710 const struct limits *l;
12711 int set, all = 0;
12712 int optc, what;
12713 struct rlimit limit;
12714
12715 what = 'f';
12716 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
12717 switch (optc) {
12718 case 'H':
12719 how = HARD;
12720 break;
12721 case 'S':
12722 how = SOFT;
12723 break;
12724 case 'a':
12725 all = 1;
12726 break;
12727 default:
12728 what = optc;
12729 }
12730
12731 for (l = limits; l->name && l->option != what; l++)
12732 ;
12733 if (!l->name)
12734 error("internal error (%c)", what);
12735
12736 set = *argptr ? 1 : 0;
12737 if (set) {
12738 char *p = *argptr;
12739
12740 if (all || argptr[1])
12741 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012742 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012743 val = RLIM_INFINITY;
12744 else {
12745 val = (rlim_t) 0;
12746
12747 while ((c = *p++) >= '0' && c <= '9')
12748 {
12749 val = (val * 10) + (long)(c - '0');
12750 if (val < (rlim_t) 0)
12751 break;
12752 }
12753 if (c)
12754 error("bad number");
12755 val *= l->factor;
12756 }
12757 }
12758 if (all) {
12759 for (l = limits; l->name; l++) {
12760 getrlimit(l->cmd, &limit);
12761 if (how & SOFT)
12762 val = limit.rlim_cur;
12763 else if (how & HARD)
12764 val = limit.rlim_max;
12765
12766 out1fmt("%-20s ", l->name);
12767 if (val == RLIM_INFINITY)
12768 out1fmt("unlimited\n");
12769 else
12770 {
12771 val /= l->factor;
12772 out1fmt("%lld\n", (long long) val);
12773 }
12774 }
12775 return 0;
12776 }
12777
12778 getrlimit(l->cmd, &limit);
12779 if (set) {
12780 if (how & HARD)
12781 limit.rlim_max = val;
12782 if (how & SOFT)
12783 limit.rlim_cur = val;
12784 if (setrlimit(l->cmd, &limit) < 0)
12785 error("error setting limit (%m)");
12786 } else {
12787 if (how & SOFT)
12788 val = limit.rlim_cur;
12789 else if (how & HARD)
12790 val = limit.rlim_max;
12791
12792 if (val == RLIM_INFINITY)
12793 out1fmt("unlimited\n");
12794 else
12795 {
12796 val /= l->factor;
12797 out1fmt("%lld\n", (long long) val);
12798 }
12799 }
12800 return 0;
12801}
12802
Eric Andersen90898442003-08-06 11:20:52 +000012803
12804#ifdef CONFIG_ASH_MATH_SUPPORT
12805
12806/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12807
12808 Permission is hereby granted, free of charge, to any person obtaining
12809 a copy of this software and associated documentation files (the
12810 "Software"), to deal in the Software without restriction, including
12811 without limitation the rights to use, copy, modify, merge, publish,
12812 distribute, sublicense, and/or sell copies of the Software, and to
12813 permit persons to whom the Software is furnished to do so, subject to
12814 the following conditions:
12815
12816 The above copyright notice and this permission notice shall be
12817 included in all copies or substantial portions of the Software.
12818
12819 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12820 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12821 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12822 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12823 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12824 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12825 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12826*/
12827
12828/* This is my infix parser/evaluator. It is optimized for size, intended
12829 * as a replacement for yacc-based parsers. However, it may well be faster
12830 * than a comparable parser writen in yacc. The supported operators are
12831 * listed in #defines below. Parens, order of operations, and error handling
12832 * are supported. This code is threadsafe. The exact expression format should
12833 * be that which POSIX specifies for shells. */
12834
12835/* The code uses a simple two-stack algorithm. See
12836 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12837 * for a detailed explaination of the infix-to-postfix algorithm on which
12838 * this is based (this code differs in that it applies operators immediately
12839 * to the stack instead of adding them to a queue to end up with an
12840 * expression). */
12841
12842/* To use the routine, call it with an expression string and error return
12843 * pointer */
12844
12845/*
12846 * Aug 24, 2001 Manuel Novoa III
12847 *
12848 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12849 *
12850 * 1) In arith_apply():
12851 * a) Cached values of *numptr and &(numptr[-1]).
12852 * b) Removed redundant test for zero denominator.
12853 *
12854 * 2) In arith():
12855 * a) Eliminated redundant code for processing operator tokens by moving
12856 * to a table-based implementation. Also folded handling of parens
12857 * into the table.
12858 * b) Combined all 3 loops which called arith_apply to reduce generated
12859 * code size at the cost of speed.
12860 *
12861 * 3) The following expressions were treated as valid by the original code:
12862 * 1() , 0! , 1 ( *3 ) .
12863 * These bugs have been fixed by internally enclosing the expression in
12864 * parens and then checking that all binary ops and right parens are
12865 * preceded by a valid expression (NUM_TOKEN).
12866 *
12867 * Note: It may be desireable to replace Aaron's test for whitespace with
12868 * ctype's isspace() if it is used by another busybox applet or if additional
12869 * whitespace chars should be considered. Look below the "#include"s for a
12870 * precompiler test.
12871 */
12872
12873/*
12874 * Aug 26, 2001 Manuel Novoa III
12875 *
12876 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12877 *
12878 * Merge in Aaron's comments previously posted to the busybox list,
12879 * modified slightly to take account of my changes to the code.
12880 *
12881 */
12882
12883/*
12884 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12885 *
12886 * - allow access to variable,
12887 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12888 * - realize assign syntax (VAR=expr, +=, *= etc)
12889 * - realize exponentiation (** operator)
12890 * - realize comma separated - expr, expr
12891 * - realise ++expr --expr expr++ expr--
12892 * - realise expr ? expr : expr (but, second expr calculate always)
12893 * - allow hexdecimal and octal numbers
12894 * - was restored loses XOR operator
12895 * - remove one goto label, added three ;-)
12896 * - protect $((num num)) as true zero expr (Manuel`s error)
12897 * - always use special isspace(), see comment from bash ;-)
12898 */
12899
12900
12901#define arith_isspace(arithval) \
12902 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12903
12904
12905typedef unsigned char operator;
12906
12907/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12908 * precedence, and 3 high bits are an ID unique accross operators of that
12909 * precedence. The ID portion is so that multiple operators can have the
12910 * same precedence, ensuring that the leftmost one is evaluated first.
12911 * Consider * and /. */
12912
12913#define tok_decl(prec,id) (((id)<<5)|(prec))
12914#define PREC(op) ((op) & 0x1F)
12915
12916#define TOK_LPAREN tok_decl(0,0)
12917
12918#define TOK_COMMA tok_decl(1,0)
12919
12920#define TOK_ASSIGN tok_decl(2,0)
12921#define TOK_AND_ASSIGN tok_decl(2,1)
12922#define TOK_OR_ASSIGN tok_decl(2,2)
12923#define TOK_XOR_ASSIGN tok_decl(2,3)
12924#define TOK_PLUS_ASSIGN tok_decl(2,4)
12925#define TOK_MINUS_ASSIGN tok_decl(2,5)
12926#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12927#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12928
12929#define TOK_MUL_ASSIGN tok_decl(3,0)
12930#define TOK_DIV_ASSIGN tok_decl(3,1)
12931#define TOK_REM_ASSIGN tok_decl(3,2)
12932
12933/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12934#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12935
12936/* conditional is right associativity too */
12937#define TOK_CONDITIONAL tok_decl(4,0)
12938#define TOK_CONDITIONAL_SEP tok_decl(4,1)
12939
12940#define TOK_OR tok_decl(5,0)
12941
12942#define TOK_AND tok_decl(6,0)
12943
12944#define TOK_BOR tok_decl(7,0)
12945
12946#define TOK_BXOR tok_decl(8,0)
12947
12948#define TOK_BAND tok_decl(9,0)
12949
12950#define TOK_EQ tok_decl(10,0)
12951#define TOK_NE tok_decl(10,1)
12952
12953#define TOK_LT tok_decl(11,0)
12954#define TOK_GT tok_decl(11,1)
12955#define TOK_GE tok_decl(11,2)
12956#define TOK_LE tok_decl(11,3)
12957
12958#define TOK_LSHIFT tok_decl(12,0)
12959#define TOK_RSHIFT tok_decl(12,1)
12960
12961#define TOK_ADD tok_decl(13,0)
12962#define TOK_SUB tok_decl(13,1)
12963
12964#define TOK_MUL tok_decl(14,0)
12965#define TOK_DIV tok_decl(14,1)
12966#define TOK_REM tok_decl(14,2)
12967
12968/* exponent is right associativity */
12969#define TOK_EXPONENT tok_decl(15,1)
12970
12971/* For now unary operators. */
12972#define UNARYPREC 16
12973#define TOK_BNOT tok_decl(UNARYPREC,0)
12974#define TOK_NOT tok_decl(UNARYPREC,1)
12975
12976#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12977#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12978
12979#define PREC_PRE (UNARYPREC+2)
12980
12981#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12982#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12983
12984#define PREC_POST (UNARYPREC+3)
12985
12986#define TOK_POST_INC tok_decl(PREC_POST, 0)
12987#define TOK_POST_DEC tok_decl(PREC_POST, 1)
12988
12989#define SPEC_PREC (UNARYPREC+4)
12990
12991#define TOK_NUM tok_decl(SPEC_PREC, 0)
12992#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12993
12994#define NUMPTR (*numstackptr)
12995
12996static inline int tok_have_assign(operator op)
12997{
12998 operator prec = PREC(op);
12999
13000 convert_prec_is_assing(prec);
13001 return (prec == PREC(TOK_ASSIGN) ||
13002 prec == PREC_PRE || prec == PREC_POST);
13003}
13004
13005static inline int is_right_associativity(operator prec)
13006{
13007 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13008 prec == PREC(TOK_CONDITIONAL));
13009}
13010
13011
13012typedef struct ARITCH_VAR_NUM {
13013 long val;
13014 long contidional_second_val;
13015 char contidional_second_val_initialized;
13016 char *var; /* if NULL then is regular number,
13017 else is varable name */
13018} v_n_t;
13019
13020
13021typedef struct CHK_VAR_RECURSIVE_LOOPED {
13022 const char *var;
13023 struct CHK_VAR_RECURSIVE_LOOPED *next;
13024} chk_var_recursive_looped_t;
13025
13026static chk_var_recursive_looped_t *prev_chk_var_recursive;
13027
13028
13029static int arith_lookup_val(v_n_t *t)
13030{
13031 if(t->var) {
13032 const char * p = lookupvar(t->var);
13033
13034 if(p) {
13035 int errcode;
13036
13037 /* recursive try as expression */
13038 chk_var_recursive_looped_t *cur;
13039 chk_var_recursive_looped_t cur_save;
13040
13041 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13042 if(strcmp(cur->var, t->var) == 0) {
13043 /* expression recursion loop detected */
13044 return -5;
13045 }
13046 }
13047 /* save current lookuped var name */
13048 cur = prev_chk_var_recursive;
13049 cur_save.var = t->var;
13050 cur_save.next = cur;
13051 prev_chk_var_recursive = &cur_save;
13052
13053 t->val = arith (p, &errcode);
13054 /* restore previous ptr after recursiving */
13055 prev_chk_var_recursive = cur;
13056 return errcode;
13057 } else {
13058 /* allow undefined var as 0 */
13059 t->val = 0;
13060 }
13061 }
13062 return 0;
13063}
13064
13065/* "applying" a token means performing it on the top elements on the integer
13066 * stack. For a unary operator it will only change the top element, but a
13067 * binary operator will pop two arguments and push a result */
13068static inline int
13069arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13070{
13071 long numptr_val;
13072 v_n_t *numptr_m1;
13073 long rez;
13074 int ret_arith_lookup_val;
13075
13076 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13077 without arguments */
13078 numptr_m1 = NUMPTR - 1;
13079
13080 /* check operand is var with noninteger value */
13081 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13082 if(ret_arith_lookup_val)
13083 return ret_arith_lookup_val;
13084
13085 rez = numptr_m1->val;
13086 if (op == TOK_UMINUS)
13087 rez *= -1;
13088 else if (op == TOK_NOT)
13089 rez = !rez;
13090 else if (op == TOK_BNOT)
13091 rez = ~rez;
13092 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13093 rez++;
13094 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13095 rez--;
13096 else if (op != TOK_UPLUS) {
13097 /* Binary operators */
13098
13099 /* check and binary operators need two arguments */
13100 if (numptr_m1 == numstack) goto err;
13101
13102 /* ... and they pop one */
13103 --NUMPTR;
13104 numptr_val = rez;
13105 if (op == TOK_CONDITIONAL) {
13106 if(! numptr_m1->contidional_second_val_initialized) {
13107 /* protect $((expr1 ? expr2)) without ": expr" */
13108 goto err;
13109 }
13110 rez = numptr_m1->contidional_second_val;
13111 } else if(numptr_m1->contidional_second_val_initialized) {
13112 /* protect $((expr1 : expr2)) without "expr ? " */
13113 goto err;
13114 }
13115 numptr_m1 = NUMPTR - 1;
13116 if(op != TOK_ASSIGN) {
13117 /* check operand is var with noninteger value for not '=' */
13118 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13119 if(ret_arith_lookup_val)
13120 return ret_arith_lookup_val;
13121 }
13122 if (op == TOK_CONDITIONAL) {
13123 numptr_m1->contidional_second_val = rez;
13124 }
13125 rez = numptr_m1->val;
13126 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13127 rez |= numptr_val;
13128 else if (op == TOK_OR)
13129 rez = numptr_val || rez;
13130 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13131 rez &= numptr_val;
13132 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13133 rez ^= numptr_val;
13134 else if (op == TOK_AND)
13135 rez = rez && numptr_val;
13136 else if (op == TOK_EQ)
13137 rez = (rez == numptr_val);
13138 else if (op == TOK_NE)
13139 rez = (rez != numptr_val);
13140 else if (op == TOK_GE)
13141 rez = (rez >= numptr_val);
13142 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13143 rez >>= numptr_val;
13144 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13145 rez <<= numptr_val;
13146 else if (op == TOK_GT)
13147 rez = (rez > numptr_val);
13148 else if (op == TOK_LT)
13149 rez = (rez < numptr_val);
13150 else if (op == TOK_LE)
13151 rez = (rez <= numptr_val);
13152 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13153 rez *= numptr_val;
13154 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13155 rez += numptr_val;
13156 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13157 rez -= numptr_val;
13158 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13159 rez = numptr_val;
13160 else if (op == TOK_CONDITIONAL_SEP) {
13161 if (numptr_m1 == numstack) {
13162 /* protect $((expr : expr)) without "expr ? " */
13163 goto err;
13164 }
13165 numptr_m1->contidional_second_val_initialized = op;
13166 numptr_m1->contidional_second_val = numptr_val;
13167 }
13168 else if (op == TOK_CONDITIONAL) {
13169 rez = rez ?
13170 numptr_val : numptr_m1->contidional_second_val;
13171 }
13172 else if(op == TOK_EXPONENT) {
13173 if(numptr_val < 0)
13174 return -3; /* exponent less than 0 */
13175 else {
13176 long c = 1;
13177
13178 if(numptr_val)
13179 while(numptr_val--)
13180 c *= rez;
13181 rez = c;
13182 }
13183 }
13184 else if(numptr_val==0) /* zero divisor check */
13185 return -2;
13186 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13187 rez /= numptr_val;
13188 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13189 rez %= numptr_val;
13190 }
13191 if(tok_have_assign(op)) {
13192 char buf[32];
13193
13194 if(numptr_m1->var == NULL) {
13195 /* Hmm, 1=2 ? */
13196 goto err;
13197 }
13198 /* save to shell variable */
13199 sprintf(buf, "%ld", rez);
13200 setvar(numptr_m1->var, buf, 0);
13201 /* after saving, make previous value for v++ or v-- */
13202 if(op == TOK_POST_INC)
13203 rez--;
13204 else if(op == TOK_POST_DEC)
13205 rez++;
13206 }
13207 numptr_m1->val = rez;
13208 /* protect geting var value, is number now */
13209 numptr_m1->var = NULL;
13210 return 0;
13211err: return(-1);
13212}
13213
13214/* longest must first */
13215static const char op_tokens[] = {
13216 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13217 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13218 '<','<', 0, TOK_LSHIFT,
13219 '>','>', 0, TOK_RSHIFT,
13220 '|','|', 0, TOK_OR,
13221 '&','&', 0, TOK_AND,
13222 '!','=', 0, TOK_NE,
13223 '<','=', 0, TOK_LE,
13224 '>','=', 0, TOK_GE,
13225 '=','=', 0, TOK_EQ,
13226 '|','=', 0, TOK_OR_ASSIGN,
13227 '&','=', 0, TOK_AND_ASSIGN,
13228 '*','=', 0, TOK_MUL_ASSIGN,
13229 '/','=', 0, TOK_DIV_ASSIGN,
13230 '%','=', 0, TOK_REM_ASSIGN,
13231 '+','=', 0, TOK_PLUS_ASSIGN,
13232 '-','=', 0, TOK_MINUS_ASSIGN,
13233 '-','-', 0, TOK_POST_DEC,
13234 '^','=', 0, TOK_XOR_ASSIGN,
13235 '+','+', 0, TOK_POST_INC,
13236 '*','*', 0, TOK_EXPONENT,
13237 '!', 0, TOK_NOT,
13238 '<', 0, TOK_LT,
13239 '>', 0, TOK_GT,
13240 '=', 0, TOK_ASSIGN,
13241 '|', 0, TOK_BOR,
13242 '&', 0, TOK_BAND,
13243 '*', 0, TOK_MUL,
13244 '/', 0, TOK_DIV,
13245 '%', 0, TOK_REM,
13246 '+', 0, TOK_ADD,
13247 '-', 0, TOK_SUB,
13248 '^', 0, TOK_BXOR,
13249 /* uniq */
13250 '~', 0, TOK_BNOT,
13251 ',', 0, TOK_COMMA,
13252 '?', 0, TOK_CONDITIONAL,
13253 ':', 0, TOK_CONDITIONAL_SEP,
13254 ')', 0, TOK_RPAREN,
13255 '(', 0, TOK_LPAREN,
13256 0
13257};
13258/* ptr to ")" */
13259#define endexpression &op_tokens[sizeof(op_tokens)-7]
13260
13261
13262extern long arith (const char *expr, int *perrcode)
13263{
13264 register char arithval; /* Current character under analysis */
13265 operator lasttok, op;
13266 operator prec;
13267
13268 const char *p = endexpression;
13269 int errcode;
13270
13271 size_t datasizes = strlen(expr) + 2;
13272
13273 /* Stack of integers */
13274 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13275 * in any given correct or incorrect expression is left as an excersize to
13276 * the reader. */
13277 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13278 *numstackptr = numstack;
13279 /* Stack of operator tokens */
13280 operator *stack = alloca((datasizes) * sizeof(operator)),
13281 *stackptr = stack;
13282
13283 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13284 *perrcode = errcode = 0;
13285
13286 while(1) {
13287 if ((arithval = *expr) == 0) {
13288 if (p == endexpression) {
13289 /* Null expression. */
13290 return 0;
13291 }
13292
13293 /* This is only reached after all tokens have been extracted from the
13294 * input stream. If there are still tokens on the operator stack, they
13295 * are to be applied in order. At the end, there should be a final
13296 * result on the integer stack */
13297
13298 if (expr != endexpression + 1) {
13299 /* If we haven't done so already, */
13300 /* append a closing right paren */
13301 expr = endexpression;
13302 /* and let the loop process it. */
13303 continue;
13304 }
13305 /* At this point, we're done with the expression. */
13306 if (numstackptr != numstack+1) {
13307 /* ... but if there isn't, it's bad */
13308 err:
13309 return (*perrcode = -1);
13310 }
13311 if(numstack->var) {
13312 /* expression is $((var)) only, lookup now */
13313 errcode = arith_lookup_val(numstack);
13314 }
13315 ret:
13316 *perrcode = errcode;
13317 return numstack->val;
13318 } else {
13319 /* Continue processing the expression. */
13320 if (arith_isspace(arithval)) {
13321 /* Skip whitespace */
13322 goto prologue;
13323 }
13324 if((p = endofname(expr)) != expr) {
13325 int var_name_size = (p-expr) + 1; /* trailing zero */
13326
13327 numstackptr->var = alloca(var_name_size);
13328 safe_strncpy(numstackptr->var, expr, var_name_size);
13329 expr = p;
13330 num:
13331 numstackptr->contidional_second_val_initialized = 0;
13332 numstackptr++;
13333 lasttok = TOK_NUM;
13334 continue;
13335 } else if (is_digit(arithval)) {
13336 numstackptr->var = NULL;
13337 numstackptr->val = strtol(expr, (char **) &expr, 0);
13338 goto num;
13339 }
13340 for(p = op_tokens; ; p++) {
13341 const char *o;
13342
13343 if(*p == 0) {
13344 /* strange operator not found */
13345 goto err;
13346 }
13347 for(o = expr; *p && *o == *p; p++)
13348 o++;
13349 if(! *p) {
13350 /* found */
13351 expr = o - 1;
13352 break;
13353 }
13354 /* skip tail uncompared token */
13355 while(*p)
13356 p++;
13357 /* skip zero delim */
13358 p++;
13359 }
13360 op = p[1];
13361
13362 /* post grammar: a++ reduce to num */
13363 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13364 lasttok = TOK_NUM;
13365
13366 /* Plus and minus are binary (not unary) _only_ if the last
13367 * token was as number, or a right paren (which pretends to be
13368 * a number, since it evaluates to one). Think about it.
13369 * It makes sense. */
13370 if (lasttok != TOK_NUM) {
13371 switch(op) {
13372 case TOK_ADD:
13373 op = TOK_UPLUS;
13374 break;
13375 case TOK_SUB:
13376 op = TOK_UMINUS;
13377 break;
13378 case TOK_POST_INC:
13379 op = TOK_PRE_INC;
13380 break;
13381 case TOK_POST_DEC:
13382 op = TOK_PRE_DEC;
13383 break;
13384 }
13385 }
13386 /* We don't want a unary operator to cause recursive descent on the
13387 * stack, because there can be many in a row and it could cause an
13388 * operator to be evaluated before its argument is pushed onto the
13389 * integer stack. */
13390 /* But for binary operators, "apply" everything on the operator
13391 * stack until we find an operator with a lesser priority than the
13392 * one we have just extracted. */
13393 /* Left paren is given the lowest priority so it will never be
13394 * "applied" in this way.
13395 * if associativity is right and priority eq, applied also skip
13396 */
13397 prec = PREC(op);
13398 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13399 /* not left paren or unary */
13400 if (lasttok != TOK_NUM) {
13401 /* binary op must be preceded by a num */
13402 goto err;
13403 }
13404 while (stackptr != stack) {
13405 if (op == TOK_RPAREN) {
13406 /* The algorithm employed here is simple: while we don't
13407 * hit an open paren nor the bottom of the stack, pop
13408 * tokens and apply them */
13409 if (stackptr[-1] == TOK_LPAREN) {
13410 --stackptr;
13411 /* Any operator directly after a */
13412 lasttok = TOK_NUM;
13413 /* close paren should consider itself binary */
13414 goto prologue;
13415 }
13416 } else {
13417 operator prev_prec = PREC(stackptr[-1]);
13418
13419 convert_prec_is_assing(prec);
13420 convert_prec_is_assing(prev_prec);
13421 if (prev_prec < prec)
13422 break;
13423 /* check right assoc */
13424 if(prev_prec == prec && is_right_associativity(prec))
13425 break;
13426 }
13427 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13428 if(errcode) goto ret;
13429 }
13430 if (op == TOK_RPAREN) {
13431 goto err;
13432 }
13433 }
13434
13435 /* Push this operator to the stack and remember it. */
13436 *stackptr++ = lasttok = op;
13437
13438 prologue:
13439 ++expr;
13440 }
13441 }
13442}
13443#endif /* CONFIG_ASH_MATH_SUPPORT */
13444
13445
Eric Andersenc470f442003-07-28 09:56:35 +000013446#ifdef DEBUG
13447const char *bb_applet_name = "debug stuff usage";
13448int main(int argc, char **argv)
13449{
13450 return ash_main(argc, argv);
13451}
13452#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013453
Eric Andersendf82f612001-06-28 07:46:40 +000013454/*-
13455 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013456 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013457 *
13458 * This code is derived from software contributed to Berkeley by
13459 * Kenneth Almquist.
13460 *
13461 * Redistribution and use in source and binary forms, with or without
13462 * modification, are permitted provided that the following conditions
13463 * are met:
13464 * 1. Redistributions of source code must retain the above copyright
13465 * notice, this list of conditions and the following disclaimer.
13466 * 2. Redistributions in binary form must reproduce the above copyright
13467 * notice, this list of conditions and the following disclaimer in the
13468 * documentation and/or other materials provided with the distribution.
13469 *
Eric Andersen2870d962001-07-02 17:27:21 +000013470 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13471 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013472 *
13473 * 4. Neither the name of the University nor the names of its contributors
13474 * may be used to endorse or promote products derived from this software
13475 * without specific prior written permission.
13476 *
13477 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13478 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13479 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13480 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13481 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13482 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13483 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13484 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13485 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13486 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13487 * SUCH DAMAGE.
13488 */