blob: 78320493398a2bdd84cade3d8e1c2ab6547c31f6 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
Eric Andersen81fe1232003-07-29 06:38:40 +00008 * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9 * was re-ported from NetBSD and debianized.
10 *
11 *
Eric Andersencb57d552001-06-28 07:25:16 +000012 * This code is derived from software contributed to Berkeley by
13 * Kenneth Almquist.
14 *
Eric Andersendf82f612001-06-28 07:46:40 +000015 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
Eric Andersencb57d552001-06-28 07:25:16 +000019 *
Eric Andersendf82f612001-06-28 07:46:40 +000020 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
Eric Andersen81fe1232003-07-29 06:38:40 +000029 * Original BSD copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000030 */
31
Eric Andersenc470f442003-07-28 09:56:35 +000032/*
Eric Andersen90898442003-08-06 11:20:52 +000033 * rewrite arith.y to micro stack based cryptic algorithm by
34 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
35 *
Eric Andersenef02f822004-03-11 13:34:24 +000036 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
37 * dynamic variables.
Eric Andersen16767e22004-03-16 05:14:10 +000038 *
39 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be
40 * used in busybox and size optimizations,
41 * rewrote arith (see notes to this), added locale support,
42 * rewrote dynamic variables.
43 *
Eric Andersen90898442003-08-06 11:20:52 +000044 */
45
46
47/*
Eric Andersenc470f442003-07-28 09:56:35 +000048 * The follow should be set to reflect the type of system you have:
49 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
50 * define SYSV if you are running under System V.
51 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
52 * define DEBUG=2 to compile in and turn on debugging.
53 *
54 * When debugging is on, debugging info will be written to ./trace and
55 * a quit signal will generate a core dump.
56 */
Eric Andersen2870d962001-07-02 17:27:21 +000057
Eric Andersen2870d962001-07-02 17:27:21 +000058
Eric Andersenc470f442003-07-28 09:56:35 +000059
Eric Andersen5bb16772001-09-06 18:00:41 +000060#define IFS_BROKEN
Eric Andersencb57d552001-06-28 07:25:16 +000061
Eric Andersenc470f442003-07-28 09:56:35 +000062#define PROFILE 0
63
64#ifdef DEBUG
65#define _GNU_SOURCE
66#endif
67
68#include <sys/types.h>
69#include <sys/cdefs.h>
70#include <sys/ioctl.h>
71#include <sys/param.h>
72#include <sys/resource.h>
73#include <sys/stat.h>
74#include <sys/time.h>
75#include <sys/wait.h>
76
77#include <stdio.h>
78#include <stdlib.h>
79#include <string.h>
80#include <unistd.h>
81
82#include <stdarg.h>
Manuel Novoa III 16815d42001-08-10 19:36:07 +000083#include <stddef.h>
Eric Andersenc470f442003-07-28 09:56:35 +000084#include <assert.h>
Eric Andersencb57d552001-06-28 07:25:16 +000085#include <ctype.h>
86#include <dirent.h>
87#include <errno.h>
88#include <fcntl.h>
89#include <limits.h>
90#include <paths.h>
Eric Andersencb57d552001-06-28 07:25:16 +000091#include <setjmp.h>
92#include <signal.h>
Eric Andersenc470f442003-07-28 09:56:35 +000093#include <stdint.h>
Eric Andersencb57d552001-06-28 07:25:16 +000094#include <sysexits.h>
Eric Andersenef02f822004-03-11 13:34:24 +000095#include <time.h>
Eric Andersenc470f442003-07-28 09:56:35 +000096#include <fnmatch.h>
Eric Andersenc470f442003-07-28 09:56:35 +000097
98
Robert Grieblea1a63a2002-06-04 20:10:23 +000099#include "busybox.h"
Eric Andersen887ca792002-07-03 23:19:26 +0000100#include "pwd_.h"
Eric Andersencb57d552001-06-28 07:25:16 +0000101
Eric Andersend35c5df2002-01-09 15:37:36 +0000102#ifdef CONFIG_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +0000103#define JOBS 1
104#else
Eric Andersenca162042003-07-29 07:15:17 +0000105#undef JOBS
Eric Andersenc470f442003-07-28 09:56:35 +0000106#endif
107
108#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000109#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000110#endif
111
Eric Andersen2870d962001-07-02 17:27:21 +0000112#include "cmdedit.h"
113
Eric Andersenc470f442003-07-28 09:56:35 +0000114#ifdef __GLIBC__
115/* glibc sucks */
116static int *dash_errno;
117#undef errno
118#define errno (*dash_errno)
119#endif
120
Eric Andersenaa1d6cc2002-09-30 20:12:32 +0000121#if defined(__uClinux__)
122#error "Do not even bother, ash will not run on uClinux"
123#endif
124
Eric Andersenc470f442003-07-28 09:56:35 +0000125#ifdef DEBUG
126#define _DIAGASSERT(assert_expr) assert(assert_expr)
127#else
128#define _DIAGASSERT(assert_expr)
Eric Andersen2870d962001-07-02 17:27:21 +0000129#endif
130
Eric Andersen2870d962001-07-02 17:27:21 +0000131
Eric Andersenc470f442003-07-28 09:56:35 +0000132#ifdef CONFIG_ASH_ALIAS
133/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
134
135#define ALIASINUSE 1
136#define ALIASDEAD 2
137
138struct alias {
139 struct alias *next;
140 char *name;
141 char *val;
142 int flag;
Eric Andersen2870d962001-07-02 17:27:21 +0000143};
144
Eric Andersenc470f442003-07-28 09:56:35 +0000145static struct alias *lookupalias(const char *, int);
146static int aliascmd(int, char **);
147static int unaliascmd(int, char **);
148static void rmaliases(void);
149static int unalias(const char *);
150static void printalias(const struct alias *);
Eric Andersen2870d962001-07-02 17:27:21 +0000151#endif
152
Eric Andersenc470f442003-07-28 09:56:35 +0000153/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
154
155
156static void setpwd(const char *, int);
157
158/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
159
160
161/*
162 * Types of operations (passed to the errmsg routine).
163 */
164
165
166static const char not_found_msg[] = "%s: not found";
167
168
169#define E_OPEN "No such file" /* opening a file */
170#define E_CREAT "Directory nonexistent" /* creating a file */
171#define E_EXEC not_found_msg+4 /* executing a program */
172
173/*
174 * We enclose jmp_buf in a structure so that we can declare pointers to
175 * jump locations. The global variable handler contains the location to
176 * jump to when an exception occurs, and the global variable exception
Eric Andersenaff114c2004-04-14 17:51:38 +0000177 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000178 * exception handlers, the user should save the value of handler on entry
179 * to an inner scope, set handler to point to a jmploc structure for the
180 * inner scope, and restore handler on exit from the scope.
181 */
182
183struct jmploc {
184 jmp_buf loc;
185};
186
187static struct jmploc *handler;
188static int exception;
189static volatile int suppressint;
190static volatile sig_atomic_t intpending;
191
192static int exerrno; /* Last exec error, error for EXEXEC */
193
194/* exceptions */
195#define EXINT 0 /* SIGINT received */
196#define EXERROR 1 /* a generic error */
197#define EXSHELLPROC 2 /* execute a shell procedure */
198#define EXEXEC 3 /* command execution failed */
199#define EXEXIT 4 /* exit the shell */
200#define EXSIG 5 /* trapped signal in wait(1) */
201
202
203/* do we generate EXSIG events */
204static int exsig;
205/* last pending signal */
206static volatile sig_atomic_t pendingsigs;
Eric Andersen2870d962001-07-02 17:27:21 +0000207
208/*
209 * These macros allow the user to suspend the handling of interrupt signals
210 * over a period of time. This is similar to SIGHOLD to or sigblock, but
211 * much more efficient and portable. (But hacking the kernel is so much
212 * more fun than worrying about efficiency and portability. :-))
213 */
214
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000215#define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
Eric Andersenc470f442003-07-28 09:56:35 +0000216#define INTOFF \
217 ({ \
218 suppressint++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000219 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000220 0; \
221 })
222#define SAVEINT(v) ((v) = suppressint)
223#define RESTOREINT(v) \
224 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000225 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000226 if ((suppressint = (v)) == 0 && intpending) onint(); \
227 0; \
228 })
229#define EXSIGON() \
230 ({ \
231 exsig++; \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000232 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000233 if (pendingsigs) \
234 exraise(EXSIG); \
235 0; \
236 })
237/* EXSIG is turned off by evalbltin(). */
Eric Andersen2870d962001-07-02 17:27:21 +0000238
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000239
Eric Andersenc470f442003-07-28 09:56:35 +0000240static void exraise(int) __attribute__((__noreturn__));
241static void onint(void) __attribute__((__noreturn__));
242
243static void error(const char *, ...) __attribute__((__noreturn__));
244static void exerror(int, const char *, ...) __attribute__((__noreturn__));
245
246static void sh_warnx(const char *, ...);
247
248#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
249static void
250inton(void) {
251 if (--suppressint == 0 && intpending) {
252 onint();
253 }
254}
255#define INTON inton()
256static void forceinton(void)
257{
258 suppressint = 0;
259 if (intpending)
260 onint();
261}
Eric Andersen3102ac42001-07-06 04:26:23 +0000262#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000263#else
Eric Andersenc470f442003-07-28 09:56:35 +0000264#define INTON \
265 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000266 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000267 if (--suppressint == 0 && intpending) onint(); \
268 0; \
269 })
270#define FORCEINTON \
271 ({ \
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000272 xbarrier(); \
Eric Andersenc470f442003-07-28 09:56:35 +0000273 suppressint = 0; \
274 if (intpending) onint(); \
275 0; \
276 })
277#endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
Eric Andersen2870d962001-07-02 17:27:21 +0000278
279/*
Eric Andersenc470f442003-07-28 09:56:35 +0000280 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
281 * so we use _setjmp instead.
Eric Andersen2870d962001-07-02 17:27:21 +0000282 */
Eric Andersen2870d962001-07-02 17:27:21 +0000283
Eric Andersenc470f442003-07-28 09:56:35 +0000284#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
285#define setjmp(jmploc) _setjmp(jmploc)
286#define longjmp(jmploc, val) _longjmp(jmploc, val)
287#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000288
Eric Andersenc470f442003-07-28 09:56:35 +0000289/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000290
291struct strlist {
292 struct strlist *next;
293 char *text;
294};
295
296
297struct arglist {
298 struct strlist *list;
299 struct strlist **lastp;
300};
301
Eric Andersenc470f442003-07-28 09:56:35 +0000302/*
303 * expandarg() flags
304 */
305#define EXP_FULL 0x1 /* perform word splitting & file globbing */
306#define EXP_TILDE 0x2 /* do normal tilde expansion */
307#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
308#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
309#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
310#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
311#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
312#define EXP_WORD 0x80 /* expand word in parameter expansion */
313#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
314
315
316union node;
317static void expandarg(union node *, struct arglist *, int);
318#define rmescapes(p) _rmescapes((p), 0)
319static char *_rmescapes(char *, int);
320static int casematch(union node *, char *);
321
322#ifdef CONFIG_ASH_MATH_SUPPORT
323static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000324#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000325
Eric Andersenc470f442003-07-28 09:56:35 +0000326/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000327
Eric Andersenc470f442003-07-28 09:56:35 +0000328static char *commandname; /* currently executing command */
329static struct strlist *cmdenviron; /* environment for builtin command */
330static int exitstatus; /* exit status of last command */
331static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000332
Eric Andersenc470f442003-07-28 09:56:35 +0000333
334struct backcmd { /* result of evalbackcmd */
335 int fd; /* file descriptor to read from */
336 char *buf; /* buffer */
337 int nleft; /* number of chars in buffer */
338 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000339};
340
Eric Andersen62483552001-07-10 06:09:16 +0000341/*
Eric Andersenc470f442003-07-28 09:56:35 +0000342 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000343 */
Eric Andersenc470f442003-07-28 09:56:35 +0000344
345#define NCMD 0
346#define NPIPE 1
347#define NREDIR 2
348#define NBACKGND 3
349#define NSUBSHELL 4
350#define NAND 5
351#define NOR 6
352#define NSEMI 7
353#define NIF 8
354#define NWHILE 9
355#define NUNTIL 10
356#define NFOR 11
357#define NCASE 12
358#define NCLIST 13
359#define NDEFUN 14
360#define NARG 15
361#define NTO 16
362#define NCLOBBER 17
363#define NFROM 18
364#define NFROMTO 19
365#define NAPPEND 20
366#define NTOFD 21
367#define NFROMFD 22
368#define NHERE 23
369#define NXHERE 24
370#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000371
372
373
Eric Andersenc470f442003-07-28 09:56:35 +0000374struct ncmd {
375 int type;
376 union node *assign;
377 union node *args;
378 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000379};
380
381
Eric Andersenc470f442003-07-28 09:56:35 +0000382struct npipe {
383 int type;
384 int backgnd;
385 struct nodelist *cmdlist;
386};
Eric Andersen62483552001-07-10 06:09:16 +0000387
388
Eric Andersenc470f442003-07-28 09:56:35 +0000389struct nredir {
390 int type;
391 union node *n;
392 union node *redirect;
393};
Eric Andersen62483552001-07-10 06:09:16 +0000394
395
Eric Andersenc470f442003-07-28 09:56:35 +0000396struct nbinary {
397 int type;
398 union node *ch1;
399 union node *ch2;
400};
Eric Andersen2870d962001-07-02 17:27:21 +0000401
Eric Andersen2870d962001-07-02 17:27:21 +0000402
Eric Andersenc470f442003-07-28 09:56:35 +0000403struct nif {
404 int type;
405 union node *test;
406 union node *ifpart;
407 union node *elsepart;
408};
409
410
411struct nfor {
412 int type;
413 union node *args;
414 union node *body;
415 char *var;
416};
417
418
419struct ncase {
420 int type;
421 union node *expr;
422 union node *cases;
423};
424
425
426struct nclist {
427 int type;
428 union node *next;
429 union node *pattern;
430 union node *body;
431};
432
433
434struct narg {
435 int type;
436 union node *next;
437 char *text;
438 struct nodelist *backquote;
439};
440
441
442struct nfile {
443 int type;
444 union node *next;
445 int fd;
446 union node *fname;
447 char *expfname;
448};
449
450
451struct ndup {
452 int type;
453 union node *next;
454 int fd;
455 int dupfd;
456 union node *vname;
457};
458
459
460struct nhere {
461 int type;
462 union node *next;
463 int fd;
464 union node *doc;
465};
466
467
468struct nnot {
469 int type;
470 union node *com;
471};
472
473
474union node {
475 int type;
476 struct ncmd ncmd;
477 struct npipe npipe;
478 struct nredir nredir;
479 struct nbinary nbinary;
480 struct nif nif;
481 struct nfor nfor;
482 struct ncase ncase;
483 struct nclist nclist;
484 struct narg narg;
485 struct nfile nfile;
486 struct ndup ndup;
487 struct nhere nhere;
488 struct nnot nnot;
489};
490
491
492struct nodelist {
493 struct nodelist *next;
494 union node *n;
495};
496
497
498struct funcnode {
499 int count;
500 union node n;
501};
502
503
504static void freefunc(struct funcnode *);
505/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
506
507/* control characters in argument strings */
508#define CTL_FIRST '\201' /* first 'special' character */
509#define CTLESC '\201' /* escape next character */
510#define CTLVAR '\202' /* variable defn */
511#define CTLENDVAR '\203'
512#define CTLBACKQ '\204'
513#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
514/* CTLBACKQ | CTLQUOTE == '\205' */
515#define CTLARI '\206' /* arithmetic expression */
516#define CTLENDARI '\207'
517#define CTLQUOTEMARK '\210'
518#define CTL_LAST '\210' /* last 'special' character */
519
520/* variable substitution byte (follows CTLVAR) */
521#define VSTYPE 0x0f /* type of variable substitution */
522#define VSNUL 0x10 /* colon--treat the empty string as unset */
523#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
524
525/* values of VSTYPE field */
526#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
527#define VSMINUS 0x2 /* ${var-text} */
528#define VSPLUS 0x3 /* ${var+text} */
529#define VSQUESTION 0x4 /* ${var?message} */
530#define VSASSIGN 0x5 /* ${var=text} */
531#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
532#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
533#define VSTRIMLEFT 0x8 /* ${var#pattern} */
534#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
535#define VSLENGTH 0xa /* ${#var} */
536
537/* values of checkkwd variable */
538#define CHKALIAS 0x1
539#define CHKKWD 0x2
540#define CHKNL 0x4
541
542#define IBUFSIZ (BUFSIZ + 1)
543
544/*
545 * NEOF is returned by parsecmd when it encounters an end of file. It
546 * must be distinct from NULL, so we use the address of a variable that
547 * happens to be handy.
548 */
549static int plinno = 1; /* input line number */
550
551/* number of characters left in input buffer */
552static int parsenleft; /* copy of parsefile->nleft */
553static int parselleft; /* copy of parsefile->lleft */
554
555/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000556static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000557
558struct strpush {
559 struct strpush *prev; /* preceding string on stack */
560 char *prevstring;
561 int prevnleft;
562#ifdef CONFIG_ASH_ALIAS
563 struct alias *ap; /* if push was associated with an alias */
564#endif
565 char *string; /* remember the string since it may change */
566};
567
568struct parsefile {
569 struct parsefile *prev; /* preceding file on stack */
570 int linno; /* current line */
571 int fd; /* file descriptor (or -1 if string) */
572 int nleft; /* number of chars left in this line */
573 int lleft; /* number of chars left in this buffer */
574 char *nextc; /* next char in buffer */
575 char *buf; /* input buffer */
576 struct strpush *strpush; /* for pushing strings at this level */
577 struct strpush basestrpush; /* so pushing one is fast */
578};
579
Eric Andersenc470f442003-07-28 09:56:35 +0000580static struct parsefile basepf; /* top level input file */
581static char basebuf[IBUFSIZ]; /* buffer for top level input file */
582static struct parsefile *parsefile = &basepf; /* current input file */
583
584
585static int tokpushback; /* last token pushed back */
586#define NEOF ((union node *)&tokpushback)
587static int parsebackquote; /* nonzero if we are inside backquotes */
588static int doprompt; /* if set, prompt the user */
589static int needprompt; /* true if interactive and at start of line */
590static int lasttoken; /* last token read */
591static char *wordtext; /* text of last word returned by readtoken */
592static int checkkwd;
593static struct nodelist *backquotelist;
594static union node *redirnode;
595static struct heredoc *heredoc;
596static int quoteflag; /* set if (part of) last token was quoted */
597static int startlinno; /* line # where last token started */
598
599static union node *parsecmd(int);
600static void fixredir(union node *, const char *, int);
601static const char *const *findkwd(const char *);
602static char *endofname(const char *);
603
604/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
605
606typedef void *pointer;
607
608static char nullstr[1]; /* zero length string */
609static const char spcstr[] = " ";
610static const char snlfmt[] = "%s\n";
611static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
612static const char illnum[] = "Illegal number: %s";
613static const char homestr[] = "HOME";
614
615#ifdef DEBUG
616#define TRACE(param) trace param
617#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000618#else
Eric Andersenc470f442003-07-28 09:56:35 +0000619#define TRACE(param)
620#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000621#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000622
Eric Andersenc470f442003-07-28 09:56:35 +0000623#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
624#define __builtin_expect(x, expected_value) (x)
625#endif
626
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000627#define xlikely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000628
Eric Andersenc470f442003-07-28 09:56:35 +0000629
630#define TEOF 0
631#define TNL 1
632#define TREDIR 2
633#define TWORD 3
634#define TSEMI 4
635#define TBACKGND 5
636#define TAND 6
637#define TOR 7
638#define TPIPE 8
639#define TLP 9
640#define TRP 10
641#define TENDCASE 11
642#define TENDBQUOTE 12
643#define TNOT 13
644#define TCASE 14
645#define TDO 15
646#define TDONE 16
647#define TELIF 17
648#define TELSE 18
649#define TESAC 19
650#define TFI 20
651#define TFOR 21
652#define TIF 22
653#define TIN 23
654#define TTHEN 24
655#define TUNTIL 25
656#define TWHILE 26
657#define TBEGIN 27
658#define TEND 28
659
660/* first char is indicating which tokens mark the end of a list */
661static const char *const tokname_array[] = {
662 "\1end of file",
663 "\0newline",
664 "\0redirection",
665 "\0word",
666 "\0;",
667 "\0&",
668 "\0&&",
669 "\0||",
670 "\0|",
671 "\0(",
672 "\1)",
673 "\1;;",
674 "\1`",
675#define KWDOFFSET 13
676 /* the following are keywords */
677 "\0!",
678 "\0case",
679 "\1do",
680 "\1done",
681 "\1elif",
682 "\1else",
683 "\1esac",
684 "\1fi",
685 "\0for",
686 "\0if",
687 "\0in",
688 "\1then",
689 "\0until",
690 "\0while",
691 "\0{",
692 "\1}",
693};
694
695static const char *tokname(int tok)
696{
697 static char buf[16];
698
699 if (tok >= TSEMI)
700 buf[0] = '"';
701 sprintf(buf + (tok >= TSEMI), "%s%c",
702 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
703 return buf;
704}
705
706/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
707
708/*
709 * Most machines require the value returned from malloc to be aligned
710 * in some way. The following macro will get this right on many machines.
711 */
712
713#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
714/*
715 * It appears that grabstackstr() will barf with such alignments
716 * because stalloc() will return a string allocated in a new stackblock.
717 */
718#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
719
720/*
721 * This file was generated by the mksyntax program.
722 */
723
724
725/* Syntax classes */
726#define CWORD 0 /* character is nothing special */
727#define CNL 1 /* newline character */
728#define CBACK 2 /* a backslash character */
729#define CSQUOTE 3 /* single quote */
730#define CDQUOTE 4 /* double quote */
731#define CENDQUOTE 5 /* a terminating quote */
732#define CBQUOTE 6 /* backwards single quote */
733#define CVAR 7 /* a dollar sign */
734#define CENDVAR 8 /* a '}' character */
735#define CLP 9 /* a left paren in arithmetic */
736#define CRP 10 /* a right paren in arithmetic */
737#define CENDFILE 11 /* end of file */
738#define CCTL 12 /* like CWORD, except it must be escaped */
739#define CSPCL 13 /* these terminate a word */
740#define CIGN 14 /* character should be ignored */
741
742#ifdef CONFIG_ASH_ALIAS
743#define SYNBASE 130
744#define PEOF -130
745#define PEOA -129
746#define PEOA_OR_PEOF PEOA
747#else
748#define SYNBASE 129
749#define PEOF -129
750#define PEOA_OR_PEOF PEOF
751#endif
752
753#define is_digit(c) ((unsigned)((c) - '0') <= 9)
754#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
755#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
756
757/*
758 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
759 * (assuming ascii char codes, as the original implementation did)
760 */
761#define is_special(c) \
762 ( (((unsigned int)c) - 33 < 32) \
763 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
764
765#define digit_val(c) ((c) - '0')
766
767/*
768 * This file was generated by the mksyntax program.
769 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000770
Eric Andersend35c5df2002-01-09 15:37:36 +0000771#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000772#define USE_SIT_FUNCTION
773#endif
774
775/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000776#define BASESYNTAX 0 /* not in quotes */
777#define DQSYNTAX 1 /* in double quotes */
778#define SQSYNTAX 2 /* in single quotes */
779#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000780
Eric Andersenc470f442003-07-28 09:56:35 +0000781#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000782static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000783#ifdef CONFIG_ASH_ALIAS
784 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
785#endif
786 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
787 {CNL, CNL, CNL, CNL}, /* 2, \n */
788 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
789 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
790 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
791 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
792 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
793 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
794 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
795 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
796 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000797#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000798 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
799 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
800 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000801#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000802};
Eric Andersenc470f442003-07-28 09:56:35 +0000803#else
804static const char S_I_T[][3] = {
805#ifdef CONFIG_ASH_ALIAS
806 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
807#endif
808 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
809 {CNL, CNL, CNL}, /* 2, \n */
810 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
811 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
812 {CVAR, CVAR, CWORD}, /* 5, $ */
813 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
814 {CSPCL, CWORD, CWORD}, /* 7, ( */
815 {CSPCL, CWORD, CWORD}, /* 8, ) */
816 {CBACK, CBACK, CCTL}, /* 9, \ */
817 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
818 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
819#ifndef USE_SIT_FUNCTION
820 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
821 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
822 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
823#endif
824};
825#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000826
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000827#ifdef USE_SIT_FUNCTION
828
829#define U_C(c) ((unsigned char)(c))
830
831static int SIT(int c, int syntax)
832{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000833 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000834#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000835 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000836 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
837 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
838 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
839 11, 3 /* "}~" */
840 };
841#else
842 static const char syntax_index_table[] = {
843 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
844 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
845 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
846 10, 2 /* "}~" */
847 };
848#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000849 const char *s;
850 int indx;
851
Eric Andersenc470f442003-07-28 09:56:35 +0000852 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000853 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000854#ifdef CONFIG_ASH_ALIAS
855 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000856 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000857 else
858#endif
859 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
860 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000861 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000862 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000863 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000864 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000865 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000866 }
867 return S_I_T[indx][syntax];
868}
869
Eric Andersenc470f442003-07-28 09:56:35 +0000870#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000871
872#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
873
Eric Andersenc470f442003-07-28 09:56:35 +0000874#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000875#define CSPCL_CIGN_CIGN_CIGN 0
876#define CSPCL_CWORD_CWORD_CWORD 1
877#define CNL_CNL_CNL_CNL 2
878#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000879#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000880#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000881#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000882#define CSPCL_CWORD_CWORD_CLP 7
883#define CSPCL_CWORD_CWORD_CRP 8
884#define CBACK_CBACK_CCTL_CBACK 9
885#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
886#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
887#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
888#define CWORD_CWORD_CWORD_CWORD 13
889#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000890#else
891#define CSPCL_CWORD_CWORD_CWORD 0
892#define CNL_CNL_CNL_CNL 1
893#define CWORD_CCTL_CCTL_CWORD 2
894#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
895#define CVAR_CVAR_CWORD_CVAR 4
896#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
897#define CSPCL_CWORD_CWORD_CLP 6
898#define CSPCL_CWORD_CWORD_CRP 7
899#define CBACK_CBACK_CCTL_CBACK 8
900#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
901#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
902#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
903#define CWORD_CWORD_CWORD_CWORD 12
904#define CCTL_CCTL_CCTL_CCTL 13
905#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000906
907static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000908 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000909 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
910#ifdef CONFIG_ASH_ALIAS
911 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
912#endif
913 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
914 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
915 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
916 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
917 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
918 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
919 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
920 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
921 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000922 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
923 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
924 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
925 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
926 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
927 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
928 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
929 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
930 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
931 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
932 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
933 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
934 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
935 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
936 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
937 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
938 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
939 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
940 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
941 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
942 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
943 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
944 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
945 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
946 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
947 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
948 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
949 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
950 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
951 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
952 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
953 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
954 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
955 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
956 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
957 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
958 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
959 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
960 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
961 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
962 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
963 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
964 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
965 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
966 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
967 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
968 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
969 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
970 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
971 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
972 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
973 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
974 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
975 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
976 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
977 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
978 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
979 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
980 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
981 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
982 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
983 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
984 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
985 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
986 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
987 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
988 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
989 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
990 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
991 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
992 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
993 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
994 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
995 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
996 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
997 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
998 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
999 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1051 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1052 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1053 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1054 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1055 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1056 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1057 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1058 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1059 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1060 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1061 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1062 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1063 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1064 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1065 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1066 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1067 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1068 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1069 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1070 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1071 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1072 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1073 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001075 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001076 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1077 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1078 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001080 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001081 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1082 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1083 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1084 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1086 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1087 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1088 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1089 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1100 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1101 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1102 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1103 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1104 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1105 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1133 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1134 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1135 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1138 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1143 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1144 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1145 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1146 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1147 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1148 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1149 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1150 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1151 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1152 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1153 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1154 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1155 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1156 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1157 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1158 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1159 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1160 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1161 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1162 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1163 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1164 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1165 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1166 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1167 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1168 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001169};
1170
Eric Andersenc470f442003-07-28 09:56:35 +00001171#endif /* USE_SIT_FUNCTION */
1172
1173/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001174
Eric Andersen2870d962001-07-02 17:27:21 +00001175
Eric Andersenc470f442003-07-28 09:56:35 +00001176#define ATABSIZE 39
1177
1178static int funcblocksize; /* size of structures in function */
1179static int funcstringsize; /* size of strings in node */
1180static pointer funcblock; /* block to allocate function from */
1181static char *funcstring; /* block to allocate strings from */
1182
1183static const short nodesize[26] = {
1184 SHELL_ALIGN(sizeof (struct ncmd)),
1185 SHELL_ALIGN(sizeof (struct npipe)),
1186 SHELL_ALIGN(sizeof (struct nredir)),
1187 SHELL_ALIGN(sizeof (struct nredir)),
1188 SHELL_ALIGN(sizeof (struct nredir)),
1189 SHELL_ALIGN(sizeof (struct nbinary)),
1190 SHELL_ALIGN(sizeof (struct nbinary)),
1191 SHELL_ALIGN(sizeof (struct nbinary)),
1192 SHELL_ALIGN(sizeof (struct nif)),
1193 SHELL_ALIGN(sizeof (struct nbinary)),
1194 SHELL_ALIGN(sizeof (struct nbinary)),
1195 SHELL_ALIGN(sizeof (struct nfor)),
1196 SHELL_ALIGN(sizeof (struct ncase)),
1197 SHELL_ALIGN(sizeof (struct nclist)),
1198 SHELL_ALIGN(sizeof (struct narg)),
1199 SHELL_ALIGN(sizeof (struct narg)),
1200 SHELL_ALIGN(sizeof (struct nfile)),
1201 SHELL_ALIGN(sizeof (struct nfile)),
1202 SHELL_ALIGN(sizeof (struct nfile)),
1203 SHELL_ALIGN(sizeof (struct nfile)),
1204 SHELL_ALIGN(sizeof (struct nfile)),
1205 SHELL_ALIGN(sizeof (struct ndup)),
1206 SHELL_ALIGN(sizeof (struct ndup)),
1207 SHELL_ALIGN(sizeof (struct nhere)),
1208 SHELL_ALIGN(sizeof (struct nhere)),
1209 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001210};
1211
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001212
Eric Andersenc470f442003-07-28 09:56:35 +00001213static void calcsize(union node *);
1214static void sizenodelist(struct nodelist *);
1215static union node *copynode(union node *);
1216static struct nodelist *copynodelist(struct nodelist *);
1217static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001218
1219
Eric Andersen2870d962001-07-02 17:27:21 +00001220
Glenn L McGrath76620622004-01-13 10:19:37 +00001221static void evalstring(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001222union node; /* BLETCH for ansi C */
1223static void evaltree(union node *, int);
1224static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001225
Eric Andersenc470f442003-07-28 09:56:35 +00001226/* in_function returns nonzero if we are currently evaluating a function */
1227#define in_function() funcnest
1228static int evalskip; /* set if we are skipping commands */
1229static int skipcount; /* number of levels to skip */
1230static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001231
1232/* reasons for skipping commands (see comment on breakcmd routine) */
1233#define SKIPBREAK 1
1234#define SKIPCONT 2
1235#define SKIPFUNC 3
1236#define SKIPFILE 4
1237
Eric Andersenc470f442003-07-28 09:56:35 +00001238/*
1239 * This file was generated by the mkbuiltins program.
1240 */
Eric Andersen2870d962001-07-02 17:27:21 +00001241
Eric Andersenc470f442003-07-28 09:56:35 +00001242#ifdef JOBS
1243static int bgcmd(int, char **);
1244#endif
1245static int breakcmd(int, char **);
1246static int cdcmd(int, char **);
1247#ifdef CONFIG_ASH_CMDCMD
1248static int commandcmd(int, char **);
1249#endif
1250static int dotcmd(int, char **);
1251static int evalcmd(int, char **);
1252static int execcmd(int, char **);
1253static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001254static int exportcmd(int, char **);
1255static int falsecmd(int, char **);
1256#ifdef JOBS
1257static int fgcmd(int, char **);
1258#endif
1259#ifdef CONFIG_ASH_GETOPTS
1260static int getoptscmd(int, char **);
1261#endif
1262static int hashcmd(int, char **);
1263#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1264static int helpcmd(int argc, char **argv);
1265#endif
1266#ifdef JOBS
1267static int jobscmd(int, char **);
1268#endif
Eric Andersen90898442003-08-06 11:20:52 +00001269#ifdef CONFIG_ASH_MATH_SUPPORT
1270static int letcmd(int, char **);
1271#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001272static int localcmd(int, char **);
1273static int pwdcmd(int, char **);
1274static int readcmd(int, char **);
1275static int returncmd(int, char **);
1276static int setcmd(int, char **);
1277static int shiftcmd(int, char **);
1278static int timescmd(int, char **);
1279static int trapcmd(int, char **);
1280static int truecmd(int, char **);
1281static int typecmd(int, char **);
1282static int umaskcmd(int, char **);
1283static int unsetcmd(int, char **);
1284static int waitcmd(int, char **);
1285static int ulimitcmd(int, char **);
1286#ifdef JOBS
1287static int killcmd(int, char **);
1288#endif
1289
1290/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1291
1292#ifdef CONFIG_ASH_MAIL
1293static void chkmail(void);
1294static void changemail(const char *);
1295#endif
1296
1297/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1298
1299/* values of cmdtype */
1300#define CMDUNKNOWN -1 /* no entry in table for command */
1301#define CMDNORMAL 0 /* command is an executable program */
1302#define CMDFUNCTION 1 /* command is a shell function */
1303#define CMDBUILTIN 2 /* command is a shell builtin */
1304
1305struct builtincmd {
1306 const char *name;
1307 int (*builtin)(int, char **);
1308 /* unsigned flags; */
1309};
1310
1311#ifdef CONFIG_ASH_CMDCMD
1312# ifdef JOBS
1313# ifdef CONFIG_ASH_ALIAS
1314# define COMMANDCMD (builtincmd + 7)
1315# define EXECCMD (builtincmd + 10)
1316# else
1317# define COMMANDCMD (builtincmd + 6)
1318# define EXECCMD (builtincmd + 9)
1319# endif
1320# else /* ! JOBS */
1321# ifdef CONFIG_ASH_ALIAS
1322# define COMMANDCMD (builtincmd + 6)
1323# define EXECCMD (builtincmd + 9)
1324# else
1325# define COMMANDCMD (builtincmd + 5)
1326# define EXECCMD (builtincmd + 8)
1327# endif
1328# endif /* JOBS */
1329#else /* ! CONFIG_ASH_CMDCMD */
1330# ifdef JOBS
1331# ifdef CONFIG_ASH_ALIAS
1332# define EXECCMD (builtincmd + 9)
1333# else
1334# define EXECCMD (builtincmd + 8)
1335# endif
1336# else /* ! JOBS */
1337# ifdef CONFIG_ASH_ALIAS
1338# define EXECCMD (builtincmd + 8)
1339# else
1340# define EXECCMD (builtincmd + 7)
1341# endif
1342# endif /* JOBS */
1343#endif /* CONFIG_ASH_CMDCMD */
1344
1345#define BUILTIN_NOSPEC "0"
1346#define BUILTIN_SPECIAL "1"
1347#define BUILTIN_REGULAR "2"
1348#define BUILTIN_SPEC_REG "3"
1349#define BUILTIN_ASSIGN "4"
1350#define BUILTIN_SPEC_ASSG "5"
1351#define BUILTIN_REG_ASSG "6"
1352#define BUILTIN_SPEC_REG_ASSG "7"
1353
1354#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1355#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
Paul Foxc3850c82005-07-20 18:23:39 +00001356#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001357
1358static const struct builtincmd builtincmd[] = {
1359 { BUILTIN_SPEC_REG ".", dotcmd },
1360 { BUILTIN_SPEC_REG ":", truecmd },
1361#ifdef CONFIG_ASH_ALIAS
1362 { BUILTIN_REG_ASSG "alias", aliascmd },
1363#endif
1364#ifdef JOBS
1365 { BUILTIN_REGULAR "bg", bgcmd },
1366#endif
1367 { BUILTIN_SPEC_REG "break", breakcmd },
1368 { BUILTIN_REGULAR "cd", cdcmd },
1369 { BUILTIN_NOSPEC "chdir", cdcmd },
1370#ifdef CONFIG_ASH_CMDCMD
1371 { BUILTIN_REGULAR "command", commandcmd },
1372#endif
1373 { BUILTIN_SPEC_REG "continue", breakcmd },
1374 { BUILTIN_SPEC_REG "eval", evalcmd },
1375 { BUILTIN_SPEC_REG "exec", execcmd },
1376 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001377 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1378 { BUILTIN_REGULAR "false", falsecmd },
1379#ifdef JOBS
1380 { BUILTIN_REGULAR "fg", fgcmd },
1381#endif
1382#ifdef CONFIG_ASH_GETOPTS
1383 { BUILTIN_REGULAR "getopts", getoptscmd },
1384#endif
1385 { BUILTIN_NOSPEC "hash", hashcmd },
1386#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1387 { BUILTIN_NOSPEC "help", helpcmd },
1388#endif
1389#ifdef JOBS
1390 { BUILTIN_REGULAR "jobs", jobscmd },
1391 { BUILTIN_REGULAR "kill", killcmd },
1392#endif
1393#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001394 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001395#endif
1396 { BUILTIN_ASSIGN "local", localcmd },
1397 { BUILTIN_NOSPEC "pwd", pwdcmd },
1398 { BUILTIN_REGULAR "read", readcmd },
1399 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1400 { BUILTIN_SPEC_REG "return", returncmd },
1401 { BUILTIN_SPEC_REG "set", setcmd },
1402 { BUILTIN_SPEC_REG "shift", shiftcmd },
1403 { BUILTIN_SPEC_REG "times", timescmd },
1404 { BUILTIN_SPEC_REG "trap", trapcmd },
1405 { BUILTIN_REGULAR "true", truecmd },
1406 { BUILTIN_NOSPEC "type", typecmd },
1407 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1408 { BUILTIN_REGULAR "umask", umaskcmd },
1409#ifdef CONFIG_ASH_ALIAS
1410 { BUILTIN_REGULAR "unalias", unaliascmd },
1411#endif
1412 { BUILTIN_SPEC_REG "unset", unsetcmd },
1413 { BUILTIN_REGULAR "wait", waitcmd },
1414};
1415
1416#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1417
1418
1419
1420struct cmdentry {
1421 int cmdtype;
1422 union param {
1423 int index;
1424 const struct builtincmd *cmd;
1425 struct funcnode *func;
1426 } u;
1427};
1428
1429
1430/* action to find_command() */
1431#define DO_ERR 0x01 /* prints errors */
1432#define DO_ABS 0x02 /* checks absolute paths */
1433#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1434#define DO_ALTPATH 0x08 /* using alternate path */
1435#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1436
1437static const char *pathopt; /* set by padvance */
1438
1439static void shellexec(char **, const char *, int)
1440 __attribute__((__noreturn__));
1441static char *padvance(const char **, const char *);
1442static void find_command(char *, struct cmdentry *, int, const char *);
1443static struct builtincmd *find_builtin(const char *);
1444static void hashcd(void);
1445static void changepath(const char *);
1446static void defun(char *, union node *);
1447static void unsetfunc(const char *);
1448
Eric Andersened9ecf72004-06-22 08:29:45 +00001449#ifdef CONFIG_ASH_MATH_SUPPORT_64
1450typedef int64_t arith_t;
1451#else
1452typedef long arith_t;
1453#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001454
1455#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001456static arith_t dash_arith(const char *);
1457static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001458#endif
1459
Eric Andersen16767e22004-03-16 05:14:10 +00001460#ifdef CONFIG_ASH_RANDOM_SUPPORT
1461static unsigned long rseed;
1462static void change_random(const char *);
1463# ifndef DYNAMIC_VAR
1464# define DYNAMIC_VAR
1465# endif
1466#endif
1467
Eric Andersenc470f442003-07-28 09:56:35 +00001468/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1469
1470static void reset(void);
1471
1472/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001473
1474/*
1475 * Shell variables.
1476 */
1477
1478/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001479#define VEXPORT 0x01 /* variable is exported */
1480#define VREADONLY 0x02 /* variable cannot be modified */
1481#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1482#define VTEXTFIXED 0x08 /* text is statically allocated */
1483#define VSTACK 0x10 /* text is allocated on the stack */
1484#define VUNSET 0x20 /* the variable is not set */
1485#define VNOFUNC 0x40 /* don't call the callback function */
1486#define VNOSET 0x80 /* do not set variable - just readonly test */
1487#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001488#ifdef DYNAMIC_VAR
1489# define VDYNAMIC 0x200 /* dynamic variable */
1490# else
1491# define VDYNAMIC 0
1492#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001493
1494struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001495 struct var *next; /* next entry in hash list */
1496 int flags; /* flags are defined above */
1497 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001498 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001499 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001500};
1501
1502struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001503 struct localvar *next; /* next local variable in list */
1504 struct var *vp; /* the variable that was made local */
1505 int flags; /* saved flags */
1506 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001507};
1508
1509
Eric Andersen2870d962001-07-02 17:27:21 +00001510static struct localvar *localvars;
1511
Eric Andersenc470f442003-07-28 09:56:35 +00001512/*
1513 * Shell variables.
1514 */
1515
1516#ifdef CONFIG_ASH_GETOPTS
1517static void getoptsreset(const char *);
1518#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001519
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001520#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001521#include <locale.h>
1522static void change_lc_all(const char *value);
1523static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001524#endif
1525
Eric Andersenef02f822004-03-11 13:34:24 +00001526
Eric Andersen2870d962001-07-02 17:27:21 +00001527#define VTABSIZE 39
1528
Eric Andersen90898442003-08-06 11:20:52 +00001529static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001530#ifdef IFS_BROKEN
1531static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001532#define defifs (defifsvar + 4)
1533#else
Eric Andersenc470f442003-07-28 09:56:35 +00001534static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001535#endif
1536
Eric Andersenc470f442003-07-28 09:56:35 +00001537
1538static struct var varinit[] = {
1539#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001540 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001541#else
Eric Andersen16767e22004-03-16 05:14:10 +00001542 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001543#endif
1544
1545#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001546 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1547 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001548#endif
1549
Eric Andersen16767e22004-03-16 05:14:10 +00001550 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1551 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1552 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1553 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001554#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001555 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1556#endif
1557#ifdef CONFIG_ASH_RANDOM_SUPPORT
1558 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001559#endif
1560#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001561 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1562 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001563#endif
1564#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001565 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001566#endif
1567};
1568
1569#define vifs varinit[0]
1570#ifdef CONFIG_ASH_MAIL
1571#define vmail (&vifs)[1]
1572#define vmpath (&vmail)[1]
1573#else
1574#define vmpath vifs
1575#endif
1576#define vpath (&vmpath)[1]
1577#define vps1 (&vpath)[1]
1578#define vps2 (&vps1)[1]
1579#define vps4 (&vps2)[1]
1580#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001581#ifdef CONFIG_ASH_GETOPTS
1582#define vrandom (&voptind)[1]
1583#else
1584#define vrandom (&vps4)[1]
1585#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001586#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001587
1588/*
1589 * The following macros access the values of the above variables.
1590 * They have to skip over the name. They return the null string
1591 * for unset variables.
1592 */
1593
1594#define ifsval() (vifs.text + 4)
1595#define ifsset() ((vifs.flags & VUNSET) == 0)
1596#define mailval() (vmail.text + 5)
1597#define mpathval() (vmpath.text + 9)
1598#define pathval() (vpath.text + 5)
1599#define ps1val() (vps1.text + 4)
1600#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001601#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001602#define optindval() (voptind.text + 7)
1603
1604#define mpathset() ((vmpath.flags & VUNSET) == 0)
1605
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001606static void setvar(const char *, const char *, int);
1607static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001608static void listsetvar(struct strlist *, int);
1609static char *lookupvar(const char *);
1610static char *bltinlookup(const char *);
1611static char **listvars(int, int, char ***);
1612#define environment() listvars(VEXPORT, VUNSET, 0)
1613static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001614static void poplocalvars(void);
1615static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001616#ifdef CONFIG_ASH_GETOPTS
1617static int setvarsafe(const char *, const char *, int);
1618#endif
1619static int varcmp(const char *, const char *);
1620static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001621
1622
Eric Andersenc470f442003-07-28 09:56:35 +00001623static inline int varequal(const char *a, const char *b) {
1624 return !varcmp(a, b);
1625}
Eric Andersen2870d962001-07-02 17:27:21 +00001626
1627
Eric Andersenc470f442003-07-28 09:56:35 +00001628static int loopnest; /* current loop nesting level */
1629
Eric Andersenc470f442003-07-28 09:56:35 +00001630/*
1631 * The parsefile structure pointed to by the global variable parsefile
1632 * contains information about the current file being read.
1633 */
1634
1635
1636struct redirtab {
1637 struct redirtab *next;
1638 int renamed[10];
1639 int nullredirs;
1640};
1641
1642static struct redirtab *redirlist;
1643static int nullredirs;
1644
1645extern char **environ;
1646
1647/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1648
1649
1650static void outstr(const char *, FILE *);
1651static void outcslow(int, FILE *);
1652static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001653static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001654static int out1fmt(const char *, ...)
1655 __attribute__((__format__(__printf__,1,2)));
1656static int fmtstr(char *, size_t, const char *, ...)
1657 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001658
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001659static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001660
Eric Andersenc470f442003-07-28 09:56:35 +00001661
1662static void out1str(const char *p)
1663{
1664 outstr(p, stdout);
1665}
1666
1667static void out2str(const char *p)
1668{
1669 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001670 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001671}
1672
1673/*
1674 * Initialization code.
1675 */
1676
1677/*
1678 * This routine initializes the builtin variables.
1679 */
1680
1681static inline void
1682initvar(void)
1683{
1684 struct var *vp;
1685 struct var *end;
1686 struct var **vpp;
1687
1688 /*
1689 * PS1 depends on uid
1690 */
1691#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1692 vps1.text = "PS1=\\w \\$ ";
1693#else
1694 if (!geteuid())
1695 vps1.text = "PS1=# ";
1696#endif
1697 vp = varinit;
1698 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1699 do {
1700 vpp = hashvar(vp->text);
1701 vp->next = *vpp;
1702 *vpp = vp;
1703 } while (++vp < end);
1704}
1705
1706static inline void
1707init(void)
1708{
1709
1710 /* from input.c: */
1711 {
1712 basepf.nextc = basepf.buf = basebuf;
1713 }
1714
1715 /* from trap.c: */
1716 {
1717 signal(SIGCHLD, SIG_DFL);
1718 }
1719
1720 /* from var.c: */
1721 {
1722 char **envp;
1723 char ppid[32];
1724
1725 initvar();
1726 for (envp = environ ; *envp ; envp++) {
1727 if (strchr(*envp, '=')) {
1728 setvareq(*envp, VEXPORT|VTEXTFIXED);
1729 }
1730 }
1731
1732 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1733 setvar("PPID", ppid, 0);
1734 setpwd(0, 0);
1735 }
1736}
1737
1738/* PEOF (the end of file marker) */
1739
1740/*
1741 * The input line number. Input.c just defines this variable, and saves
1742 * and restores it when files are pushed and popped. The user of this
1743 * package must set its value.
1744 */
1745
1746static int pgetc(void);
1747static int pgetc2(void);
1748static int preadbuffer(void);
1749static void pungetc(void);
1750static void pushstring(char *, void *);
1751static void popstring(void);
1752static void setinputfile(const char *, int);
1753static void setinputfd(int, int);
1754static void setinputstring(char *);
1755static void popfile(void);
1756static void popallfiles(void);
1757static void closescript(void);
1758
1759
1760/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1761
1762
1763/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1764#define FORK_FG 0
1765#define FORK_BG 1
1766#define FORK_NOJOB 2
1767
1768/* mode flags for showjob(s) */
1769#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1770#define SHOW_PID 0x04 /* include process pid */
1771#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1772
1773
1774/*
1775 * A job structure contains information about a job. A job is either a
1776 * single process or a set of processes contained in a pipeline. In the
1777 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1778 * array of pids.
1779 */
1780
1781struct procstat {
1782 pid_t pid; /* process id */
1783 int status; /* last process status from wait() */
1784 char *cmd; /* text of command being run */
1785};
1786
1787struct job {
1788 struct procstat ps0; /* status of process */
1789 struct procstat *ps; /* status or processes when more than one */
1790#if JOBS
1791 int stopstatus; /* status of a stopped job */
1792#endif
1793 uint32_t
1794 nprocs: 16, /* number of processes */
1795 state: 8,
1796#define JOBRUNNING 0 /* at least one proc running */
1797#define JOBSTOPPED 1 /* all procs are stopped */
1798#define JOBDONE 2 /* all procs are completed */
1799#if JOBS
1800 sigint: 1, /* job was killed by SIGINT */
1801 jobctl: 1, /* job running under job control */
1802#endif
1803 waited: 1, /* true if this entry has been waited for */
1804 used: 1, /* true if this entry is in used */
1805 changed: 1; /* true if status has changed */
1806 struct job *prev_job; /* previous job */
1807};
1808
1809static pid_t backgndpid; /* pid of last background process */
1810static int job_warning; /* user was warned about stopped jobs */
1811#if JOBS
1812static int jobctl; /* true if doing job control */
1813#endif
1814
1815static struct job *makejob(union node *, int);
1816static int forkshell(struct job *, union node *, int);
1817static int waitforjob(struct job *);
1818static int stoppedjobs(void);
1819
1820#if ! JOBS
1821#define setjobctl(on) /* do nothing */
1822#else
1823static void setjobctl(int);
1824static void showjobs(FILE *, int);
1825#endif
1826
1827/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1828
1829
1830/* pid of main shell */
1831static int rootpid;
1832/* true if we aren't a child of the main shell */
1833static int rootshell;
1834
1835static void readcmdfile(char *);
1836static void cmdloop(int);
1837
1838/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1839
1840
1841struct stackmark {
1842 struct stack_block *stackp;
1843 char *stacknxt;
1844 size_t stacknleft;
1845 struct stackmark *marknext;
1846};
1847
1848/* minimum size of a block */
1849#define MINSIZE SHELL_ALIGN(504)
1850
1851struct stack_block {
1852 struct stack_block *prev;
1853 char space[MINSIZE];
1854};
1855
1856static struct stack_block stackbase;
1857static struct stack_block *stackp = &stackbase;
1858static struct stackmark *markp;
1859static char *stacknxt = stackbase.space;
1860static size_t stacknleft = MINSIZE;
1861static char *sstrend = stackbase.space + MINSIZE;
1862static int herefd = -1;
1863
1864
1865static pointer ckmalloc(size_t);
1866static pointer ckrealloc(pointer, size_t);
1867static char *savestr(const char *);
1868static pointer stalloc(size_t);
1869static void stunalloc(pointer);
1870static void setstackmark(struct stackmark *);
1871static void popstackmark(struct stackmark *);
1872static void growstackblock(void);
1873static void *growstackstr(void);
1874static char *makestrspace(size_t, char *);
1875static char *stnputs(const char *, size_t, char *);
1876static char *stputs(const char *, char *);
1877
1878
1879static inline char *_STPUTC(char c, char *p) {
1880 if (p == sstrend)
1881 p = growstackstr();
1882 *p++ = c;
1883 return p;
1884}
1885
1886#define stackblock() ((void *)stacknxt)
1887#define stackblocksize() stacknleft
1888#define STARTSTACKSTR(p) ((p) = stackblock())
1889#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1890#define CHECKSTRSPACE(n, p) \
1891 ({ \
1892 char *q = (p); \
1893 size_t l = (n); \
1894 size_t m = sstrend - q; \
1895 if (l > m) \
1896 (p) = makestrspace(l, q); \
1897 0; \
1898 })
1899#define USTPUTC(c, p) (*p++ = (c))
1900#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1901#define STUNPUTC(p) (--p)
1902#define STTOPC(p) p[-1]
1903#define STADJUST(amount, p) (p += (amount))
1904
1905#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1906#define ungrabstackstr(s, p) stunalloc((s))
1907#define stackstrend() ((void *)sstrend)
1908
1909#define ckfree(p) free((pointer)(p))
1910
1911/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1912
1913
1914#define DOLATSTRLEN 4
1915
1916static char *prefix(const char *, const char *);
1917static int number(const char *);
1918static int is_number(const char *);
1919static char *single_quote(const char *);
1920static char *sstrdup(const char *);
1921
1922#define equal(s1, s2) (strcmp(s1, s2) == 0)
1923#define scopy(s1, s2) ((void)strcpy(s2, s1))
1924
1925/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1926
1927struct shparam {
1928 int nparam; /* # of positional parameters (without $0) */
1929 unsigned char malloc; /* if parameter list dynamically allocated */
1930 char **p; /* parameter list */
1931#ifdef CONFIG_ASH_GETOPTS
1932 int optind; /* next parameter to be processed by getopts */
1933 int optoff; /* used by getopts */
1934#endif
1935};
1936
1937
1938#define eflag optlist[0]
1939#define fflag optlist[1]
1940#define Iflag optlist[2]
1941#define iflag optlist[3]
1942#define mflag optlist[4]
1943#define nflag optlist[5]
1944#define sflag optlist[6]
1945#define xflag optlist[7]
1946#define vflag optlist[8]
1947#define Cflag optlist[9]
1948#define aflag optlist[10]
1949#define bflag optlist[11]
1950#define uflag optlist[12]
1951#define qflag optlist[13]
1952
1953#ifdef DEBUG
1954#define nolog optlist[14]
1955#define debug optlist[15]
1956#define NOPTS 16
1957#else
1958#define NOPTS 14
1959#endif
1960
1961/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1962
1963
1964static const char *const optletters_optnames[NOPTS] = {
1965 "e" "errexit",
1966 "f" "noglob",
1967 "I" "ignoreeof",
1968 "i" "interactive",
1969 "m" "monitor",
1970 "n" "noexec",
1971 "s" "stdin",
1972 "x" "xtrace",
1973 "v" "verbose",
1974 "C" "noclobber",
1975 "a" "allexport",
1976 "b" "notify",
1977 "u" "nounset",
1978 "q" "quietprofile",
1979#ifdef DEBUG
1980 "\0" "nolog",
1981 "\0" "debug",
1982#endif
1983};
1984
1985#define optletters(n) optletters_optnames[(n)][0]
1986#define optnames(n) (&optletters_optnames[(n)][1])
1987
1988
1989static char optlist[NOPTS];
1990
1991
1992static char *arg0; /* value of $0 */
1993static struct shparam shellparam; /* $@ current positional parameters */
1994static char **argptr; /* argument list for builtin commands */
1995static char *optionarg; /* set by nextopt (like getopt) */
1996static char *optptr; /* used by nextopt */
1997
1998static char *minusc; /* argument to -c option */
1999
2000
2001static void procargs(int, char **);
2002static void optschanged(void);
2003static void setparam(char **);
2004static void freeparam(volatile struct shparam *);
2005static int shiftcmd(int, char **);
2006static int setcmd(int, char **);
2007static int nextopt(const char *);
2008
2009/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
2010
2011/* flags passed to redirect */
2012#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002013#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00002014
2015union node;
2016static void redirect(union node *, int);
2017static void popredir(int);
2018static void clearredir(int);
2019static int copyfd(int, int);
2020static int redirectsafe(union node *, int);
2021
2022/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2023
2024
2025#ifdef DEBUG
2026static void showtree(union node *);
2027static void trace(const char *, ...);
2028static void tracev(const char *, va_list);
2029static void trargs(char **);
2030static void trputc(int);
2031static void trputs(const char *);
2032static void opentrace(void);
2033#endif
2034
2035/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2036
2037
2038/* trap handler commands */
2039static char *trap[NSIG];
2040/* current value of signal */
2041static char sigmode[NSIG - 1];
2042/* indicates specified signal received */
2043static char gotsig[NSIG - 1];
2044
2045static void clear_traps(void);
2046static void setsignal(int);
2047static void ignoresig(int);
2048static void onsig(int);
2049static void dotrap(void);
2050static void setinteractive(int);
2051static void exitshell(void) __attribute__((__noreturn__));
2052static int decode_signal(const char *, int);
2053
2054/*
2055 * This routine is called when an error or an interrupt occurs in an
2056 * interactive shell and control is returned to the main command loop.
2057 */
2058
2059static void
2060reset(void)
2061{
2062 /* from eval.c: */
2063 {
2064 evalskip = 0;
2065 loopnest = 0;
2066 funcnest = 0;
2067 }
2068
2069 /* from input.c: */
2070 {
2071 parselleft = parsenleft = 0; /* clear input buffer */
2072 popallfiles();
2073 }
2074
2075 /* from parser.c: */
2076 {
2077 tokpushback = 0;
2078 checkkwd = 0;
2079 }
2080
2081 /* from redir.c: */
2082 {
2083 clearredir(0);
2084 }
2085
2086}
2087
2088#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002089static struct alias *atab[ATABSIZE];
2090
Eric Andersenc470f442003-07-28 09:56:35 +00002091static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002092static struct alias *freealias(struct alias *);
2093static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002094
Eric Andersenc470f442003-07-28 09:56:35 +00002095static void
2096setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002097{
2098 struct alias *ap, **app;
2099
2100 app = __lookupalias(name);
2101 ap = *app;
2102 INTOFF;
2103 if (ap) {
2104 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002105 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002106 }
Eric Andersenc470f442003-07-28 09:56:35 +00002107 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002108 ap->flag &= ~ALIASDEAD;
2109 } else {
2110 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002111 ap = ckmalloc(sizeof (struct alias));
2112 ap->name = savestr(name);
2113 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002114 ap->flag = 0;
2115 ap->next = 0;
2116 *app = ap;
2117 }
2118 INTON;
2119}
2120
Eric Andersenc470f442003-07-28 09:56:35 +00002121static int
2122unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002123{
Eric Andersencb57d552001-06-28 07:25:16 +00002124 struct alias **app;
2125
2126 app = __lookupalias(name);
2127
2128 if (*app) {
2129 INTOFF;
2130 *app = freealias(*app);
2131 INTON;
2132 return (0);
2133 }
2134
2135 return (1);
2136}
2137
Eric Andersenc470f442003-07-28 09:56:35 +00002138static void
2139rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002140{
Eric Andersencb57d552001-06-28 07:25:16 +00002141 struct alias *ap, **app;
2142 int i;
2143
2144 INTOFF;
2145 for (i = 0; i < ATABSIZE; i++) {
2146 app = &atab[i];
2147 for (ap = *app; ap; ap = *app) {
2148 *app = freealias(*app);
2149 if (ap == *app) {
2150 app = &ap->next;
2151 }
2152 }
2153 }
2154 INTON;
2155}
2156
Eric Andersenc470f442003-07-28 09:56:35 +00002157static struct alias *
2158lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002159{
Eric Andersenc470f442003-07-28 09:56:35 +00002160 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002161
Eric Andersenc470f442003-07-28 09:56:35 +00002162 if (check && ap && (ap->flag & ALIASINUSE))
2163 return (NULL);
2164 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002165}
2166
Eric Andersencb57d552001-06-28 07:25:16 +00002167/*
2168 * TODO - sort output
2169 */
Eric Andersenc470f442003-07-28 09:56:35 +00002170static int
2171aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002172{
2173 char *n, *v;
2174 int ret = 0;
2175 struct alias *ap;
2176
2177 if (argc == 1) {
2178 int i;
2179
2180 for (i = 0; i < ATABSIZE; i++)
2181 for (ap = atab[i]; ap; ap = ap->next) {
2182 printalias(ap);
2183 }
2184 return (0);
2185 }
2186 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002187 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002188 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002189 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002190 ret = 1;
2191 } else
2192 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002193 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002194 *v++ = '\0';
2195 setalias(n, v);
2196 }
2197 }
2198
2199 return (ret);
2200}
2201
Eric Andersenc470f442003-07-28 09:56:35 +00002202static int
2203unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002204{
2205 int i;
2206
2207 while ((i = nextopt("a")) != '\0') {
2208 if (i == 'a') {
2209 rmaliases();
2210 return (0);
2211 }
2212 }
2213 for (i = 0; *argptr; argptr++) {
2214 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002215 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002216 i = 1;
2217 }
2218 }
2219
2220 return (i);
2221}
2222
Eric Andersenc470f442003-07-28 09:56:35 +00002223static struct alias *
2224freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002225 struct alias *next;
2226
2227 if (ap->flag & ALIASINUSE) {
2228 ap->flag |= ALIASDEAD;
2229 return ap;
2230 }
2231
2232 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002233 ckfree(ap->name);
2234 ckfree(ap->val);
2235 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002236 return next;
2237}
2238
Eric Andersenc470f442003-07-28 09:56:35 +00002239static void
2240printalias(const struct alias *ap) {
2241 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2242}
Eric Andersencb57d552001-06-28 07:25:16 +00002243
Eric Andersenc470f442003-07-28 09:56:35 +00002244static struct alias **
2245__lookupalias(const char *name) {
2246 unsigned int hashval;
2247 struct alias **app;
2248 const char *p;
2249 unsigned int ch;
2250
2251 p = name;
2252
2253 ch = (unsigned char)*p;
2254 hashval = ch << 4;
2255 while (ch) {
2256 hashval += ch;
2257 ch = (unsigned char)*++p;
2258 }
2259 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002260
2261 for (; *app; app = &(*app)->next) {
2262 if (equal(name, (*app)->name)) {
2263 break;
2264 }
2265 }
2266
2267 return app;
2268}
Eric Andersenc470f442003-07-28 09:56:35 +00002269#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002270
Eric Andersencb57d552001-06-28 07:25:16 +00002271
Eric Andersenc470f442003-07-28 09:56:35 +00002272/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00002273
Eric Andersencb57d552001-06-28 07:25:16 +00002274/*
Eric Andersenc470f442003-07-28 09:56:35 +00002275 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002276 */
2277
Eric Andersenc470f442003-07-28 09:56:35 +00002278#define CD_PHYSICAL 1
2279#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002280
Eric Andersenc470f442003-07-28 09:56:35 +00002281static int docd(const char *, int);
2282static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002283
Eric Andersenc470f442003-07-28 09:56:35 +00002284static char *curdir = nullstr; /* current working directory */
2285static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002286
Eric Andersenc470f442003-07-28 09:56:35 +00002287static int
2288cdopt(void)
2289{
2290 int flags = 0;
2291 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002292
Eric Andersenc470f442003-07-28 09:56:35 +00002293 j = 'L';
2294 while ((i = nextopt("LP"))) {
2295 if (i != j) {
2296 flags ^= CD_PHYSICAL;
2297 j = i;
2298 }
2299 }
Eric Andersencb57d552001-06-28 07:25:16 +00002300
Eric Andersenc470f442003-07-28 09:56:35 +00002301 return flags;
2302}
Eric Andersen2870d962001-07-02 17:27:21 +00002303
Eric Andersenc470f442003-07-28 09:56:35 +00002304static int
2305cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002306{
2307 const char *dest;
2308 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002309 const char *p;
2310 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002311 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002312 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002313
Eric Andersenc470f442003-07-28 09:56:35 +00002314 flags = cdopt();
2315 dest = *argptr;
2316 if (!dest)
2317 dest = bltinlookup(homestr);
2318 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002319 dest = bltinlookup("OLDPWD");
Eric Andersenc00e11d2004-10-08 08:14:58 +00002320 if ( !dest ) goto out;
Eric Andersenc470f442003-07-28 09:56:35 +00002321 flags |= CD_PRINT;
2322 goto step7;
Eric Andersencb57d552001-06-28 07:25:16 +00002323 }
Eric Andersenc470f442003-07-28 09:56:35 +00002324 if (!dest)
2325 dest = nullstr;
2326 if (*dest == '/')
2327 goto step7;
2328 if (*dest == '.') {
2329 c = dest[1];
2330dotdot:
2331 switch (c) {
2332 case '\0':
2333 case '/':
2334 goto step6;
2335 case '.':
2336 c = dest[2];
2337 if (c != '.')
2338 goto dotdot;
2339 }
2340 }
2341 if (!*dest)
2342 dest = ".";
2343 if (!(path = bltinlookup("CDPATH"))) {
2344step6:
2345step7:
2346 p = dest;
2347 goto docd;
2348 }
2349 do {
2350 c = *path;
2351 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002352 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002353 if (c && c != ':')
2354 flags |= CD_PRINT;
2355docd:
2356 if (!docd(p, flags))
2357 goto out;
2358 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002359 }
Eric Andersenc470f442003-07-28 09:56:35 +00002360 } while (path);
Eric Andersencb57d552001-06-28 07:25:16 +00002361 error("can't cd to %s", dest);
2362 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002363out:
2364 if (flags & CD_PRINT)
2365 out1fmt(snlfmt, curdir);
2366 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002367}
2368
2369
2370/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002371 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002372 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002373 */
2374
Eric Andersenc470f442003-07-28 09:56:35 +00002375static inline const char *
2376updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002377{
Eric Andersenc470f442003-07-28 09:56:35 +00002378 char *new;
2379 char *p;
2380 char *cdcomppath;
2381 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002382
Eric Andersenc470f442003-07-28 09:56:35 +00002383 cdcomppath = sstrdup(dir);
2384 STARTSTACKSTR(new);
2385 if (*dir != '/') {
2386 if (curdir == nullstr)
2387 return 0;
2388 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002389 }
Eric Andersenc470f442003-07-28 09:56:35 +00002390 new = makestrspace(strlen(dir) + 2, new);
2391 lim = stackblock() + 1;
2392 if (*dir != '/') {
2393 if (new[-1] != '/')
2394 USTPUTC('/', new);
2395 if (new > lim && *lim == '/')
2396 lim++;
2397 } else {
2398 USTPUTC('/', new);
2399 cdcomppath++;
2400 if (dir[1] == '/' && dir[2] != '/') {
2401 USTPUTC('/', new);
2402 cdcomppath++;
2403 lim++;
2404 }
2405 }
2406 p = strtok(cdcomppath, "/");
2407 while (p) {
2408 switch(*p) {
2409 case '.':
2410 if (p[1] == '.' && p[2] == '\0') {
2411 while (new > lim) {
2412 STUNPUTC(new);
2413 if (new[-1] == '/')
2414 break;
2415 }
2416 break;
2417 } else if (p[1] == '\0')
2418 break;
2419 /* fall through */
2420 default:
2421 new = stputs(p, new);
2422 USTPUTC('/', new);
2423 }
2424 p = strtok(0, "/");
2425 }
2426 if (new > lim)
2427 STUNPUTC(new);
2428 *new = 0;
2429 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002430}
2431
2432/*
Eric Andersenc470f442003-07-28 09:56:35 +00002433 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2434 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002435 */
2436
Eric Andersenc470f442003-07-28 09:56:35 +00002437static int
2438docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002439{
Eric Andersenc470f442003-07-28 09:56:35 +00002440 const char *dir = 0;
2441 int err;
2442
2443 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2444
Eric Andersencb57d552001-06-28 07:25:16 +00002445 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002446 if (!(flags & CD_PHYSICAL)) {
2447 dir = updatepwd(dest);
2448 if (dir)
2449 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002450 }
Eric Andersenc470f442003-07-28 09:56:35 +00002451 err = chdir(dest);
2452 if (err)
2453 goto out;
2454 setpwd(dir, 1);
2455 hashcd();
2456out:
Eric Andersencb57d552001-06-28 07:25:16 +00002457 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002458 return err;
2459}
2460
2461/*
2462 * Find out what the current directory is. If we already know the current
2463 * directory, this routine returns immediately.
2464 */
2465static inline char *
2466getpwd(void)
2467{
2468 char *dir = getcwd(0, 0);
2469 return dir ? dir : nullstr;
2470}
2471
2472static int
2473pwdcmd(int argc, char **argv)
2474{
2475 int flags;
2476 const char *dir = curdir;
2477
2478 flags = cdopt();
2479 if (flags) {
2480 if (physdir == nullstr)
2481 setpwd(dir, 0);
2482 dir = physdir;
2483 }
2484 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002485 return 0;
2486}
2487
Eric Andersenc470f442003-07-28 09:56:35 +00002488static void
2489setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002490{
Eric Andersenc470f442003-07-28 09:56:35 +00002491 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002492
Eric Andersenc470f442003-07-28 09:56:35 +00002493 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002494
Eric Andersencb57d552001-06-28 07:25:16 +00002495 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002496 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002497 }
2498 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002499 if (physdir != nullstr) {
2500 if (physdir != oldcur)
2501 free(physdir);
2502 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002503 }
Eric Andersenc470f442003-07-28 09:56:35 +00002504 if (oldcur == val || !val) {
2505 char *s = getpwd();
2506 physdir = s;
2507 if (!val)
2508 dir = s;
2509 } else
2510 dir = savestr(val);
2511 if (oldcur != dir && oldcur != nullstr) {
2512 free(oldcur);
2513 }
2514 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002515 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002516 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002517}
2518
Eric Andersenc470f442003-07-28 09:56:35 +00002519/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2520
Eric Andersencb57d552001-06-28 07:25:16 +00002521/*
2522 * Errors and exceptions.
2523 */
2524
2525/*
2526 * Code to handle exceptions in C.
2527 */
2528
Eric Andersen2870d962001-07-02 17:27:21 +00002529
Eric Andersencb57d552001-06-28 07:25:16 +00002530
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002531static void exverror(int, const char *, va_list)
Eric Andersenc470f442003-07-28 09:56:35 +00002532 __attribute__((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00002533
2534/*
2535 * Called to raise an exception. Since C doesn't include exceptions, we
2536 * just do a longjmp to the exception handler. The type of exception is
2537 * stored in the global variable "exception".
2538 */
2539
Eric Andersenc470f442003-07-28 09:56:35 +00002540static void
2541exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002542{
2543#ifdef DEBUG
2544 if (handler == NULL)
2545 abort();
2546#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002547 INTOFF;
2548
Eric Andersencb57d552001-06-28 07:25:16 +00002549 exception = e;
2550 longjmp(handler->loc, 1);
2551}
2552
2553
2554/*
2555 * Called from trap.c when a SIGINT is received. (If the user specifies
2556 * that SIGINT is to be trapped or ignored using the trap builtin, then
2557 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002558 * are held using the INTOFF macro. (The test for iflag is just
2559 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002560 */
2561
Eric Andersenc470f442003-07-28 09:56:35 +00002562static void
2563onint(void) {
2564 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002565
Eric Andersencb57d552001-06-28 07:25:16 +00002566 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002567 sigsetmask(0);
2568 i = EXSIG;
2569 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2570 if (!(rootshell && iflag)) {
2571 signal(SIGINT, SIG_DFL);
2572 raise(SIGINT);
2573 }
2574 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002575 }
Eric Andersenc470f442003-07-28 09:56:35 +00002576 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002577 /* NOTREACHED */
2578}
2579
Eric Andersenc470f442003-07-28 09:56:35 +00002580static void
2581exvwarning(const char *msg, va_list ap)
2582{
2583 FILE *errs;
2584 const char *name;
2585 const char *fmt;
Eric Andersencb57d552001-06-28 07:25:16 +00002586
Eric Andersenc470f442003-07-28 09:56:35 +00002587 errs = stderr;
2588 name = arg0;
2589 fmt = "%s: ";
2590 if (commandname) {
2591 name = commandname;
2592 fmt = "%s: %d: ";
2593 }
2594 fprintf(errs, fmt, name, startlinno);
2595 vfprintf(errs, msg, ap);
2596 outcslow('\n', errs);
2597}
Eric Andersen2870d962001-07-02 17:27:21 +00002598
Eric Andersencb57d552001-06-28 07:25:16 +00002599/*
Eric Andersenc470f442003-07-28 09:56:35 +00002600 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002601 * is not NULL then error prints an error message using printf style
2602 * formatting. It then raises the error exception.
2603 */
Eric Andersenc470f442003-07-28 09:56:35 +00002604static void
2605exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002606{
Eric Andersencb57d552001-06-28 07:25:16 +00002607#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002608 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002609 TRACE(("exverror(%d, \"", cond));
2610 TRACEV((msg, ap));
2611 TRACE(("\") pid=%d\n", getpid()));
2612 } else
2613 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2614 if (msg)
2615#endif
2616 exvwarning(msg, ap);
2617
2618 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002619 exraise(cond);
2620 /* NOTREACHED */
2621}
2622
2623
Eric Andersenc470f442003-07-28 09:56:35 +00002624static void
2625error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002626{
Eric Andersencb57d552001-06-28 07:25:16 +00002627 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002628
Eric Andersencb57d552001-06-28 07:25:16 +00002629 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002630 exverror(EXERROR, msg, ap);
2631 /* NOTREACHED */
2632 va_end(ap);
2633}
2634
2635
Eric Andersenc470f442003-07-28 09:56:35 +00002636static void
2637exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002638{
Eric Andersencb57d552001-06-28 07:25:16 +00002639 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002640
Eric Andersencb57d552001-06-28 07:25:16 +00002641 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002642 exverror(cond, msg, ap);
2643 /* NOTREACHED */
2644 va_end(ap);
2645}
2646
Eric Andersencb57d552001-06-28 07:25:16 +00002647/*
Eric Andersenc470f442003-07-28 09:56:35 +00002648 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002649 */
2650
Eric Andersenc470f442003-07-28 09:56:35 +00002651static void
2652sh_warnx(const char *fmt, ...)
2653{
2654 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002655
Eric Andersenc470f442003-07-28 09:56:35 +00002656 va_start(ap, fmt);
2657 exvwarning(fmt, ap);
2658 va_end(ap);
2659}
Eric Andersen2870d962001-07-02 17:27:21 +00002660
Eric Andersencb57d552001-06-28 07:25:16 +00002661
2662/*
2663 * Return a string describing an error. The returned string may be a
2664 * pointer to a static buffer that will be overwritten on the next call.
2665 * Action describes the operation that got the error.
2666 */
2667
Eric Andersenc470f442003-07-28 09:56:35 +00002668static const char *
2669errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002670{
Eric Andersenc470f442003-07-28 09:56:35 +00002671 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002672
Eric Andersenc470f442003-07-28 09:56:35 +00002673 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002674 }
Eric Andersenc470f442003-07-28 09:56:35 +00002675 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002676}
2677
2678
Eric Andersenc470f442003-07-28 09:56:35 +00002679/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2680
2681/*
2682 * Evaluate a command.
2683 */
Eric Andersencb57d552001-06-28 07:25:16 +00002684
2685/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002686#define EV_EXIT 01 /* exit after evaluating tree */
2687#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2688#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002689
2690
Eric Andersenc470f442003-07-28 09:56:35 +00002691static void evalloop(union node *, int);
2692static void evalfor(union node *, int);
2693static void evalcase(union node *, int);
2694static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002695static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002696static void evalpipe(union node *, int);
2697static void evalcommand(union node *, int);
2698static int evalbltin(const struct builtincmd *, int, char **);
2699static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002700static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002701static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002702
Eric Andersenc470f442003-07-28 09:56:35 +00002703
2704static const struct builtincmd bltin = {
2705 "\0\0", bltincmd
2706};
2707
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002708
Eric Andersencb57d552001-06-28 07:25:16 +00002709/*
2710 * Called to reset things after an exception.
2711 */
2712
Eric Andersencb57d552001-06-28 07:25:16 +00002713/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002714 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002715 */
2716
Eric Andersenc470f442003-07-28 09:56:35 +00002717static int
2718evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002719{
Eric Andersen2870d962001-07-02 17:27:21 +00002720 char *p;
2721 char *concat;
2722 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002723
Eric Andersen2870d962001-07-02 17:27:21 +00002724 if (argc > 1) {
2725 p = argv[1];
2726 if (argc > 2) {
2727 STARTSTACKSTR(concat);
2728 ap = argv + 2;
2729 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002730 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002731 if ((p = *ap++) == NULL)
2732 break;
2733 STPUTC(' ', concat);
2734 }
2735 STPUTC('\0', concat);
2736 p = grabstackstr(concat);
2737 }
Glenn L McGrath76620622004-01-13 10:19:37 +00002738 evalstring(p);
Eric Andersen2870d962001-07-02 17:27:21 +00002739 }
2740 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002741}
2742
Eric Andersenc470f442003-07-28 09:56:35 +00002743
Eric Andersencb57d552001-06-28 07:25:16 +00002744/*
2745 * Execute a command or commands contained in a string.
2746 */
2747
Eric Andersenc470f442003-07-28 09:56:35 +00002748static void
Glenn L McGrath76620622004-01-13 10:19:37 +00002749evalstring(char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00002750{
Eric Andersencb57d552001-06-28 07:25:16 +00002751 union node *n;
2752 struct stackmark smark;
2753
2754 setstackmark(&smark);
2755 setinputstring(s);
Eric Andersenc470f442003-07-28 09:56:35 +00002756
Eric Andersencb57d552001-06-28 07:25:16 +00002757 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002758 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002759 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002760 if (evalskip)
2761 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002762 }
2763 popfile();
2764 popstackmark(&smark);
2765}
2766
Eric Andersenc470f442003-07-28 09:56:35 +00002767
Eric Andersen62483552001-07-10 06:09:16 +00002768
2769/*
Eric Andersenc470f442003-07-28 09:56:35 +00002770 * Evaluate a parse tree. The value is left in the global variable
2771 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002772 */
2773
Eric Andersenc470f442003-07-28 09:56:35 +00002774static void
2775evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002776{
Eric Andersenc470f442003-07-28 09:56:35 +00002777 int checkexit = 0;
2778 void (*evalfn)(union node *, int);
2779 unsigned isor;
2780 int status;
2781 if (n == NULL) {
2782 TRACE(("evaltree(NULL) called\n"));
2783 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002784 }
Eric Andersenc470f442003-07-28 09:56:35 +00002785 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2786 getpid(), n, n->type, flags));
2787 switch (n->type) {
2788 default:
2789#ifdef DEBUG
2790 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002791 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002792 break;
2793#endif
2794 case NNOT:
2795 evaltree(n->nnot.com, EV_TESTED);
2796 status = !exitstatus;
2797 goto setstatus;
2798 case NREDIR:
2799 expredir(n->nredir.redirect);
2800 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2801 if (!status) {
2802 evaltree(n->nredir.n, flags & EV_TESTED);
2803 status = exitstatus;
2804 }
2805 popredir(0);
2806 goto setstatus;
2807 case NCMD:
2808 evalfn = evalcommand;
2809checkexit:
2810 if (eflag && !(flags & EV_TESTED))
2811 checkexit = ~0;
2812 goto calleval;
2813 case NFOR:
2814 evalfn = evalfor;
2815 goto calleval;
2816 case NWHILE:
2817 case NUNTIL:
2818 evalfn = evalloop;
2819 goto calleval;
2820 case NSUBSHELL:
2821 case NBACKGND:
2822 evalfn = evalsubshell;
2823 goto calleval;
2824 case NPIPE:
2825 evalfn = evalpipe;
2826 goto checkexit;
2827 case NCASE:
2828 evalfn = evalcase;
2829 goto calleval;
2830 case NAND:
2831 case NOR:
2832 case NSEMI:
2833#if NAND + 1 != NOR
2834#error NAND + 1 != NOR
2835#endif
2836#if NOR + 1 != NSEMI
2837#error NOR + 1 != NSEMI
2838#endif
2839 isor = n->type - NAND;
2840 evaltree(
2841 n->nbinary.ch1,
2842 (flags | ((isor >> 1) - 1)) & EV_TESTED
2843 );
2844 if (!exitstatus == isor)
2845 break;
2846 if (!evalskip) {
2847 n = n->nbinary.ch2;
2848evaln:
2849 evalfn = evaltree;
2850calleval:
2851 evalfn(n, flags);
2852 break;
2853 }
2854 break;
2855 case NIF:
2856 evaltree(n->nif.test, EV_TESTED);
2857 if (evalskip)
2858 break;
2859 if (exitstatus == 0) {
2860 n = n->nif.ifpart;
2861 goto evaln;
2862 } else if (n->nif.elsepart) {
2863 n = n->nif.elsepart;
2864 goto evaln;
2865 }
2866 goto success;
2867 case NDEFUN:
2868 defun(n->narg.text, n->narg.next);
2869success:
2870 status = 0;
2871setstatus:
2872 exitstatus = status;
2873 break;
2874 }
2875out:
2876 if (pendingsigs)
2877 dotrap();
2878 if (flags & EV_EXIT || checkexit & exitstatus)
2879 exraise(EXEXIT);
Eric Andersen62483552001-07-10 06:09:16 +00002880}
2881
Eric Andersenc470f442003-07-28 09:56:35 +00002882
2883#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2884static
2885#endif
2886void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2887
2888
2889static void
2890evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002891{
2892 int status;
2893
2894 loopnest++;
2895 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002896 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002897 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002898 int i;
2899
Eric Andersencb57d552001-06-28 07:25:16 +00002900 evaltree(n->nbinary.ch1, EV_TESTED);
2901 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002902skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002903 evalskip = 0;
2904 continue;
2905 }
2906 if (evalskip == SKIPBREAK && --skipcount <= 0)
2907 evalskip = 0;
2908 break;
2909 }
Eric Andersenc470f442003-07-28 09:56:35 +00002910 i = exitstatus;
2911 if (n->type != NWHILE)
2912 i = !i;
2913 if (i != 0)
2914 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002915 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002916 status = exitstatus;
2917 if (evalskip)
2918 goto skipping;
2919 }
2920 loopnest--;
2921 exitstatus = status;
2922}
2923
Eric Andersenc470f442003-07-28 09:56:35 +00002924
2925
2926static void
2927evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002928{
2929 struct arglist arglist;
2930 union node *argp;
2931 struct strlist *sp;
2932 struct stackmark smark;
2933
2934 setstackmark(&smark);
2935 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002936 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002937 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002938 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002939 if (evalskip)
2940 goto out;
2941 }
2942 *arglist.lastp = NULL;
2943
2944 exitstatus = 0;
2945 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002946 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002947 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002948 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002949 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002950 if (evalskip) {
2951 if (evalskip == SKIPCONT && --skipcount <= 0) {
2952 evalskip = 0;
2953 continue;
2954 }
2955 if (evalskip == SKIPBREAK && --skipcount <= 0)
2956 evalskip = 0;
2957 break;
2958 }
2959 }
2960 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002961out:
Eric Andersencb57d552001-06-28 07:25:16 +00002962 popstackmark(&smark);
2963}
2964
Eric Andersenc470f442003-07-28 09:56:35 +00002965
2966
2967static void
2968evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002969{
2970 union node *cp;
2971 union node *patp;
2972 struct arglist arglist;
2973 struct stackmark smark;
2974
2975 setstackmark(&smark);
2976 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002977 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002978 exitstatus = 0;
2979 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2980 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002981 if (casematch(patp, arglist.list->text)) {
2982 if (evalskip == 0) {
2983 evaltree(cp->nclist.body, flags);
2984 }
2985 goto out;
2986 }
2987 }
2988 }
Eric Andersenc470f442003-07-28 09:56:35 +00002989out:
Eric Andersencb57d552001-06-28 07:25:16 +00002990 popstackmark(&smark);
2991}
2992
Eric Andersenc470f442003-07-28 09:56:35 +00002993
2994
2995/*
2996 * Kick off a subshell to evaluate a tree.
2997 */
2998
2999static void
3000evalsubshell(union node *n, int flags)
3001{
3002 struct job *jp;
3003 int backgnd = (n->type == NBACKGND);
3004 int status;
3005
3006 expredir(n->nredir.redirect);
3007 if (!backgnd && flags & EV_EXIT && !trap[0])
3008 goto nofork;
3009 INTOFF;
3010 jp = makejob(n, 1);
3011 if (forkshell(jp, n, backgnd) == 0) {
3012 INTON;
3013 flags |= EV_EXIT;
3014 if (backgnd)
3015 flags &=~ EV_TESTED;
3016nofork:
3017 redirect(n->nredir.redirect, 0);
3018 evaltreenr(n->nredir.n, flags);
3019 /* never returns */
3020 }
3021 status = 0;
3022 if (! backgnd)
3023 status = waitforjob(jp);
3024 exitstatus = status;
3025 INTON;
3026}
3027
3028
3029
3030/*
3031 * Compute the names of the files in a redirection list.
3032 */
3033
3034static void
3035expredir(union node *n)
3036{
3037 union node *redir;
3038
3039 for (redir = n ; redir ; redir = redir->nfile.next) {
3040 struct arglist fn;
3041 fn.lastp = &fn.list;
3042 switch (redir->type) {
3043 case NFROMTO:
3044 case NFROM:
3045 case NTO:
3046 case NCLOBBER:
3047 case NAPPEND:
3048 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3049 redir->nfile.expfname = fn.list->text;
3050 break;
3051 case NFROMFD:
3052 case NTOFD:
3053 if (redir->ndup.vname) {
3054 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3055 fixredir(redir, fn.list->text, 1);
3056 }
3057 break;
3058 }
3059 }
3060}
3061
3062
3063
Eric Andersencb57d552001-06-28 07:25:16 +00003064/*
Eric Andersencb57d552001-06-28 07:25:16 +00003065 * Evaluate a pipeline. All the processes in the pipeline are children
3066 * of the process creating the pipeline. (This differs from some versions
3067 * of the shell, which make the last process in a pipeline the parent
3068 * of all the rest.)
3069 */
3070
Eric Andersenc470f442003-07-28 09:56:35 +00003071static void
3072evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003073{
3074 struct job *jp;
3075 struct nodelist *lp;
3076 int pipelen;
3077 int prevfd;
3078 int pip[2];
3079
Eric Andersenc470f442003-07-28 09:56:35 +00003080 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003081 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003082 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003083 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003084 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003085 INTOFF;
3086 jp = makejob(n, pipelen);
3087 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003088 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003089 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003090 pip[1] = -1;
3091 if (lp->next) {
3092 if (pipe(pip) < 0) {
3093 close(prevfd);
3094 error("Pipe call failed");
3095 }
3096 }
3097 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3098 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003099 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003100 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003101 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003102 if (prevfd > 0) {
3103 dup2(prevfd, 0);
3104 close(prevfd);
3105 }
3106 if (pip[1] > 1) {
3107 dup2(pip[1], 1);
3108 close(pip[1]);
3109 }
Eric Andersenc470f442003-07-28 09:56:35 +00003110 evaltreenr(lp->n, flags);
3111 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003112 }
3113 if (prevfd >= 0)
3114 close(prevfd);
3115 prevfd = pip[0];
3116 close(pip[1]);
3117 }
Eric Andersencb57d552001-06-28 07:25:16 +00003118 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003119 exitstatus = waitforjob(jp);
3120 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003121 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003122 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003123}
3124
Eric Andersen62483552001-07-10 06:09:16 +00003125
3126
3127/*
3128 * Execute a command inside back quotes. If it's a builtin command, we
3129 * want to save its output in a block obtained from malloc. Otherwise
3130 * we fork off a subprocess and get the output of the command via a pipe.
3131 * Should be called with interrupts off.
3132 */
3133
Eric Andersenc470f442003-07-28 09:56:35 +00003134static void
3135evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003136{
Eric Andersenc470f442003-07-28 09:56:35 +00003137 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003138
Eric Andersen62483552001-07-10 06:09:16 +00003139 result->fd = -1;
3140 result->buf = NULL;
3141 result->nleft = 0;
3142 result->jp = NULL;
3143 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003144 goto out;
3145 }
Eric Andersenc470f442003-07-28 09:56:35 +00003146
3147 saveherefd = herefd;
3148 herefd = -1;
3149
3150 {
3151 int pip[2];
3152 struct job *jp;
3153
3154 if (pipe(pip) < 0)
3155 error("Pipe call failed");
3156 jp = makejob(n, 1);
3157 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3158 FORCEINTON;
3159 close(pip[0]);
3160 if (pip[1] != 1) {
3161 close(1);
3162 copyfd(pip[1], 1);
3163 close(pip[1]);
3164 }
3165 eflag = 0;
3166 evaltreenr(n, EV_EXIT);
3167 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003168 }
Eric Andersenc470f442003-07-28 09:56:35 +00003169 close(pip[1]);
3170 result->fd = pip[0];
3171 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003172 }
Eric Andersenc470f442003-07-28 09:56:35 +00003173 herefd = saveherefd;
3174out:
Eric Andersen62483552001-07-10 06:09:16 +00003175 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003176 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003177}
3178
Eric Andersenc470f442003-07-28 09:56:35 +00003179#ifdef CONFIG_ASH_CMDCMD
3180static inline char **
3181parse_command_args(char **argv, const char **path)
3182{
3183 char *cp, c;
3184
3185 for (;;) {
3186 cp = *++argv;
3187 if (!cp)
3188 return 0;
3189 if (*cp++ != '-')
3190 break;
3191 if (!(c = *cp++))
3192 break;
3193 if (c == '-' && !*cp) {
3194 argv++;
3195 break;
3196 }
3197 do {
3198 switch (c) {
3199 case 'p':
3200 *path = defpath;
3201 break;
3202 default:
3203 /* run 'typecmd' for other options */
3204 return 0;
3205 }
3206 } while ((c = *cp++));
3207 }
3208 return argv;
3209}
3210#endif
3211
Paul Foxc3850c82005-07-20 18:23:39 +00003212static inline int
3213isassignment(const char *p)
3214{
3215 const char *q = endofname(p);
3216 if (p == q)
3217 return 0;
3218 return *q == '=';
3219}
Eric Andersen62483552001-07-10 06:09:16 +00003220
3221/*
3222 * Execute a simple command.
3223 */
Eric Andersencb57d552001-06-28 07:25:16 +00003224
Eric Andersenc470f442003-07-28 09:56:35 +00003225static void
3226evalcommand(union node *cmd, int flags)
3227{
3228 struct stackmark smark;
3229 union node *argp;
3230 struct arglist arglist;
3231 struct arglist varlist;
3232 char **argv;
3233 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003234 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003235 struct cmdentry cmdentry;
3236 struct job *jp;
3237 char *lastarg;
3238 const char *path;
3239 int spclbltin;
3240 int cmd_is_exec;
3241 int status;
3242 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003243 struct builtincmd *bcmd;
3244 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003245
3246 /* First expand the arguments. */
3247 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3248 setstackmark(&smark);
3249 back_exitstatus = 0;
3250
3251 cmdentry.cmdtype = CMDBUILTIN;
3252 cmdentry.u.cmd = &bltin;
3253 varlist.lastp = &varlist.list;
3254 *varlist.lastp = NULL;
3255 arglist.lastp = &arglist.list;
3256 *arglist.lastp = NULL;
3257
3258 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003259 if (cmd->ncmd.args)
3260 {
3261 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3262 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3263 }
3264
Eric Andersenc470f442003-07-28 09:56:35 +00003265 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3266 struct strlist **spp;
3267
3268 spp = arglist.lastp;
Paul Foxc3850c82005-07-20 18:23:39 +00003269 if (pseudovarflag && isassignment(argp->narg.text))
3270 expandarg(argp, &arglist, EXP_VARTILDE);
3271 else
3272 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3273
Eric Andersenc470f442003-07-28 09:56:35 +00003274 for (sp = *spp; sp; sp = sp->next)
3275 argc++;
3276 }
3277
3278 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3279 for (sp = arglist.list ; sp ; sp = sp->next) {
3280 TRACE(("evalcommand arg: %s\n", sp->text));
3281 *nargv++ = sp->text;
3282 }
3283 *nargv = NULL;
3284
3285 lastarg = NULL;
3286 if (iflag && funcnest == 0 && argc > 0)
3287 lastarg = nargv[-1];
3288
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003289 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003290 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003291 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003292
3293 path = vpath.text;
3294 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3295 struct strlist **spp;
3296 char *p;
3297
3298 spp = varlist.lastp;
3299 expandarg(argp, &varlist, EXP_VARTILDE);
3300
3301 /*
3302 * Modify the command lookup path, if a PATH= assignment
3303 * is present
3304 */
3305 p = (*spp)->text;
3306 if (varequal(p, path))
3307 path = p;
3308 }
3309
3310 /* Print the command if xflag is set. */
3311 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003312 int n;
3313 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003314
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003315 p++;
3316 dprintf(preverrout_fd, p, ps4val());
3317
3318 sp = varlist.list;
3319 for(n = 0; n < 2; n++) {
3320 while (sp) {
3321 dprintf(preverrout_fd, p, sp->text);
3322 sp = sp->next;
3323 if(*p == '%') {
3324 p--;
3325 }
3326 }
3327 sp = arglist.list;
3328 }
Eric Andersen16767e22004-03-16 05:14:10 +00003329 bb_full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003330 }
3331
3332 cmd_is_exec = 0;
3333 spclbltin = -1;
3334
3335 /* Now locate the command. */
3336 if (argc) {
3337 const char *oldpath;
3338 int cmd_flag = DO_ERR;
3339
3340 path += 5;
3341 oldpath = path;
3342 for (;;) {
3343 find_command(argv[0], &cmdentry, cmd_flag, path);
3344 if (cmdentry.cmdtype == CMDUNKNOWN) {
3345 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003346 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003347 goto bail;
3348 }
3349
3350 /* implement bltin and command here */
3351 if (cmdentry.cmdtype != CMDBUILTIN)
3352 break;
3353 if (spclbltin < 0)
3354 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3355 if (cmdentry.u.cmd == EXECCMD)
3356 cmd_is_exec++;
3357#ifdef CONFIG_ASH_CMDCMD
3358 if (cmdentry.u.cmd == COMMANDCMD) {
3359
3360 path = oldpath;
3361 nargv = parse_command_args(argv, &path);
3362 if (!nargv)
3363 break;
3364 argc -= nargv - argv;
3365 argv = nargv;
3366 cmd_flag |= DO_NOFUNC;
3367 } else
3368#endif
3369 break;
3370 }
3371 }
3372
3373 if (status) {
3374 /* We have a redirection error. */
3375 if (spclbltin > 0)
3376 exraise(EXERROR);
3377bail:
3378 exitstatus = status;
3379 goto out;
3380 }
3381
3382 /* Execute the command. */
3383 switch (cmdentry.cmdtype) {
3384 default:
3385 /* Fork off a child process if necessary. */
3386 if (!(flags & EV_EXIT) || trap[0]) {
3387 INTOFF;
3388 jp = makejob(cmd, 1);
3389 if (forkshell(jp, cmd, FORK_FG) != 0) {
3390 exitstatus = waitforjob(jp);
3391 INTON;
3392 break;
3393 }
3394 FORCEINTON;
3395 }
3396 listsetvar(varlist.list, VEXPORT|VSTACK);
3397 shellexec(argv, path, cmdentry.u.index);
3398 /* NOTREACHED */
3399
3400 case CMDBUILTIN:
3401 cmdenviron = varlist.list;
3402 if (cmdenviron) {
3403 struct strlist *list = cmdenviron;
3404 int i = VNOSET;
3405 if (spclbltin > 0 || argc == 0) {
3406 i = 0;
3407 if (cmd_is_exec && argc > 1)
3408 i = VEXPORT;
3409 }
3410 listsetvar(list, i);
3411 }
3412 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3413 int exit_status;
3414 int i, j;
3415
3416 i = exception;
3417 if (i == EXEXIT)
3418 goto raise;
3419
3420 exit_status = 2;
3421 j = 0;
3422 if (i == EXINT)
3423 j = SIGINT;
3424 if (i == EXSIG)
3425 j = pendingsigs;
3426 if (j)
3427 exit_status = j + 128;
3428 exitstatus = exit_status;
3429
3430 if (i == EXINT || spclbltin > 0) {
3431raise:
3432 longjmp(handler->loc, 1);
3433 }
3434 FORCEINTON;
3435 }
3436 break;
3437
3438 case CMDFUNCTION:
3439 listsetvar(varlist.list, 0);
3440 if (evalfun(cmdentry.u.func, argc, argv, flags))
3441 goto raise;
3442 break;
3443 }
3444
3445out:
3446 popredir(cmd_is_exec);
3447 if (lastarg)
3448 /* dsl: I think this is intended to be used to support
3449 * '_' in 'vi' command mode during line editing...
3450 * However I implemented that within libedit itself.
3451 */
3452 setvar("_", lastarg, 0);
3453 popstackmark(&smark);
3454}
3455
3456static int
3457evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3458 char *volatile savecmdname;
3459 struct jmploc *volatile savehandler;
3460 struct jmploc jmploc;
3461 int i;
3462
3463 savecmdname = commandname;
3464 if ((i = setjmp(jmploc.loc)))
3465 goto cmddone;
3466 savehandler = handler;
3467 handler = &jmploc;
3468 commandname = argv[0];
3469 argptr = argv + 1;
3470 optptr = NULL; /* initialize nextopt */
3471 exitstatus = (*cmd->builtin)(argc, argv);
3472 flushall();
3473cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003474 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003475 commandname = savecmdname;
3476 exsig = 0;
3477 handler = savehandler;
3478
3479 return i;
3480}
3481
3482static int
3483evalfun(struct funcnode *func, int argc, char **argv, int flags)
3484{
3485 volatile struct shparam saveparam;
3486 struct localvar *volatile savelocalvars;
3487 struct jmploc *volatile savehandler;
3488 struct jmploc jmploc;
3489 int e;
3490
3491 saveparam = shellparam;
3492 savelocalvars = localvars;
3493 if ((e = setjmp(jmploc.loc))) {
3494 goto funcdone;
3495 }
3496 INTOFF;
3497 savehandler = handler;
3498 handler = &jmploc;
3499 localvars = NULL;
3500 shellparam.malloc = 0;
3501 func->count++;
3502 INTON;
3503 shellparam.nparam = argc - 1;
3504 shellparam.p = argv + 1;
3505#ifdef CONFIG_ASH_GETOPTS
3506 shellparam.optind = 1;
3507 shellparam.optoff = -1;
3508#endif
3509 funcnest++;
3510 evaltree(&func->n, flags & EV_TESTED);
3511 funcnest--;
3512funcdone:
3513 INTOFF;
3514 freefunc(func);
3515 poplocalvars();
3516 localvars = savelocalvars;
3517 freeparam(&shellparam);
3518 shellparam = saveparam;
3519 handler = savehandler;
3520 INTON;
3521 if (evalskip == SKIPFUNC) {
3522 evalskip = 0;
3523 skipcount = 0;
3524 }
3525 return e;
3526}
3527
3528
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003529static inline int
3530goodname(const char *p)
3531{
3532 return !*endofname(p);
3533}
3534
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003535/*
3536 * Search for a command. This is called before we fork so that the
3537 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003538 * the child. The check for "goodname" is an overly conservative
3539 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003540 */
3541
Eric Andersenc470f442003-07-28 09:56:35 +00003542static void
3543prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003544{
3545 struct cmdentry entry;
3546
3547 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003548 if (goodname(n->ncmd.args->narg.text))
3549 find_command(n->ncmd.args->narg.text, &entry, 0,
3550 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003551}
3552
Eric Andersencb57d552001-06-28 07:25:16 +00003553
Eric Andersenc470f442003-07-28 09:56:35 +00003554
Eric Andersencb57d552001-06-28 07:25:16 +00003555/*
3556 * Builtin commands. Builtin commands whose functions are closely
3557 * tied to evaluation are implemented here.
3558 */
3559
3560/*
Eric Andersenc470f442003-07-28 09:56:35 +00003561 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003562 */
3563
Eric Andersenc470f442003-07-28 09:56:35 +00003564static int
3565bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003566{
3567 /*
3568 * Preserve exitstatus of a previous possible redirection
3569 * as POSIX mandates
3570 */
Eric Andersenc470f442003-07-28 09:56:35 +00003571 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003572}
3573
3574
3575/*
3576 * Handle break and continue commands. Break, continue, and return are
3577 * all handled by setting the evalskip flag. The evaluation routines
3578 * above all check this flag, and if it is set they start skipping
3579 * commands rather than executing them. The variable skipcount is
3580 * the number of loops to break/continue, or the number of function
3581 * levels to return. (The latter is always 1.) It should probably
3582 * be an error to break out of more loops than exist, but it isn't
3583 * in the standard shell so we don't make it one here.
3584 */
3585
Eric Andersenc470f442003-07-28 09:56:35 +00003586static int
3587breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003588{
3589 int n = argc > 1 ? number(argv[1]) : 1;
3590
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003591 if (n <= 0)
Eric Andersenc470f442003-07-28 09:56:35 +00003592 error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003593 if (n > loopnest)
3594 n = loopnest;
3595 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003596 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003597 skipcount = n;
3598 }
3599 return 0;
3600}
3601
3602
3603/*
3604 * The return command.
3605 */
3606
Eric Andersenc470f442003-07-28 09:56:35 +00003607static int
3608returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003609{
Eric Andersenc470f442003-07-28 09:56:35 +00003610 int ret = argc > 1 ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003611
3612 if (funcnest) {
3613 evalskip = SKIPFUNC;
3614 skipcount = 1;
3615 return ret;
Eric Andersenc470f442003-07-28 09:56:35 +00003616 }
3617 else {
Eric Andersencb57d552001-06-28 07:25:16 +00003618 /* Do what ksh does; skip the rest of the file */
3619 evalskip = SKIPFILE;
3620 skipcount = 1;
3621 return ret;
3622 }
3623}
3624
3625
Eric Andersenc470f442003-07-28 09:56:35 +00003626static int
3627falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003628{
3629 return 1;
3630}
3631
Eric Andersenc470f442003-07-28 09:56:35 +00003632
3633static int
3634truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003635{
3636 return 0;
3637}
Eric Andersen2870d962001-07-02 17:27:21 +00003638
Eric Andersencb57d552001-06-28 07:25:16 +00003639
Eric Andersenc470f442003-07-28 09:56:35 +00003640static int
3641execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003642{
3643 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003644 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003645 mflag = 0;
3646 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003647 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003648 }
3649 return 0;
3650}
3651
Eric Andersenc470f442003-07-28 09:56:35 +00003652
Eric Andersenc470f442003-07-28 09:56:35 +00003653/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3654
3655/*
3656 * When commands are first encountered, they are entered in a hash table.
3657 * This ensures that a full path search will not have to be done for them
3658 * on each invocation.
3659 *
3660 * We should investigate converting to a linear search, even though that
3661 * would make the command name "hash" a misnomer.
3662 */
3663
3664#define CMDTABLESIZE 31 /* should be prime */
3665#define ARB 1 /* actual size determined at run time */
3666
3667
3668
3669struct tblentry {
3670 struct tblentry *next; /* next entry in hash chain */
3671 union param param; /* definition of builtin function */
3672 short cmdtype; /* index identifying command */
3673 char rehash; /* if set, cd done since entry created */
3674 char cmdname[ARB]; /* name of command */
3675};
3676
3677
3678static struct tblentry *cmdtable[CMDTABLESIZE];
3679static int builtinloc = -1; /* index in path of %builtin, or -1 */
3680
3681
3682static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003683static void clearcmdentry(int);
3684static struct tblentry *cmdlookup(const char *, int);
3685static void delete_cmd_entry(void);
3686
Eric Andersencb57d552001-06-28 07:25:16 +00003687
3688/*
3689 * Exec a program. Never returns. If you change this routine, you may
3690 * have to change the find_command routine as well.
3691 */
3692
Eric Andersenc470f442003-07-28 09:56:35 +00003693static void
3694shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003695{
3696 char *cmdname;
3697 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003698 char **envp;
Eric Andersencb57d552001-06-28 07:25:16 +00003699
Eric Andersenc470f442003-07-28 09:56:35 +00003700 clearredir(1);
3701 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003702 if (strchr(argv[0], '/') != NULL
3703#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3704 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003705#endif
3706 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003707 tryexec(argv[0], argv, envp);
3708 e = errno;
3709 } else {
3710 e = ENOENT;
3711 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3712 if (--idx < 0 && pathopt == NULL) {
3713 tryexec(cmdname, argv, envp);
3714 if (errno != ENOENT && errno != ENOTDIR)
3715 e = errno;
3716 }
3717 stunalloc(cmdname);
3718 }
3719 }
3720
3721 /* Map to POSIX errors */
3722 switch (e) {
3723 case EACCES:
3724 exerrno = 126;
3725 break;
3726 case ENOENT:
3727 exerrno = 127;
3728 break;
3729 default:
3730 exerrno = 2;
3731 break;
3732 }
Eric Andersenc470f442003-07-28 09:56:35 +00003733 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3734 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003735 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3736 /* NOTREACHED */
3737}
3738
Eric Andersen2870d962001-07-02 17:27:21 +00003739
Eric Andersenc470f442003-07-28 09:56:35 +00003740static void
3741tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003742{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003743 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003744#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003745 if(find_applet_by_name(cmd) != NULL) {
3746 /* re-exec ourselves with the new arguments */
3747 execve("/proc/self/exe",argv,envp);
3748 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3749 execve("/bin/busybox",argv,envp);
3750 /* If they called chroot or otherwise made the binary no longer
3751 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003752 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003753#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003754
3755repeat:
3756#ifdef SYSV
3757 do {
3758 execve(cmd, argv, envp);
3759 } while (errno == EINTR);
3760#else
Eric Andersencb57d552001-06-28 07:25:16 +00003761 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003762#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003763 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003764 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003765 } else if (errno == ENOEXEC) {
3766 char **ap;
3767 char **new;
3768
Eric Andersenc470f442003-07-28 09:56:35 +00003769 for (ap = argv; *ap; ap++)
3770 ;
3771 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003772 ap[1] = cmd;
3773 *ap = cmd = (char *)DEFAULT_SHELL;
3774 ap += 2;
3775 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003776 while ((*ap++ = *argv++))
3777 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003778 argv = new;
3779 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003780 }
Eric Andersencb57d552001-06-28 07:25:16 +00003781}
3782
Eric Andersenc470f442003-07-28 09:56:35 +00003783
Eric Andersencb57d552001-06-28 07:25:16 +00003784
3785/*
3786 * Do a path search. The variable path (passed by reference) should be
3787 * set to the start of the path before the first call; padvance will update
3788 * this value as it proceeds. Successive calls to padvance will return
3789 * the possible path expansions in sequence. If an option (indicated by
3790 * a percent sign) appears in the path entry then the global variable
3791 * pathopt will be set to point to it; otherwise pathopt will be set to
3792 * NULL.
3793 */
3794
Eric Andersenc470f442003-07-28 09:56:35 +00003795static char *
3796padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003797{
Eric Andersencb57d552001-06-28 07:25:16 +00003798 const char *p;
3799 char *q;
3800 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003801 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003802
3803 if (*path == NULL)
3804 return NULL;
3805 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003806 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3807 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003808 while (stackblocksize() < len)
3809 growstackblock();
3810 q = stackblock();
3811 if (p != start) {
3812 memcpy(q, start, p - start);
3813 q += p - start;
3814 *q++ = '/';
3815 }
3816 strcpy(q, name);
3817 pathopt = NULL;
3818 if (*p == '%') {
3819 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003820 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003821 }
3822 if (*p == ':')
3823 *path = p + 1;
3824 else
3825 *path = NULL;
3826 return stalloc(len);
3827}
3828
3829
Eric Andersencb57d552001-06-28 07:25:16 +00003830/*** Command hashing code ***/
3831
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003832static void
3833printentry(struct tblentry *cmdp)
3834{
3835 int idx;
3836 const char *path;
3837 char *name;
3838
3839 idx = cmdp->param.index;
3840 path = pathval();
3841 do {
3842 name = padvance(&path, cmdp->cmdname);
3843 stunalloc(name);
3844 } while (--idx >= 0);
3845 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3846}
3847
Eric Andersenc470f442003-07-28 09:56:35 +00003848
3849static int
3850hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003851{
3852 struct tblentry **pp;
3853 struct tblentry *cmdp;
3854 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003855 struct cmdentry entry;
3856 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003857
Eric Andersenc470f442003-07-28 09:56:35 +00003858 while ((c = nextopt("r")) != '\0') {
3859 clearcmdentry(0);
3860 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003861 }
3862 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003863 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3864 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3865 if (cmdp->cmdtype == CMDNORMAL)
3866 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003867 }
3868 }
3869 return 0;
3870 }
3871 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003872 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003873 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003874 && (cmdp->cmdtype == CMDNORMAL
3875 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003876 delete_cmd_entry();
3877 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003878 if (entry.cmdtype == CMDUNKNOWN)
3879 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003880 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003881 }
3882 return c;
3883}
3884
Eric Andersenc470f442003-07-28 09:56:35 +00003885
Eric Andersencb57d552001-06-28 07:25:16 +00003886/*
3887 * Resolve a command name. If you change this routine, you may have to
3888 * change the shellexec routine as well.
3889 */
3890
3891static void
Eric Andersenc470f442003-07-28 09:56:35 +00003892find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003893{
3894 struct tblentry *cmdp;
3895 int idx;
3896 int prev;
3897 char *fullname;
3898 struct stat statb;
3899 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003900 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003901 struct builtincmd *bcmd;
3902
Eric Andersenc470f442003-07-28 09:56:35 +00003903 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003904 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003905 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003906 if (act & DO_ABS) {
3907 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003908#ifdef SYSV
3909 if (errno == EINTR)
3910 continue;
3911#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003912 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003913 return;
3914 }
Eric Andersencb57d552001-06-28 07:25:16 +00003915 }
3916 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003917 return;
3918 }
3919
Eric Andersenbf8bf102002-09-17 08:41:08 +00003920#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3921 if (find_applet_by_name(name)) {
3922 entry->cmdtype = CMDNORMAL;
3923 entry->u.index = -1;
3924 return;
3925 }
3926#endif
3927
Eric Andersenc470f442003-07-28 09:56:35 +00003928 updatetbl = (path == pathval());
3929 if (!updatetbl) {
3930 act |= DO_ALTPATH;
3931 if (strstr(path, "%builtin") != NULL)
3932 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003933 }
3934
Eric Andersenc470f442003-07-28 09:56:35 +00003935 /* If name is in the table, check answer will be ok */
3936 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3937 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003938
Eric Andersenc470f442003-07-28 09:56:35 +00003939 switch (cmdp->cmdtype) {
3940 default:
3941#if DEBUG
3942 abort();
3943#endif
3944 case CMDNORMAL:
3945 bit = DO_ALTPATH;
3946 break;
3947 case CMDFUNCTION:
3948 bit = DO_NOFUNC;
3949 break;
3950 case CMDBUILTIN:
3951 bit = DO_ALTBLTIN;
3952 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003953 }
Eric Andersenc470f442003-07-28 09:56:35 +00003954 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003955 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003956 cmdp = NULL;
3957 } else if (cmdp->rehash == 0)
3958 /* if not invalidated by cd, we're done */
3959 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003960 }
3961
3962 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003963 bcmd = find_builtin(name);
3964 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3965 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3966 )))
3967 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003968
3969 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003970 prev = -1; /* where to start */
3971 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003972 if (cmdp->cmdtype == CMDBUILTIN)
3973 prev = builtinloc;
3974 else
3975 prev = cmdp->param.index;
3976 }
3977
3978 e = ENOENT;
3979 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003980loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003981 while ((fullname = padvance(&path, name)) != NULL) {
3982 stunalloc(fullname);
3983 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003984 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003985 if (prefix(pathopt, "builtin")) {
3986 if (bcmd)
3987 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003988 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003989 } else if (!(act & DO_NOFUNC) &&
3990 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003991 /* handled below */
3992 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003993 /* ignore unimplemented options */
3994 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003995 }
3996 }
3997 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003998 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003999 if (idx < prev)
4000 continue;
4001 TRACE(("searchexec \"%s\": no change\n", name));
4002 goto success;
4003 }
4004 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00004005#ifdef SYSV
4006 if (errno == EINTR)
4007 continue;
4008#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004009 if (errno != ENOENT && errno != ENOTDIR)
4010 e = errno;
4011 goto loop;
4012 }
Eric Andersenc470f442003-07-28 09:56:35 +00004013 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004014 if (!S_ISREG(statb.st_mode))
4015 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00004016 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004017 stalloc(strlen(fullname) + 1);
4018 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004019 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4020 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004021 error("%s not defined in %s", name, fullname);
4022 stunalloc(fullname);
4023 goto success;
4024 }
Eric Andersencb57d552001-06-28 07:25:16 +00004025 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004026 if (!updatetbl) {
4027 entry->cmdtype = CMDNORMAL;
4028 entry->u.index = idx;
4029 return;
4030 }
4031 INTOFF;
4032 cmdp = cmdlookup(name, 1);
4033 cmdp->cmdtype = CMDNORMAL;
4034 cmdp->param.index = idx;
4035 INTON;
4036 goto success;
4037 }
4038
4039 /* We failed. If there was an entry for this command, delete it */
4040 if (cmdp && updatetbl)
4041 delete_cmd_entry();
4042 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004043 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004044 entry->cmdtype = CMDUNKNOWN;
4045 return;
4046
Eric Andersenc470f442003-07-28 09:56:35 +00004047builtin_success:
4048 if (!updatetbl) {
4049 entry->cmdtype = CMDBUILTIN;
4050 entry->u.cmd = bcmd;
4051 return;
4052 }
4053 INTOFF;
4054 cmdp = cmdlookup(name, 1);
4055 cmdp->cmdtype = CMDBUILTIN;
4056 cmdp->param.cmd = bcmd;
4057 INTON;
4058success:
Eric Andersencb57d552001-06-28 07:25:16 +00004059 cmdp->rehash = 0;
4060 entry->cmdtype = cmdp->cmdtype;
4061 entry->u = cmdp->param;
4062}
4063
4064
Eric Andersenc470f442003-07-28 09:56:35 +00004065/*
4066 * Wrapper around strcmp for qsort/bsearch/...
4067 */
4068static int pstrcmp(const void *a, const void *b)
4069{
4070 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4071}
Eric Andersencb57d552001-06-28 07:25:16 +00004072
4073/*
4074 * Search the table of builtin commands.
4075 */
4076
Eric Andersenc470f442003-07-28 09:56:35 +00004077static struct builtincmd *
4078find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004079{
4080 struct builtincmd *bp;
4081
Eric Andersenc470f442003-07-28 09:56:35 +00004082 bp = bsearch(
4083 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4084 pstrcmp
4085 );
Eric Andersencb57d552001-06-28 07:25:16 +00004086 return bp;
4087}
4088
4089
Eric Andersenc470f442003-07-28 09:56:35 +00004090
Eric Andersencb57d552001-06-28 07:25:16 +00004091/*
4092 * Called when a cd is done. Marks all commands so the next time they
4093 * are executed they will be rehashed.
4094 */
4095
Eric Andersenc470f442003-07-28 09:56:35 +00004096static void
4097hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004098{
Eric Andersencb57d552001-06-28 07:25:16 +00004099 struct tblentry **pp;
4100 struct tblentry *cmdp;
4101
Eric Andersenc470f442003-07-28 09:56:35 +00004102 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4103 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4104 if (cmdp->cmdtype == CMDNORMAL || (
4105 cmdp->cmdtype == CMDBUILTIN &&
4106 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4107 builtinloc > 0
4108 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004109 cmdp->rehash = 1;
4110 }
4111 }
4112}
4113
4114
4115
4116/*
Eric Andersenc470f442003-07-28 09:56:35 +00004117 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004118 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004119 * pathval() still returns the old value at this point.
4120 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004121 */
4122
Eric Andersenc470f442003-07-28 09:56:35 +00004123static void
4124changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004125{
Eric Andersenc470f442003-07-28 09:56:35 +00004126 const char *old, *new;
4127 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004128 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004129 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004130
Eric Andersenc470f442003-07-28 09:56:35 +00004131 old = pathval();
4132 new = newval;
4133 firstchange = 9999; /* assume no change */
4134 idx = 0;
4135 idx_bltin = -1;
4136 for (;;) {
4137 if (*old != *new) {
4138 firstchange = idx;
4139 if ((*old == '\0' && *new == ':')
4140 || (*old == ':' && *new == '\0'))
4141 firstchange++;
4142 old = new; /* ignore subsequent differences */
4143 }
4144 if (*new == '\0')
4145 break;
4146 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4147 idx_bltin = idx;
4148 if (*new == ':') {
4149 idx++;
4150 }
4151 new++, old++;
4152 }
4153 if (builtinloc < 0 && idx_bltin >= 0)
4154 builtinloc = idx_bltin; /* zap builtins */
4155 if (builtinloc >= 0 && idx_bltin < 0)
4156 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004157 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004158 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004159}
4160
4161
4162/*
4163 * Clear out command entries. The argument specifies the first entry in
4164 * PATH which has changed.
4165 */
4166
Eric Andersenc470f442003-07-28 09:56:35 +00004167static void
4168clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004169{
4170 struct tblentry **tblp;
4171 struct tblentry **pp;
4172 struct tblentry *cmdp;
4173
4174 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004175 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004176 pp = tblp;
4177 while ((cmdp = *pp) != NULL) {
4178 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004179 cmdp->param.index >= firstchange)
4180 || (cmdp->cmdtype == CMDBUILTIN &&
4181 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004182 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004183 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004184 } else {
4185 pp = &cmdp->next;
4186 }
4187 }
4188 }
4189 INTON;
4190}
4191
4192
Eric Andersenc470f442003-07-28 09:56:35 +00004193
Eric Andersencb57d552001-06-28 07:25:16 +00004194/*
Eric Andersencb57d552001-06-28 07:25:16 +00004195 * Locate a command in the command hash table. If "add" is nonzero,
4196 * add the command to the table if it is not already present. The
4197 * variable "lastcmdentry" is set to point to the address of the link
4198 * pointing to the entry, so that delete_cmd_entry can delete the
4199 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004200 *
4201 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004202 */
4203
Eric Andersen2870d962001-07-02 17:27:21 +00004204static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004205
Eric Andersenc470f442003-07-28 09:56:35 +00004206
4207static struct tblentry *
4208cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004209{
Eric Andersenc470f442003-07-28 09:56:35 +00004210 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004211 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004212 struct tblentry *cmdp;
4213 struct tblentry **pp;
4214
4215 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004216 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004217 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004218 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004219 hashval &= 0x7FFF;
4220 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004221 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004222 if (equal(cmdp->cmdname, name))
4223 break;
4224 pp = &cmdp->next;
4225 }
4226 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004227 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4228 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004229 cmdp->next = NULL;
4230 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004231 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004232 }
4233 lastcmdentry = pp;
4234 return cmdp;
4235}
4236
4237/*
4238 * Delete the command entry returned on the last lookup.
4239 */
4240
Eric Andersenc470f442003-07-28 09:56:35 +00004241static void
4242delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004243{
Eric Andersencb57d552001-06-28 07:25:16 +00004244 struct tblentry *cmdp;
4245
4246 INTOFF;
4247 cmdp = *lastcmdentry;
4248 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004249 if (cmdp->cmdtype == CMDFUNCTION)
4250 freefunc(cmdp->param.func);
4251 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004252 INTON;
4253}
4254
4255
Eric Andersenc470f442003-07-28 09:56:35 +00004256/*
4257 * Add a new command entry, replacing any existing command entry for
4258 * the same name - except special builtins.
4259 */
Eric Andersencb57d552001-06-28 07:25:16 +00004260
Eric Andersenc470f442003-07-28 09:56:35 +00004261static inline void
4262addcmdentry(char *name, struct cmdentry *entry)
4263{
4264 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004265
Eric Andersenc470f442003-07-28 09:56:35 +00004266 cmdp = cmdlookup(name, 1);
4267 if (cmdp->cmdtype == CMDFUNCTION) {
4268 freefunc(cmdp->param.func);
4269 }
4270 cmdp->cmdtype = entry->cmdtype;
4271 cmdp->param = entry->u;
4272 cmdp->rehash = 0;
4273}
Eric Andersencb57d552001-06-28 07:25:16 +00004274
Eric Andersenc470f442003-07-28 09:56:35 +00004275/*
4276 * Make a copy of a parse tree.
4277 */
Eric Andersencb57d552001-06-28 07:25:16 +00004278
Eric Andersenc470f442003-07-28 09:56:35 +00004279static inline struct funcnode *
4280copyfunc(union node *n)
4281{
4282 struct funcnode *f;
4283 size_t blocksize;
4284
4285 funcblocksize = offsetof(struct funcnode, n);
4286 funcstringsize = 0;
4287 calcsize(n);
4288 blocksize = funcblocksize;
4289 f = ckmalloc(blocksize + funcstringsize);
4290 funcblock = (char *) f + offsetof(struct funcnode, n);
4291 funcstring = (char *) f + blocksize;
4292 copynode(n);
4293 f->count = 0;
4294 return f;
4295}
4296
4297/*
4298 * Define a shell function.
4299 */
4300
4301static void
4302defun(char *name, union node *func)
4303{
4304 struct cmdentry entry;
4305
4306 INTOFF;
4307 entry.cmdtype = CMDFUNCTION;
4308 entry.u.func = copyfunc(func);
4309 addcmdentry(name, &entry);
4310 INTON;
4311}
Eric Andersencb57d552001-06-28 07:25:16 +00004312
4313
4314/*
4315 * Delete a function if it exists.
4316 */
4317
Eric Andersenc470f442003-07-28 09:56:35 +00004318static void
4319unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004320{
Eric Andersencb57d552001-06-28 07:25:16 +00004321 struct tblentry *cmdp;
4322
Eric Andersenc470f442003-07-28 09:56:35 +00004323 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4324 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004325 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004326}
4327
Eric Andersen2870d962001-07-02 17:27:21 +00004328/*
Eric Andersencb57d552001-06-28 07:25:16 +00004329 * Locate and print what a word is...
4330 */
4331
Eric Andersenc470f442003-07-28 09:56:35 +00004332
4333#ifdef CONFIG_ASH_CMDCMD
4334static int
4335describe_command(char *command, int describe_command_verbose)
4336#else
4337#define describe_command_verbose 1
4338static int
4339describe_command(char *command)
4340#endif
4341{
4342 struct cmdentry entry;
4343 struct tblentry *cmdp;
4344#ifdef CONFIG_ASH_ALIAS
4345 const struct alias *ap;
4346#endif
4347 const char *path = pathval();
4348
4349 if (describe_command_verbose) {
4350 out1str(command);
4351 }
4352
4353 /* First look at the keywords */
4354 if (findkwd(command)) {
4355 out1str(describe_command_verbose ? " is a shell keyword" : command);
4356 goto out;
4357 }
4358
4359#ifdef CONFIG_ASH_ALIAS
4360 /* Then look at the aliases */
4361 if ((ap = lookupalias(command, 0)) != NULL) {
4362 if (describe_command_verbose) {
4363 out1fmt(" is an alias for %s", ap->val);
4364 } else {
4365 out1str("alias ");
4366 printalias(ap);
4367 return 0;
4368 }
4369 goto out;
4370 }
4371#endif
4372 /* Then check if it is a tracked alias */
4373 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4374 entry.cmdtype = cmdp->cmdtype;
4375 entry.u = cmdp->param;
4376 } else {
4377 /* Finally use brute force */
4378 find_command(command, &entry, DO_ABS, path);
4379 }
4380
4381 switch (entry.cmdtype) {
4382 case CMDNORMAL: {
4383 int j = entry.u.index;
4384 char *p;
4385 if (j == -1) {
4386 p = command;
4387 } else {
4388 do {
4389 p = padvance(&path, command);
4390 stunalloc(p);
4391 } while (--j >= 0);
4392 }
4393 if (describe_command_verbose) {
4394 out1fmt(" is%s %s",
4395 (cmdp ? " a tracked alias for" : nullstr), p
4396 );
4397 } else {
4398 out1str(p);
4399 }
4400 break;
4401 }
4402
4403 case CMDFUNCTION:
4404 if (describe_command_verbose) {
4405 out1str(" is a shell function");
4406 } else {
4407 out1str(command);
4408 }
4409 break;
4410
4411 case CMDBUILTIN:
4412 if (describe_command_verbose) {
4413 out1fmt(" is a %sshell builtin",
4414 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4415 "special " : nullstr
4416 );
4417 } else {
4418 out1str(command);
4419 }
4420 break;
4421
4422 default:
4423 if (describe_command_verbose) {
4424 out1str(": not found\n");
4425 }
4426 return 127;
4427 }
4428
4429out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004430 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004431 return 0;
4432}
4433
4434static int
4435typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004436{
4437 int i;
4438 int err = 0;
4439
4440 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004441#ifdef CONFIG_ASH_CMDCMD
4442 err |= describe_command(argv[i], 1);
4443#else
4444 err |= describe_command(argv[i]);
4445#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004446 }
4447 return err;
4448}
4449
Eric Andersend35c5df2002-01-09 15:37:36 +00004450#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004451static int
4452commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004453{
4454 int c;
4455 int default_path = 0;
4456 int verify_only = 0;
4457 int verbose_verify_only = 0;
4458
4459 while ((c = nextopt("pvV")) != '\0')
4460 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004461 default:
4462#ifdef DEBUG
4463 fprintf(stderr,
4464"command: nextopt returned character code 0%o\n", c);
4465 return EX_SOFTWARE;
4466#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004467 case 'p':
4468 default_path = 1;
4469 break;
4470 case 'v':
4471 verify_only = 1;
4472 break;
4473 case 'V':
4474 verbose_verify_only = 1;
4475 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004476 }
4477
Eric Andersenc470f442003-07-28 09:56:35 +00004478 if (default_path + verify_only + verbose_verify_only > 1 ||
4479 !*argptr) {
4480 fprintf(stderr,
4481 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004482 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004483 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004484 }
4485
Eric Andersencb57d552001-06-28 07:25:16 +00004486 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004487 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004488 }
Eric Andersencb57d552001-06-28 07:25:16 +00004489
4490 return 0;
4491}
Eric Andersen2870d962001-07-02 17:27:21 +00004492#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004493
Eric Andersenc470f442003-07-28 09:56:35 +00004494/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004495
Eric Andersencb57d552001-06-28 07:25:16 +00004496/*
4497 * Routines to expand arguments to commands. We have to deal with
4498 * backquotes, shell variables, and file metacharacters.
4499 */
Eric Andersenc470f442003-07-28 09:56:35 +00004500
Eric Andersencb57d552001-06-28 07:25:16 +00004501/*
4502 * _rmescape() flags
4503 */
Eric Andersenc470f442003-07-28 09:56:35 +00004504#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4505#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4506#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4507#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4508#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004509
4510/*
4511 * Structure specifying which parts of the string should be searched
4512 * for IFS characters.
4513 */
4514
4515struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004516 struct ifsregion *next; /* next region in list */
4517 int begoff; /* offset of start of region */
4518 int endoff; /* offset of end of region */
4519 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004520};
4521
Eric Andersenc470f442003-07-28 09:56:35 +00004522/* output of current string */
4523static char *expdest;
4524/* list of back quote expressions */
4525static struct nodelist *argbackq;
4526/* first struct in list of ifs regions */
4527static struct ifsregion ifsfirst;
4528/* last struct in list */
4529static struct ifsregion *ifslastp;
4530/* holds expanded arg list */
4531static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004532
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004533static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004534static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004535static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004536static const char *subevalvar(char *, char *, int, int, int, int, int);
4537static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004538static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004539static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004540static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004541static void recordregion(int, int, int);
4542static void removerecordregions(int);
4543static void ifsbreakup(char *, struct arglist *);
4544static void ifsfree(void);
4545static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004546static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004547
Eric Andersened9ecf72004-06-22 08:29:45 +00004548static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004549static size_t esclen(const char *, const char *);
4550static char *scanleft(char *, char *, char *, char *, int, int);
4551static char *scanright(char *, char *, char *, char *, int, int);
4552static void varunset(const char *, const char *, const char *, int)
4553 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004554
Eric Andersenc470f442003-07-28 09:56:35 +00004555
4556#define pmatch(a, b) !fnmatch((a), (b), 0)
4557/*
Eric Andersen90898442003-08-06 11:20:52 +00004558 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004559 *
4560 * Returns an stalloced string.
4561 */
4562
4563static inline char *
4564preglob(const char *pattern, int quoted, int flag) {
4565 flag |= RMESCAPE_GLOB;
4566 if (quoted) {
4567 flag |= RMESCAPE_QUOTED;
4568 }
4569 return _rmescapes((char *)pattern, flag);
4570}
4571
4572
4573static size_t
4574esclen(const char *start, const char *p) {
4575 size_t esc = 0;
4576
4577 while (p > start && *--p == CTLESC) {
4578 esc++;
4579 }
4580 return esc;
4581}
4582
Eric Andersencb57d552001-06-28 07:25:16 +00004583
4584/*
4585 * Expand shell variables and backquotes inside a here document.
4586 */
4587
Eric Andersenc470f442003-07-28 09:56:35 +00004588static inline void
4589expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004590{
Eric Andersencb57d552001-06-28 07:25:16 +00004591 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004592 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004593 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004594}
4595
4596
4597/*
4598 * Perform variable substitution and command substitution on an argument,
4599 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4600 * perform splitting and file name expansion. When arglist is NULL, perform
4601 * here document expansion.
4602 */
4603
Eric Andersenc470f442003-07-28 09:56:35 +00004604void
4605expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004606{
4607 struct strlist *sp;
4608 char *p;
4609
4610 argbackq = arg->narg.backquote;
4611 STARTSTACKSTR(expdest);
4612 ifsfirst.next = NULL;
4613 ifslastp = NULL;
4614 argstr(arg->narg.text, flag);
4615 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004616 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004617 }
4618 STPUTC('\0', expdest);
4619 p = grabstackstr(expdest);
4620 exparg.lastp = &exparg.list;
4621 /*
4622 * TODO - EXP_REDIR
4623 */
4624 if (flag & EXP_FULL) {
4625 ifsbreakup(p, &exparg);
4626 *exparg.lastp = NULL;
4627 exparg.lastp = &exparg.list;
4628 expandmeta(exparg.list, flag);
4629 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004630 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004631 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004632 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004633 sp->text = p;
4634 *exparg.lastp = sp;
4635 exparg.lastp = &sp->next;
4636 }
Eric Andersenc470f442003-07-28 09:56:35 +00004637 if (ifsfirst.next)
4638 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004639 *exparg.lastp = NULL;
4640 if (exparg.list) {
4641 *arglist->lastp = exparg.list;
4642 arglist->lastp = exparg.lastp;
4643 }
4644}
4645
4646
Eric Andersenc470f442003-07-28 09:56:35 +00004647/*
4648 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4649 * characters to allow for further processing. Otherwise treat
4650 * $@ like $* since no splitting will be performed.
4651 */
4652
4653static void
4654argstr(char *p, int flag)
4655{
4656 static const char spclchars[] = {
4657 '=',
4658 ':',
4659 CTLQUOTEMARK,
4660 CTLENDVAR,
4661 CTLESC,
4662 CTLVAR,
4663 CTLBACKQ,
4664 CTLBACKQ | CTLQUOTE,
4665#ifdef CONFIG_ASH_MATH_SUPPORT
4666 CTLENDARI,
4667#endif
4668 0
4669 };
4670 const char *reject = spclchars;
4671 int c;
4672 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4673 int breakall = flag & EXP_WORD;
4674 int inquotes;
4675 size_t length;
4676 int startloc;
4677
4678 if (!(flag & EXP_VARTILDE)) {
4679 reject += 2;
4680 } else if (flag & EXP_VARTILDE2) {
4681 reject++;
4682 }
4683 inquotes = 0;
4684 length = 0;
4685 if (flag & EXP_TILDE) {
4686 char *q;
4687
4688 flag &= ~EXP_TILDE;
4689tilde:
4690 q = p;
4691 if (*q == CTLESC && (flag & EXP_QWORD))
4692 q++;
4693 if (*q == '~')
4694 p = exptilde(p, q, flag);
4695 }
4696start:
4697 startloc = expdest - (char *)stackblock();
4698 for (;;) {
4699 length += strcspn(p + length, reject);
4700 c = p[length];
4701 if (c && (!(c & 0x80)
4702#ifdef CONFIG_ASH_MATH_SUPPORT
4703 || c == CTLENDARI
4704#endif
4705 )) {
4706 /* c == '=' || c == ':' || c == CTLENDARI */
4707 length++;
4708 }
4709 if (length > 0) {
4710 int newloc;
4711 expdest = stnputs(p, length, expdest);
4712 newloc = expdest - (char *)stackblock();
4713 if (breakall && !inquotes && newloc > startloc) {
4714 recordregion(startloc, newloc, 0);
4715 }
4716 startloc = newloc;
4717 }
4718 p += length + 1;
4719 length = 0;
4720
4721 switch (c) {
4722 case '\0':
4723 goto breakloop;
4724 case '=':
4725 if (flag & EXP_VARTILDE2) {
4726 p--;
4727 continue;
4728 }
4729 flag |= EXP_VARTILDE2;
4730 reject++;
4731 /* fall through */
4732 case ':':
4733 /*
4734 * sort of a hack - expand tildes in variable
4735 * assignments (after the first '=' and after ':'s).
4736 */
4737 if (*--p == '~') {
4738 goto tilde;
4739 }
4740 continue;
4741 }
4742
4743 switch (c) {
4744 case CTLENDVAR: /* ??? */
4745 goto breakloop;
4746 case CTLQUOTEMARK:
4747 /* "$@" syntax adherence hack */
4748 if (
4749 !inquotes &&
4750 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4751 (p[4] == CTLQUOTEMARK || (
4752 p[4] == CTLENDVAR &&
4753 p[5] == CTLQUOTEMARK
4754 ))
4755 ) {
4756 p = evalvar(p + 1, flag) + 1;
4757 goto start;
4758 }
4759 inquotes = !inquotes;
4760addquote:
4761 if (quotes) {
4762 p--;
4763 length++;
4764 startloc++;
4765 }
4766 break;
4767 case CTLESC:
4768 startloc++;
4769 length++;
4770 goto addquote;
4771 case CTLVAR:
4772 p = evalvar(p, flag);
4773 goto start;
4774 case CTLBACKQ:
4775 c = 0;
4776 case CTLBACKQ|CTLQUOTE:
4777 expbackq(argbackq->n, c, quotes);
4778 argbackq = argbackq->next;
4779 goto start;
4780#ifdef CONFIG_ASH_MATH_SUPPORT
4781 case CTLENDARI:
4782 p--;
4783 expari(quotes);
4784 goto start;
4785#endif
4786 }
4787 }
4788breakloop:
4789 ;
4790}
4791
4792static char *
4793exptilde(char *startp, char *p, int flag)
4794{
4795 char c;
4796 char *name;
4797 struct passwd *pw;
4798 const char *home;
4799 int quotes = flag & (EXP_FULL | EXP_CASE);
4800 int startloc;
4801
4802 name = p + 1;
4803
4804 while ((c = *++p) != '\0') {
4805 switch(c) {
4806 case CTLESC:
4807 return (startp);
4808 case CTLQUOTEMARK:
4809 return (startp);
4810 case ':':
4811 if (flag & EXP_VARTILDE)
4812 goto done;
4813 break;
4814 case '/':
4815 case CTLENDVAR:
4816 goto done;
4817 }
4818 }
4819done:
4820 *p = '\0';
4821 if (*name == '\0') {
4822 if ((home = lookupvar(homestr)) == NULL)
4823 goto lose;
4824 } else {
4825 if ((pw = getpwnam(name)) == NULL)
4826 goto lose;
4827 home = pw->pw_dir;
4828 }
4829 if (*home == '\0')
4830 goto lose;
4831 *p = c;
4832 startloc = expdest - (char *)stackblock();
4833 strtodest(home, SQSYNTAX, quotes);
4834 recordregion(startloc, expdest - (char *)stackblock(), 0);
4835 return (p);
4836lose:
4837 *p = c;
4838 return (startp);
4839}
4840
4841
4842static void
4843removerecordregions(int endoff)
4844{
4845 if (ifslastp == NULL)
4846 return;
4847
4848 if (ifsfirst.endoff > endoff) {
4849 while (ifsfirst.next != NULL) {
4850 struct ifsregion *ifsp;
4851 INTOFF;
4852 ifsp = ifsfirst.next->next;
4853 ckfree(ifsfirst.next);
4854 ifsfirst.next = ifsp;
4855 INTON;
4856 }
4857 if (ifsfirst.begoff > endoff)
4858 ifslastp = NULL;
4859 else {
4860 ifslastp = &ifsfirst;
4861 ifsfirst.endoff = endoff;
4862 }
4863 return;
4864 }
4865
4866 ifslastp = &ifsfirst;
4867 while (ifslastp->next && ifslastp->next->begoff < endoff)
4868 ifslastp=ifslastp->next;
4869 while (ifslastp->next != NULL) {
4870 struct ifsregion *ifsp;
4871 INTOFF;
4872 ifsp = ifslastp->next->next;
4873 ckfree(ifslastp->next);
4874 ifslastp->next = ifsp;
4875 INTON;
4876 }
4877 if (ifslastp->endoff > endoff)
4878 ifslastp->endoff = endoff;
4879}
4880
4881
4882#ifdef CONFIG_ASH_MATH_SUPPORT
4883/*
4884 * Expand arithmetic expression. Backup to start of expression,
4885 * evaluate, place result in (backed up) result, adjust string position.
4886 */
4887void
4888expari(int quotes)
4889{
4890 char *p, *start;
4891 int begoff;
4892 int flag;
4893 int len;
4894
4895 /* ifsfree(); */
4896
4897 /*
4898 * This routine is slightly over-complicated for
4899 * efficiency. Next we scan backwards looking for the
4900 * start of arithmetic.
4901 */
4902 start = stackblock();
4903 p = expdest - 1;
4904 *p = '\0';
4905 p--;
4906 do {
4907 int esc;
4908
4909 while (*p != CTLARI) {
4910 p--;
4911#ifdef DEBUG
4912 if (p < start) {
4913 error("missing CTLARI (shouldn't happen)");
4914 }
4915#endif
4916 }
4917
4918 esc = esclen(start, p);
4919 if (!(esc % 2)) {
4920 break;
4921 }
4922
4923 p -= esc + 1;
4924 } while (1);
4925
4926 begoff = p - start;
4927
4928 removerecordregions(begoff);
4929
4930 flag = p[1];
4931
4932 expdest = p;
4933
4934 if (quotes)
4935 rmescapes(p + 2);
4936
4937 len = cvtnum(dash_arith(p + 2));
4938
4939 if (flag != '"')
4940 recordregion(begoff, begoff + len, 0);
4941}
4942#endif
4943
4944/*
4945 * Expand stuff in backwards quotes.
4946 */
4947
4948static void
4949expbackq(union node *cmd, int quoted, int quotes)
4950{
4951 struct backcmd in;
4952 int i;
4953 char buf[128];
4954 char *p;
4955 char *dest;
4956 int startloc;
4957 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4958 struct stackmark smark;
4959
4960 INTOFF;
4961 setstackmark(&smark);
4962 dest = expdest;
4963 startloc = dest - (char *)stackblock();
4964 grabstackstr(dest);
4965 evalbackcmd(cmd, (struct backcmd *) &in);
4966 popstackmark(&smark);
4967
4968 p = in.buf;
4969 i = in.nleft;
4970 if (i == 0)
4971 goto read;
4972 for (;;) {
4973 memtodest(p, i, syntax, quotes);
4974read:
4975 if (in.fd < 0)
4976 break;
4977 i = safe_read(in.fd, buf, sizeof buf);
4978 TRACE(("expbackq: read returns %d\n", i));
4979 if (i <= 0)
4980 break;
4981 p = buf;
4982 }
4983
4984 if (in.buf)
4985 ckfree(in.buf);
4986 if (in.fd >= 0) {
4987 close(in.fd);
4988 back_exitstatus = waitforjob(in.jp);
4989 }
4990 INTON;
4991
4992 /* Eat all trailing newlines */
4993 dest = expdest;
4994 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4995 STUNPUTC(dest);
4996 expdest = dest;
4997
4998 if (quoted == 0)
4999 recordregion(startloc, dest - (char *)stackblock(), 0);
5000 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5001 (dest - (char *)stackblock()) - startloc,
5002 (dest - (char *)stackblock()) - startloc,
5003 stackblock() + startloc));
5004}
5005
5006
5007static char *
Eric Andersen90898442003-08-06 11:20:52 +00005008scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5009 int zero)
5010{
Eric Andersenc470f442003-07-28 09:56:35 +00005011 char *loc;
5012 char *loc2;
5013 char c;
5014
5015 loc = startp;
5016 loc2 = rmesc;
5017 do {
5018 int match;
5019 const char *s = loc2;
5020 c = *loc2;
5021 if (zero) {
5022 *loc2 = '\0';
5023 s = rmesc;
5024 }
5025 match = pmatch(str, s);
5026 *loc2 = c;
5027 if (match)
5028 return loc;
5029 if (quotes && *loc == CTLESC)
5030 loc++;
5031 loc++;
5032 loc2++;
5033 } while (c);
5034 return 0;
5035}
5036
5037
5038static char *
Eric Andersen90898442003-08-06 11:20:52 +00005039scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5040 int zero)
5041{
Eric Andersenc470f442003-07-28 09:56:35 +00005042 int esc = 0;
5043 char *loc;
5044 char *loc2;
5045
5046 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5047 int match;
5048 char c = *loc2;
5049 const char *s = loc2;
5050 if (zero) {
5051 *loc2 = '\0';
5052 s = rmesc;
5053 }
5054 match = pmatch(str, s);
5055 *loc2 = c;
5056 if (match)
5057 return loc;
5058 loc--;
5059 if (quotes) {
5060 if (--esc < 0) {
5061 esc = esclen(startp, loc);
5062 }
5063 if (esc % 2) {
5064 esc--;
5065 loc--;
5066 }
5067 }
5068 }
5069 return 0;
5070}
5071
5072static const char *
5073subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5074{
5075 char *startp;
5076 char *loc;
5077 int saveherefd = herefd;
5078 struct nodelist *saveargbackq = argbackq;
5079 int amount;
5080 char *rmesc, *rmescend;
5081 int zero;
5082 char *(*scan)(char *, char *, char *, char *, int , int);
5083
5084 herefd = -1;
5085 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5086 STPUTC('\0', expdest);
5087 herefd = saveherefd;
5088 argbackq = saveargbackq;
5089 startp = stackblock() + startloc;
5090
5091 switch (subtype) {
5092 case VSASSIGN:
5093 setvar(str, startp, 0);
5094 amount = startp - expdest;
5095 STADJUST(amount, expdest);
5096 return startp;
5097
5098 case VSQUESTION:
5099 varunset(p, str, startp, varflags);
5100 /* NOTREACHED */
5101 }
5102
5103 subtype -= VSTRIMRIGHT;
5104#ifdef DEBUG
5105 if (subtype < 0 || subtype > 3)
5106 abort();
5107#endif
5108
5109 rmesc = startp;
5110 rmescend = stackblock() + strloc;
5111 if (quotes) {
5112 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5113 if (rmesc != startp) {
5114 rmescend = expdest;
5115 startp = stackblock() + startloc;
5116 }
5117 }
5118 rmescend--;
5119 str = stackblock() + strloc;
5120 preglob(str, varflags & VSQUOTE, 0);
5121
5122 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5123 zero = subtype >> 1;
5124 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5125 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5126
5127 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5128 if (loc) {
5129 if (zero) {
5130 memmove(startp, loc, str - loc);
5131 loc = startp + (str - loc) - 1;
5132 }
5133 *loc = '\0';
5134 amount = loc - expdest;
5135 STADJUST(amount, expdest);
5136 }
5137 return loc;
5138}
5139
5140
Eric Andersen62483552001-07-10 06:09:16 +00005141/*
5142 * Expand a variable, and return a pointer to the next character in the
5143 * input string.
5144 */
Eric Andersenc470f442003-07-28 09:56:35 +00005145static char *
5146evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005147{
5148 int subtype;
5149 int varflags;
5150 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005151 int patloc;
5152 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005153 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005154 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005155 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005156 int quotes;
5157 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005158
Eric Andersenc470f442003-07-28 09:56:35 +00005159 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005160 varflags = *p++;
5161 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005162 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005163 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005164 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005165 startloc = expdest - (char *)stackblock();
5166 p = strchr(p, '=') + 1;
5167
Eric Andersenc470f442003-07-28 09:56:35 +00005168again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005169 varlen = varvalue(var, varflags, flag);
5170 if (varflags & VSNUL)
5171 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005172
Glenn L McGrath76620622004-01-13 10:19:37 +00005173 if (subtype == VSPLUS) {
5174 varlen = -1 - varlen;
5175 goto vsplus;
5176 }
Eric Andersen62483552001-07-10 06:09:16 +00005177
Eric Andersenc470f442003-07-28 09:56:35 +00005178 if (subtype == VSMINUS) {
5179vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005180 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005181 argstr(
5182 p, flag | EXP_TILDE |
5183 (quoted ? EXP_QWORD : EXP_WORD)
5184 );
5185 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005186 }
5187 if (easy)
5188 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005189 goto end;
5190 }
Eric Andersen62483552001-07-10 06:09:16 +00005191
Eric Andersenc470f442003-07-28 09:56:35 +00005192 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005193 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005194 if (subevalvar(p, var, 0, subtype, startloc,
5195 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005196 varflags &= ~VSNUL;
5197 /*
5198 * Remove any recorded regions beyond
5199 * start of variable
5200 */
5201 removerecordregions(startloc);
5202 goto again;
5203 }
Eric Andersenc470f442003-07-28 09:56:35 +00005204 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005205 }
5206 if (easy)
5207 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005208 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005209 }
5210
Glenn L McGrath76620622004-01-13 10:19:37 +00005211 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005212 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005213
Eric Andersenc470f442003-07-28 09:56:35 +00005214 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005215 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005216 goto record;
5217 }
5218
5219 if (subtype == VSNORMAL) {
5220 if (!easy)
5221 goto end;
5222record:
5223 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5224 goto end;
5225 }
5226
5227#ifdef DEBUG
5228 switch (subtype) {
5229 case VSTRIMLEFT:
5230 case VSTRIMLEFTMAX:
5231 case VSTRIMRIGHT:
5232 case VSTRIMRIGHTMAX:
5233 break;
5234 default:
5235 abort();
5236 }
5237#endif
5238
Glenn L McGrath76620622004-01-13 10:19:37 +00005239 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005240 /*
5241 * Terminate the string and start recording the pattern
5242 * right after it
5243 */
5244 STPUTC('\0', expdest);
5245 patloc = expdest - (char *)stackblock();
5246 if (subevalvar(p, NULL, patloc, subtype,
5247 startloc, varflags, quotes) == 0) {
5248 int amount = expdest - (
5249 (char *)stackblock() + patloc - 1
5250 );
5251 STADJUST(-amount, expdest);
5252 }
5253 /* Remove any recorded regions beyond start of variable */
5254 removerecordregions(startloc);
5255 goto record;
5256 }
5257
5258end:
5259 if (subtype != VSNORMAL) { /* skip to end of alternative */
5260 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005261 for (;;) {
5262 if ((c = *p++) == CTLESC)
5263 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005264 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005265 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005266 argbackq = argbackq->next;
5267 } else if (c == CTLVAR) {
5268 if ((*p++ & VSTYPE) != VSNORMAL)
5269 nesting++;
5270 } else if (c == CTLENDVAR) {
5271 if (--nesting == 0)
5272 break;
5273 }
5274 }
5275 }
5276 return p;
5277}
5278
Eric Andersencb57d552001-06-28 07:25:16 +00005279
Eric Andersencb57d552001-06-28 07:25:16 +00005280/*
5281 * Put a string on the stack.
5282 */
5283
Eric Andersenc470f442003-07-28 09:56:35 +00005284static void
5285memtodest(const char *p, size_t len, int syntax, int quotes) {
5286 char *q = expdest;
5287
5288 q = makestrspace(len * 2, q);
5289
5290 while (len--) {
5291 int c = *p++;
5292 if (!c)
5293 continue;
5294 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5295 USTPUTC(CTLESC, q);
5296 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005297 }
Eric Andersenc470f442003-07-28 09:56:35 +00005298
5299 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005300}
5301
Eric Andersenc470f442003-07-28 09:56:35 +00005302
5303static void
5304strtodest(const char *p, int syntax, int quotes)
5305{
5306 memtodest(p, strlen(p), syntax, quotes);
5307}
5308
5309
Eric Andersencb57d552001-06-28 07:25:16 +00005310/*
5311 * Add the value of a specialized variable to the stack string.
5312 */
5313
Glenn L McGrath76620622004-01-13 10:19:37 +00005314static ssize_t
5315varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005316{
5317 int num;
5318 char *p;
5319 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005320 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005321 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005322 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005323 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005324 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005325 int quoted = varflags & VSQUOTE;
5326 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005327 int quotes = flags & (EXP_FULL | EXP_CASE);
5328
Glenn L McGrath76620622004-01-13 10:19:37 +00005329 if (quoted && (flags & EXP_FULL))
5330 sep = 1 << CHAR_BIT;
5331
Eric Andersencb57d552001-06-28 07:25:16 +00005332 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5333 switch (*name) {
5334 case '$':
5335 num = rootpid;
5336 goto numvar;
5337 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005338 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005339 goto numvar;
5340 case '#':
5341 num = shellparam.nparam;
5342 goto numvar;
5343 case '!':
5344 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005345 if (num == 0)
5346 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005347numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005348 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005349 break;
5350 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005351 p = makestrspace(NOPTS, expdest);
5352 for (i = NOPTS - 1; i >= 0; i--) {
5353 if (optlist[i]) {
5354 USTPUTC(optletters(i), p);
5355 len++;
5356 }
Eric Andersencb57d552001-06-28 07:25:16 +00005357 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005358 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005359 break;
5360 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005361 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005362 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005363 /* fall through */
5364 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005365 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005366 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5367 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005368param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005369 if (!(ap = shellparam.p))
5370 return -1;
5371 while ((p = *ap++)) {
5372 size_t partlen;
5373
5374 partlen = strlen(p);
5375
5376 len += partlen;
5377 if (len > partlen && sep) {
5378 char *q;
5379
5380 len++;
5381 if (subtype == VSPLUS || subtype == VSLENGTH) {
5382 continue;
5383 }
5384 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005385 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005386 STPUTC(CTLESC, q);
5387 STPUTC(sep, q);
5388 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005389 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005390
5391 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5392 memtodest(p, partlen, syntax, quotes);
Eric Andersencb57d552001-06-28 07:25:16 +00005393 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005394 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005395 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005396 case '1':
5397 case '2':
5398 case '3':
5399 case '4':
5400 case '5':
5401 case '6':
5402 case '7':
5403 case '8':
5404 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005405 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005406 if (num < 0 || num > shellparam.nparam)
5407 return -1;
5408 p = num ? shellparam.p[num - 1] : arg0;
5409 goto value;
5410 default:
5411 p = lookupvar(name);
5412value:
5413 if (!p)
5414 return -1;
5415
5416 len = strlen(p);
5417 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5418 memtodest(p, len, syntax, quotes);
5419 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005420 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005421
5422 if (subtype == VSPLUS || subtype == VSLENGTH)
5423 STADJUST(-len, expdest);
5424 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005425}
5426
5427
Eric Andersencb57d552001-06-28 07:25:16 +00005428/*
5429 * Record the fact that we have to scan this region of the
5430 * string for IFS characters.
5431 */
5432
Eric Andersenc470f442003-07-28 09:56:35 +00005433static void
5434recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005435{
5436 struct ifsregion *ifsp;
5437
5438 if (ifslastp == NULL) {
5439 ifsp = &ifsfirst;
5440 } else {
5441 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005442 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005443 ifsp->next = NULL;
5444 ifslastp->next = ifsp;
5445 INTON;
5446 }
5447 ifslastp = ifsp;
5448 ifslastp->begoff = start;
5449 ifslastp->endoff = end;
5450 ifslastp->nulonly = nulonly;
5451}
5452
5453
Eric Andersencb57d552001-06-28 07:25:16 +00005454/*
5455 * Break the argument string into pieces based upon IFS and add the
5456 * strings to the argument list. The regions of the string to be
5457 * searched for IFS characters have been stored by recordregion.
5458 */
Eric Andersenc470f442003-07-28 09:56:35 +00005459static void
5460ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005461{
Eric Andersencb57d552001-06-28 07:25:16 +00005462 struct ifsregion *ifsp;
5463 struct strlist *sp;
5464 char *start;
5465 char *p;
5466 char *q;
5467 const char *ifs, *realifs;
5468 int ifsspc;
5469 int nulonly;
5470
5471
5472 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005473 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005474 ifsspc = 0;
5475 nulonly = 0;
5476 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005477 ifsp = &ifsfirst;
5478 do {
5479 p = string + ifsp->begoff;
5480 nulonly = ifsp->nulonly;
5481 ifs = nulonly ? nullstr : realifs;
5482 ifsspc = 0;
5483 while (p < string + ifsp->endoff) {
5484 q = p;
5485 if (*p == CTLESC)
5486 p++;
5487 if (strchr(ifs, *p)) {
5488 if (!nulonly)
5489 ifsspc = (strchr(defifs, *p) != NULL);
5490 /* Ignore IFS whitespace at start */
5491 if (q == start && ifsspc) {
5492 p++;
5493 start = p;
5494 continue;
5495 }
5496 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005497 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005498 sp->text = start;
5499 *arglist->lastp = sp;
5500 arglist->lastp = &sp->next;
5501 p++;
5502 if (!nulonly) {
5503 for (;;) {
5504 if (p >= string + ifsp->endoff) {
5505 break;
5506 }
5507 q = p;
5508 if (*p == CTLESC)
5509 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005510 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005511 p = q;
5512 break;
5513 } else if (strchr(defifs, *p) == NULL) {
5514 if (ifsspc) {
5515 p++;
5516 ifsspc = 0;
5517 } else {
5518 p = q;
5519 break;
5520 }
5521 } else
5522 p++;
5523 }
5524 }
5525 start = p;
5526 } else
5527 p++;
5528 }
5529 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005530 if (nulonly)
5531 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005532 }
5533
Eric Andersenc470f442003-07-28 09:56:35 +00005534 if (!*start)
5535 return;
5536
5537add:
5538 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005539 sp->text = start;
5540 *arglist->lastp = sp;
5541 arglist->lastp = &sp->next;
5542}
5543
Eric Andersenc470f442003-07-28 09:56:35 +00005544static void
5545ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005546{
Eric Andersenc470f442003-07-28 09:56:35 +00005547 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005548
Eric Andersenc470f442003-07-28 09:56:35 +00005549 INTOFF;
5550 p = ifsfirst.next;
5551 do {
5552 struct ifsregion *ifsp;
5553 ifsp = p->next;
5554 ckfree(p);
5555 p = ifsp;
5556 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005557 ifslastp = NULL;
5558 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005559 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005560}
5561
Eric Andersen90898442003-08-06 11:20:52 +00005562static void expmeta(char *, char *);
5563static struct strlist *expsort(struct strlist *);
5564static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005565
Eric Andersen90898442003-08-06 11:20:52 +00005566static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005567
Eric Andersencb57d552001-06-28 07:25:16 +00005568
Eric Andersenc470f442003-07-28 09:56:35 +00005569static void
Eric Andersen90898442003-08-06 11:20:52 +00005570expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005571{
Eric Andersen90898442003-08-06 11:20:52 +00005572 static const char metachars[] = {
5573 '*', '?', '[', 0
5574 };
Eric Andersencb57d552001-06-28 07:25:16 +00005575 /* TODO - EXP_REDIR */
5576
5577 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005578 struct strlist **savelastp;
5579 struct strlist *sp;
5580 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005581
Eric Andersencb57d552001-06-28 07:25:16 +00005582 if (fflag)
5583 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005584 if (!strpbrk(str->text, metachars))
5585 goto nometa;
5586 savelastp = exparg.lastp;
5587
Eric Andersencb57d552001-06-28 07:25:16 +00005588 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005589 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005590 {
5591 int i = strlen(str->text);
5592 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5593 }
5594
5595 expmeta(expdir, p);
5596 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005597 if (p != str->text)
5598 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005599 INTON;
5600 if (exparg.lastp == savelastp) {
5601 /*
5602 * no matches
5603 */
Eric Andersenc470f442003-07-28 09:56:35 +00005604nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005605 *exparg.lastp = str;
5606 rmescapes(str->text);
5607 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005608 } else {
5609 *exparg.lastp = NULL;
5610 *savelastp = sp = expsort(*savelastp);
5611 while (sp->next != NULL)
5612 sp = sp->next;
5613 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005614 }
5615 str = str->next;
5616 }
5617}
5618
Eric Andersencb57d552001-06-28 07:25:16 +00005619/*
Eric Andersenc470f442003-07-28 09:56:35 +00005620 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005621 */
5622
Eric Andersenc470f442003-07-28 09:56:35 +00005623static void
Eric Andersen90898442003-08-06 11:20:52 +00005624addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005625{
Eric Andersencb57d552001-06-28 07:25:16 +00005626 struct strlist *sp;
5627
Eric Andersenc470f442003-07-28 09:56:35 +00005628 sp = (struct strlist *)stalloc(sizeof *sp);
5629 sp->text = sstrdup(name);
5630 *exparg.lastp = sp;
5631 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005632}
5633
5634
Eric Andersencb57d552001-06-28 07:25:16 +00005635/*
Eric Andersen90898442003-08-06 11:20:52 +00005636 * Do metacharacter (i.e. *, ?, [...]) expansion.
5637 */
5638
5639static void
5640expmeta(char *enddir, char *name)
5641{
5642 char *p;
5643 const char *cp;
5644 char *start;
5645 char *endname;
5646 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005647 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005648 DIR *dirp;
5649 struct dirent *dp;
5650 int atend;
5651 int matchdot;
5652
5653 metaflag = 0;
5654 start = name;
5655 for (p = name; *p; p++) {
5656 if (*p == '*' || *p == '?')
5657 metaflag = 1;
5658 else if (*p == '[') {
5659 char *q = p + 1;
5660 if (*q == '!')
5661 q++;
5662 for (;;) {
5663 if (*q == '\\')
5664 q++;
5665 if (*q == '/' || *q == '\0')
5666 break;
5667 if (*++q == ']') {
5668 metaflag = 1;
5669 break;
5670 }
5671 }
5672 } else if (*p == '\\')
5673 p++;
5674 else if (*p == '/') {
5675 if (metaflag)
5676 goto out;
5677 start = p + 1;
5678 }
5679 }
5680out:
5681 if (metaflag == 0) { /* we've reached the end of the file name */
5682 if (enddir != expdir)
5683 metaflag++;
5684 p = name;
5685 do {
5686 if (*p == '\\')
5687 p++;
5688 *enddir++ = *p;
5689 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005690 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005691 addfname(expdir);
5692 return;
5693 }
5694 endname = p;
5695 if (name < start) {
5696 p = name;
5697 do {
5698 if (*p == '\\')
5699 p++;
5700 *enddir++ = *p++;
5701 } while (p < start);
5702 }
5703 if (enddir == expdir) {
5704 cp = ".";
5705 } else if (enddir == expdir + 1 && *expdir == '/') {
5706 cp = "/";
5707 } else {
5708 cp = expdir;
5709 enddir[-1] = '\0';
5710 }
5711 if ((dirp = opendir(cp)) == NULL)
5712 return;
5713 if (enddir != expdir)
5714 enddir[-1] = '/';
5715 if (*endname == 0) {
5716 atend = 1;
5717 } else {
5718 atend = 0;
5719 *endname++ = '\0';
5720 }
5721 matchdot = 0;
5722 p = start;
5723 if (*p == '\\')
5724 p++;
5725 if (*p == '.')
5726 matchdot++;
5727 while (! intpending && (dp = readdir(dirp)) != NULL) {
5728 if (dp->d_name[0] == '.' && ! matchdot)
5729 continue;
5730 if (pmatch(start, dp->d_name)) {
5731 if (atend) {
5732 scopy(dp->d_name, enddir);
5733 addfname(expdir);
5734 } else {
5735 for (p = enddir, cp = dp->d_name;
5736 (*p++ = *cp++) != '\0';)
5737 continue;
5738 p[-1] = '/';
5739 expmeta(p, endname);
5740 }
5741 }
5742 }
5743 closedir(dirp);
5744 if (! atend)
5745 endname[-1] = '/';
5746}
5747
5748/*
5749 * Sort the results of file name expansion. It calculates the number of
5750 * strings to sort and then calls msort (short for merge sort) to do the
5751 * work.
5752 */
5753
5754static struct strlist *
5755expsort(struct strlist *str)
5756{
5757 int len;
5758 struct strlist *sp;
5759
5760 len = 0;
5761 for (sp = str ; sp ; sp = sp->next)
5762 len++;
5763 return msort(str, len);
5764}
5765
5766
5767static struct strlist *
5768msort(struct strlist *list, int len)
5769{
5770 struct strlist *p, *q = NULL;
5771 struct strlist **lpp;
5772 int half;
5773 int n;
5774
5775 if (len <= 1)
5776 return list;
5777 half = len >> 1;
5778 p = list;
5779 for (n = half ; --n >= 0 ; ) {
5780 q = p;
5781 p = p->next;
5782 }
5783 q->next = NULL; /* terminate first half of list */
5784 q = msort(list, half); /* sort first half of list */
5785 p = msort(p, len - half); /* sort second half */
5786 lpp = &list;
5787 for (;;) {
5788#ifdef CONFIG_LOCALE_SUPPORT
5789 if (strcoll(p->text, q->text) < 0)
5790#else
5791 if (strcmp(p->text, q->text) < 0)
5792#endif
5793 {
5794 *lpp = p;
5795 lpp = &p->next;
5796 if ((p = *lpp) == NULL) {
5797 *lpp = q;
5798 break;
5799 }
5800 } else {
5801 *lpp = q;
5802 lpp = &q->next;
5803 if ((q = *lpp) == NULL) {
5804 *lpp = p;
5805 break;
5806 }
5807 }
5808 }
5809 return list;
5810}
5811
5812
5813/*
Eric Andersencb57d552001-06-28 07:25:16 +00005814 * Returns true if the pattern matches the string.
5815 */
5816
Eric Andersenc470f442003-07-28 09:56:35 +00005817static inline int
5818patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005819{
Eric Andersenc470f442003-07-28 09:56:35 +00005820 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005821}
5822
5823
Eric Andersencb57d552001-06-28 07:25:16 +00005824/*
5825 * Remove any CTLESC characters from a string.
5826 */
5827
Eric Andersenc470f442003-07-28 09:56:35 +00005828static char *
5829_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005830{
5831 char *p, *q, *r;
5832 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005833 unsigned inquotes;
5834 int notescaped;
5835 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005836
5837 p = strpbrk(str, qchars);
5838 if (!p) {
5839 return str;
5840 }
5841 q = p;
5842 r = str;
5843 if (flag & RMESCAPE_ALLOC) {
5844 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005845 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005846
Eric Andersenc470f442003-07-28 09:56:35 +00005847 if (flag & RMESCAPE_GROW) {
5848 r = makestrspace(fulllen, expdest);
5849 } else if (flag & RMESCAPE_HEAP) {
5850 r = ckmalloc(fulllen);
5851 } else {
5852 r = stalloc(fulllen);
5853 }
5854 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005855 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005856 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005857 }
5858 }
Eric Andersenc470f442003-07-28 09:56:35 +00005859 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5860 globbing = flag & RMESCAPE_GLOB;
5861 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005862 while (*p) {
5863 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005864 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005865 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005866 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005867 continue;
5868 }
Eric Andersenc470f442003-07-28 09:56:35 +00005869 if (*p == '\\') {
5870 /* naked back slash */
5871 notescaped = 0;
5872 goto copy;
5873 }
Eric Andersencb57d552001-06-28 07:25:16 +00005874 if (*p == CTLESC) {
5875 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005876 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005877 *q++ = '\\';
5878 }
5879 }
Eric Andersenc470f442003-07-28 09:56:35 +00005880 notescaped = globbing;
5881copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005882 *q++ = *p++;
5883 }
5884 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005885 if (flag & RMESCAPE_GROW) {
5886 expdest = r;
5887 STADJUST(q - r + 1, expdest);
5888 }
Eric Andersencb57d552001-06-28 07:25:16 +00005889 return r;
5890}
Eric Andersencb57d552001-06-28 07:25:16 +00005891
5892
Eric Andersencb57d552001-06-28 07:25:16 +00005893/*
5894 * See if a pattern matches in a case statement.
5895 */
5896
Eric Andersenc470f442003-07-28 09:56:35 +00005897int
5898casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005899{
Eric Andersencb57d552001-06-28 07:25:16 +00005900 struct stackmark smark;
5901 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005902
5903 setstackmark(&smark);
5904 argbackq = pattern->narg.backquote;
5905 STARTSTACKSTR(expdest);
5906 ifslastp = NULL;
5907 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005908 STACKSTRNUL(expdest);
5909 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005910 popstackmark(&smark);
5911 return result;
5912}
5913
5914/*
5915 * Our own itoa().
5916 */
5917
Eric Andersenc470f442003-07-28 09:56:35 +00005918static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005919cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005920{
Eric Andersencb57d552001-06-28 07:25:16 +00005921 int len;
5922
Eric Andersenc470f442003-07-28 09:56:35 +00005923 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005924#ifdef CONFIG_ASH_MATH_SUPPORT_64
5925 len = fmtstr(expdest, 32, "%lld", (long long) num);
5926#else
Eric Andersenc470f442003-07-28 09:56:35 +00005927 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005928#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005929 STADJUST(len, expdest);
5930 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005931}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005932
Eric Andersenc470f442003-07-28 09:56:35 +00005933static void
5934varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005935{
Eric Andersenc470f442003-07-28 09:56:35 +00005936 const char *msg;
5937 const char *tail;
5938
5939 tail = nullstr;
5940 msg = "parameter not set";
5941 if (umsg) {
5942 if (*end == CTLENDVAR) {
5943 if (varflags & VSNUL)
5944 tail = " or null";
5945 } else
5946 msg = umsg;
5947 }
5948 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005949}
Eric Andersen90898442003-08-06 11:20:52 +00005950
5951
Eric Andersenc470f442003-07-28 09:56:35 +00005952/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005953
Eric Andersencb57d552001-06-28 07:25:16 +00005954/*
Eric Andersen90898442003-08-06 11:20:52 +00005955 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005956 */
5957
Eric Andersenc470f442003-07-28 09:56:35 +00005958#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5959#define IBUFSIZ (BUFSIZ + 1)
Eric Andersencb57d552001-06-28 07:25:16 +00005960
Eric Andersenc470f442003-07-28 09:56:35 +00005961static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005962
Eric Andersencb57d552001-06-28 07:25:16 +00005963/*
Eric Andersenc470f442003-07-28 09:56:35 +00005964 * Read a character from the script, returning PEOF on end of file.
5965 * Nul characters in the input are silently discarded.
5966 */
5967
5968#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5969
5970#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5971#define pgetc_macro() pgetc()
5972static int
5973pgetc(void)
5974{
5975 return pgetc_as_macro();
5976}
5977#else
5978#define pgetc_macro() pgetc_as_macro()
5979static int
5980pgetc(void)
5981{
5982 return pgetc_macro();
5983}
5984#endif
5985
5986
5987/*
5988 * Same as pgetc(), but ignores PEOA.
5989 */
5990#ifdef CONFIG_ASH_ALIAS
5991static int pgetc2(void)
5992{
5993 int c;
5994
5995 do {
5996 c = pgetc_macro();
5997 } while (c == PEOA);
5998 return c;
5999}
6000#else
6001static inline int pgetc2(void)
6002{
6003 return pgetc_macro();
6004}
6005#endif
6006
Glenn L McGrath28939ad2004-07-21 10:20:19 +00006007/*
6008 * Read a line from the script.
6009 */
6010
6011static inline char *
6012pfgets(char *line, int len)
6013{
6014 char *p = line;
6015 int nleft = len;
6016 int c;
6017
6018 while (--nleft > 0) {
6019 c = pgetc2();
6020 if (c == PEOF) {
6021 if (p == line)
6022 return NULL;
6023 break;
6024 }
6025 *p++ = c;
6026 if (c == '\n')
6027 break;
6028 }
6029 *p = '\0';
6030 return line;
6031}
6032
6033
Eric Andersenc470f442003-07-28 09:56:35 +00006034
6035#ifdef CONFIG_FEATURE_COMMAND_EDITING
6036static const char *cmdedit_prompt;
6037static inline void putprompt(const char *s)
6038{
6039 cmdedit_prompt = s;
6040}
6041#else
6042static inline void putprompt(const char *s)
6043{
6044 out2str(s);
6045}
6046#endif
6047
6048static inline int
6049preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006050{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006051 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006052 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006053 parsenextc = buf;
6054
Eric Andersenc470f442003-07-28 09:56:35 +00006055retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006056#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006057 if (!iflag || parsefile->fd)
6058 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6059 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006060#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006061 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006062#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006063 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6064 if(nr == 0) {
6065 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006066 if(trap[SIGINT]) {
6067 buf[0] = '\n';
6068 buf[1] = 0;
6069 raise(SIGINT);
6070 return 1;
6071 }
Eric Andersenc470f442003-07-28 09:56:35 +00006072 goto retry;
6073 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006074 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006075 /* Ctrl+D presend */
6076 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006077 }
Eric Andersencb57d552001-06-28 07:25:16 +00006078 }
6079#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006080 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006081#endif
6082
6083 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006084 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6085 int flags = fcntl(0, F_GETFL, 0);
6086 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006087 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006088 if (fcntl(0, F_SETFL, flags) >= 0) {
6089 out2str("sh: turning off NDELAY mode\n");
6090 goto retry;
6091 }
6092 }
6093 }
6094 }
6095 return nr;
6096}
6097
6098/*
6099 * Refill the input buffer and return the next input character:
6100 *
6101 * 1) If a string was pushed back on the input, pop it;
6102 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6103 * from a string so we can't refill the buffer, return EOF.
6104 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6105 * 4) Process input up to the next newline, deleting nul characters.
6106 */
6107
Eric Andersenc470f442003-07-28 09:56:35 +00006108int
6109preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006110{
6111 char *p, *q;
6112 int more;
6113 char savec;
6114
6115 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006116#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006117 if (parsenleft == -1 && parsefile->strpush->ap &&
6118 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006119 return PEOA;
6120 }
Eric Andersen2870d962001-07-02 17:27:21 +00006121#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006122 popstring();
6123 if (--parsenleft >= 0)
6124 return (*parsenextc++);
6125 }
6126 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6127 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006128 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006129
Eric Andersenc470f442003-07-28 09:56:35 +00006130again:
Eric Andersencb57d552001-06-28 07:25:16 +00006131 if (parselleft <= 0) {
6132 if ((parselleft = preadfd()) <= 0) {
6133 parselleft = parsenleft = EOF_NLEFT;
6134 return PEOF;
6135 }
6136 }
6137
6138 q = p = parsenextc;
6139
6140 /* delete nul characters */
6141 for (more = 1; more;) {
6142 switch (*p) {
6143 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006144 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006145 goto check;
6146
Eric Andersencb57d552001-06-28 07:25:16 +00006147 case '\n':
6148 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006149 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006150 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006151
Eric Andersencb57d552001-06-28 07:25:16 +00006152 }
6153
6154 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006155check:
Eric Andersencb57d552001-06-28 07:25:16 +00006156 if (--parselleft <= 0 && more) {
6157 parsenleft = q - parsenextc - 1;
6158 if (parsenleft < 0)
6159 goto again;
6160 more = 0;
6161 }
6162 }
6163
6164 savec = *q;
6165 *q = '\0';
6166
6167 if (vflag) {
6168 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006169 }
6170
6171 *q = savec;
6172
6173 return *parsenextc++;
6174}
6175
Eric Andersenc470f442003-07-28 09:56:35 +00006176/*
6177 * Undo the last call to pgetc. Only one character may be pushed back.
6178 * PEOF may be pushed back.
6179 */
6180
6181void
6182pungetc(void)
6183{
6184 parsenleft++;
6185 parsenextc--;
6186}
Eric Andersencb57d552001-06-28 07:25:16 +00006187
6188/*
6189 * Push a string back onto the input at this current parsefile level.
6190 * We handle aliases this way.
6191 */
Eric Andersenc470f442003-07-28 09:56:35 +00006192void
6193pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006194{
Eric Andersencb57d552001-06-28 07:25:16 +00006195 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006196 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006197
Eric Andersenc470f442003-07-28 09:56:35 +00006198 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006199 INTOFF;
6200/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6201 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006202 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006203 sp->prev = parsefile->strpush;
6204 parsefile->strpush = sp;
6205 } else
6206 sp = parsefile->strpush = &(parsefile->basestrpush);
6207 sp->prevstring = parsenextc;
6208 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006209#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006210 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006211 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006212 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006213 sp->string = s;
6214 }
Eric Andersen2870d962001-07-02 17:27:21 +00006215#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006216 parsenextc = s;
6217 parsenleft = len;
6218 INTON;
6219}
6220
Eric Andersenc470f442003-07-28 09:56:35 +00006221void
6222popstring(void)
6223{
6224 struct strpush *sp = parsefile->strpush;
6225
6226 INTOFF;
6227#ifdef CONFIG_ASH_ALIAS
6228 if (sp->ap) {
6229 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6230 checkkwd |= CHKALIAS;
6231 }
6232 if (sp->string != sp->ap->val) {
6233 ckfree(sp->string);
6234 }
6235 sp->ap->flag &= ~ALIASINUSE;
6236 if (sp->ap->flag & ALIASDEAD) {
6237 unalias(sp->ap->name);
6238 }
6239 }
6240#endif
6241 parsenextc = sp->prevstring;
6242 parsenleft = sp->prevnleft;
6243/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6244 parsefile->strpush = sp->prev;
6245 if (sp != &(parsefile->basestrpush))
6246 ckfree(sp);
6247 INTON;
6248}
6249
6250/*
6251 * Set the input to take input from a file. If push is set, push the
6252 * old input onto the stack first.
6253 */
6254
6255void
6256setinputfile(const char *fname, int push)
6257{
6258 int fd;
6259 int fd2;
6260
6261 INTOFF;
6262 if ((fd = open(fname, O_RDONLY)) < 0)
6263 error("Can't open %s", fname);
6264 if (fd < 10) {
6265 fd2 = copyfd(fd, 10);
6266 close(fd);
6267 if (fd2 < 0)
6268 error("Out of file descriptors");
6269 fd = fd2;
6270 }
6271 setinputfd(fd, push);
6272 INTON;
6273}
6274
6275
6276/*
6277 * Like setinputfile, but takes an open file descriptor. Call this with
6278 * interrupts off.
6279 */
6280
6281static void
6282setinputfd(int fd, int push)
6283{
6284 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6285 if (push) {
6286 pushfile();
6287 parsefile->buf = 0;
6288 }
6289 parsefile->fd = fd;
6290 if (parsefile->buf == NULL)
6291 parsefile->buf = ckmalloc(IBUFSIZ);
6292 parselleft = parsenleft = 0;
6293 plinno = 1;
6294}
6295
Eric Andersencb57d552001-06-28 07:25:16 +00006296
Eric Andersencb57d552001-06-28 07:25:16 +00006297/*
6298 * Like setinputfile, but takes input from a string.
6299 */
6300
Eric Andersenc470f442003-07-28 09:56:35 +00006301static void
6302setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006303{
Eric Andersencb57d552001-06-28 07:25:16 +00006304 INTOFF;
6305 pushfile();
6306 parsenextc = string;
6307 parsenleft = strlen(string);
6308 parsefile->buf = NULL;
6309 plinno = 1;
6310 INTON;
6311}
6312
6313
Eric Andersencb57d552001-06-28 07:25:16 +00006314/*
6315 * To handle the "." command, a stack of input files is used. Pushfile
6316 * adds a new entry to the stack and popfile restores the previous level.
6317 */
6318
Eric Andersenc470f442003-07-28 09:56:35 +00006319static void
6320pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006321{
Eric Andersencb57d552001-06-28 07:25:16 +00006322 struct parsefile *pf;
6323
6324 parsefile->nleft = parsenleft;
6325 parsefile->lleft = parselleft;
6326 parsefile->nextc = parsenextc;
6327 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006328 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006329 pf->prev = parsefile;
6330 pf->fd = -1;
6331 pf->strpush = NULL;
6332 pf->basestrpush.prev = NULL;
6333 parsefile = pf;
6334}
6335
Eric Andersenc470f442003-07-28 09:56:35 +00006336
6337static void
6338popfile(void)
6339{
6340 struct parsefile *pf = parsefile;
6341
6342 INTOFF;
6343 if (pf->fd >= 0)
6344 close(pf->fd);
6345 if (pf->buf)
6346 ckfree(pf->buf);
6347 while (pf->strpush)
6348 popstring();
6349 parsefile = pf->prev;
6350 ckfree(pf);
6351 parsenleft = parsefile->nleft;
6352 parselleft = parsefile->lleft;
6353 parsenextc = parsefile->nextc;
6354 plinno = parsefile->linno;
6355 INTON;
6356}
Eric Andersencb57d552001-06-28 07:25:16 +00006357
6358
Eric Andersen2870d962001-07-02 17:27:21 +00006359/*
Eric Andersenc470f442003-07-28 09:56:35 +00006360 * Return to top level.
6361 */
Eric Andersen2870d962001-07-02 17:27:21 +00006362
Eric Andersenc470f442003-07-28 09:56:35 +00006363static void
6364popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006365{
Eric Andersenc470f442003-07-28 09:56:35 +00006366 while (parsefile != &basepf)
6367 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006368}
6369
Eric Andersen2870d962001-07-02 17:27:21 +00006370
Eric Andersenc470f442003-07-28 09:56:35 +00006371/*
6372 * Close the file(s) that the shell is reading commands from. Called
6373 * after a fork is done.
6374 */
6375
6376static void
6377closescript(void)
6378{
6379 popallfiles();
6380 if (parsefile->fd > 0) {
6381 close(parsefile->fd);
6382 parsefile->fd = 0;
6383 }
6384}
Eric Andersenc470f442003-07-28 09:56:35 +00006385
Eric Andersen90898442003-08-06 11:20:52 +00006386/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006387
6388/* mode flags for set_curjob */
6389#define CUR_DELETE 2
6390#define CUR_RUNNING 1
6391#define CUR_STOPPED 0
6392
6393/* mode flags for dowait */
6394#define DOWAIT_NORMAL 0
6395#define DOWAIT_BLOCK 1
6396
6397/* array of jobs */
6398static struct job *jobtab;
6399/* size of array */
6400static unsigned njobs;
6401#if JOBS
6402/* pgrp of shell on invocation */
6403static int initialpgrp;
6404static int ttyfd = -1;
6405#endif
6406/* current job */
6407static struct job *curjob;
6408/* number of presumed living untracked jobs */
6409static int jobless;
6410
6411static void set_curjob(struct job *, unsigned);
6412#if JOBS
6413static int restartjob(struct job *, int);
6414static void xtcsetpgrp(int, pid_t);
6415static char *commandtext(union node *);
6416static void cmdlist(union node *, int);
6417static void cmdtxt(union node *);
6418static void cmdputs(const char *);
6419static void showpipe(struct job *, FILE *);
6420#endif
6421static int sprint_status(char *, int, int);
6422static void freejob(struct job *);
6423static struct job *getjob(const char *, int);
6424static struct job *growjobtab(void);
6425static void forkchild(struct job *, union node *, int);
6426static void forkparent(struct job *, union node *, int, pid_t);
6427static int dowait(int, struct job *);
6428static int getstatus(struct job *);
6429
6430static void
6431set_curjob(struct job *jp, unsigned mode)
6432{
6433 struct job *jp1;
6434 struct job **jpp, **curp;
6435
6436 /* first remove from list */
6437 jpp = curp = &curjob;
6438 do {
6439 jp1 = *jpp;
6440 if (jp1 == jp)
6441 break;
6442 jpp = &jp1->prev_job;
6443 } while (1);
6444 *jpp = jp1->prev_job;
6445
6446 /* Then re-insert in correct position */
6447 jpp = curp;
6448 switch (mode) {
6449 default:
6450#ifdef DEBUG
6451 abort();
6452#endif
6453 case CUR_DELETE:
6454 /* job being deleted */
6455 break;
6456 case CUR_RUNNING:
6457 /* newly created job or backgrounded job,
6458 put after all stopped jobs. */
6459 do {
6460 jp1 = *jpp;
6461#ifdef JOBS
6462 if (!jp1 || jp1->state != JOBSTOPPED)
6463#endif
6464 break;
6465 jpp = &jp1->prev_job;
6466 } while (1);
6467 /* FALLTHROUGH */
6468#ifdef JOBS
6469 case CUR_STOPPED:
6470#endif
6471 /* newly stopped job - becomes curjob */
6472 jp->prev_job = *jpp;
6473 *jpp = jp;
6474 break;
6475 }
6476}
6477
6478#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006479/*
6480 * Turn job control on and off.
6481 *
6482 * Note: This code assumes that the third arg to ioctl is a character
6483 * pointer, which is true on Berkeley systems but not System V. Since
6484 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006485 *
6486 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006487 */
6488
Eric Andersenc470f442003-07-28 09:56:35 +00006489void
6490setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006491{
Eric Andersenc470f442003-07-28 09:56:35 +00006492 int fd;
6493 int pgrp;
6494
6495 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006496 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006497 if (on) {
6498 int ofd;
6499 ofd = fd = open(_PATH_TTY, O_RDWR);
6500 if (fd < 0) {
6501 fd += 3;
6502 while (!isatty(fd) && --fd >= 0)
6503 ;
6504 }
6505 fd = fcntl(fd, F_DUPFD, 10);
6506 close(ofd);
6507 if (fd < 0)
6508 goto out;
6509 fcntl(fd, F_SETFD, FD_CLOEXEC);
6510 do { /* while we are in the background */
6511 if ((pgrp = tcgetpgrp(fd)) < 0) {
6512out:
6513 sh_warnx("can't access tty; job control turned off");
6514 mflag = on = 0;
6515 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006516 }
Eric Andersenc470f442003-07-28 09:56:35 +00006517 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006518 break;
6519 killpg(0, SIGTTIN);
6520 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006521 initialpgrp = pgrp;
6522
Eric Andersencb57d552001-06-28 07:25:16 +00006523 setsignal(SIGTSTP);
6524 setsignal(SIGTTOU);
6525 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006526 pgrp = rootpid;
6527 setpgid(0, pgrp);
6528 xtcsetpgrp(fd, pgrp);
6529 } else {
6530 /* turning job control off */
6531 fd = ttyfd;
6532 pgrp = initialpgrp;
6533 xtcsetpgrp(fd, pgrp);
6534 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006535 setsignal(SIGTSTP);
6536 setsignal(SIGTTOU);
6537 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006538close:
6539 close(fd);
6540 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006541 }
Eric Andersenc470f442003-07-28 09:56:35 +00006542 ttyfd = fd;
6543 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006544}
Eric Andersencb57d552001-06-28 07:25:16 +00006545
Eric Andersenc470f442003-07-28 09:56:35 +00006546static int
Eric Andersen90898442003-08-06 11:20:52 +00006547killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006548{
6549 int signo = -1;
6550 int list = 0;
6551 int i;
6552 pid_t pid;
6553 struct job *jp;
6554
6555 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006556usage:
6557 error(
6558"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6559"kill -l [exitstatus]"
6560 );
Eric Andersencb57d552001-06-28 07:25:16 +00006561 }
6562
Eric Andersenc470f442003-07-28 09:56:35 +00006563 if (**++argv == '-') {
6564 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006565 if (signo < 0) {
6566 int c;
6567
6568 while ((c = nextopt("ls:")) != '\0')
6569 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006570 default:
6571#ifdef DEBUG
6572 abort();
6573#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006574 case 'l':
6575 list = 1;
6576 break;
6577 case 's':
6578 signo = decode_signal(optionarg, 1);
6579 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006580 error(
6581 "invalid signal number or name: %s",
6582 optionarg
6583 );
Eric Andersencb57d552001-06-28 07:25:16 +00006584 }
Eric Andersen2870d962001-07-02 17:27:21 +00006585 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006586 }
Eric Andersenc470f442003-07-28 09:56:35 +00006587 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006588 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006589 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006590 }
6591
6592 if (!list && signo < 0)
6593 signo = SIGTERM;
6594
Eric Andersenc470f442003-07-28 09:56:35 +00006595 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006596 goto usage;
6597 }
6598
6599 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006600 const char *name;
6601
Eric Andersenc470f442003-07-28 09:56:35 +00006602 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006603 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006604 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006605 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006606 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006607 }
6608 return 0;
6609 }
Eric Andersen34506362001-08-02 05:02:46 +00006610 name = u_signal_names(*argptr, &signo, -1);
6611 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006612 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006613 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006614 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006615 return 0;
6616 }
6617
Eric Andersenc470f442003-07-28 09:56:35 +00006618 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006619 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006620 if (**argv == '%') {
6621 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006622 pid = -jp->ps[0].pid;
6623 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006624 pid = number(*argv);
6625 if (kill(pid, signo) != 0) {
6626 sh_warnx("%m\n");
6627 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006628 }
Eric Andersenc470f442003-07-28 09:56:35 +00006629 } while (*++argv);
6630
6631 return i;
6632}
6633#endif /* JOBS */
6634
6635#if defined(JOBS) || defined(DEBUG)
6636static int
6637jobno(const struct job *jp)
6638{
6639 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006640}
6641#endif
6642
Eric Andersenc470f442003-07-28 09:56:35 +00006643#ifdef JOBS
6644static int
6645fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006646{
Eric Andersenc470f442003-07-28 09:56:35 +00006647 struct job *jp;
6648 FILE *out;
6649 int mode;
6650 int retval;
6651
6652 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6653 nextopt(nullstr);
6654 argv = argptr;
6655 out = stdout;
6656 do {
6657 jp = getjob(*argv, 1);
6658 if (mode == FORK_BG) {
6659 set_curjob(jp, CUR_RUNNING);
6660 fprintf(out, "[%d] ", jobno(jp));
6661 }
6662 outstr(jp->ps->cmd, out);
6663 showpipe(jp, out);
6664 retval = restartjob(jp, mode);
6665 } while (*argv && *++argv);
6666 return retval;
6667}
6668
6669static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6670
6671
6672static int
6673restartjob(struct job *jp, int mode)
6674{
6675 struct procstat *ps;
6676 int i;
6677 int status;
6678 pid_t pgid;
6679
6680 INTOFF;
6681 if (jp->state == JOBDONE)
6682 goto out;
6683 jp->state = JOBRUNNING;
6684 pgid = jp->ps->pid;
6685 if (mode == FORK_FG)
6686 xtcsetpgrp(ttyfd, pgid);
6687 killpg(pgid, SIGCONT);
6688 ps = jp->ps;
6689 i = jp->nprocs;
6690 do {
6691 if (WIFSTOPPED(ps->status)) {
6692 ps->status = -1;
6693 }
6694 } while (ps++, --i);
6695out:
6696 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6697 INTON;
6698 return status;
6699}
6700#endif
6701
6702static int
6703sprint_status(char *s, int status, int sigonly)
6704{
6705 int col;
6706 int st;
6707
6708 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006709 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006710#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006711 if (WIFSTOPPED(status))
6712 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006713 else
Eric Andersenc470f442003-07-28 09:56:35 +00006714#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006715 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006716 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006717 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006718 goto out;
6719#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006720 if (WIFSTOPPED(status))
6721 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006722#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006723 }
6724 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006725 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006726 if (WCOREDUMP(status)) {
6727 col += fmtstr(s + col, 16, " (core dumped)");
6728 }
6729 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006730 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006731 if (st)
6732 col = fmtstr(s, 16, "Done(%d)", st);
6733 else
6734 col = fmtstr(s, 16, "Done");
6735 }
6736
6737out:
6738 return col;
6739}
6740
6741#if JOBS
6742static void
6743showjob(FILE *out, struct job *jp, int mode)
6744{
6745 struct procstat *ps;
6746 struct procstat *psend;
6747 int col;
6748 int indent;
6749 char s[80];
6750
6751 ps = jp->ps;
6752
6753 if (mode & SHOW_PGID) {
6754 /* just output process (group) id of pipeline */
6755 fprintf(out, "%d\n", ps->pid);
6756 return;
6757 }
6758
6759 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6760 indent = col;
6761
6762 if (jp == curjob)
6763 s[col - 2] = '+';
6764 else if (curjob && jp == curjob->prev_job)
6765 s[col - 2] = '-';
6766
6767 if (mode & SHOW_PID)
6768 col += fmtstr(s + col, 16, "%d ", ps->pid);
6769
6770 psend = ps + jp->nprocs;
6771
6772 if (jp->state == JOBRUNNING) {
6773 scopy("Running", s + col);
6774 col += strlen("Running");
6775 } else {
6776 int status = psend[-1].status;
6777#if JOBS
6778 if (jp->state == JOBSTOPPED)
6779 status = jp->stopstatus;
6780#endif
6781 col += sprint_status(s + col, status, 0);
6782 }
6783
6784 goto start;
6785
6786 do {
6787 /* for each process */
6788 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6789
6790start:
Eric Andersen90898442003-08-06 11:20:52 +00006791 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006792 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6793 );
6794 if (!(mode & SHOW_PID)) {
6795 showpipe(jp, out);
6796 break;
6797 }
6798 if (++ps == psend) {
6799 outcslow('\n', out);
6800 break;
6801 }
6802 } while (1);
6803
6804 jp->changed = 0;
6805
6806 if (jp->state == JOBDONE) {
6807 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6808 freejob(jp);
6809 }
6810}
6811
6812
6813static int
6814jobscmd(int argc, char **argv)
6815{
6816 int mode, m;
6817 FILE *out;
6818
6819 mode = 0;
6820 while ((m = nextopt("lp")))
6821 if (m == 'l')
6822 mode = SHOW_PID;
6823 else
6824 mode = SHOW_PGID;
6825
6826 out = stdout;
6827 argv = argptr;
6828 if (*argv)
6829 do
6830 showjob(out, getjob(*argv,0), mode);
6831 while (*++argv);
6832 else
6833 showjobs(out, mode);
6834
Eric Andersencb57d552001-06-28 07:25:16 +00006835 return 0;
6836}
6837
6838
6839/*
6840 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6841 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006842 */
6843
Eric Andersenc470f442003-07-28 09:56:35 +00006844static void
6845showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006846{
Eric Andersencb57d552001-06-28 07:25:16 +00006847 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006848
Eric Andersenc470f442003-07-28 09:56:35 +00006849 TRACE(("showjobs(%x) called\n", mode));
6850
6851 /* If not even one one job changed, there is nothing to do */
6852 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6853 continue;
6854
6855 for (jp = curjob; jp; jp = jp->prev_job) {
6856 if (!(mode & SHOW_CHANGED) || jp->changed)
6857 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006858 }
6859}
Eric Andersenc470f442003-07-28 09:56:35 +00006860#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006861
6862/*
6863 * Mark a job structure as unused.
6864 */
6865
Eric Andersenc470f442003-07-28 09:56:35 +00006866static void
6867freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006868{
Eric Andersenc470f442003-07-28 09:56:35 +00006869 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006870 int i;
6871
6872 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006873 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006874 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006875 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006876 }
6877 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006878 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006879 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006880 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006881 INTON;
6882}
6883
6884
Eric Andersenc470f442003-07-28 09:56:35 +00006885static int
6886waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006887{
6888 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006889 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006890 struct job *jp;
6891
Eric Andersenc470f442003-07-28 09:56:35 +00006892 EXSIGON();
6893
6894 nextopt(nullstr);
6895 retval = 0;
6896
6897 argv = argptr;
6898 if (!*argv) {
6899 /* wait for all jobs */
6900 for (;;) {
6901 jp = curjob;
6902 while (1) {
6903 if (!jp) {
6904 /* no running procs */
6905 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006906 }
Eric Andersenc470f442003-07-28 09:56:35 +00006907 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006908 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006909 jp->waited = 1;
6910 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006911 }
Eric Andersenc470f442003-07-28 09:56:35 +00006912 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006913 }
6914 }
Eric Andersenc470f442003-07-28 09:56:35 +00006915
6916 retval = 127;
6917 do {
6918 if (**argv != '%') {
6919 pid_t pid = number(*argv);
6920 job = curjob;
6921 goto start;
6922 do {
6923 if (job->ps[job->nprocs - 1].pid == pid)
6924 break;
6925 job = job->prev_job;
6926start:
6927 if (!job)
6928 goto repeat;
6929 } while (1);
6930 } else
6931 job = getjob(*argv, 0);
6932 /* loop until process terminated or stopped */
6933 while (job->state == JOBRUNNING)
6934 dowait(DOWAIT_BLOCK, 0);
6935 job->waited = 1;
6936 retval = getstatus(job);
6937repeat:
6938 ;
6939 } while (*++argv);
6940
6941out:
6942 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006943}
6944
6945
Eric Andersencb57d552001-06-28 07:25:16 +00006946/*
6947 * Convert a job name to a job structure.
6948 */
6949
Eric Andersenc470f442003-07-28 09:56:35 +00006950static struct job *
6951getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006952{
Eric Andersencb57d552001-06-28 07:25:16 +00006953 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006954 struct job *found;
6955 const char *err_msg = "No such job: %s";
6956 unsigned num;
6957 int c;
6958 const char *p;
6959 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006960
Eric Andersenc470f442003-07-28 09:56:35 +00006961 jp = curjob;
6962 p = name;
6963 if (!p)
6964 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006965
Eric Andersenc470f442003-07-28 09:56:35 +00006966 if (*p != '%')
6967 goto err;
6968
6969 c = *++p;
6970 if (!c)
6971 goto currentjob;
6972
6973 if (!p[1]) {
6974 if (c == '+' || c == '%') {
6975currentjob:
6976 err_msg = "No current job";
6977 goto check;
6978 } else if (c == '-') {
6979 if (jp)
6980 jp = jp->prev_job;
6981 err_msg = "No previous job";
6982check:
6983 if (!jp)
6984 goto err;
6985 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006986 }
6987 }
Eric Andersenc470f442003-07-28 09:56:35 +00006988
6989 if (is_number(p)) {
6990 num = atoi(p);
6991 if (num < njobs) {
6992 jp = jobtab + num - 1;
6993 if (jp->used)
6994 goto gotit;
6995 goto err;
6996 }
6997 }
6998
6999 match = prefix;
7000 if (*p == '?') {
7001 match = strstr;
7002 p++;
7003 }
7004
7005 found = 0;
7006 while (1) {
7007 if (!jp)
7008 goto err;
7009 if (match(jp->ps[0].cmd, p)) {
7010 if (found)
7011 goto err;
7012 found = jp;
7013 err_msg = "%s: ambiguous";
7014 }
7015 jp = jp->prev_job;
7016 }
7017
7018gotit:
7019#if JOBS
7020 err_msg = "job %s not created under job control";
7021 if (getctl && jp->jobctl == 0)
7022 goto err;
7023#endif
7024 return jp;
7025err:
7026 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007027}
7028
7029
Eric Andersencb57d552001-06-28 07:25:16 +00007030/*
Eric Andersenc470f442003-07-28 09:56:35 +00007031 * Return a new job structure.
7032 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007033 */
7034
Eric Andersenc470f442003-07-28 09:56:35 +00007035static struct job *
7036makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007037{
7038 int i;
7039 struct job *jp;
7040
Eric Andersenc470f442003-07-28 09:56:35 +00007041 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007042 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007043 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007044 break;
7045 }
7046 if (jp->used == 0)
7047 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007048 if (jp->state != JOBDONE || !jp->waited)
7049 continue;
7050#if JOBS
7051 if (jobctl)
7052 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007053#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007054 freejob(jp);
7055 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007056 }
Eric Andersenc470f442003-07-28 09:56:35 +00007057 memset(jp, 0, sizeof(*jp));
7058#if JOBS
7059 if (jobctl)
7060 jp->jobctl = 1;
7061#endif
7062 jp->prev_job = curjob;
7063 curjob = jp;
7064 jp->used = 1;
7065 jp->ps = &jp->ps0;
7066 if (nprocs > 1) {
7067 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7068 }
7069 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7070 jobno(jp)));
7071 return jp;
7072}
7073
7074static struct job *
7075growjobtab(void)
7076{
7077 size_t len;
7078 ptrdiff_t offset;
7079 struct job *jp, *jq;
7080
7081 len = njobs * sizeof(*jp);
7082 jq = jobtab;
7083 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7084
7085 offset = (char *)jp - (char *)jq;
7086 if (offset) {
7087 /* Relocate pointers */
7088 size_t l = len;
7089
7090 jq = (struct job *)((char *)jq + l);
7091 while (l) {
7092 l -= sizeof(*jp);
7093 jq--;
7094#define joff(p) ((struct job *)((char *)(p) + l))
7095#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007096 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007097 jmove(joff(jp)->ps);
7098 if (joff(jp)->prev_job)
7099 jmove(joff(jp)->prev_job);
7100 }
7101 if (curjob)
7102 jmove(curjob);
7103#undef joff
7104#undef jmove
7105 }
7106
7107 njobs += 4;
7108 jobtab = jp;
7109 jp = (struct job *)((char *)jp + len);
7110 jq = jp + 3;
7111 do {
7112 jq->used = 0;
7113 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007114 return jp;
7115}
7116
7117
7118/*
Eric Andersenc470f442003-07-28 09:56:35 +00007119 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007120 * own process group. Jp is a job structure that the job is to be added to.
7121 * N is the command that will be evaluated by the child. Both jp and n may
7122 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007123 * FORK_FG - Fork off a foreground process.
7124 * FORK_BG - Fork off a background process.
7125 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7126 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007127 *
7128 * When job control is turned off, background processes have their standard
7129 * input redirected to /dev/null (except for the second and later processes
7130 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007131 *
7132 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007133 */
7134
Eric Andersenc470f442003-07-28 09:56:35 +00007135static inline void
7136forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007137{
Eric Andersenc470f442003-07-28 09:56:35 +00007138 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007139
Eric Andersenc470f442003-07-28 09:56:35 +00007140 TRACE(("Child shell %d\n", getpid()));
7141 wasroot = rootshell;
7142 rootshell = 0;
7143
7144 closescript();
7145 clear_traps();
7146#if JOBS
7147 /* do job control only in root shell */
7148 jobctl = 0;
7149 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7150 pid_t pgrp;
7151
7152 if (jp->nprocs == 0)
7153 pgrp = getpid();
7154 else
7155 pgrp = jp->ps[0].pid;
7156 /* This can fail because we are doing it in the parent also */
7157 (void)setpgid(0, pgrp);
7158 if (mode == FORK_FG)
7159 xtcsetpgrp(ttyfd, pgrp);
7160 setsignal(SIGTSTP);
7161 setsignal(SIGTTOU);
7162 } else
Eric Andersen62483552001-07-10 06:09:16 +00007163#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007164 if (mode == FORK_BG) {
7165 ignoresig(SIGINT);
7166 ignoresig(SIGQUIT);
7167 if (jp->nprocs == 0) {
7168 close(0);
7169 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7170 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007171 }
Eric Andersencb57d552001-06-28 07:25:16 +00007172 }
Eric Andersenc470f442003-07-28 09:56:35 +00007173 if (wasroot && iflag) {
7174 setsignal(SIGINT);
7175 setsignal(SIGQUIT);
7176 setsignal(SIGTERM);
7177 }
7178 for (jp = curjob; jp; jp = jp->prev_job)
7179 freejob(jp);
7180 jobless = 0;
7181}
7182
7183static inline void
7184forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7185{
7186 TRACE(("In parent shell: child = %d\n", pid));
7187 if (!jp) {
7188 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7189 jobless++;
7190 return;
7191 }
7192#if JOBS
7193 if (mode != FORK_NOJOB && jp->jobctl) {
7194 int pgrp;
7195
7196 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007197 pgrp = pid;
7198 else
7199 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007200 /* This can fail because we are doing it in the child also */
7201 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007202 }
Eric Andersen62483552001-07-10 06:09:16 +00007203#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007204 if (mode == FORK_BG) {
7205 backgndpid = pid; /* set $! */
7206 set_curjob(jp, CUR_RUNNING);
7207 }
Eric Andersencb57d552001-06-28 07:25:16 +00007208 if (jp) {
7209 struct procstat *ps = &jp->ps[jp->nprocs++];
7210 ps->pid = pid;
7211 ps->status = -1;
7212 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007213#if JOBS
7214 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007215 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007216#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007217 }
Eric Andersencb57d552001-06-28 07:25:16 +00007218}
7219
Eric Andersenc470f442003-07-28 09:56:35 +00007220static int
7221forkshell(struct job *jp, union node *n, int mode)
7222{
7223 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007224
Eric Andersenc470f442003-07-28 09:56:35 +00007225 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7226 pid = fork();
7227 if (pid < 0) {
7228 TRACE(("Fork failed, errno=%d", errno));
7229 if (jp)
7230 freejob(jp);
7231 error("Cannot fork");
7232 }
7233 if (pid == 0)
7234 forkchild(jp, n, mode);
7235 else
7236 forkparent(jp, n, mode, pid);
7237 return pid;
7238}
Eric Andersencb57d552001-06-28 07:25:16 +00007239
7240/*
7241 * Wait for job to finish.
7242 *
7243 * Under job control we have the problem that while a child process is
7244 * running interrupts generated by the user are sent to the child but not
7245 * to the shell. This means that an infinite loop started by an inter-
7246 * active user may be hard to kill. With job control turned off, an
7247 * interactive user may place an interactive program inside a loop. If
7248 * the interactive program catches interrupts, the user doesn't want
7249 * these interrupts to also abort the loop. The approach we take here
7250 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007251 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007252 * signal if the child process was terminated by an interrupt signal.
7253 * Unfortunately, some programs want to do a bit of cleanup and then
7254 * exit on interrupt; unless these processes terminate themselves by
7255 * sending a signal to themselves (instead of calling exit) they will
7256 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007257 *
7258 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007259 */
7260
Eric Andersenc470f442003-07-28 09:56:35 +00007261int
7262waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007263{
Eric Andersencb57d552001-06-28 07:25:16 +00007264 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007265
Eric Andersenc470f442003-07-28 09:56:35 +00007266 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7267 while (jp->state == JOBRUNNING) {
7268 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007269 }
Eric Andersenc470f442003-07-28 09:56:35 +00007270 st = getstatus(jp);
7271#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007272 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007273 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007274 /*
7275 * This is truly gross.
7276 * If we're doing job control, then we did a TIOCSPGRP which
7277 * caused us (the shell) to no longer be in the controlling
7278 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7279 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007280 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007281 */
Eric Andersenc470f442003-07-28 09:56:35 +00007282 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007283 raise(SIGINT);
7284 }
Eric Andersen2870d962001-07-02 17:27:21 +00007285 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007286#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007287 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007288 return st;
7289}
7290
7291
Eric Andersen62483552001-07-10 06:09:16 +00007292/*
7293 * Do a wait system call. If job control is compiled in, we accept
7294 * stopped processes. If block is zero, we return a value of zero
7295 * rather than blocking.
7296 *
7297 * System V doesn't have a non-blocking wait system call. It does
7298 * have a SIGCLD signal that is sent to a process when one of it's
7299 * children dies. The obvious way to use SIGCLD would be to install
7300 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7301 * was received, and have waitproc bump another counter when it got
7302 * the status of a process. Waitproc would then know that a wait
7303 * system call would not block if the two counters were different.
7304 * This approach doesn't work because if a process has children that
7305 * have not been waited for, System V will send it a SIGCLD when it
7306 * installs a signal handler for SIGCLD. What this means is that when
7307 * a child exits, the shell will be sent SIGCLD signals continuously
7308 * until is runs out of stack space, unless it does a wait call before
7309 * restoring the signal handler. The code below takes advantage of
7310 * this (mis)feature by installing a signal handler for SIGCLD and
7311 * then checking to see whether it was called. If there are any
7312 * children to be waited for, it will be.
7313 *
Eric Andersenc470f442003-07-28 09:56:35 +00007314 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7315 * waits at all. In this case, the user will not be informed when
7316 * a background process until the next time she runs a real program
7317 * (as opposed to running a builtin command or just typing return),
7318 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007319 */
7320
Eric Andersenc470f442003-07-28 09:56:35 +00007321static inline int
7322waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007323{
Eric Andersenc470f442003-07-28 09:56:35 +00007324 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007325
Eric Andersenc470f442003-07-28 09:56:35 +00007326#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007327 if (jobctl)
7328 flags |= WUNTRACED;
7329#endif
7330 if (block == 0)
7331 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007332 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007333}
7334
Eric Andersenc470f442003-07-28 09:56:35 +00007335/*
7336 * Wait for a process to terminate.
7337 */
7338
7339static int
7340dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007341{
7342 int pid;
7343 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007344 struct job *jp;
7345 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007346 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007347
7348 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007349 pid = waitproc(block, &status);
7350 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007351 if (pid <= 0)
7352 return pid;
7353 INTOFF;
7354 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007355 for (jp = curjob; jp; jp = jp->prev_job) {
7356 struct procstat *sp;
7357 struct procstat *spend;
7358 if (jp->state == JOBDONE)
7359 continue;
7360 state = JOBDONE;
7361 spend = jp->ps + jp->nprocs;
7362 sp = jp->ps;
7363 do {
7364 if (sp->pid == pid) {
7365 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7366 sp->status = status;
7367 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007368 }
Eric Andersenc470f442003-07-28 09:56:35 +00007369 if (sp->status == -1)
7370 state = JOBRUNNING;
7371#ifdef JOBS
7372 if (state == JOBRUNNING)
7373 continue;
7374 if (WIFSTOPPED(sp->status)) {
7375 jp->stopstatus = sp->status;
7376 state = JOBSTOPPED;
7377 }
Eric Andersencb57d552001-06-28 07:25:16 +00007378#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007379 } while (++sp < spend);
7380 if (thisjob)
7381 goto gotjob;
7382 }
7383#ifdef JOBS
7384 if (!WIFSTOPPED(status))
7385#endif
7386
7387 jobless--;
7388 goto out;
7389
7390gotjob:
7391 if (state != JOBRUNNING) {
7392 thisjob->changed = 1;
7393
7394 if (thisjob->state != state) {
7395 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7396 thisjob->state = state;
7397#ifdef JOBS
7398 if (state == JOBSTOPPED) {
7399 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007400 }
Eric Andersenc470f442003-07-28 09:56:35 +00007401#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007402 }
7403 }
Eric Andersencb57d552001-06-28 07:25:16 +00007404
Eric Andersenc470f442003-07-28 09:56:35 +00007405out:
7406 INTON;
7407
7408 if (thisjob && thisjob == job) {
7409 char s[48 + 1];
7410 int len;
7411
7412 len = sprint_status(s, status, 1);
7413 if (len) {
7414 s[len] = '\n';
7415 s[len + 1] = 0;
7416 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007417 }
Eric Andersencb57d552001-06-28 07:25:16 +00007418 }
7419 return pid;
7420}
7421
7422
Eric Andersencb57d552001-06-28 07:25:16 +00007423/*
7424 * return 1 if there are stopped jobs, otherwise 0
7425 */
Eric Andersen90898442003-08-06 11:20:52 +00007426
Eric Andersenc470f442003-07-28 09:56:35 +00007427int
7428stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007429{
Eric Andersencb57d552001-06-28 07:25:16 +00007430 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007431 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007432
Eric Andersenc470f442003-07-28 09:56:35 +00007433 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007434 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007435 goto out;
7436 jp = curjob;
7437 if (jp && jp->state == JOBSTOPPED) {
7438 out2str("You have stopped jobs.\n");
7439 job_warning = 2;
7440 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007441 }
7442
Eric Andersenc470f442003-07-28 09:56:35 +00007443out:
7444 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007445}
7446
7447/*
7448 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007449 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007450 */
7451
Eric Andersenc470f442003-07-28 09:56:35 +00007452#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007453static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007454
Eric Andersenc470f442003-07-28 09:56:35 +00007455static char *
7456commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007457{
Eric Andersenc470f442003-07-28 09:56:35 +00007458 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007459
Eric Andersenc470f442003-07-28 09:56:35 +00007460 STARTSTACKSTR(cmdnextc);
7461 cmdtxt(n);
7462 name = stackblock();
7463 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7464 name, cmdnextc, cmdnextc));
7465 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007466}
7467
Eric Andersenc470f442003-07-28 09:56:35 +00007468static void
7469cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007470{
Eric Andersencb57d552001-06-28 07:25:16 +00007471 union node *np;
7472 struct nodelist *lp;
7473 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007474 char s[2];
7475
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007476 if (!n)
7477 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007478 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007479 default:
7480#if DEBUG
7481 abort();
7482#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007483 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007484 lp = n->npipe.cmdlist;
7485 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007486 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007487 lp = lp->next;
7488 if (!lp)
7489 break;
7490 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007491 }
7492 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007493 case NSEMI:
7494 p = "; ";
7495 goto binop;
7496 case NAND:
7497 p = " && ";
7498 goto binop;
7499 case NOR:
7500 p = " || ";
7501binop:
7502 cmdtxt(n->nbinary.ch1);
7503 cmdputs(p);
7504 n = n->nbinary.ch2;
7505 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007506 case NREDIR:
7507 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007508 n = n->nredir.n;
7509 goto donode;
7510 case NNOT:
7511 cmdputs("!");
7512 n = n->nnot.com;
7513donode:
7514 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007515 break;
7516 case NIF:
7517 cmdputs("if ");
7518 cmdtxt(n->nif.test);
7519 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007520 n = n->nif.ifpart;
7521 if (n->nif.elsepart) {
7522 cmdtxt(n);
7523 cmdputs("; else ");
7524 n = n->nif.elsepart;
7525 }
7526 p = "; fi";
7527 goto dotail;
7528 case NSUBSHELL:
7529 cmdputs("(");
7530 n = n->nredir.n;
7531 p = ")";
7532 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007533 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007534 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007535 goto until;
7536 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007537 p = "until ";
7538until:
7539 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007540 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007541 n = n->nbinary.ch2;
7542 p = "; done";
7543dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007544 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007545dotail:
7546 cmdtxt(n);
7547 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007548 case NFOR:
7549 cmdputs("for ");
7550 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007551 cmdputs(" in ");
7552 cmdlist(n->nfor.args, 1);
7553 n = n->nfor.body;
7554 p = "; done";
7555 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007556 case NDEFUN:
7557 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007558 p = "() { ... }";
7559 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007560 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007561 cmdlist(n->ncmd.args, 1);
7562 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007563 break;
7564 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007565 p = n->narg.text;
7566dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007567 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007568 break;
7569 case NHERE:
7570 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007571 p = "<<...";
7572 goto dotail2;
7573 case NCASE:
7574 cmdputs("case ");
7575 cmdputs(n->ncase.expr->narg.text);
7576 cmdputs(" in ");
7577 for (np = n->ncase.cases; np; np = np->nclist.next) {
7578 cmdtxt(np->nclist.pattern);
7579 cmdputs(") ");
7580 cmdtxt(np->nclist.body);
7581 cmdputs(";; ");
7582 }
7583 p = "esac";
7584 goto dotail2;
7585 case NTO:
7586 p = ">";
7587 goto redir;
7588 case NCLOBBER:
7589 p = ">|";
7590 goto redir;
7591 case NAPPEND:
7592 p = ">>";
7593 goto redir;
7594 case NTOFD:
7595 p = ">&";
7596 goto redir;
7597 case NFROM:
7598 p = "<";
7599 goto redir;
7600 case NFROMFD:
7601 p = "<&";
7602 goto redir;
7603 case NFROMTO:
7604 p = "<>";
7605redir:
7606 s[0] = n->nfile.fd + '0';
7607 s[1] = '\0';
7608 cmdputs(s);
7609 cmdputs(p);
7610 if (n->type == NTOFD || n->type == NFROMFD) {
7611 s[0] = n->ndup.dupfd + '0';
7612 p = s;
7613 goto dotail2;
7614 } else {
7615 n = n->nfile.fname;
7616 goto donode;
7617 }
Eric Andersencb57d552001-06-28 07:25:16 +00007618 }
7619}
Eric Andersencb57d552001-06-28 07:25:16 +00007620
Eric Andersenc470f442003-07-28 09:56:35 +00007621static void
7622cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007623{
Eric Andersenc470f442003-07-28 09:56:35 +00007624 for (; np; np = np->narg.next) {
7625 if (!sep)
7626 cmdputs(spcstr);
7627 cmdtxt(np);
7628 if (sep && np->narg.next)
7629 cmdputs(spcstr);
7630 }
Eric Andersencb57d552001-06-28 07:25:16 +00007631}
7632
Eric Andersenc470f442003-07-28 09:56:35 +00007633static void
7634cmdputs(const char *s)
7635{
7636 const char *p, *str;
7637 char c, cc[2] = " ";
7638 char *nextc;
7639 int subtype = 0;
7640 int quoted = 0;
7641 static const char *const vstype[16] = {
7642 nullstr, "}", "-", "+", "?", "=",
Eric Andersenc7bda1c2004-03-15 08:29:22 +00007643 "%", "%%", "#", "##", nullstr
Eric Andersenc470f442003-07-28 09:56:35 +00007644 };
7645
7646 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7647 p = s;
7648 while ((c = *p++) != 0) {
7649 str = 0;
7650 switch (c) {
7651 case CTLESC:
7652 c = *p++;
7653 break;
7654 case CTLVAR:
7655 subtype = *p++;
7656 if ((subtype & VSTYPE) == VSLENGTH)
7657 str = "${#";
7658 else
7659 str = "${";
7660 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7661 quoted ^= 1;
7662 c = '"';
7663 } else
7664 goto dostr;
7665 break;
7666 case CTLENDVAR:
7667 quoted >>= 1;
7668 subtype = 0;
7669 if (quoted & 1) {
7670 str = "\"}";
7671 goto dostr;
7672 }
7673 c = '}';
7674 break;
7675 case CTLBACKQ:
7676 str = "$(...)";
7677 goto dostr;
7678 case CTLBACKQ+CTLQUOTE:
7679 str = "\"$(...)\"";
7680 goto dostr;
7681#ifdef CONFIG_ASH_MATH_SUPPORT
7682 case CTLARI:
7683 str = "$((";
7684 goto dostr;
7685 case CTLENDARI:
7686 str = "))";
7687 goto dostr;
7688#endif
7689 case CTLQUOTEMARK:
7690 quoted ^= 1;
7691 c = '"';
7692 break;
7693 case '=':
7694 if (subtype == 0)
7695 break;
7696 str = vstype[subtype & VSTYPE];
7697 if (subtype & VSNUL)
7698 c = ':';
7699 else
7700 c = *str++;
7701 if (c != '}')
7702 quoted <<= 1;
7703 break;
7704 case '\'':
7705 case '\\':
7706 case '"':
7707 case '$':
7708 /* These can only happen inside quotes */
7709 cc[0] = c;
7710 str = cc;
7711 c = '\\';
7712 break;
7713 default:
7714 break;
7715 }
7716 USTPUTC(c, nextc);
7717 if (!str)
7718 continue;
7719dostr:
7720 while ((c = *str++)) {
7721 USTPUTC(c, nextc);
7722 }
7723 }
7724 if (quoted & 1) {
7725 USTPUTC('"', nextc);
7726 }
7727 *nextc = 0;
7728 cmdnextc = nextc;
7729}
7730
7731
7732static void
7733showpipe(struct job *jp, FILE *out)
7734{
7735 struct procstat *sp;
7736 struct procstat *spend;
7737
7738 spend = jp->ps + jp->nprocs;
7739 for (sp = jp->ps + 1; sp < spend; sp++)
7740 fprintf(out, " | %s", sp->cmd);
7741 outcslow('\n', out);
7742 flushall();
7743}
7744
7745static void
7746xtcsetpgrp(int fd, pid_t pgrp)
7747{
7748 if (tcsetpgrp(fd, pgrp))
7749 error("Cannot set tty process group (%m)");
7750}
7751#endif /* JOBS */
7752
7753static int
7754getstatus(struct job *job) {
7755 int status;
7756 int retval;
7757
7758 status = job->ps[job->nprocs - 1].status;
7759 retval = WEXITSTATUS(status);
7760 if (!WIFEXITED(status)) {
7761#if JOBS
7762 retval = WSTOPSIG(status);
7763 if (!WIFSTOPPED(status))
7764#endif
7765 {
7766 /* XXX: limits number of signals */
7767 retval = WTERMSIG(status);
7768#if JOBS
7769 if (retval == SIGINT)
7770 job->sigint = 1;
7771#endif
7772 }
7773 retval += 128;
7774 }
7775 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7776 jobno(job), job->nprocs, status, retval));
7777 return retval;
7778}
7779
Eric Andersend35c5df2002-01-09 15:37:36 +00007780#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007781/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007782
Eric Andersencb57d552001-06-28 07:25:16 +00007783/*
Eric Andersenc470f442003-07-28 09:56:35 +00007784 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007785 */
7786
Eric Andersencb57d552001-06-28 07:25:16 +00007787#define MAXMBOXES 10
7788
Eric Andersenc470f442003-07-28 09:56:35 +00007789/* times of mailboxes */
7790static time_t mailtime[MAXMBOXES];
7791/* Set if MAIL or MAILPATH is changed. */
7792static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007793
7794
7795
7796/*
Eric Andersenc470f442003-07-28 09:56:35 +00007797 * Print appropriate message(s) if mail has arrived.
7798 * If mail_var_path_changed is set,
7799 * then the value of MAIL has mail_var_path_changed,
7800 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007801 */
7802
Eric Andersenc470f442003-07-28 09:56:35 +00007803static void
7804chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007805{
Eric Andersencb57d552001-06-28 07:25:16 +00007806 const char *mpath;
7807 char *p;
7808 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007809 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007810 struct stackmark smark;
7811 struct stat statb;
7812
Eric Andersencb57d552001-06-28 07:25:16 +00007813 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007814 mpath = mpathset() ? mpathval() : mailval();
7815 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007816 p = padvance(&mpath, nullstr);
7817 if (p == NULL)
7818 break;
7819 if (*p == '\0')
7820 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007821 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007822#ifdef DEBUG
7823 if (q[-1] != '/')
7824 abort();
7825#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007826 q[-1] = '\0'; /* delete trailing '/' */
7827 if (stat(p, &statb) < 0) {
7828 *mtp = 0;
7829 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007830 }
Eric Andersenc470f442003-07-28 09:56:35 +00007831 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7832 fprintf(
7833 stderr, snlfmt,
7834 pathopt ? pathopt : "you have mail"
7835 );
7836 }
7837 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007838 }
Eric Andersenc470f442003-07-28 09:56:35 +00007839 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007840 popstackmark(&smark);
7841}
Eric Andersencb57d552001-06-28 07:25:16 +00007842
Eric Andersenec074692001-10-31 11:05:49 +00007843
Eric Andersenc470f442003-07-28 09:56:35 +00007844static void
7845changemail(const char *val)
7846{
7847 mail_var_path_changed++;
7848}
7849
7850#endif /* CONFIG_ASH_MAIL */
7851
7852/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7853
Eric Andersencb57d552001-06-28 07:25:16 +00007854
Eric Andersencb57d552001-06-28 07:25:16 +00007855#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007856static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007857extern int etext();
7858#endif
7859
Eric Andersenc470f442003-07-28 09:56:35 +00007860static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007861
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007862static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007863
Eric Andersencb57d552001-06-28 07:25:16 +00007864/*
7865 * Main routine. We initialize things, parse the arguments, execute
7866 * profiles if we're a login shell, and then call cmdloop to execute
7867 * commands. The setjmp call sets up the location to jump to when an
7868 * exception occurs. When an exception occurs the variable "state"
7869 * is used to figure out how far we had gotten.
7870 */
7871
Eric Andersenc470f442003-07-28 09:56:35 +00007872int
7873ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007874{
Eric Andersenc470f442003-07-28 09:56:35 +00007875 char *shinit;
7876 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007877 struct jmploc jmploc;
7878 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007879
Eric Andersenc470f442003-07-28 09:56:35 +00007880#ifdef __GLIBC__
7881 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007882#endif
7883
Eric Andersencb57d552001-06-28 07:25:16 +00007884#if PROFILE
7885 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7886#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007887 state = 0;
7888 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007889 int status;
7890 int e;
7891
Eric Andersencb57d552001-06-28 07:25:16 +00007892 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007893
7894 e = exception;
7895 switch (exception) {
7896 case EXEXEC:
7897 status = exerrno;
7898 break;
7899
7900 case EXERROR:
7901 status = 2;
7902 break;
7903
7904 default:
7905 status = exitstatus;
7906 break;
7907 }
7908 exitstatus = status;
7909
7910 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7911 exitshell();
7912
Eric Andersen90898442003-08-06 11:20:52 +00007913 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007914 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007915 }
7916 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007917 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007918 if (state == 1)
7919 goto state1;
7920 else if (state == 2)
7921 goto state2;
7922 else if (state == 3)
7923 goto state3;
7924 else
7925 goto state4;
7926 }
7927 handler = &jmploc;
7928#ifdef DEBUG
7929 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007930 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007931#endif
7932 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007933
7934#ifdef CONFIG_ASH_RANDOM_SUPPORT
7935 rseed = rootpid + ((time_t)time((time_t *)0));
7936#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007937 rootshell = 1;
7938 init();
7939 setstackmark(&smark);
7940 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007941#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7942 if ( iflag ) {
7943 const char *hp = lookupvar("HISTFILE");
7944
7945 if(hp == NULL ) {
7946 hp = lookupvar("HOME");
7947 if(hp != NULL) {
7948 char *defhp = concat_path_file(hp, ".ash_history");
7949 setvar("HISTFILE", defhp, 0);
7950 free(defhp);
7951 }
7952 }
7953 }
7954#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007955 if (argv[0] && argv[0][0] == '-')
7956 isloginsh = 1;
7957 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007958 state = 1;
7959 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007960state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007961 state = 2;
7962 read_profile(".profile");
7963 }
Eric Andersenc470f442003-07-28 09:56:35 +00007964state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007965 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007966 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007967#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007968 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007969#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007970 iflag
7971 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007972 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007973 read_profile(shinit);
7974 }
Eric Andersencb57d552001-06-28 07:25:16 +00007975 }
Eric Andersenc470f442003-07-28 09:56:35 +00007976state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007977 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007978 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007979 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007980
7981 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007982#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007983 if ( iflag ) {
7984 const char *hp = lookupvar("HISTFILE");
7985
7986 if(hp != NULL )
7987 load_history ( hp );
7988 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007989#endif
Eric Andersen90898442003-08-06 11:20:52 +00007990state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007991 cmdloop(1);
7992 }
7993#if PROFILE
7994 monitor(0);
7995#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007996#if GPROF
7997 {
7998 extern void _mcleanup(void);
7999 _mcleanup();
8000 }
8001#endif
8002 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00008003 /* NOTREACHED */
8004}
8005
8006
8007/*
8008 * Read and execute commands. "Top" is nonzero for the top level command
8009 * loop; it turns on prompting if the shell is interactive.
8010 */
8011
Eric Andersenc470f442003-07-28 09:56:35 +00008012static void
8013cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008014{
8015 union node *n;
8016 struct stackmark smark;
8017 int inter;
8018 int numeof = 0;
8019
8020 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008021 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00008022 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00008023 if (pendingsigs)
8024 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00008025#if JOBS
8026 if (jobctl)
8027 showjobs(stderr, SHOW_CHANGED);
8028#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008029 inter = 0;
8030 if (iflag && top) {
8031 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008032#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008033 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008034#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008035 }
8036 n = parsecmd(inter);
8037 /* showtree(n); DEBUG */
8038 if (n == NEOF) {
8039 if (!top || numeof >= 50)
8040 break;
8041 if (!stoppedjobs()) {
8042 if (!Iflag)
8043 break;
8044 out2str("\nUse \"exit\" to leave shell.\n");
8045 }
8046 numeof++;
8047 } else if (n != NULL && nflag == 0) {
8048 job_warning = (job_warning == 2) ? 1 : 0;
8049 numeof = 0;
8050 evaltree(n, 0);
8051 }
8052 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008053 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008054 evalskip = 0;
8055 break;
8056 }
8057 }
Eric Andersencb57d552001-06-28 07:25:16 +00008058}
8059
8060
Eric Andersencb57d552001-06-28 07:25:16 +00008061/*
8062 * Read /etc/profile or .profile. Return on error.
8063 */
8064
Eric Andersenc470f442003-07-28 09:56:35 +00008065static void
8066read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008067{
8068 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008069 int xflag_set = 0;
8070 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008071
8072 INTOFF;
8073 if ((fd = open(name, O_RDONLY)) >= 0)
8074 setinputfd(fd, 1);
8075 INTON;
8076 if (fd < 0)
8077 return;
8078 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008079 if (qflag) {
8080 if (xflag)
8081 xflag = 0, xflag_set = 1;
8082 if (vflag)
8083 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008084 }
8085 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008086 if (qflag) {
8087 if (xflag_set)
8088 xflag = 1;
8089 if (vflag_set)
8090 vflag = 1;
8091 }
Eric Andersencb57d552001-06-28 07:25:16 +00008092 popfile();
8093}
8094
8095
Eric Andersencb57d552001-06-28 07:25:16 +00008096/*
8097 * Read a file containing shell functions.
8098 */
8099
Eric Andersenc470f442003-07-28 09:56:35 +00008100static void
8101readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008102{
8103 int fd;
8104
8105 INTOFF;
8106 if ((fd = open(name, O_RDONLY)) >= 0)
8107 setinputfd(fd, 1);
8108 else
8109 error("Can't open %s", name);
8110 INTON;
8111 cmdloop(0);
8112 popfile();
8113}
8114
8115
Eric Andersencb57d552001-06-28 07:25:16 +00008116/*
Eric Andersenc470f442003-07-28 09:56:35 +00008117 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008118 * search for the file, which is necessary to find sub-commands.
8119 */
8120
Eric Andersenc470f442003-07-28 09:56:35 +00008121static inline char *
8122find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008123{
8124 char *fullname;
8125 const char *path = pathval();
8126 struct stat statb;
8127
8128 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008129 if (strchr(name, '/'))
8130 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008131
Eric Andersenc470f442003-07-28 09:56:35 +00008132 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008133 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8134 /*
8135 * Don't bother freeing here, since it will
8136 * be freed by the caller.
8137 */
8138 return fullname;
8139 }
8140 stunalloc(fullname);
8141 }
8142
8143 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008144 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008145 /* NOTREACHED */
8146}
8147
Eric Andersen1e6aba92004-04-12 19:12:13 +00008148static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008149{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008150 struct strlist *sp;
8151 volatile struct shparam saveparam;
8152
Eric Andersencb57d552001-06-28 07:25:16 +00008153 exitstatus = 0;
8154
Eric Andersen1e6aba92004-04-12 19:12:13 +00008155 for (sp = cmdenviron; sp; sp = sp->next)
8156 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8157
8158 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008159 char *fullname;
8160 struct stackmark smark;
8161
8162 setstackmark(&smark);
8163 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008164
8165 if (argc > 2) {
8166 saveparam = shellparam;
8167 shellparam.malloc = 0;
8168 shellparam.nparam = argc - 2;
8169 shellparam.p = argv + 2;
8170 };
8171
Eric Andersencb57d552001-06-28 07:25:16 +00008172 setinputfile(fullname, 1);
8173 commandname = fullname;
8174 cmdloop(0);
8175 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008176
8177 if (argc > 2) {
8178 freeparam(&shellparam);
8179 shellparam = saveparam;
8180 };
8181
Eric Andersencb57d552001-06-28 07:25:16 +00008182 popstackmark(&smark);
8183 }
8184 return exitstatus;
8185}
8186
8187
Eric Andersenc470f442003-07-28 09:56:35 +00008188static int
8189exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008190{
8191 if (stoppedjobs())
8192 return 0;
8193 if (argc > 1)
8194 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008195 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008196 /* NOTREACHED */
8197}
Eric Andersen62483552001-07-10 06:09:16 +00008198
Eric Andersenc470f442003-07-28 09:56:35 +00008199/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8200
8201/*
Eric Andersen90898442003-08-06 11:20:52 +00008202 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008203 */
8204
8205static pointer
8206ckrealloc(pointer p, size_t nbytes)
8207{
8208 p = realloc(p, nbytes);
8209 if (p == NULL)
8210 error(bb_msg_memory_exhausted);
8211 return p;
8212}
8213
Eric Andersen90898442003-08-06 11:20:52 +00008214static pointer
8215ckmalloc(size_t nbytes)
8216{
8217 return ckrealloc(NULL, nbytes);
8218}
Eric Andersenc470f442003-07-28 09:56:35 +00008219
8220/*
8221 * Make a copy of a string in safe storage.
8222 */
8223
8224static char *
8225savestr(const char *s)
8226{
8227 char *p = strdup(s);
8228 if (!p)
8229 error(bb_msg_memory_exhausted);
8230 return p;
8231}
8232
8233
8234/*
8235 * Parse trees for commands are allocated in lifo order, so we use a stack
8236 * to make this more efficient, and also to avoid all sorts of exception
8237 * handling code to handle interrupts in the middle of a parse.
8238 *
8239 * The size 504 was chosen because the Ultrix malloc handles that size
8240 * well.
8241 */
8242
8243
8244static pointer
8245stalloc(size_t nbytes)
8246{
8247 char *p;
8248 size_t aligned;
8249
8250 aligned = SHELL_ALIGN(nbytes);
8251 if (aligned > stacknleft) {
8252 size_t len;
8253 size_t blocksize;
8254 struct stack_block *sp;
8255
8256 blocksize = aligned;
8257 if (blocksize < MINSIZE)
8258 blocksize = MINSIZE;
8259 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8260 if (len < blocksize)
8261 error(bb_msg_memory_exhausted);
8262 INTOFF;
8263 sp = ckmalloc(len);
8264 sp->prev = stackp;
8265 stacknxt = sp->space;
8266 stacknleft = blocksize;
8267 sstrend = stacknxt + blocksize;
8268 stackp = sp;
8269 INTON;
8270 }
8271 p = stacknxt;
8272 stacknxt += aligned;
8273 stacknleft -= aligned;
8274 return p;
8275}
8276
8277
8278void
8279stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008280{
Eric Andersencb57d552001-06-28 07:25:16 +00008281#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008282 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008283 write(2, "stunalloc\n", 10);
8284 abort();
8285 }
8286#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008287 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008288 stacknxt = p;
8289}
8290
8291
Eric Andersenc470f442003-07-28 09:56:35 +00008292void
8293setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008294{
Eric Andersencb57d552001-06-28 07:25:16 +00008295 mark->stackp = stackp;
8296 mark->stacknxt = stacknxt;
8297 mark->stacknleft = stacknleft;
8298 mark->marknext = markp;
8299 markp = mark;
8300}
8301
8302
Eric Andersenc470f442003-07-28 09:56:35 +00008303void
8304popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008305{
Eric Andersencb57d552001-06-28 07:25:16 +00008306 struct stack_block *sp;
8307
8308 INTOFF;
8309 markp = mark->marknext;
8310 while (stackp != mark->stackp) {
8311 sp = stackp;
8312 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008313 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008314 }
8315 stacknxt = mark->stacknxt;
8316 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008317 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008318 INTON;
8319}
8320
8321
8322/*
8323 * When the parser reads in a string, it wants to stick the string on the
8324 * stack and only adjust the stack pointer when it knows how big the
8325 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8326 * of space on top of the stack and stackblocklen returns the length of
8327 * this block. Growstackblock will grow this space by at least one byte,
8328 * possibly moving it (like realloc). Grabstackblock actually allocates the
8329 * part of the block that has been used.
8330 */
8331
Eric Andersenc470f442003-07-28 09:56:35 +00008332void
8333growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008334{
Eric Andersenc470f442003-07-28 09:56:35 +00008335 size_t newlen;
8336
8337 newlen = stacknleft * 2;
8338 if (newlen < stacknleft)
8339 error(bb_msg_memory_exhausted);
8340 if (newlen < 128)
8341 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008342
8343 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008344 struct stack_block *oldstackp;
8345 struct stackmark *xmark;
8346 struct stack_block *sp;
8347 struct stack_block *prevstackp;
8348 size_t grosslen;
8349
Eric Andersencb57d552001-06-28 07:25:16 +00008350 INTOFF;
8351 oldstackp = stackp;
8352 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008353 prevstackp = sp->prev;
8354 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8355 sp = ckrealloc((pointer)sp, grosslen);
8356 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008357 stackp = sp;
8358 stacknxt = sp->space;
8359 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008360 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008361
Eric Andersenc470f442003-07-28 09:56:35 +00008362 /*
8363 * Stack marks pointing to the start of the old block
8364 * must be relocated to point to the new block
8365 */
8366 xmark = markp;
8367 while (xmark != NULL && xmark->stackp == oldstackp) {
8368 xmark->stackp = stackp;
8369 xmark->stacknxt = stacknxt;
8370 xmark->stacknleft = stacknleft;
8371 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008372 }
8373 INTON;
8374 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008375 char *oldspace = stacknxt;
8376 int oldlen = stacknleft;
8377 char *p = stalloc(newlen);
8378
8379 /* free the space we just allocated */
8380 stacknxt = memcpy(p, oldspace, oldlen);
8381 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008382 }
8383}
8384
Eric Andersenc470f442003-07-28 09:56:35 +00008385static inline void
8386grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008387{
Eric Andersenc470f442003-07-28 09:56:35 +00008388 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008389 stacknxt += len;
8390 stacknleft -= len;
8391}
8392
Eric Andersencb57d552001-06-28 07:25:16 +00008393/*
Eric Andersenc470f442003-07-28 09:56:35 +00008394 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008395 * The user declares a variable of type STACKSTR, which may be declared
8396 * to be a register. The macro STARTSTACKSTR initializes things. Then
8397 * the user uses the macro STPUTC to add characters to the string. In
8398 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8399 * grown as necessary. When the user is done, she can just leave the
8400 * string there and refer to it using stackblock(). Or she can allocate
8401 * the space for it using grabstackstr(). If it is necessary to allow
8402 * someone else to use the stack temporarily and then continue to grow
8403 * the string, the user should use grabstack to allocate the space, and
8404 * then call ungrabstr(p) to return to the previous mode of operation.
8405 *
8406 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8407 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8408 * is space for at least one character.
8409 */
8410
Eric Andersenc470f442003-07-28 09:56:35 +00008411void *
8412growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008413{
Eric Andersenc470f442003-07-28 09:56:35 +00008414 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008415 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008416 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008417 return stackblock();
8418 }
8419 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008420 return stackblock() + len;
8421}
8422
Eric Andersencb57d552001-06-28 07:25:16 +00008423/*
8424 * Called from CHECKSTRSPACE.
8425 */
8426
Eric Andersenc470f442003-07-28 09:56:35 +00008427char *
8428makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008429{
Eric Andersenc470f442003-07-28 09:56:35 +00008430 size_t len = p - stacknxt;
8431 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008432
Eric Andersenc470f442003-07-28 09:56:35 +00008433 for (;;) {
8434 size_t nleft;
8435
8436 size = stackblocksize();
8437 nleft = size - len;
8438 if (nleft >= newlen)
8439 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008440 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008441 }
Eric Andersencb57d552001-06-28 07:25:16 +00008442 return stackblock() + len;
8443}
8444
Eric Andersenc470f442003-07-28 09:56:35 +00008445char *
8446stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008447{
Eric Andersenc470f442003-07-28 09:56:35 +00008448 p = makestrspace(n, p);
8449 p = mempcpy(p, s, n);
8450 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008451}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008452
Eric Andersenc470f442003-07-28 09:56:35 +00008453char *
8454stputs(const char *s, char *p)
8455{
8456 return stnputs(s, strlen(s), p);
8457}
8458
8459/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8460
Eric Andersencb57d552001-06-28 07:25:16 +00008461/*
Eric Andersenc470f442003-07-28 09:56:35 +00008462 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008463 *
Eric Andersenc470f442003-07-28 09:56:35 +00008464 * number(s) Convert a string of digits to an integer.
8465 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008466 */
8467
Eric Andersencb57d552001-06-28 07:25:16 +00008468/*
8469 * prefix -- see if pfx is a prefix of string.
8470 */
8471
Eric Andersenc470f442003-07-28 09:56:35 +00008472char *
8473prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008474{
Eric Andersencb57d552001-06-28 07:25:16 +00008475 while (*pfx) {
8476 if (*pfx++ != *string++)
8477 return 0;
8478 }
Eric Andersenc470f442003-07-28 09:56:35 +00008479 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008480}
8481
8482
8483/*
8484 * Convert a string of digits to an integer, printing an error message on
8485 * failure.
8486 */
8487
Eric Andersenc470f442003-07-28 09:56:35 +00008488int
8489number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008490{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008491
Eric Andersenc470f442003-07-28 09:56:35 +00008492 if (! is_number(s))
8493 error(illnum, s);
8494 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008495}
8496
Eric Andersenc470f442003-07-28 09:56:35 +00008497
Eric Andersenc470f442003-07-28 09:56:35 +00008498/*
8499 * Check for a valid number. This should be elsewhere.
8500 */
8501
8502int
8503is_number(const char *p)
8504{
8505 do {
8506 if (! is_digit(*p))
8507 return 0;
8508 } while (*++p != '\0');
8509 return 1;
8510}
8511
8512
Eric Andersencb57d552001-06-28 07:25:16 +00008513/*
8514 * Produce a possibly single quoted string suitable as input to the shell.
8515 * The return string is allocated on the stack.
8516 */
8517
Eric Andersenc470f442003-07-28 09:56:35 +00008518char *
8519single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008520 char *p;
8521
8522 STARTSTACKSTR(p);
8523
8524 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008525 char *q;
8526 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008527
Eric Andersenc470f442003-07-28 09:56:35 +00008528 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008529
Eric Andersenc470f442003-07-28 09:56:35 +00008530 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008531
Eric Andersenc470f442003-07-28 09:56:35 +00008532 *q++ = '\'';
8533 q = mempcpy(q, s, len);
8534 *q++ = '\'';
8535 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008536
Eric Andersenc470f442003-07-28 09:56:35 +00008537 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008538
Eric Andersenc470f442003-07-28 09:56:35 +00008539 len = strspn(s, "'");
8540 if (!len)
8541 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008542
Eric Andersenc470f442003-07-28 09:56:35 +00008543 q = p = makestrspace(len + 3, p);
8544
8545 *q++ = '"';
8546 q = mempcpy(q, s, len);
8547 *q++ = '"';
8548 s += len;
8549
8550 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008551 } while (*s);
8552
8553 USTPUTC(0, p);
8554
Eric Andersenc470f442003-07-28 09:56:35 +00008555 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008556}
8557
8558/*
Eric Andersenc470f442003-07-28 09:56:35 +00008559 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008560 */
8561
Eric Andersenc470f442003-07-28 09:56:35 +00008562char *
8563sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008564{
Eric Andersenc470f442003-07-28 09:56:35 +00008565 size_t len = strlen(p) + 1;
8566 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008567}
Eric Andersenc470f442003-07-28 09:56:35 +00008568
8569
8570static void
8571calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008572{
Eric Andersenc470f442003-07-28 09:56:35 +00008573 if (n == NULL)
8574 return;
8575 funcblocksize += nodesize[n->type];
8576 switch (n->type) {
8577 case NCMD:
8578 calcsize(n->ncmd.redirect);
8579 calcsize(n->ncmd.args);
8580 calcsize(n->ncmd.assign);
8581 break;
8582 case NPIPE:
8583 sizenodelist(n->npipe.cmdlist);
8584 break;
8585 case NREDIR:
8586 case NBACKGND:
8587 case NSUBSHELL:
8588 calcsize(n->nredir.redirect);
8589 calcsize(n->nredir.n);
8590 break;
8591 case NAND:
8592 case NOR:
8593 case NSEMI:
8594 case NWHILE:
8595 case NUNTIL:
8596 calcsize(n->nbinary.ch2);
8597 calcsize(n->nbinary.ch1);
8598 break;
8599 case NIF:
8600 calcsize(n->nif.elsepart);
8601 calcsize(n->nif.ifpart);
8602 calcsize(n->nif.test);
8603 break;
8604 case NFOR:
8605 funcstringsize += strlen(n->nfor.var) + 1;
8606 calcsize(n->nfor.body);
8607 calcsize(n->nfor.args);
8608 break;
8609 case NCASE:
8610 calcsize(n->ncase.cases);
8611 calcsize(n->ncase.expr);
8612 break;
8613 case NCLIST:
8614 calcsize(n->nclist.body);
8615 calcsize(n->nclist.pattern);
8616 calcsize(n->nclist.next);
8617 break;
8618 case NDEFUN:
8619 case NARG:
8620 sizenodelist(n->narg.backquote);
8621 funcstringsize += strlen(n->narg.text) + 1;
8622 calcsize(n->narg.next);
8623 break;
8624 case NTO:
8625 case NCLOBBER:
8626 case NFROM:
8627 case NFROMTO:
8628 case NAPPEND:
8629 calcsize(n->nfile.fname);
8630 calcsize(n->nfile.next);
8631 break;
8632 case NTOFD:
8633 case NFROMFD:
8634 calcsize(n->ndup.vname);
8635 calcsize(n->ndup.next);
8636 break;
8637 case NHERE:
8638 case NXHERE:
8639 calcsize(n->nhere.doc);
8640 calcsize(n->nhere.next);
8641 break;
8642 case NNOT:
8643 calcsize(n->nnot.com);
8644 break;
8645 };
Eric Andersencb57d552001-06-28 07:25:16 +00008646}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008647
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008648
Eric Andersenc470f442003-07-28 09:56:35 +00008649static void
8650sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008651{
8652 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008653 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008654 calcsize(lp->n);
8655 lp = lp->next;
8656 }
8657}
Eric Andersencb57d552001-06-28 07:25:16 +00008658
8659
Eric Andersenc470f442003-07-28 09:56:35 +00008660static union node *
8661copynode(union node *n)
8662{
8663 union node *new;
8664
8665 if (n == NULL)
8666 return NULL;
8667 new = funcblock;
8668 funcblock = (char *) funcblock + nodesize[n->type];
8669 switch (n->type) {
8670 case NCMD:
8671 new->ncmd.redirect = copynode(n->ncmd.redirect);
8672 new->ncmd.args = copynode(n->ncmd.args);
8673 new->ncmd.assign = copynode(n->ncmd.assign);
8674 break;
8675 case NPIPE:
8676 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8677 new->npipe.backgnd = n->npipe.backgnd;
8678 break;
8679 case NREDIR:
8680 case NBACKGND:
8681 case NSUBSHELL:
8682 new->nredir.redirect = copynode(n->nredir.redirect);
8683 new->nredir.n = copynode(n->nredir.n);
8684 break;
8685 case NAND:
8686 case NOR:
8687 case NSEMI:
8688 case NWHILE:
8689 case NUNTIL:
8690 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8691 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8692 break;
8693 case NIF:
8694 new->nif.elsepart = copynode(n->nif.elsepart);
8695 new->nif.ifpart = copynode(n->nif.ifpart);
8696 new->nif.test = copynode(n->nif.test);
8697 break;
8698 case NFOR:
8699 new->nfor.var = nodesavestr(n->nfor.var);
8700 new->nfor.body = copynode(n->nfor.body);
8701 new->nfor.args = copynode(n->nfor.args);
8702 break;
8703 case NCASE:
8704 new->ncase.cases = copynode(n->ncase.cases);
8705 new->ncase.expr = copynode(n->ncase.expr);
8706 break;
8707 case NCLIST:
8708 new->nclist.body = copynode(n->nclist.body);
8709 new->nclist.pattern = copynode(n->nclist.pattern);
8710 new->nclist.next = copynode(n->nclist.next);
8711 break;
8712 case NDEFUN:
8713 case NARG:
8714 new->narg.backquote = copynodelist(n->narg.backquote);
8715 new->narg.text = nodesavestr(n->narg.text);
8716 new->narg.next = copynode(n->narg.next);
8717 break;
8718 case NTO:
8719 case NCLOBBER:
8720 case NFROM:
8721 case NFROMTO:
8722 case NAPPEND:
8723 new->nfile.fname = copynode(n->nfile.fname);
8724 new->nfile.fd = n->nfile.fd;
8725 new->nfile.next = copynode(n->nfile.next);
8726 break;
8727 case NTOFD:
8728 case NFROMFD:
8729 new->ndup.vname = copynode(n->ndup.vname);
8730 new->ndup.dupfd = n->ndup.dupfd;
8731 new->ndup.fd = n->ndup.fd;
8732 new->ndup.next = copynode(n->ndup.next);
8733 break;
8734 case NHERE:
8735 case NXHERE:
8736 new->nhere.doc = copynode(n->nhere.doc);
8737 new->nhere.fd = n->nhere.fd;
8738 new->nhere.next = copynode(n->nhere.next);
8739 break;
8740 case NNOT:
8741 new->nnot.com = copynode(n->nnot.com);
8742 break;
8743 };
8744 new->type = n->type;
8745 return new;
8746}
8747
8748
8749static struct nodelist *
8750copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008751{
8752 struct nodelist *start;
8753 struct nodelist **lpp;
8754
8755 lpp = &start;
8756 while (lp) {
8757 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008758 funcblock = (char *) funcblock +
8759 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008760 (*lpp)->n = copynode(lp->n);
8761 lp = lp->next;
8762 lpp = &(*lpp)->next;
8763 }
8764 *lpp = NULL;
8765 return start;
8766}
8767
8768
Eric Andersenc470f442003-07-28 09:56:35 +00008769static char *
8770nodesavestr(char *s)
8771{
8772 char *rtn = funcstring;
8773
8774 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008775 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008776}
8777
Eric Andersenc470f442003-07-28 09:56:35 +00008778
Eric Andersenc470f442003-07-28 09:56:35 +00008779/*
8780 * Free a parse tree.
8781 */
8782
8783static void
8784freefunc(struct funcnode *f)
8785{
8786 if (f && --f->count < 0)
8787 ckfree(f);
8788}
8789
8790
8791static void options(int);
8792static void setoption(int, int);
8793
Eric Andersencb57d552001-06-28 07:25:16 +00008794
Eric Andersencb57d552001-06-28 07:25:16 +00008795/*
8796 * Process the shell command line arguments.
8797 */
8798
Eric Andersenc470f442003-07-28 09:56:35 +00008799void
8800procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008801{
8802 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008803 const char *xminusc;
8804 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008805
Eric Andersenc470f442003-07-28 09:56:35 +00008806 xargv = argv;
8807 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008808 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008809 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008810 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008811 optlist[i] = 2;
8812 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008813 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008814 xargv = argptr;
8815 xminusc = minusc;
8816 if (*xargv == NULL) {
8817 if (xminusc)
8818 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008819 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008820 }
Eric Andersencb57d552001-06-28 07:25:16 +00008821 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8822 iflag = 1;
8823 if (mflag == 2)
8824 mflag = iflag;
8825 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008826 if (optlist[i] == 2)
8827 optlist[i] = 0;
8828#if DEBUG == 2
8829 debug = 1;
8830#endif
8831 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8832 if (xminusc) {
8833 minusc = *xargv++;
8834 if (*xargv)
8835 goto setarg0;
8836 } else if (!sflag) {
8837 setinputfile(*xargv, 0);
8838setarg0:
8839 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008840 commandname = arg0;
8841 }
Eric Andersencb57d552001-06-28 07:25:16 +00008842
Eric Andersenc470f442003-07-28 09:56:35 +00008843 shellparam.p = xargv;
8844#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008845 shellparam.optind = 1;
8846 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008847#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008848 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008849 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008850 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008851 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008852 }
8853 optschanged();
8854}
8855
8856
Eric Andersenc470f442003-07-28 09:56:35 +00008857void
8858optschanged(void)
8859{
8860#ifdef DEBUG
8861 opentrace();
8862#endif
8863 setinteractive(iflag);
8864 setjobctl(mflag);
8865}
Eric Andersencb57d552001-06-28 07:25:16 +00008866
Eric Andersenc470f442003-07-28 09:56:35 +00008867static inline void
8868minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008869{
8870 int i;
8871
8872 if (name == NULL) {
8873 out1str("Current option settings\n");
8874 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008875 out1fmt("%-16s%s\n", optnames(i),
8876 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008877 } else {
8878 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008879 if (equal(name, optnames(i))) {
8880 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008881 return;
8882 }
8883 error("Illegal option -o %s", name);
8884 }
8885}
8886
Eric Andersenc470f442003-07-28 09:56:35 +00008887/*
8888 * Process shell options. The global variable argptr contains a pointer
8889 * to the argument list; we advance it past the options.
8890 */
Eric Andersen62483552001-07-10 06:09:16 +00008891
Eric Andersenc470f442003-07-28 09:56:35 +00008892static void
8893options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008894{
8895 char *p;
8896 int val;
8897 int c;
8898
8899 if (cmdline)
8900 minusc = NULL;
8901 while ((p = *argptr) != NULL) {
8902 argptr++;
8903 if ((c = *p++) == '-') {
8904 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008905 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8906 if (!cmdline) {
8907 /* "-" means turn off -x and -v */
8908 if (p[0] == '\0')
8909 xflag = vflag = 0;
8910 /* "--" means reset params */
8911 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008912 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008913 }
Eric Andersenc470f442003-07-28 09:56:35 +00008914 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008915 }
8916 } else if (c == '+') {
8917 val = 0;
8918 } else {
8919 argptr--;
8920 break;
8921 }
8922 while ((c = *p++) != '\0') {
8923 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008924 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008925 } else if (c == 'o') {
8926 minus_o(*argptr, val);
8927 if (*argptr)
8928 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008929 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008930 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008931 isloginsh = 1;
8932 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008933 } else {
8934 setoption(c, val);
8935 }
8936 }
8937 }
8938}
8939
Eric Andersencb57d552001-06-28 07:25:16 +00008940
Eric Andersenc470f442003-07-28 09:56:35 +00008941static void
8942setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008943{
Eric Andersencb57d552001-06-28 07:25:16 +00008944 int i;
8945
8946 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008947 if (optletters(i) == flag) {
8948 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008949 return;
8950 }
8951 error("Illegal option -%c", flag);
8952 /* NOTREACHED */
8953}
8954
8955
8956
Eric Andersencb57d552001-06-28 07:25:16 +00008957/*
8958 * Set the shell parameters.
8959 */
8960
Eric Andersenc470f442003-07-28 09:56:35 +00008961void
8962setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008963{
Eric Andersencb57d552001-06-28 07:25:16 +00008964 char **newparam;
8965 char **ap;
8966 int nparam;
8967
Eric Andersenc470f442003-07-28 09:56:35 +00008968 for (nparam = 0 ; argv[nparam] ; nparam++);
8969 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008970 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008971 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008972 }
8973 *ap = NULL;
8974 freeparam(&shellparam);
8975 shellparam.malloc = 1;
8976 shellparam.nparam = nparam;
8977 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008978#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008979 shellparam.optind = 1;
8980 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008981#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008982}
8983
8984
8985/*
8986 * Free the list of positional parameters.
8987 */
8988
Eric Andersenc470f442003-07-28 09:56:35 +00008989void
8990freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008991{
Eric Andersencb57d552001-06-28 07:25:16 +00008992 char **ap;
8993
8994 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008995 for (ap = param->p ; *ap ; ap++)
8996 ckfree(*ap);
8997 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008998 }
8999}
9000
9001
9002
9003/*
9004 * The shift builtin command.
9005 */
9006
Eric Andersenc470f442003-07-28 09:56:35 +00009007int
9008shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009009{
9010 int n;
9011 char **ap1, **ap2;
9012
9013 n = 1;
9014 if (argc > 1)
9015 n = number(argv[1]);
9016 if (n > shellparam.nparam)
9017 error("can't shift that many");
9018 INTOFF;
9019 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009020 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009021 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009022 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009023 }
9024 ap2 = shellparam.p;
9025 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009026#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009027 shellparam.optind = 1;
9028 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009029#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009030 INTON;
9031 return 0;
9032}
9033
9034
9035
9036/*
9037 * The set command builtin.
9038 */
9039
Eric Andersenc470f442003-07-28 09:56:35 +00009040int
9041setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009042{
9043 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009044 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009045 INTOFF;
9046 options(0);
9047 optschanged();
9048 if (*argptr != NULL) {
9049 setparam(argptr);
9050 }
9051 INTON;
9052 return 0;
9053}
9054
9055
Eric Andersenc470f442003-07-28 09:56:35 +00009056#ifdef CONFIG_ASH_GETOPTS
9057static void
9058getoptsreset(value)
9059 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009060{
9061 shellparam.optind = number(value);
9062 shellparam.optoff = -1;
9063}
Eric Andersenc470f442003-07-28 09:56:35 +00009064#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009065
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009066#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009067static void change_lc_all(const char *value)
9068{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009069 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009070 setlocale(LC_ALL, value);
9071}
9072
9073static void change_lc_ctype(const char *value)
9074{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009075 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009076 setlocale(LC_CTYPE, value);
9077}
9078
9079#endif
9080
Eric Andersen16767e22004-03-16 05:14:10 +00009081#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009082/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009083static void change_random(const char *value)
9084{
Eric Andersen16767e22004-03-16 05:14:10 +00009085 if(value == NULL) {
9086 /* "get", generate */
9087 char buf[16];
9088
9089 rseed = rseed * 1103515245 + 12345;
9090 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9091 /* set without recursion */
9092 setvar(vrandom.text, buf, VNOFUNC);
9093 vrandom.flags &= ~VNOFUNC;
9094 } else {
9095 /* set/reset */
9096 rseed = strtoul(value, (char **)NULL, 10);
9097 }
Eric Andersenef02f822004-03-11 13:34:24 +00009098}
Eric Andersen16767e22004-03-16 05:14:10 +00009099#endif
9100
Eric Andersenef02f822004-03-11 13:34:24 +00009101
Eric Andersend35c5df2002-01-09 15:37:36 +00009102#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009103static int
Eric Andersenc470f442003-07-28 09:56:35 +00009104getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009105{
9106 char *p, *q;
9107 char c = '?';
9108 int done = 0;
9109 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009110 char s[12];
9111 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009112
Eric Andersena48b0a32003-10-22 10:56:47 +00009113 if(*param_optind < 1)
9114 return 1;
9115 optnext = optfirst + *param_optind - 1;
9116
9117 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009118 p = NULL;
9119 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009120 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009121 if (p == NULL || *p == '\0') {
9122 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009123 p = *optnext;
9124 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009125atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009126 p = NULL;
9127 done = 1;
9128 goto out;
9129 }
9130 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009131 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009132 goto atend;
9133 }
9134
9135 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009136 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009137 if (*q == '\0') {
9138 if (optstr[0] == ':') {
9139 s[0] = c;
9140 s[1] = '\0';
9141 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009142 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009143 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009144 (void) unsetvar("OPTARG");
9145 }
9146 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009147 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009148 }
9149 if (*++q == ':')
9150 q++;
9151 }
9152
9153 if (*++q == ':') {
9154 if (*p == '\0' && (p = *optnext) == NULL) {
9155 if (optstr[0] == ':') {
9156 s[0] = c;
9157 s[1] = '\0';
9158 err |= setvarsafe("OPTARG", s, 0);
9159 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009160 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009161 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009162 (void) unsetvar("OPTARG");
9163 c = '?';
9164 }
Eric Andersenc470f442003-07-28 09:56:35 +00009165 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009166 }
9167
9168 if (p == *optnext)
9169 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009170 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009171 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009172 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009173 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009174
Eric Andersenc470f442003-07-28 09:56:35 +00009175out:
Eric Andersencb57d552001-06-28 07:25:16 +00009176 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009177 *param_optind = optnext - optfirst + 1;
9178 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009179 err |= setvarsafe("OPTIND", s, VNOFUNC);
9180 s[0] = c;
9181 s[1] = '\0';
9182 err |= setvarsafe(optvar, s, 0);
9183 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009184 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009185 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009186 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009187 exraise(EXERROR);
9188 }
9189 return done;
9190}
Eric Andersenc470f442003-07-28 09:56:35 +00009191
9192/*
9193 * The getopts builtin. Shellparam.optnext points to the next argument
9194 * to be processed. Shellparam.optptr points to the next character to
9195 * be processed in the current argument. If shellparam.optnext is NULL,
9196 * then it's the first time getopts has been called.
9197 */
9198
9199int
9200getoptscmd(int argc, char **argv)
9201{
9202 char **optbase;
9203
9204 if (argc < 3)
9205 error("Usage: getopts optstring var [arg]");
9206 else if (argc == 3) {
9207 optbase = shellparam.p;
9208 if (shellparam.optind > shellparam.nparam + 1) {
9209 shellparam.optind = 1;
9210 shellparam.optoff = -1;
9211 }
9212 }
9213 else {
9214 optbase = &argv[3];
9215 if (shellparam.optind > argc - 2) {
9216 shellparam.optind = 1;
9217 shellparam.optoff = -1;
9218 }
9219 }
9220
9221 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9222 &shellparam.optoff);
9223}
9224#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009225
9226/*
9227 * XXX - should get rid of. have all builtins use getopt(3). the
9228 * library getopt must have the BSD extension static variable "optreset"
9229 * otherwise it can't be used within the shell safely.
9230 *
9231 * Standard option processing (a la getopt) for builtin routines. The
9232 * only argument that is passed to nextopt is the option string; the
9233 * other arguments are unnecessary. It return the character, or '\0' on
9234 * end of input.
9235 */
9236
Eric Andersenc470f442003-07-28 09:56:35 +00009237static int
9238nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009239{
Eric Andersencb57d552001-06-28 07:25:16 +00009240 char *p;
9241 const char *q;
9242 char c;
9243
9244 if ((p = optptr) == NULL || *p == '\0') {
9245 p = *argptr;
9246 if (p == NULL || *p != '-' || *++p == '\0')
9247 return '\0';
9248 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009249 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009250 return '\0';
9251 }
9252 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009253 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009254 if (*q == '\0')
9255 error("Illegal option -%c", c);
9256 if (*++q == ':')
9257 q++;
9258 }
9259 if (*++q == ':') {
9260 if (*p == '\0' && (p = *argptr++) == NULL)
9261 error("No arg for -%c option", c);
9262 optionarg = p;
9263 p = NULL;
9264 }
9265 optptr = p;
9266 return c;
9267}
9268
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009269
Eric Andersenc470f442003-07-28 09:56:35 +00009270/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9271
Eric Andersenc470f442003-07-28 09:56:35 +00009272void
9273outstr(const char *p, FILE *file)
9274{
9275 INTOFF;
9276 fputs(p, file);
9277 INTON;
9278}
9279
9280void
9281flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009282{
Eric Andersencb57d552001-06-28 07:25:16 +00009283 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009284 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009285 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009286 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009287}
9288
Eric Andersenc470f442003-07-28 09:56:35 +00009289void
Eric Andersen16767e22004-03-16 05:14:10 +00009290flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009291{
9292 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009293 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009294 INTON;
9295}
9296
9297static void
9298outcslow(int c, FILE *dest)
9299{
9300 INTOFF;
9301 putc(c, dest);
9302 fflush(dest);
9303 INTON;
9304}
9305
9306
9307static int
9308out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009309{
9310 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009311 int r;
9312
9313 INTOFF;
9314 va_start(ap, fmt);
9315 r = vprintf(fmt, ap);
9316 va_end(ap);
9317 INTON;
9318 return r;
9319}
9320
9321
9322int
9323fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9324{
9325 va_list ap;
9326 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009327
Eric Andersencb57d552001-06-28 07:25:16 +00009328 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009329 INTOFF;
9330 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009331 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009332 INTON;
9333 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009334}
9335
Eric Andersenc470f442003-07-28 09:56:35 +00009336
Eric Andersencb57d552001-06-28 07:25:16 +00009337
Eric Andersenc470f442003-07-28 09:56:35 +00009338/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9339
9340
Eric Andersencb57d552001-06-28 07:25:16 +00009341/*
9342 * Shell command parser.
9343 */
9344
9345#define EOFMARKLEN 79
9346
9347
Eric Andersencb57d552001-06-28 07:25:16 +00009348struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009349 struct heredoc *next; /* next here document in list */
9350 union node *here; /* redirection node */
9351 char *eofmark; /* string indicating end of input */
9352 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009353};
9354
9355
9356
Eric Andersenc470f442003-07-28 09:56:35 +00009357static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009358
9359
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009360static union node *list(int);
9361static union node *andor(void);
9362static union node *pipeline(void);
9363static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009364static union node *simplecmd(void);
9365static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009366static void parsefname(void);
9367static void parseheredoc(void);
9368static char peektoken(void);
9369static int readtoken(void);
9370static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009371static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009372static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009373static void synexpect(int) __attribute__((__noreturn__));
9374static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009375static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009376
9377
Eric Andersenc470f442003-07-28 09:56:35 +00009378
Eric Andersenc470f442003-07-28 09:56:35 +00009379
Eric Andersencb57d552001-06-28 07:25:16 +00009380/*
9381 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9382 * valid parse tree indicating a blank line.)
9383 */
9384
Eric Andersenc470f442003-07-28 09:56:35 +00009385union node *
9386parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009387{
9388 int t;
9389
9390 tokpushback = 0;
9391 doprompt = interact;
9392 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009393 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009394 needprompt = 0;
9395 t = readtoken();
9396 if (t == TEOF)
9397 return NEOF;
9398 if (t == TNL)
9399 return NULL;
9400 tokpushback++;
9401 return list(1);
9402}
9403
9404
Eric Andersenc470f442003-07-28 09:56:35 +00009405static union node *
9406list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009407{
9408 union node *n1, *n2, *n3;
9409 int tok;
9410
Eric Andersenc470f442003-07-28 09:56:35 +00009411 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9412 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009413 return NULL;
9414 n1 = NULL;
9415 for (;;) {
9416 n2 = andor();
9417 tok = readtoken();
9418 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009419 if (n2->type == NPIPE) {
9420 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009421 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009422 if (n2->type != NREDIR) {
9423 n3 = stalloc(sizeof(struct nredir));
9424 n3->nredir.n = n2;
9425 n3->nredir.redirect = NULL;
9426 n2 = n3;
9427 }
9428 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009429 }
9430 }
9431 if (n1 == NULL) {
9432 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009433 }
9434 else {
9435 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009436 n3->type = NSEMI;
9437 n3->nbinary.ch1 = n1;
9438 n3->nbinary.ch2 = n2;
9439 n1 = n3;
9440 }
9441 switch (tok) {
9442 case TBACKGND:
9443 case TSEMI:
9444 tok = readtoken();
9445 /* fall through */
9446 case TNL:
9447 if (tok == TNL) {
9448 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009449 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009450 return n1;
9451 } else {
9452 tokpushback++;
9453 }
Eric Andersenc470f442003-07-28 09:56:35 +00009454 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009455 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009456 return n1;
9457 break;
9458 case TEOF:
9459 if (heredoclist)
9460 parseheredoc();
9461 else
Eric Andersenc470f442003-07-28 09:56:35 +00009462 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009463 return n1;
9464 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009465 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009466 synexpect(-1);
9467 tokpushback++;
9468 return n1;
9469 }
9470 }
9471}
9472
9473
9474
Eric Andersenc470f442003-07-28 09:56:35 +00009475static union node *
9476andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009477{
Eric Andersencb57d552001-06-28 07:25:16 +00009478 union node *n1, *n2, *n3;
9479 int t;
9480
Eric Andersencb57d552001-06-28 07:25:16 +00009481 n1 = pipeline();
9482 for (;;) {
9483 if ((t = readtoken()) == TAND) {
9484 t = NAND;
9485 } else if (t == TOR) {
9486 t = NOR;
9487 } else {
9488 tokpushback++;
9489 return n1;
9490 }
Eric Andersenc470f442003-07-28 09:56:35 +00009491 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009492 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009493 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009494 n3->type = t;
9495 n3->nbinary.ch1 = n1;
9496 n3->nbinary.ch2 = n2;
9497 n1 = n3;
9498 }
9499}
9500
9501
9502
Eric Andersenc470f442003-07-28 09:56:35 +00009503static union node *
9504pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009505{
Eric Andersencb57d552001-06-28 07:25:16 +00009506 union node *n1, *n2, *pipenode;
9507 struct nodelist *lp, *prev;
9508 int negate;
9509
9510 negate = 0;
9511 TRACE(("pipeline: entered\n"));
9512 if (readtoken() == TNOT) {
9513 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009514 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009515 } else
9516 tokpushback++;
9517 n1 = command();
9518 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009519 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009520 pipenode->type = NPIPE;
9521 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009522 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009523 pipenode->npipe.cmdlist = lp;
9524 lp->n = n1;
9525 do {
9526 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009527 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9528 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009529 lp->n = command();
9530 prev->next = lp;
9531 } while (readtoken() == TPIPE);
9532 lp->next = NULL;
9533 n1 = pipenode;
9534 }
9535 tokpushback++;
9536 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009537 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009538 n2->type = NNOT;
9539 n2->nnot.com = n1;
9540 return n2;
9541 } else
9542 return n1;
9543}
9544
9545
9546
Eric Andersenc470f442003-07-28 09:56:35 +00009547static union node *
9548command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009549{
Eric Andersencb57d552001-06-28 07:25:16 +00009550 union node *n1, *n2;
9551 union node *ap, **app;
9552 union node *cp, **cpp;
9553 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009554 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009555 int t;
9556
9557 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009558 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009559
Eric Andersencb57d552001-06-28 07:25:16 +00009560 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009561 default:
9562 synexpect(-1);
9563 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009564 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009565 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009566 n1->type = NIF;
9567 n1->nif.test = list(0);
9568 if (readtoken() != TTHEN)
9569 synexpect(TTHEN);
9570 n1->nif.ifpart = list(0);
9571 n2 = n1;
9572 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009573 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009574 n2 = n2->nif.elsepart;
9575 n2->type = NIF;
9576 n2->nif.test = list(0);
9577 if (readtoken() != TTHEN)
9578 synexpect(TTHEN);
9579 n2->nif.ifpart = list(0);
9580 }
9581 if (lasttoken == TELSE)
9582 n2->nif.elsepart = list(0);
9583 else {
9584 n2->nif.elsepart = NULL;
9585 tokpushback++;
9586 }
Eric Andersenc470f442003-07-28 09:56:35 +00009587 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009588 break;
9589 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009590 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009591 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009592 n1 = (union node *)stalloc(sizeof (struct nbinary));
9593 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009594 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009595 if ((got=readtoken()) != TDO) {
9596TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009597 synexpect(TDO);
9598 }
9599 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009600 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009601 break;
9602 }
9603 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009604 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009605 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009606 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009607 n1->type = NFOR;
9608 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009609 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009610 if (readtoken() == TIN) {
9611 app = &ap;
9612 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009613 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009614 n2->type = NARG;
9615 n2->narg.text = wordtext;
9616 n2->narg.backquote = backquotelist;
9617 *app = n2;
9618 app = &n2->narg.next;
9619 }
9620 *app = NULL;
9621 n1->nfor.args = ap;
9622 if (lasttoken != TNL && lasttoken != TSEMI)
9623 synexpect(-1);
9624 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009625 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009626 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009627 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009628 n2->narg.backquote = NULL;
9629 n2->narg.next = NULL;
9630 n1->nfor.args = n2;
9631 /*
9632 * Newline or semicolon here is optional (but note
9633 * that the original Bourne shell only allowed NL).
9634 */
9635 if (lasttoken != TNL && lasttoken != TSEMI)
9636 tokpushback++;
9637 }
Eric Andersenc470f442003-07-28 09:56:35 +00009638 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009639 if (readtoken() != TDO)
9640 synexpect(TDO);
9641 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009642 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009643 break;
9644 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009645 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009646 n1->type = NCASE;
9647 if (readtoken() != TWORD)
9648 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009649 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009650 n2->type = NARG;
9651 n2->narg.text = wordtext;
9652 n2->narg.backquote = backquotelist;
9653 n2->narg.next = NULL;
9654 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009655 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009656 } while (readtoken() == TNL);
9657 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009658 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009659 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009660next_case:
9661 checkkwd = CHKNL | CHKKWD;
9662 t = readtoken();
9663 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009664 if (lasttoken == TLP)
9665 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009666 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009667 cp->type = NCLIST;
9668 app = &cp->nclist.pattern;
9669 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009670 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009671 ap->type = NARG;
9672 ap->narg.text = wordtext;
9673 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009674 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009675 break;
9676 app = &ap->narg.next;
9677 readtoken();
9678 }
9679 ap->narg.next = NULL;
9680 if (lasttoken != TRP)
9681 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009682 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009683
Eric Andersenc470f442003-07-28 09:56:35 +00009684 cpp = &cp->nclist.next;
9685
9686 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009687 if ((t = readtoken()) != TESAC) {
9688 if (t != TENDCASE)
9689 synexpect(TENDCASE);
9690 else
Eric Andersenc470f442003-07-28 09:56:35 +00009691 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009692 }
Eric Andersenc470f442003-07-28 09:56:35 +00009693 }
Eric Andersencb57d552001-06-28 07:25:16 +00009694 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009695 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009696 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009697 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009698 n1->type = NSUBSHELL;
9699 n1->nredir.n = list(0);
9700 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009701 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009702 break;
9703 case TBEGIN:
9704 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009705 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009706 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009707 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009708 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009709 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009710 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009711 }
9712
Eric Andersenc470f442003-07-28 09:56:35 +00009713 if (readtoken() != t)
9714 synexpect(t);
9715
9716redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009717 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009718 checkkwd = CHKKWD | CHKALIAS;
9719 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009720 while (readtoken() == TREDIR) {
9721 *rpp = n2 = redirnode;
9722 rpp = &n2->nfile.next;
9723 parsefname();
9724 }
9725 tokpushback++;
9726 *rpp = NULL;
9727 if (redir) {
9728 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009729 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009730 n2->type = NREDIR;
9731 n2->nredir.n = n1;
9732 n1 = n2;
9733 }
9734 n1->nredir.redirect = redir;
9735 }
9736
9737 return n1;
9738}
9739
9740
Eric Andersenc470f442003-07-28 09:56:35 +00009741static union node *
9742simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009743 union node *args, **app;
9744 union node *n = NULL;
9745 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009746 union node **rpp, *redir;
9747 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009748
9749 args = NULL;
9750 app = &args;
9751 vars = NULL;
9752 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009753 redir = NULL;
9754 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009755
Eric Andersenc470f442003-07-28 09:56:35 +00009756 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009757 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009758 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009759 switch (readtoken()) {
9760 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009761 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009762 n->type = NARG;
9763 n->narg.text = wordtext;
9764 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009765 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009766 *vpp = n;
9767 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009768 } else {
9769 *app = n;
9770 app = &n->narg.next;
9771 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009772 }
9773 break;
9774 case TREDIR:
9775 *rpp = n = redirnode;
9776 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009777 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009778 break;
9779 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009780 if (
9781 args && app == &args->narg.next &&
9782 !vars && !redir
9783 ) {
9784 struct builtincmd *bcmd;
9785 const char *name;
9786
Eric Andersencb57d552001-06-28 07:25:16 +00009787 /* We have a function */
9788 if (readtoken() != TRP)
9789 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009790 name = n->narg.text;
9791 if (
9792 !goodname(name) || (
9793 (bcmd = find_builtin(name)) &&
9794 IS_BUILTIN_SPECIAL(bcmd)
9795 )
9796 )
9797 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009798 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009799 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009800 n->narg.next = command();
9801 return n;
9802 }
9803 /* fall through */
9804 default:
9805 tokpushback++;
9806 goto out;
9807 }
9808 }
Eric Andersenc470f442003-07-28 09:56:35 +00009809out:
Eric Andersencb57d552001-06-28 07:25:16 +00009810 *app = NULL;
9811 *vpp = NULL;
9812 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009813 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009814 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009815 n->ncmd.args = args;
9816 n->ncmd.assign = vars;
9817 n->ncmd.redirect = redir;
9818 return n;
9819}
9820
Eric Andersenc470f442003-07-28 09:56:35 +00009821static union node *
9822makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009823{
Eric Andersencb57d552001-06-28 07:25:16 +00009824 union node *n;
9825
Eric Andersenc470f442003-07-28 09:56:35 +00009826 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009827 n->type = NARG;
9828 n->narg.next = NULL;
9829 n->narg.text = wordtext;
9830 n->narg.backquote = backquotelist;
9831 return n;
9832}
9833
Eric Andersenc470f442003-07-28 09:56:35 +00009834void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009835{
Eric Andersencb57d552001-06-28 07:25:16 +00009836 TRACE(("Fix redir %s %d\n", text, err));
9837 if (!err)
9838 n->ndup.vname = NULL;
9839
9840 if (is_digit(text[0]) && text[1] == '\0')
9841 n->ndup.dupfd = digit_val(text[0]);
9842 else if (text[0] == '-' && text[1] == '\0')
9843 n->ndup.dupfd = -1;
9844 else {
9845
9846 if (err)
9847 synerror("Bad fd number");
9848 else
9849 n->ndup.vname = makename();
9850 }
9851}
9852
9853
Eric Andersenc470f442003-07-28 09:56:35 +00009854static void
9855parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009856{
Eric Andersencb57d552001-06-28 07:25:16 +00009857 union node *n = redirnode;
9858
9859 if (readtoken() != TWORD)
9860 synexpect(-1);
9861 if (n->type == NHERE) {
9862 struct heredoc *here = heredoc;
9863 struct heredoc *p;
9864 int i;
9865
9866 if (quoteflag == 0)
9867 n->type = NXHERE;
9868 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009869 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009870 synerror("Illegal eof marker for << redirection");
9871 rmescapes(wordtext);
9872 here->eofmark = wordtext;
9873 here->next = NULL;
9874 if (heredoclist == NULL)
9875 heredoclist = here;
9876 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009877 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009878 p->next = here;
9879 }
9880 } else if (n->type == NTOFD || n->type == NFROMFD) {
9881 fixredir(n, wordtext, 0);
9882 } else {
9883 n->nfile.fname = makename();
9884 }
9885}
9886
9887
9888/*
9889 * Input any here documents.
9890 */
9891
Eric Andersenc470f442003-07-28 09:56:35 +00009892static void
9893parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009894{
Eric Andersencb57d552001-06-28 07:25:16 +00009895 struct heredoc *here;
9896 union node *n;
9897
Eric Andersenc470f442003-07-28 09:56:35 +00009898 here = heredoclist;
9899 heredoclist = 0;
9900
9901 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009902 if (needprompt) {
9903 setprompt(2);
9904 needprompt = 0;
9905 }
Eric Andersenc470f442003-07-28 09:56:35 +00009906 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9907 here->eofmark, here->striptabs);
9908 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009909 n->narg.type = NARG;
9910 n->narg.next = NULL;
9911 n->narg.text = wordtext;
9912 n->narg.backquote = backquotelist;
9913 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009914 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009915 }
9916}
9917
Eric Andersenc470f442003-07-28 09:56:35 +00009918static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009919{
Eric Andersencb57d552001-06-28 07:25:16 +00009920 int t;
9921
9922 t = readtoken();
9923 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009924 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009925}
9926
Eric Andersenc470f442003-07-28 09:56:35 +00009927static int
9928readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009929{
Eric Andersencb57d552001-06-28 07:25:16 +00009930 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009931#ifdef DEBUG
9932 int alreadyseen = tokpushback;
9933#endif
9934
Eric Andersend35c5df2002-01-09 15:37:36 +00009935#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009936top:
Eric Andersen2870d962001-07-02 17:27:21 +00009937#endif
9938
Eric Andersencb57d552001-06-28 07:25:16 +00009939 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009940
Eric Andersenc470f442003-07-28 09:56:35 +00009941 /*
9942 * eat newlines
9943 */
9944 if (checkkwd & CHKNL) {
9945 while (t == TNL) {
9946 parseheredoc();
9947 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009948 }
9949 }
9950
Eric Andersenc470f442003-07-28 09:56:35 +00009951 if (t != TWORD || quoteflag) {
9952 goto out;
9953 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009954
Eric Andersenc470f442003-07-28 09:56:35 +00009955 /*
9956 * check for keywords
9957 */
9958 if (checkkwd & CHKKWD) {
9959 const char *const *pp;
9960
9961 if ((pp = findkwd(wordtext))) {
9962 lasttoken = t = pp - tokname_array;
9963 TRACE(("keyword %s recognized\n", tokname(t)));
9964 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009965 }
Eric Andersenc470f442003-07-28 09:56:35 +00009966 }
9967
9968 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009969#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009970 struct alias *ap;
9971 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009972 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009973 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009974 }
Eric Andersencb57d552001-06-28 07:25:16 +00009975 goto top;
9976 }
Eric Andersen2870d962001-07-02 17:27:21 +00009977#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009978 }
Eric Andersenc470f442003-07-28 09:56:35 +00009979out:
9980 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009981#ifdef DEBUG
9982 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009983 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009984 else
Eric Andersenc470f442003-07-28 09:56:35 +00009985 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009986#endif
9987 return (t);
9988}
9989
9990
9991/*
9992 * Read the next input token.
9993 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009994 * backquotes. We set quoteflag to true if any part of the word was
9995 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009996 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009997 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009998 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009999 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010000 *
10001 * [Change comment: here documents and internal procedures]
10002 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10003 * word parsing code into a separate routine. In this case, readtoken
10004 * doesn't need to have any internal procedures, but parseword does.
10005 * We could also make parseoperator in essence the main routine, and
10006 * have parseword (readtoken1?) handle both words and redirection.]
10007 */
10008
Eric Andersen81fe1232003-07-29 06:38:40 +000010009#define NEW_xxreadtoken
10010#ifdef NEW_xxreadtoken
10011
10012/* singles must be first! */
10013static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10014
10015static const char xxreadtoken_tokens[] = {
10016 TNL, TLP, TRP, /* only single occurrence allowed */
10017 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10018 TEOF, /* corresponds to trailing nul */
10019 TAND, TOR, TENDCASE, /* if double occurrence */
10020};
10021
10022#define xxreadtoken_doubles \
10023 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10024#define xxreadtoken_singles \
10025 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10026
10027static int xxreadtoken()
10028{
10029 int c;
10030
10031 if (tokpushback) {
10032 tokpushback = 0;
10033 return lasttoken;
10034 }
10035 if (needprompt) {
10036 setprompt(2);
10037 needprompt = 0;
10038 }
10039 startlinno = plinno;
10040 for (;;) { /* until token or start of word found */
10041 c = pgetc_macro();
10042
10043 if ((c != ' ') && (c != '\t')
10044#ifdef CONFIG_ASH_ALIAS
10045 && (c != PEOA)
10046#endif
10047 ) {
10048 if (c == '#') {
10049 while ((c = pgetc()) != '\n' && c != PEOF);
10050 pungetc();
10051 } else if (c == '\\') {
10052 if (pgetc() != '\n') {
10053 pungetc();
10054 goto READTOKEN1;
10055 }
10056 startlinno = ++plinno;
10057 if (doprompt)
10058 setprompt(2);
10059 } else {
10060 const char *p
10061 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10062
10063 if (c != PEOF) {
10064 if (c == '\n') {
10065 plinno++;
10066 needprompt = doprompt;
10067 }
10068
10069 p = strchr(xxreadtoken_chars, c);
10070 if (p == NULL) {
10071 READTOKEN1:
10072 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10073 }
10074
10075 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10076 if (pgetc() == *p) { /* double occurrence? */
10077 p += xxreadtoken_doubles + 1;
10078 } else {
10079 pungetc();
10080 }
10081 }
10082 }
10083
10084 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10085 }
10086 }
10087 }
10088}
10089
10090
10091#else
Eric Andersen2870d962001-07-02 17:27:21 +000010092#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010093
Eric Andersenc470f442003-07-28 09:56:35 +000010094static int
10095xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010096{
Eric Andersencb57d552001-06-28 07:25:16 +000010097 int c;
10098
10099 if (tokpushback) {
10100 tokpushback = 0;
10101 return lasttoken;
10102 }
10103 if (needprompt) {
10104 setprompt(2);
10105 needprompt = 0;
10106 }
10107 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010108 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010109 c = pgetc_macro();
10110 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010111 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010112#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010113 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010114#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010115 continue;
10116 case '#':
10117 while ((c = pgetc()) != '\n' && c != PEOF);
10118 pungetc();
10119 continue;
10120 case '\\':
10121 if (pgetc() == '\n') {
10122 startlinno = ++plinno;
10123 if (doprompt)
10124 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010125 continue;
10126 }
10127 pungetc();
10128 goto breakloop;
10129 case '\n':
10130 plinno++;
10131 needprompt = doprompt;
10132 RETURN(TNL);
10133 case PEOF:
10134 RETURN(TEOF);
10135 case '&':
10136 if (pgetc() == '&')
10137 RETURN(TAND);
10138 pungetc();
10139 RETURN(TBACKGND);
10140 case '|':
10141 if (pgetc() == '|')
10142 RETURN(TOR);
10143 pungetc();
10144 RETURN(TPIPE);
10145 case ';':
10146 if (pgetc() == ';')
10147 RETURN(TENDCASE);
10148 pungetc();
10149 RETURN(TSEMI);
10150 case '(':
10151 RETURN(TLP);
10152 case ')':
10153 RETURN(TRP);
10154 default:
10155 goto breakloop;
10156 }
10157 }
Eric Andersenc470f442003-07-28 09:56:35 +000010158breakloop:
10159 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010160#undef RETURN
10161}
Eric Andersen81fe1232003-07-29 06:38:40 +000010162#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010163
Eric Andersencb57d552001-06-28 07:25:16 +000010164
Eric Andersencb57d552001-06-28 07:25:16 +000010165/*
10166 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10167 * is not NULL, read a here document. In the latter case, eofmark is the
10168 * word which marks the end of the document and striptabs is true if
10169 * leading tabs should be stripped from the document. The argument firstc
10170 * is the first character of the input token or document.
10171 *
10172 * Because C does not have internal subroutines, I have simulated them
10173 * using goto's to implement the subroutine linkage. The following macros
10174 * will run code that appears at the end of readtoken1.
10175 */
10176
Eric Andersen2870d962001-07-02 17:27:21 +000010177#define CHECKEND() {goto checkend; checkend_return:;}
10178#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10179#define PARSESUB() {goto parsesub; parsesub_return:;}
10180#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10181#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10182#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010183
10184static int
Eric Andersenc470f442003-07-28 09:56:35 +000010185readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010186{
Eric Andersencb57d552001-06-28 07:25:16 +000010187 int c = firstc;
10188 char *out;
10189 int len;
10190 char line[EOFMARKLEN + 1];
10191 struct nodelist *bqlist;
10192 int quotef;
10193 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010194 int varnest; /* levels of variables expansion */
10195 int arinest; /* levels of arithmetic expansion */
10196 int parenlevel; /* levels of parens in arithmetic */
10197 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010198 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010199 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010200#if __GNUC__
10201 /* Avoid longjmp clobbering */
10202 (void) &out;
10203 (void) &quotef;
10204 (void) &dblquote;
10205 (void) &varnest;
10206 (void) &arinest;
10207 (void) &parenlevel;
10208 (void) &dqvarnest;
10209 (void) &oldstyle;
10210 (void) &prevsyntax;
10211 (void) &syntax;
10212#endif
10213
10214 startlinno = plinno;
10215 dblquote = 0;
10216 if (syntax == DQSYNTAX)
10217 dblquote = 1;
10218 quotef = 0;
10219 bqlist = NULL;
10220 varnest = 0;
10221 arinest = 0;
10222 parenlevel = 0;
10223 dqvarnest = 0;
10224
10225 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010226 loop: { /* for each line, until end of word */
10227 CHECKEND(); /* set c to PEOF if at end of here document */
10228 for (;;) { /* until end of line or end of word */
10229 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10230 switch(SIT(c, syntax)) {
10231 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010232 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010233 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010234 USTPUTC(c, out);
10235 plinno++;
10236 if (doprompt)
10237 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010238 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010239 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010240 case CWORD:
10241 USTPUTC(c, out);
10242 break;
10243 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010244 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010245 USTPUTC(CTLESC, out);
10246 USTPUTC(c, out);
10247 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010248 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010249 c = pgetc2();
10250 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010251 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010252 USTPUTC('\\', out);
10253 pungetc();
10254 } else if (c == '\n') {
10255 if (doprompt)
10256 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010257 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010258 if (
10259 dblquote &&
10260 c != '\\' && c != '`' &&
10261 c != '$' && (
10262 c != '"' ||
10263 eofmark != NULL
10264 )
10265 ) {
10266 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010267 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010268 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010269 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010270 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010271 USTPUTC(c, out);
10272 quotef++;
10273 }
10274 break;
10275 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010276 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010277quotemark:
10278 if (eofmark == NULL) {
10279 USTPUTC(CTLQUOTEMARK, out);
10280 }
Eric Andersencb57d552001-06-28 07:25:16 +000010281 break;
10282 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010283 syntax = DQSYNTAX;
10284 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010285 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010286 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010287 if (eofmark != NULL && arinest == 0 &&
10288 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010289 USTPUTC(c, out);
10290 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010291 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010292 syntax = BASESYNTAX;
10293 dblquote = 0;
10294 }
10295 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010296 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010297 }
10298 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010299 case CVAR: /* '$' */
10300 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010301 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010302 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010303 if (varnest > 0) {
10304 varnest--;
10305 if (dqvarnest > 0) {
10306 dqvarnest--;
10307 }
10308 USTPUTC(CTLENDVAR, out);
10309 } else {
10310 USTPUTC(c, out);
10311 }
10312 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010313#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010314 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010315 parenlevel++;
10316 USTPUTC(c, out);
10317 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010318 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010319 if (parenlevel > 0) {
10320 USTPUTC(c, out);
10321 --parenlevel;
10322 } else {
10323 if (pgetc() == ')') {
10324 if (--arinest == 0) {
10325 USTPUTC(CTLENDARI, out);
10326 syntax = prevsyntax;
10327 if (syntax == DQSYNTAX)
10328 dblquote = 1;
10329 else
10330 dblquote = 0;
10331 } else
10332 USTPUTC(')', out);
10333 } else {
10334 /*
10335 * unbalanced parens
10336 * (don't 2nd guess - no error)
10337 */
10338 pungetc();
10339 USTPUTC(')', out);
10340 }
10341 }
10342 break;
10343#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010344 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010345 PARSEBACKQOLD();
10346 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010347 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010348 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010349 case CIGN:
10350 break;
10351 default:
10352 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010353 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010354#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010355 if (c != PEOA)
10356#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010357 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010358
Eric Andersencb57d552001-06-28 07:25:16 +000010359 }
10360 c = pgetc_macro();
10361 }
10362 }
Eric Andersenc470f442003-07-28 09:56:35 +000010363endword:
10364#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010365 if (syntax == ARISYNTAX)
10366 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010367#endif
10368 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010369 synerror("Unterminated quoted string");
10370 if (varnest != 0) {
10371 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010372 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010373 synerror("Missing '}'");
10374 }
10375 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010376 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010377 out = stackblock();
10378 if (eofmark == NULL) {
10379 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010380 && quotef == 0
10381 && len <= 2
10382 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010383 PARSEREDIR();
10384 return lasttoken = TREDIR;
10385 } else {
10386 pungetc();
10387 }
10388 }
10389 quoteflag = quotef;
10390 backquotelist = bqlist;
10391 grabstackblock(len);
10392 wordtext = out;
10393 return lasttoken = TWORD;
10394/* end of readtoken routine */
10395
10396
10397
10398/*
10399 * Check to see whether we are at the end of the here document. When this
10400 * is called, c is set to the first character of the next input line. If
10401 * we are at the end of the here document, this routine sets the c to PEOF.
10402 */
10403
Eric Andersenc470f442003-07-28 09:56:35 +000010404checkend: {
10405 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010406#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010407 if (c == PEOA) {
10408 c = pgetc2();
10409 }
10410#endif
10411 if (striptabs) {
10412 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010413 c = pgetc2();
10414 }
Eric Andersenc470f442003-07-28 09:56:35 +000010415 }
10416 if (c == *eofmark) {
10417 if (pfgets(line, sizeof line) != NULL) {
10418 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010419
Eric Andersenc470f442003-07-28 09:56:35 +000010420 p = line;
10421 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10422 if (*p == '\n' && *q == '\0') {
10423 c = PEOF;
10424 plinno++;
10425 needprompt = doprompt;
10426 } else {
10427 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010428 }
10429 }
10430 }
10431 }
Eric Andersenc470f442003-07-28 09:56:35 +000010432 goto checkend_return;
10433}
Eric Andersencb57d552001-06-28 07:25:16 +000010434
10435
10436/*
10437 * Parse a redirection operator. The variable "out" points to a string
10438 * specifying the fd to be redirected. The variable "c" contains the
10439 * first character of the redirection operator.
10440 */
10441
Eric Andersenc470f442003-07-28 09:56:35 +000010442parseredir: {
10443 char fd = *out;
10444 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010445
Eric Andersenc470f442003-07-28 09:56:35 +000010446 np = (union node *)stalloc(sizeof (struct nfile));
10447 if (c == '>') {
10448 np->nfile.fd = 1;
10449 c = pgetc();
10450 if (c == '>')
10451 np->type = NAPPEND;
10452 else if (c == '|')
10453 np->type = NCLOBBER;
10454 else if (c == '&')
10455 np->type = NTOFD;
10456 else {
10457 np->type = NTO;
10458 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010459 }
Eric Andersenc470f442003-07-28 09:56:35 +000010460 } else { /* c == '<' */
10461 np->nfile.fd = 0;
10462 switch (c = pgetc()) {
10463 case '<':
10464 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10465 np = (union node *)stalloc(sizeof (struct nhere));
10466 np->nfile.fd = 0;
10467 }
10468 np->type = NHERE;
10469 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10470 heredoc->here = np;
10471 if ((c = pgetc()) == '-') {
10472 heredoc->striptabs = 1;
10473 } else {
10474 heredoc->striptabs = 0;
10475 pungetc();
10476 }
10477 break;
10478
10479 case '&':
10480 np->type = NFROMFD;
10481 break;
10482
10483 case '>':
10484 np->type = NFROMTO;
10485 break;
10486
10487 default:
10488 np->type = NFROM;
10489 pungetc();
10490 break;
10491 }
Eric Andersencb57d552001-06-28 07:25:16 +000010492 }
Eric Andersenc470f442003-07-28 09:56:35 +000010493 if (fd != '\0')
10494 np->nfile.fd = digit_val(fd);
10495 redirnode = np;
10496 goto parseredir_return;
10497}
Eric Andersencb57d552001-06-28 07:25:16 +000010498
10499
10500/*
10501 * Parse a substitution. At this point, we have read the dollar sign
10502 * and nothing else.
10503 */
10504
Eric Andersenc470f442003-07-28 09:56:35 +000010505parsesub: {
10506 int subtype;
10507 int typeloc;
10508 int flags;
10509 char *p;
10510 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010511
Eric Andersenc470f442003-07-28 09:56:35 +000010512 c = pgetc();
10513 if (
10514 c <= PEOA_OR_PEOF ||
10515 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10516 ) {
10517 USTPUTC('$', out);
10518 pungetc();
10519 } else if (c == '(') { /* $(command) or $((arith)) */
10520 if (pgetc() == '(') {
10521#ifdef CONFIG_ASH_MATH_SUPPORT
10522 PARSEARITH();
10523#else
10524 synerror("We unsupport $((arith))");
10525#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010526 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010527 pungetc();
10528 PARSEBACKQNEW();
10529 }
10530 } else {
10531 USTPUTC(CTLVAR, out);
10532 typeloc = out - (char *)stackblock();
10533 USTPUTC(VSNORMAL, out);
10534 subtype = VSNORMAL;
10535 if (c == '{') {
10536 c = pgetc();
10537 if (c == '#') {
10538 if ((c = pgetc()) == '}')
10539 c = '#';
10540 else
10541 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010542 }
Eric Andersenc470f442003-07-28 09:56:35 +000010543 else
10544 subtype = 0;
10545 }
10546 if (c > PEOA_OR_PEOF && is_name(c)) {
10547 do {
10548 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010549 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010550 } while (c > PEOA_OR_PEOF && is_in_name(c));
10551 } else if (is_digit(c)) {
10552 do {
10553 STPUTC(c, out);
10554 c = pgetc();
10555 } while (is_digit(c));
10556 }
10557 else if (is_special(c)) {
10558 USTPUTC(c, out);
10559 c = pgetc();
10560 }
10561 else
10562badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010563
Eric Andersenc470f442003-07-28 09:56:35 +000010564 STPUTC('=', out);
10565 flags = 0;
10566 if (subtype == 0) {
10567 switch (c) {
10568 case ':':
10569 flags = VSNUL;
10570 c = pgetc();
10571 /*FALLTHROUGH*/
10572 default:
10573 p = strchr(types, c);
10574 if (p == NULL)
10575 goto badsub;
10576 subtype = p - types + VSNORMAL;
10577 break;
10578 case '%':
10579 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010580 {
10581 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010582 subtype = c == '#' ? VSTRIMLEFT :
10583 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010584 c = pgetc();
10585 if (c == cc)
10586 subtype++;
10587 else
10588 pungetc();
10589 break;
10590 }
10591 }
Eric Andersenc470f442003-07-28 09:56:35 +000010592 } else {
10593 pungetc();
10594 }
10595 if (dblquote || arinest)
10596 flags |= VSQUOTE;
10597 *((char *)stackblock() + typeloc) = subtype | flags;
10598 if (subtype != VSNORMAL) {
10599 varnest++;
10600 if (dblquote || arinest) {
10601 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010602 }
10603 }
10604 }
Eric Andersenc470f442003-07-28 09:56:35 +000010605 goto parsesub_return;
10606}
Eric Andersencb57d552001-06-28 07:25:16 +000010607
10608
10609/*
10610 * Called to parse command substitutions. Newstyle is set if the command
10611 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10612 * list of commands (passed by reference), and savelen is the number of
10613 * characters on the top of the stack which must be preserved.
10614 */
10615
Eric Andersenc470f442003-07-28 09:56:35 +000010616parsebackq: {
10617 struct nodelist **nlpp;
10618 int savepbq;
10619 union node *n;
10620 char *volatile str;
10621 struct jmploc jmploc;
10622 struct jmploc *volatile savehandler;
10623 size_t savelen;
10624 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010625#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010626 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010627#endif
10628
Eric Andersenc470f442003-07-28 09:56:35 +000010629 savepbq = parsebackquote;
10630 if (setjmp(jmploc.loc)) {
10631 if (str)
10632 ckfree(str);
10633 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010634 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010635 longjmp(handler->loc, 1);
10636 }
10637 INTOFF;
10638 str = NULL;
10639 savelen = out - (char *)stackblock();
10640 if (savelen > 0) {
10641 str = ckmalloc(savelen);
10642 memcpy(str, stackblock(), savelen);
10643 }
10644 savehandler = handler;
10645 handler = &jmploc;
10646 INTON;
10647 if (oldstyle) {
10648 /* We must read until the closing backquote, giving special
10649 treatment to some slashes, and then push the string and
10650 reread it as input, interpreting it normally. */
10651 char *pout;
10652 int pc;
10653 size_t psavelen;
10654 char *pstr;
10655
10656
10657 STARTSTACKSTR(pout);
10658 for (;;) {
10659 if (needprompt) {
10660 setprompt(2);
10661 needprompt = 0;
10662 }
10663 switch (pc = pgetc()) {
10664 case '`':
10665 goto done;
10666
10667 case '\\':
10668 if ((pc = pgetc()) == '\n') {
10669 plinno++;
10670 if (doprompt)
10671 setprompt(2);
10672 /*
10673 * If eating a newline, avoid putting
10674 * the newline into the new character
10675 * stream (via the STPUTC after the
10676 * switch).
10677 */
10678 continue;
10679 }
10680 if (pc != '\\' && pc != '`' && pc != '$'
10681 && (!dblquote || pc != '"'))
10682 STPUTC('\\', pout);
10683 if (pc > PEOA_OR_PEOF) {
10684 break;
10685 }
10686 /* fall through */
10687
10688 case PEOF:
10689#ifdef CONFIG_ASH_ALIAS
10690 case PEOA:
10691#endif
10692 startlinno = plinno;
10693 synerror("EOF in backquote substitution");
10694
10695 case '\n':
10696 plinno++;
10697 needprompt = doprompt;
10698 break;
10699
10700 default:
10701 break;
10702 }
10703 STPUTC(pc, pout);
10704 }
10705done:
10706 STPUTC('\0', pout);
10707 psavelen = pout - (char *)stackblock();
10708 if (psavelen > 0) {
10709 pstr = grabstackstr(pout);
10710 setinputstring(pstr);
10711 }
10712 }
10713 nlpp = &bqlist;
10714 while (*nlpp)
10715 nlpp = &(*nlpp)->next;
10716 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10717 (*nlpp)->next = NULL;
10718 parsebackquote = oldstyle;
10719
10720 if (oldstyle) {
10721 saveprompt = doprompt;
10722 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010723 }
10724
Eric Andersenc470f442003-07-28 09:56:35 +000010725 n = list(2);
10726
10727 if (oldstyle)
10728 doprompt = saveprompt;
10729 else {
10730 if (readtoken() != TRP)
10731 synexpect(TRP);
10732 }
10733
10734 (*nlpp)->n = n;
10735 if (oldstyle) {
10736 /*
10737 * Start reading from old file again, ignoring any pushed back
10738 * tokens left from the backquote parsing
10739 */
10740 popfile();
10741 tokpushback = 0;
10742 }
10743 while (stackblocksize() <= savelen)
10744 growstackblock();
10745 STARTSTACKSTR(out);
10746 if (str) {
10747 memcpy(out, str, savelen);
10748 STADJUST(savelen, out);
10749 INTOFF;
10750 ckfree(str);
10751 str = NULL;
10752 INTON;
10753 }
10754 parsebackquote = savepbq;
10755 handler = savehandler;
10756 if (arinest || dblquote)
10757 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10758 else
10759 USTPUTC(CTLBACKQ, out);
10760 if (oldstyle)
10761 goto parsebackq_oldreturn;
10762 else
10763 goto parsebackq_newreturn;
10764}
10765
10766#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010767/*
10768 * Parse an arithmetic expansion (indicate start of one and set state)
10769 */
Eric Andersenc470f442003-07-28 09:56:35 +000010770parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010771
Eric Andersenc470f442003-07-28 09:56:35 +000010772 if (++arinest == 1) {
10773 prevsyntax = syntax;
10774 syntax = ARISYNTAX;
10775 USTPUTC(CTLARI, out);
10776 if (dblquote)
10777 USTPUTC('"',out);
10778 else
10779 USTPUTC(' ',out);
10780 } else {
10781 /*
10782 * we collapse embedded arithmetic expansion to
10783 * parenthesis, which should be equivalent
10784 */
10785 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010786 }
Eric Andersenc470f442003-07-28 09:56:35 +000010787 goto parsearith_return;
10788}
10789#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010790
Eric Andersenc470f442003-07-28 09:56:35 +000010791} /* end of readtoken */
10792
Eric Andersencb57d552001-06-28 07:25:16 +000010793
10794
Eric Andersencb57d552001-06-28 07:25:16 +000010795/*
10796 * Returns true if the text contains nothing to expand (no dollar signs
10797 * or backquotes).
10798 */
10799
Eric Andersenc470f442003-07-28 09:56:35 +000010800static int
10801noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010802{
Eric Andersencb57d552001-06-28 07:25:16 +000010803 char *p;
10804 char c;
10805
10806 p = text;
10807 while ((c = *p++) != '\0') {
10808 if (c == CTLQUOTEMARK)
10809 continue;
10810 if (c == CTLESC)
10811 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010812 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010813 return 0;
10814 }
10815 return 1;
10816}
10817
10818
10819/*
Eric Andersenc470f442003-07-28 09:56:35 +000010820 * Return of a legal variable name (a letter or underscore followed by zero or
10821 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010822 */
10823
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010824static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010825endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010826{
Eric Andersenc470f442003-07-28 09:56:35 +000010827 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010828
Eric Andersenc470f442003-07-28 09:56:35 +000010829 p = (char *) name;
10830 if (! is_name(*p))
10831 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010832 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010833 if (! is_in_name(*p))
10834 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010835 }
Eric Andersenc470f442003-07-28 09:56:35 +000010836 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010837}
10838
10839
10840/*
10841 * Called when an unexpected token is read during the parse. The argument
10842 * is the token that is expected, or -1 if more than one type of token can
10843 * occur at this point.
10844 */
10845
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010846static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010847{
10848 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010849 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010850
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010851 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10852 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010853 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010854 synerror(msg);
10855 /* NOTREACHED */
10856}
10857
Eric Andersenc470f442003-07-28 09:56:35 +000010858static void
10859synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010860{
Eric Andersenc470f442003-07-28 09:56:35 +000010861 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010862 /* NOTREACHED */
10863}
10864
Eric Andersencb57d552001-06-28 07:25:16 +000010865
10866/*
10867 * called by editline -- any expansions to the prompt
10868 * should be added here.
10869 */
Eric Andersenc470f442003-07-28 09:56:35 +000010870
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010871static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010872{
Eric Andersenc470f442003-07-28 09:56:35 +000010873 const char *prompt;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010874
10875 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010876 case 1:
10877 prompt = ps1val();
10878 break;
10879 case 2:
10880 prompt = ps2val();
10881 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010882 default: /* 0 */
10883 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010884 }
10885 putprompt(prompt);
Eric Andersencb57d552001-06-28 07:25:16 +000010886}
10887
Eric Andersencb57d552001-06-28 07:25:16 +000010888
Eric Andersenc470f442003-07-28 09:56:35 +000010889static const char *const *findkwd(const char *s)
10890{
10891 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010892 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010893 sizeof(const char *), pstrcmp);
10894}
10895
10896/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10897
Eric Andersencb57d552001-06-28 07:25:16 +000010898/*
10899 * Code for dealing with input/output redirection.
10900 */
10901
Eric Andersenc470f442003-07-28 09:56:35 +000010902#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010903#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010904# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010905#else
10906# define PIPESIZE PIPE_BUF
10907#endif
10908
Eric Andersen62483552001-07-10 06:09:16 +000010909/*
10910 * Open a file in noclobber mode.
10911 * The code was copied from bash.
10912 */
Eric Andersenc470f442003-07-28 09:56:35 +000010913static inline int
10914noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010915{
10916 int r, fd;
10917 struct stat finfo, finfo2;
10918
10919 /*
10920 * If the file exists and is a regular file, return an error
10921 * immediately.
10922 */
10923 r = stat(fname, &finfo);
10924 if (r == 0 && S_ISREG(finfo.st_mode)) {
10925 errno = EEXIST;
10926 return -1;
10927 }
10928
10929 /*
10930 * If the file was not present (r != 0), make sure we open it
10931 * exclusively so that if it is created before we open it, our open
10932 * will fail. Make sure that we do not truncate an existing file.
10933 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10934 * file was not a regular file, we leave O_EXCL off.
10935 */
10936 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010937 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10938 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010939
10940 /* If the open failed, return the file descriptor right away. */
10941 if (fd < 0)
10942 return fd;
10943
10944 /*
10945 * OK, the open succeeded, but the file may have been changed from a
10946 * non-regular file to a regular file between the stat and the open.
10947 * We are assuming that the O_EXCL open handles the case where FILENAME
10948 * did not exist and is symlinked to an existing file between the stat
10949 * and open.
10950 */
10951
10952 /*
10953 * If we can open it and fstat the file descriptor, and neither check
10954 * revealed that it was a regular file, and the file has not been
10955 * replaced, return the file descriptor.
10956 */
Eric Andersenc470f442003-07-28 09:56:35 +000010957 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10958 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010959 return fd;
10960
10961 /* The file has been replaced. badness. */
10962 close(fd);
10963 errno = EEXIST;
10964 return -1;
10965}
Eric Andersencb57d552001-06-28 07:25:16 +000010966
10967/*
Eric Andersen62483552001-07-10 06:09:16 +000010968 * Handle here documents. Normally we fork off a process to write the
10969 * data to a pipe. If the document is short, we can stuff the data in
10970 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010971 */
10972
Eric Andersenc470f442003-07-28 09:56:35 +000010973static inline int
10974openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000010975{
10976 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000010977 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010978
Eric Andersen62483552001-07-10 06:09:16 +000010979 if (pipe(pip) < 0)
10980 error("Pipe call failed");
10981 if (redir->type == NHERE) {
10982 len = strlen(redir->nhere.doc->narg.text);
10983 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000010984 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010985 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010986 }
Eric Andersencb57d552001-06-28 07:25:16 +000010987 }
Eric Andersenc470f442003-07-28 09:56:35 +000010988 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000010989 close(pip[0]);
10990 signal(SIGINT, SIG_IGN);
10991 signal(SIGQUIT, SIG_IGN);
10992 signal(SIGHUP, SIG_IGN);
10993#ifdef SIGTSTP
10994 signal(SIGTSTP, SIG_IGN);
10995#endif
10996 signal(SIGPIPE, SIG_DFL);
10997 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000010998 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000010999 else
11000 expandhere(redir->nhere.doc, pip[1]);
11001 _exit(0);
11002 }
Eric Andersenc470f442003-07-28 09:56:35 +000011003out:
Eric Andersen62483552001-07-10 06:09:16 +000011004 close(pip[1]);
11005 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011006}
11007
Eric Andersenc470f442003-07-28 09:56:35 +000011008static int
11009openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011010{
Eric Andersencb57d552001-06-28 07:25:16 +000011011 char *fname;
11012 int f;
11013
11014 switch (redir->nfile.type) {
11015 case NFROM:
11016 fname = redir->nfile.expfname;
11017 if ((f = open(fname, O_RDONLY)) < 0)
11018 goto eopen;
11019 break;
11020 case NFROMTO:
11021 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011022 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011023 goto ecreate;
11024 break;
11025 case NTO:
11026 /* Take care of noclobber mode. */
11027 if (Cflag) {
11028 fname = redir->nfile.expfname;
11029 if ((f = noclobberopen(fname)) < 0)
11030 goto ecreate;
11031 break;
11032 }
Eric Andersenc470f442003-07-28 09:56:35 +000011033 /* FALLTHROUGH */
11034 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011035 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011036 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011037 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011038 break;
11039 case NAPPEND:
11040 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011041 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011042 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011043 break;
11044 default:
11045#ifdef DEBUG
11046 abort();
11047#endif
11048 /* Fall through to eliminate warning. */
11049 case NTOFD:
11050 case NFROMFD:
11051 f = -1;
11052 break;
11053 case NHERE:
11054 case NXHERE:
11055 f = openhere(redir);
11056 break;
11057 }
11058
11059 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011060ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011061 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011062eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011063 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11064}
11065
Eric Andersenc470f442003-07-28 09:56:35 +000011066static inline void
11067dupredirect(union node *redir, int f)
11068{
11069 int fd = redir->nfile.fd;
11070
11071 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11072 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11073 copyfd(redir->ndup.dupfd, fd);
11074 }
11075 return;
11076 }
11077
11078 if (f != fd) {
11079 copyfd(f, fd);
11080 close(f);
11081 }
11082 return;
11083}
Eric Andersencb57d552001-06-28 07:25:16 +000011084
Eric Andersen62483552001-07-10 06:09:16 +000011085/*
11086 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11087 * old file descriptors are stashed away so that the redirection can be
11088 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11089 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011090 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011091 */
11092
Eric Andersenc470f442003-07-28 09:56:35 +000011093static void
11094redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011095{
11096 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011097 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011098 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011099 int fd;
11100 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011101 int *p;
11102 nullredirs++;
11103 if (!redir) {
11104 return;
Eric Andersen62483552001-07-10 06:09:16 +000011105 }
Eric Andersenc470f442003-07-28 09:56:35 +000011106 sv = NULL;
11107 INTOFF;
11108 if (flags & REDIR_PUSH) {
11109 struct redirtab *q;
11110 q = ckmalloc(sizeof (struct redirtab));
11111 q->next = redirlist;
11112 redirlist = q;
11113 q->nullredirs = nullredirs - 1;
11114 for (i = 0 ; i < 10 ; i++)
11115 q->renamed[i] = EMPTY;
11116 nullredirs = 0;
11117 sv = q;
11118 }
11119 n = redir;
11120 do {
Eric Andersen62483552001-07-10 06:09:16 +000011121 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011122 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011123 n->ndup.dupfd == fd)
11124 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011125
Eric Andersen62483552001-07-10 06:09:16 +000011126 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011127 if (fd == newfd)
11128 continue;
11129 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11130 i = fcntl(fd, F_DUPFD, 10);
11131
11132 if (i == -1) {
11133 i = errno;
11134 if (i != EBADF) {
11135 close(newfd);
11136 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011137 error("%d: %m", fd);
11138 /* NOTREACHED */
11139 }
Eric Andersenc470f442003-07-28 09:56:35 +000011140 } else {
11141 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011142 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011143 }
Eric Andersenc470f442003-07-28 09:56:35 +000011144 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011145 close(fd);
11146 }
Eric Andersenc470f442003-07-28 09:56:35 +000011147 dupredirect(n, newfd);
11148 } while ((n = n->nfile.next));
11149 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011150 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11151 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011152}
11153
11154
Eric Andersencb57d552001-06-28 07:25:16 +000011155/*
11156 * Undo the effects of the last redirection.
11157 */
11158
Eric Andersenc470f442003-07-28 09:56:35 +000011159void
11160popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011161{
Eric Andersenc470f442003-07-28 09:56:35 +000011162 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011163 int i;
11164
Eric Andersenc470f442003-07-28 09:56:35 +000011165 if (--nullredirs >= 0)
11166 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011167 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011168 rp = redirlist;
11169 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011170 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011171 if (!drop) {
11172 close(i);
11173 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011174 }
Eric Andersenc470f442003-07-28 09:56:35 +000011175 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011176 }
11177 }
11178 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011179 nullredirs = rp->nullredirs;
11180 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011181 INTON;
11182}
11183
11184/*
Eric Andersenc470f442003-07-28 09:56:35 +000011185 * Undo all redirections. Called on error or interrupt.
11186 */
11187
11188/*
Eric Andersencb57d552001-06-28 07:25:16 +000011189 * Discard all saved file descriptors.
11190 */
11191
Eric Andersenc470f442003-07-28 09:56:35 +000011192void
11193clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011194{
Eric Andersenc470f442003-07-28 09:56:35 +000011195 for (;;) {
11196 nullredirs = 0;
11197 if (!redirlist)
11198 break;
11199 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011200 }
Eric Andersencb57d552001-06-28 07:25:16 +000011201}
11202
11203
Eric Andersencb57d552001-06-28 07:25:16 +000011204/*
11205 * Copy a file descriptor to be >= to. Returns -1
11206 * if the source file descriptor is closed, EMPTY if there are no unused
11207 * file descriptors left.
11208 */
11209
Eric Andersenc470f442003-07-28 09:56:35 +000011210int
11211copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011212{
11213 int newfd;
11214
11215 newfd = fcntl(from, F_DUPFD, to);
11216 if (newfd < 0) {
11217 if (errno == EMFILE)
11218 return EMPTY;
11219 else
Eric Andersen2870d962001-07-02 17:27:21 +000011220 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011221 }
11222 return newfd;
11223}
11224
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011225
Eric Andersenc470f442003-07-28 09:56:35 +000011226int
11227redirectsafe(union node *redir, int flags)
11228{
11229 int err;
11230 volatile int saveint;
11231 struct jmploc *volatile savehandler = handler;
11232 struct jmploc jmploc;
11233
11234 SAVEINT(saveint);
11235 if (!(err = setjmp(jmploc.loc) * 2)) {
11236 handler = &jmploc;
11237 redirect(redir, flags);
11238 }
11239 handler = savehandler;
11240 if (err && exception != EXERROR)
11241 longjmp(handler->loc, 1);
11242 RESTOREINT(saveint);
11243 return err;
11244}
11245
11246/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11247
11248#ifdef DEBUG
11249static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011250static void shcmd(union node *, FILE *);
11251static void sharg(union node *, FILE *);
11252static void indent(int, char *, FILE *);
11253static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011254
11255
Eric Andersenc470f442003-07-28 09:56:35 +000011256void
11257showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011258{
11259 trputs("showtree called\n");
11260 shtree(n, 1, NULL, stdout);
11261}
Eric Andersencb57d552001-06-28 07:25:16 +000011262
Eric Andersenc470f442003-07-28 09:56:35 +000011263
11264static void
11265shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011266{
11267 struct nodelist *lp;
11268 const char *s;
11269
11270 if (n == NULL)
11271 return;
11272
11273 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011274 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011275 case NSEMI:
11276 s = "; ";
11277 goto binop;
11278 case NAND:
11279 s = " && ";
11280 goto binop;
11281 case NOR:
11282 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011283binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011284 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011285 /* if (ind < 0) */
11286 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011287 shtree(n->nbinary.ch2, ind, NULL, fp);
11288 break;
11289 case NCMD:
11290 shcmd(n, fp);
11291 if (ind >= 0)
11292 putc('\n', fp);
11293 break;
11294 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011295 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011296 shcmd(lp->n, fp);
11297 if (lp->next)
11298 fputs(" | ", fp);
11299 }
11300 if (n->npipe.backgnd)
11301 fputs(" &", fp);
11302 if (ind >= 0)
11303 putc('\n', fp);
11304 break;
11305 default:
11306 fprintf(fp, "<node type %d>", n->type);
11307 if (ind >= 0)
11308 putc('\n', fp);
11309 break;
11310 }
11311}
11312
11313
Eric Andersenc470f442003-07-28 09:56:35 +000011314static void
11315shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011316{
11317 union node *np;
11318 int first;
11319 const char *s;
11320 int dftfd;
11321
11322 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011323 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11324 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011325 putchar(' ');
11326 sharg(np, fp);
11327 first = 0;
11328 }
Eric Andersenc470f442003-07-28 09:56:35 +000011329 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11330 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011331 putchar(' ');
11332 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011333 case NTO: s = ">"; dftfd = 1; break;
11334 case NCLOBBER: s = ">|"; dftfd = 1; break;
11335 case NAPPEND: s = ">>"; dftfd = 1; break;
11336 case NTOFD: s = ">&"; dftfd = 1; break;
11337 case NFROM: s = "<"; dftfd = 0; break;
11338 case NFROMFD: s = "<&"; dftfd = 0; break;
11339 case NFROMTO: s = "<>"; dftfd = 0; break;
11340 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011341 }
11342 if (np->nfile.fd != dftfd)
11343 fprintf(fp, "%d", np->nfile.fd);
11344 fputs(s, fp);
11345 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11346 fprintf(fp, "%d", np->ndup.dupfd);
11347 } else {
11348 sharg(np->nfile.fname, fp);
11349 }
11350 first = 0;
11351 }
11352}
11353
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011354
Eric Andersenc470f442003-07-28 09:56:35 +000011355
11356static void
11357sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011358{
Eric Andersencb57d552001-06-28 07:25:16 +000011359 char *p;
11360 struct nodelist *bqlist;
11361 int subtype;
11362
11363 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011364 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011365 abort();
11366 }
11367 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011368 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011369 switch (*p) {
11370 case CTLESC:
11371 putc(*++p, fp);
11372 break;
11373 case CTLVAR:
11374 putc('$', fp);
11375 putc('{', fp);
11376 subtype = *++p;
11377 if (subtype == VSLENGTH)
11378 putc('#', fp);
11379
11380 while (*p != '=')
11381 putc(*p++, fp);
11382
11383 if (subtype & VSNUL)
11384 putc(':', fp);
11385
11386 switch (subtype & VSTYPE) {
11387 case VSNORMAL:
11388 putc('}', fp);
11389 break;
11390 case VSMINUS:
11391 putc('-', fp);
11392 break;
11393 case VSPLUS:
11394 putc('+', fp);
11395 break;
11396 case VSQUESTION:
11397 putc('?', fp);
11398 break;
11399 case VSASSIGN:
11400 putc('=', fp);
11401 break;
11402 case VSTRIMLEFT:
11403 putc('#', fp);
11404 break;
11405 case VSTRIMLEFTMAX:
11406 putc('#', fp);
11407 putc('#', fp);
11408 break;
11409 case VSTRIMRIGHT:
11410 putc('%', fp);
11411 break;
11412 case VSTRIMRIGHTMAX:
11413 putc('%', fp);
11414 putc('%', fp);
11415 break;
11416 case VSLENGTH:
11417 break;
11418 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011419 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011420 }
11421 break;
11422 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011423 putc('}', fp);
11424 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011425 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011426 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011427 putc('$', fp);
11428 putc('(', fp);
11429 shtree(bqlist->n, -1, NULL, fp);
11430 putc(')', fp);
11431 break;
11432 default:
11433 putc(*p, fp);
11434 break;
11435 }
11436 }
11437}
11438
11439
Eric Andersenc470f442003-07-28 09:56:35 +000011440static void
11441indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011442{
11443 int i;
11444
Eric Andersenc470f442003-07-28 09:56:35 +000011445 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011446 if (pfx && i == amount - 1)
11447 fputs(pfx, fp);
11448 putc('\t', fp);
11449 }
11450}
Eric Andersencb57d552001-06-28 07:25:16 +000011451
Eric Andersenc470f442003-07-28 09:56:35 +000011452
11453
11454/*
11455 * Debugging stuff.
11456 */
11457
11458
Eric Andersencb57d552001-06-28 07:25:16 +000011459FILE *tracefile;
11460
Eric Andersencb57d552001-06-28 07:25:16 +000011461
Eric Andersenc470f442003-07-28 09:56:35 +000011462void
11463trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011464{
Eric Andersenc470f442003-07-28 09:56:35 +000011465 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011466 return;
11467 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011468}
11469
Eric Andersenc470f442003-07-28 09:56:35 +000011470void
11471trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011472{
11473 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011474
Eric Andersenc470f442003-07-28 09:56:35 +000011475 if (debug != 1)
11476 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011477 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011478 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011479 va_end(va);
11480}
11481
Eric Andersenc470f442003-07-28 09:56:35 +000011482void
11483tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011484{
Eric Andersenc470f442003-07-28 09:56:35 +000011485 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011486 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011487 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011488}
11489
11490
Eric Andersenc470f442003-07-28 09:56:35 +000011491void
11492trputs(const char *s)
11493{
11494 if (debug != 1)
11495 return;
11496 fputs(s, tracefile);
11497}
11498
11499
11500static void
11501trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011502{
11503 char *p;
11504 char c;
11505
Eric Andersenc470f442003-07-28 09:56:35 +000011506 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011507 return;
11508 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011509 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011510 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011511 case '\n': c = 'n'; goto backslash;
11512 case '\t': c = 't'; goto backslash;
11513 case '\r': c = 'r'; goto backslash;
11514 case '"': c = '"'; goto backslash;
11515 case '\\': c = '\\'; goto backslash;
11516 case CTLESC: c = 'e'; goto backslash;
11517 case CTLVAR: c = 'v'; goto backslash;
11518 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11519 case CTLBACKQ: c = 'q'; goto backslash;
11520 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11521backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011522 putc(c, tracefile);
11523 break;
11524 default:
11525 if (*p >= ' ' && *p <= '~')
11526 putc(*p, tracefile);
11527 else {
11528 putc('\\', tracefile);
11529 putc(*p >> 6 & 03, tracefile);
11530 putc(*p >> 3 & 07, tracefile);
11531 putc(*p & 07, tracefile);
11532 }
11533 break;
11534 }
11535 }
11536 putc('"', tracefile);
11537}
11538
11539
Eric Andersenc470f442003-07-28 09:56:35 +000011540void
11541trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011542{
Eric Andersenc470f442003-07-28 09:56:35 +000011543 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011544 return;
11545 while (*ap) {
11546 trstring(*ap++);
11547 if (*ap)
11548 putc(' ', tracefile);
11549 else
11550 putc('\n', tracefile);
11551 }
Eric Andersencb57d552001-06-28 07:25:16 +000011552}
11553
11554
Eric Andersenc470f442003-07-28 09:56:35 +000011555void
11556opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011557{
Eric Andersencb57d552001-06-28 07:25:16 +000011558 char s[100];
11559#ifdef O_APPEND
11560 int flags;
11561#endif
11562
Eric Andersenc470f442003-07-28 09:56:35 +000011563 if (debug != 1) {
11564 if (tracefile)
11565 fflush(tracefile);
11566 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011567 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011568 }
Eric Andersenc470f442003-07-28 09:56:35 +000011569 scopy("./trace", s);
11570 if (tracefile) {
11571 if (!freopen(s, "a", tracefile)) {
11572 fprintf(stderr, "Can't re-open %s\n", s);
11573 debug = 0;
11574 return;
11575 }
11576 } else {
11577 if ((tracefile = fopen(s, "a")) == NULL) {
11578 fprintf(stderr, "Can't open %s\n", s);
11579 debug = 0;
11580 return;
11581 }
11582 }
Eric Andersencb57d552001-06-28 07:25:16 +000011583#ifdef O_APPEND
11584 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11585 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11586#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011587 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011588 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011589}
Eric Andersenc470f442003-07-28 09:56:35 +000011590#endif /* DEBUG */
11591
11592
11593/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11594
11595/*
11596 * Sigmode records the current value of the signal handlers for the various
11597 * modes. A value of zero means that the current handler is not known.
11598 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11599 */
11600
11601#define S_DFL 1 /* default signal handling (SIG_DFL) */
11602#define S_CATCH 2 /* signal is caught */
11603#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11604#define S_HARD_IGN 4 /* signal is ignored permenantly */
11605#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11606
Eric Andersencb57d552001-06-28 07:25:16 +000011607
11608
11609/*
Eric Andersencb57d552001-06-28 07:25:16 +000011610 * The trap builtin.
11611 */
11612
Eric Andersenc470f442003-07-28 09:56:35 +000011613int
11614trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011615{
11616 char *action;
11617 char **ap;
11618 int signo;
11619
Eric Andersenc470f442003-07-28 09:56:35 +000011620 nextopt(nullstr);
11621 ap = argptr;
11622 if (!*ap) {
11623 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011624 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011625 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011626
Eric Andersenc470f442003-07-28 09:56:35 +000011627 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011628 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011629 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011630 out1fmt("trap -- %s %s\n",
11631 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011632 }
11633 }
11634 return 0;
11635 }
Eric Andersenc470f442003-07-28 09:56:35 +000011636 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011637 action = NULL;
11638 else
11639 action = *ap++;
11640 while (*ap) {
11641 if ((signo = decode_signal(*ap, 0)) < 0)
11642 error("%s: bad trap", *ap);
11643 INTOFF;
11644 if (action) {
11645 if (action[0] == '-' && action[1] == '\0')
11646 action = NULL;
11647 else
Eric Andersenc470f442003-07-28 09:56:35 +000011648 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011649 }
Eric Andersenc470f442003-07-28 09:56:35 +000011650 if (trap[signo])
11651 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011652 trap[signo] = action;
11653 if (signo != 0)
11654 setsignal(signo);
11655 INTON;
11656 ap++;
11657 }
11658 return 0;
11659}
11660
11661
Eric Andersenc470f442003-07-28 09:56:35 +000011662/*
11663 * Clear traps on a fork.
11664 */
11665
11666void
11667clear_traps(void)
11668{
11669 char **tp;
11670
11671 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11672 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11673 INTOFF;
11674 ckfree(*tp);
11675 *tp = NULL;
11676 if (tp != &trap[0])
11677 setsignal(tp - trap);
11678 INTON;
11679 }
11680 }
11681}
11682
11683
Eric Andersencb57d552001-06-28 07:25:16 +000011684/*
11685 * Set the signal handler for the specified signal. The routine figures
11686 * out what it should be set to.
11687 */
11688
Eric Andersenc470f442003-07-28 09:56:35 +000011689void
11690setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011691{
11692 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011693 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011694 struct sigaction act;
11695
11696 if ((t = trap[signo]) == NULL)
11697 action = S_DFL;
11698 else if (*t != '\0')
11699 action = S_CATCH;
11700 else
11701 action = S_IGN;
11702 if (rootshell && action == S_DFL) {
11703 switch (signo) {
11704 case SIGINT:
11705 if (iflag || minusc || sflag == 0)
11706 action = S_CATCH;
11707 break;
11708 case SIGQUIT:
11709#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011710 if (debug)
11711 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011712#endif
11713 /* FALLTHROUGH */
11714 case SIGTERM:
11715 if (iflag)
11716 action = S_IGN;
11717 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011718#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011719 case SIGTSTP:
11720 case SIGTTOU:
11721 if (mflag)
11722 action = S_IGN;
11723 break;
11724#endif
11725 }
11726 }
11727
11728 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011729 tsig = *t;
11730 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011731 /*
11732 * current setting unknown
11733 */
11734 if (sigaction(signo, 0, &act) == -1) {
11735 /*
11736 * Pretend it worked; maybe we should give a warning
11737 * here, but other shells don't. We don't alter
11738 * sigmode, so that we retry every time.
11739 */
11740 return;
11741 }
11742 if (act.sa_handler == SIG_IGN) {
11743 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011744 signo == SIGTTIN || signo == SIGTTOU)) {
11745 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011746 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011747 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011748 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011749 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011750 }
11751 }
Eric Andersenc470f442003-07-28 09:56:35 +000011752 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011753 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011754 switch (action) {
11755 case S_CATCH:
11756 act.sa_handler = onsig;
11757 break;
11758 case S_IGN:
11759 act.sa_handler = SIG_IGN;
11760 break;
11761 default:
11762 act.sa_handler = SIG_DFL;
11763 }
Eric Andersencb57d552001-06-28 07:25:16 +000011764 *t = action;
11765 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011766 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011767 sigaction(signo, &act, 0);
11768}
11769
11770/*
11771 * Ignore a signal.
11772 */
11773
Eric Andersenc470f442003-07-28 09:56:35 +000011774void
11775ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011776{
11777 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11778 signal(signo, SIG_IGN);
11779 }
11780 sigmode[signo - 1] = S_HARD_IGN;
11781}
11782
11783
Eric Andersencb57d552001-06-28 07:25:16 +000011784/*
11785 * Signal handler.
11786 */
11787
Eric Andersenc470f442003-07-28 09:56:35 +000011788void
11789onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011790{
Eric Andersencb57d552001-06-28 07:25:16 +000011791 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011792 pendingsigs = signo;
11793
11794 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11795 if (!suppressint)
11796 onint();
11797 intpending = 1;
11798 }
Eric Andersencb57d552001-06-28 07:25:16 +000011799}
11800
11801
Eric Andersencb57d552001-06-28 07:25:16 +000011802/*
11803 * Called to execute a trap. Perhaps we should avoid entering new trap
11804 * handlers while we are executing a trap handler.
11805 */
11806
Eric Andersenc470f442003-07-28 09:56:35 +000011807void
11808dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011809{
Eric Andersenc470f442003-07-28 09:56:35 +000011810 char *p;
11811 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011812 int savestatus;
11813
Eric Andersenc470f442003-07-28 09:56:35 +000011814 savestatus = exitstatus;
11815 q = gotsig;
Glenn L McGrath2f325a02004-08-06 01:49:04 +000011816 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
Eric Andersenc470f442003-07-28 09:56:35 +000011817 *p = 0;
11818 p = trap[p - q + 1];
11819 if (!p)
11820 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011821 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011822 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011823 }
Eric Andersencb57d552001-06-28 07:25:16 +000011824}
11825
Eric Andersenc470f442003-07-28 09:56:35 +000011826
Eric Andersenc470f442003-07-28 09:56:35 +000011827/*
11828 * Controls whether the shell is interactive or not.
11829 */
11830
Eric Andersenc470f442003-07-28 09:56:35 +000011831void
11832setinteractive(int on)
11833{
11834 static int is_interactive;
11835
11836 if (++on == is_interactive)
11837 return;
11838 is_interactive = on;
11839 setsignal(SIGINT);
11840 setsignal(SIGQUIT);
11841 setsignal(SIGTERM);
11842#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11843 if(is_interactive > 1) {
11844 /* Looks like they want an interactive shell */
11845 static int do_banner;
11846
11847 if(!do_banner) {
11848 out1fmt(
11849 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11850 "Enter 'help' for a list of built-in commands.\n\n");
11851 do_banner++;
11852 }
11853 }
11854#endif
11855}
11856
11857
11858#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11859/*** List the available builtins ***/
11860
11861static int helpcmd(int argc, char **argv)
11862{
11863 int col, i;
11864
11865 out1fmt("\nBuilt-in commands:\n-------------------\n");
11866 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11867 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11868 builtincmd[i].name + 1);
11869 if (col > 60) {
11870 out1fmt("\n");
11871 col = 0;
11872 }
11873 }
11874#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11875 {
11876 extern const struct BB_applet applets[];
11877 extern const size_t NUM_APPLETS;
11878
11879 for (i = 0; i < NUM_APPLETS; i++) {
11880
11881 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11882 if (col > 60) {
11883 out1fmt("\n");
11884 col = 0;
11885 }
11886 }
11887 }
11888#endif
11889 out1fmt("\n\n");
11890 return EXIT_SUCCESS;
11891}
11892#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11893
Eric Andersencb57d552001-06-28 07:25:16 +000011894/*
11895 * Called to exit the shell.
11896 */
11897
Eric Andersenc470f442003-07-28 09:56:35 +000011898void
11899exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011900{
Eric Andersenc470f442003-07-28 09:56:35 +000011901 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011902 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011903 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011904 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011905
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011906 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011907 status = exitstatus;
11908 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011909 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011910 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011911 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011912 if ((p = trap[0]) != NULL && *p != '\0') {
11913 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011914 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011915 }
Eric Andersencb57d552001-06-28 07:25:16 +000011916 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011917 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011918#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11919 if (iflag && rootshell) {
11920 const char *hp = lookupvar("HISTFILE");
11921
11922 if(hp != NULL )
11923 save_history ( hp );
11924 }
11925#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011926out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011927 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011928 /* NOTREACHED */
11929}
11930
11931static int decode_signal(const char *string, int minsig)
11932{
11933 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011934 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011935
Eric Andersen34506362001-08-02 05:02:46 +000011936 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011937}
Eric Andersen34506362001-08-02 05:02:46 +000011938
Eric Andersenc470f442003-07-28 09:56:35 +000011939/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11940
11941static struct var *vartab[VTABSIZE];
11942
11943static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011944static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011945
11946/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011947 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011948 */
11949
Eric Andersenc470f442003-07-28 09:56:35 +000011950
11951#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011952/*
Eric Andersenc470f442003-07-28 09:56:35 +000011953 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011954 */
11955
Eric Andersenc470f442003-07-28 09:56:35 +000011956int
11957setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011958{
Eric Andersenc470f442003-07-28 09:56:35 +000011959 int err;
11960 volatile int saveint;
11961 struct jmploc *volatile savehandler = handler;
11962 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011963
Eric Andersenc470f442003-07-28 09:56:35 +000011964 SAVEINT(saveint);
11965 if (setjmp(jmploc.loc))
11966 err = 1;
11967 else {
11968 handler = &jmploc;
11969 setvar(name, val, flags);
11970 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011971 }
Eric Andersenc470f442003-07-28 09:56:35 +000011972 handler = savehandler;
11973 RESTOREINT(saveint);
11974 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000011975}
Eric Andersenc470f442003-07-28 09:56:35 +000011976#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011977
11978/*
11979 * Set the value of a variable. The flags argument is ored with the
11980 * flags of the variable. If val is NULL, the variable is unset.
11981 */
11982
Eric Andersenc470f442003-07-28 09:56:35 +000011983static void
11984setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000011985{
Eric Andersenc470f442003-07-28 09:56:35 +000011986 char *p, *q;
11987 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000011988 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000011989 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000011990
Eric Andersenc470f442003-07-28 09:56:35 +000011991 q = endofname(name);
11992 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000011993 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000011994 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000011995 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000011996 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011997 if (val == NULL) {
11998 flags |= VUNSET;
11999 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012000 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000012001 }
12002 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012003 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
Paul Fox8de331d2005-07-21 12:03:05 +000012004 *p++ = '\0';
12005 if (val) {
12006 p[-1] = '=';
Eric Andersenc470f442003-07-28 09:56:35 +000012007 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000012008 }
Eric Andersenc470f442003-07-28 09:56:35 +000012009 *p = '\0';
12010 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012011 INTON;
12012}
12013
12014
Eric Andersencb57d552001-06-28 07:25:16 +000012015/*
12016 * Same as setvar except that the variable and value are passed in
12017 * the first argument as name=value. Since the first argument will
12018 * be actually stored in the table, it should not be a string that
12019 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012020 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012021 */
12022
Eric Andersenc470f442003-07-28 09:56:35 +000012023void
12024setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012025{
12026 struct var *vp, **vpp;
12027
12028 vpp = hashvar(s);
12029 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012030 vp = *findvar(vpp, s);
12031 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012032 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12033 const char *n;
12034
Eric Andersenc470f442003-07-28 09:56:35 +000012035 if (flags & VNOSAVE)
12036 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012037 n = vp->text;
12038 error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012039 }
Eric Andersenc470f442003-07-28 09:56:35 +000012040
12041 if (flags & VNOSET)
12042 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012043
12044 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012045 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012046
Eric Andersenc470f442003-07-28 09:56:35 +000012047 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12048 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012049
Eric Andersenc470f442003-07-28 09:56:35 +000012050 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12051 } else {
12052 if (flags & VNOSET)
12053 return;
12054 /* not found */
12055 vp = ckmalloc(sizeof (*vp));
12056 vp->next = *vpp;
12057 vp->func = NULL;
12058 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012059 }
Eric Andersenc470f442003-07-28 09:56:35 +000012060 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12061 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012062 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012063 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012064}
12065
12066
Eric Andersencb57d552001-06-28 07:25:16 +000012067/*
12068 * Process a linked list of variable assignments.
12069 */
12070
Eric Andersenc470f442003-07-28 09:56:35 +000012071static void
12072listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012073{
Eric Andersenc470f442003-07-28 09:56:35 +000012074 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012075
Eric Andersenc470f442003-07-28 09:56:35 +000012076 if (!lp)
12077 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012078 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012079 do {
12080 setvareq(lp->text, flags);
12081 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012082 INTON;
12083}
12084
12085
Eric Andersencb57d552001-06-28 07:25:16 +000012086/*
12087 * Find the value of a variable. Returns NULL if not set.
12088 */
12089
Eric Andersenc470f442003-07-28 09:56:35 +000012090static char *
12091lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012092{
Eric Andersencb57d552001-06-28 07:25:16 +000012093 struct var *v;
12094
Eric Andersen16767e22004-03-16 05:14:10 +000012095 if ((v = *findvar(hashvar(name), name))) {
12096#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012097 /*
12098 * Dynamic variables are implemented roughly the same way they are
12099 * in bash. Namely, they're "special" so long as they aren't unset.
12100 * As soon as they're unset, they're no longer dynamic, and dynamic
12101 * lookup will no longer happen at that point. -- PFM.
12102 */
Eric Andersen16767e22004-03-16 05:14:10 +000012103 if((v->flags & VDYNAMIC))
12104 (*v->func)(NULL);
12105#endif
12106 if(!(v->flags & VUNSET))
12107 return strchrnul(v->text, '=') + 1;
12108 }
Eric Andersenef02f822004-03-11 13:34:24 +000012109
Eric Andersencb57d552001-06-28 07:25:16 +000012110 return NULL;
12111}
12112
12113
Eric Andersencb57d552001-06-28 07:25:16 +000012114/*
12115 * Search the environment of a builtin command.
12116 */
12117
Eric Andersenc470f442003-07-28 09:56:35 +000012118static char *
12119bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012120{
Eric Andersenc470f442003-07-28 09:56:35 +000012121 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012122
Eric Andersenc470f442003-07-28 09:56:35 +000012123 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012124 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012125 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012126 }
12127 return lookupvar(name);
12128}
12129
12130
Eric Andersencb57d552001-06-28 07:25:16 +000012131/*
Eric Andersenc470f442003-07-28 09:56:35 +000012132 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012133 */
12134
Eric Andersenc470f442003-07-28 09:56:35 +000012135static char **
12136listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012137{
Eric Andersencb57d552001-06-28 07:25:16 +000012138 struct var **vpp;
12139 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012140 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012141 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012142
Eric Andersenc470f442003-07-28 09:56:35 +000012143 STARTSTACKSTR(ep);
12144 vpp = vartab;
12145 mask = on | off;
12146 do {
12147 for (vp = *vpp ; vp ; vp = vp->next)
12148 if ((vp->flags & mask) == on) {
12149 if (ep == stackstrend())
12150 ep = growstackstr();
12151 *ep++ = (char *) vp->text;
12152 }
12153 } while (++vpp < vartab + VTABSIZE);
12154 if (ep == stackstrend())
12155 ep = growstackstr();
12156 if (end)
12157 *end = ep;
12158 *ep++ = NULL;
12159 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012160}
12161
12162
12163/*
Eric Andersenc470f442003-07-28 09:56:35 +000012164 * POSIX requires that 'set' (but not export or readonly) output the
12165 * variables in lexicographic order - by the locale's collating order (sigh).
12166 * Maybe we could keep them in an ordered balanced binary tree
12167 * instead of hashed lists.
12168 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012169 */
12170
Eric Andersenc470f442003-07-28 09:56:35 +000012171static int
12172showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012173{
Eric Andersenc470f442003-07-28 09:56:35 +000012174 const char *sep;
12175 char **ep, **epend;
12176
12177 ep = listvars(on, off, &epend);
12178 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12179
12180 sep = *sep_prefix ? spcstr : sep_prefix;
12181
12182 for (; ep < epend; ep++) {
12183 const char *p;
12184 const char *q;
12185
12186 p = strchrnul(*ep, '=');
12187 q = nullstr;
12188 if (*p)
12189 q = single_quote(++p);
12190
12191 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12192 }
12193
Eric Andersencb57d552001-06-28 07:25:16 +000012194 return 0;
12195}
12196
12197
12198
12199/*
12200 * The export and readonly commands.
12201 */
12202
Eric Andersenc470f442003-07-28 09:56:35 +000012203static int
12204exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012205{
12206 struct var *vp;
12207 char *name;
12208 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012209 char **aptr;
12210 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12211 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012212
Eric Andersenc470f442003-07-28 09:56:35 +000012213 notp = nextopt("p") - 'p';
12214 if (notp && ((name = *(aptr = argptr)))) {
12215 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012216 if ((p = strchr(name, '=')) != NULL) {
12217 p++;
12218 } else {
12219 if ((vp = *findvar(hashvar(name), name))) {
12220 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012221 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012222 }
12223 }
12224 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012225 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012226 } else {
12227 showvars(argv[0], flag, 0);
12228 }
12229 return 0;
12230}
12231
Eric Andersen34506362001-08-02 05:02:46 +000012232
Eric Andersencb57d552001-06-28 07:25:16 +000012233/*
Eric Andersencb57d552001-06-28 07:25:16 +000012234 * Make a variable a local variable. When a variable is made local, it's
12235 * value and flags are saved in a localvar structure. The saved values
12236 * will be restored when the shell function returns. We handle the name
12237 * "-" as a special case.
12238 */
12239
Eric Andersenc470f442003-07-28 09:56:35 +000012240static inline void
12241mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012242{
Eric Andersencb57d552001-06-28 07:25:16 +000012243 struct localvar *lvp;
12244 struct var **vpp;
12245 struct var *vp;
12246
12247 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012248 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012249 if (name[0] == '-' && name[1] == '\0') {
12250 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012251 p = ckmalloc(sizeof(optlist));
12252 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012253 vp = NULL;
12254 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012255 char *eq;
12256
Eric Andersencb57d552001-06-28 07:25:16 +000012257 vpp = hashvar(name);
12258 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012259 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012260 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012261 if (eq)
12262 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012263 else
12264 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012265 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012266 lvp->flags = VUNSET;
12267 } else {
12268 lvp->text = vp->text;
12269 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012270 vp->flags |= VSTRFIXED|VTEXTFIXED;
12271 if (eq)
12272 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012273 }
12274 }
12275 lvp->vp = vp;
12276 lvp->next = localvars;
12277 localvars = lvp;
12278 INTON;
12279}
12280
Eric Andersenc470f442003-07-28 09:56:35 +000012281/*
12282 * The "local" command.
12283 */
12284
12285static int
12286localcmd(int argc, char **argv)
12287{
12288 char *name;
12289
12290 argv = argptr;
12291 while ((name = *argv++) != NULL) {
12292 mklocal(name);
12293 }
12294 return 0;
12295}
12296
12297
Eric Andersencb57d552001-06-28 07:25:16 +000012298/*
12299 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012300 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012301 */
12302
Eric Andersenc470f442003-07-28 09:56:35 +000012303static void
12304poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012305{
Eric Andersencb57d552001-06-28 07:25:16 +000012306 struct localvar *lvp;
12307 struct var *vp;
12308
12309 while ((lvp = localvars) != NULL) {
12310 localvars = lvp->next;
12311 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012312 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12313 if (vp == NULL) { /* $- saved */
12314 memcpy(optlist, lvp->text, sizeof(optlist));
12315 ckfree(lvp->text);
12316 optschanged();
12317 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12318 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012319 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012320 if (vp->func)
12321 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12322 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12323 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012324 vp->flags = lvp->flags;
12325 vp->text = lvp->text;
12326 }
Eric Andersenc470f442003-07-28 09:56:35 +000012327 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012328 }
12329}
12330
12331
Eric Andersencb57d552001-06-28 07:25:16 +000012332/*
12333 * The unset builtin command. We unset the function before we unset the
12334 * variable to allow a function to be unset when there is a readonly variable
12335 * with the same name.
12336 */
12337
Eric Andersenc470f442003-07-28 09:56:35 +000012338int
12339unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012340{
12341 char **ap;
12342 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012343 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012344 int ret = 0;
12345
12346 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012347 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012348 }
Eric Andersencb57d552001-06-28 07:25:16 +000012349
Eric Andersenc470f442003-07-28 09:56:35 +000012350 for (ap = argptr; *ap ; ap++) {
12351 if (flag != 'f') {
12352 i = unsetvar(*ap);
12353 ret |= i;
12354 if (!(i & 2))
12355 continue;
12356 }
12357 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012358 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012359 }
Eric Andersenc470f442003-07-28 09:56:35 +000012360 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012361}
12362
12363
12364/*
12365 * Unset the specified variable.
12366 */
12367
Eric Andersenc470f442003-07-28 09:56:35 +000012368int
12369unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012370{
Eric Andersencb57d552001-06-28 07:25:16 +000012371 struct var **vpp;
12372 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012373 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012374
12375 vpp = findvar(hashvar(s), s);
12376 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012377 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012378 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012379 int flags = vp->flags;
12380
12381 retval = 1;
12382 if (flags & VREADONLY)
12383 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012384#ifdef DYNAMIC_VAR
12385 vp->flags &= ~VDYNAMIC;
12386#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012387 if (flags & VUNSET)
12388 goto ok;
12389 if ((flags & VSTRFIXED) == 0) {
12390 INTOFF;
12391 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12392 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012393 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012394 ckfree(vp);
12395 INTON;
12396 } else {
12397 setvar(s, 0, 0);
12398 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012399 }
Eric Andersenc470f442003-07-28 09:56:35 +000012400ok:
12401 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012402 }
12403
Eric Andersenc470f442003-07-28 09:56:35 +000012404out:
12405 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012406}
12407
12408
12409
12410/*
12411 * Find the appropriate entry in the hash table from the name.
12412 */
12413
Eric Andersenc470f442003-07-28 09:56:35 +000012414static struct var **
12415hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012416{
Eric Andersencb57d552001-06-28 07:25:16 +000012417 unsigned int hashval;
12418
12419 hashval = ((unsigned char) *p) << 4;
12420 while (*p && *p != '=')
12421 hashval += (unsigned char) *p++;
12422 return &vartab[hashval % VTABSIZE];
12423}
12424
12425
12426
12427/*
Eric Andersenc470f442003-07-28 09:56:35 +000012428 * Compares two strings up to the first = or '\0'. The first
12429 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012430 * either '=' or '\0'.
12431 */
12432
Eric Andersenc470f442003-07-28 09:56:35 +000012433int
12434varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012435{
Eric Andersenc470f442003-07-28 09:56:35 +000012436 int c, d;
12437
12438 while ((c = *p) == (d = *q)) {
12439 if (!c || c == '=')
12440 goto out;
12441 p++;
12442 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012443 }
Eric Andersenc470f442003-07-28 09:56:35 +000012444 if (c == '=')
12445 c = 0;
12446 if (d == '=')
12447 d = 0;
12448out:
12449 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012450}
12451
Eric Andersenc470f442003-07-28 09:56:35 +000012452static int
12453vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012454{
Eric Andersenc470f442003-07-28 09:56:35 +000012455 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012456}
12457
Eric Andersenc470f442003-07-28 09:56:35 +000012458static struct var **
12459findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012460{
12461 for (; *vpp; vpp = &(*vpp)->next) {
12462 if (varequal((*vpp)->text, name)) {
12463 break;
12464 }
12465 }
12466 return vpp;
12467}
Eric Andersenc470f442003-07-28 09:56:35 +000012468/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012469
Eric Andersenc470f442003-07-28 09:56:35 +000012470#include <sys/times.h>
12471
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012472static const unsigned char timescmd_str[] = {
12473 ' ', offsetof(struct tms, tms_utime),
12474 '\n', offsetof(struct tms, tms_stime),
12475 ' ', offsetof(struct tms, tms_cutime),
12476 '\n', offsetof(struct tms, tms_cstime),
12477 0
12478};
Eric Andersencb57d552001-06-28 07:25:16 +000012479
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012480static int timescmd(int ac, char **av)
12481{
12482 long int clk_tck, s, t;
12483 const unsigned char *p;
12484 struct tms buf;
12485
12486 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012487 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012488
12489 p = timescmd_str;
12490 do {
12491 t = *(clock_t *)(((char *) &buf) + p[1]);
12492 s = t / clk_tck;
12493 out1fmt("%ldm%ld.%.3lds%c",
12494 s/60, s%60,
12495 ((t - s * clk_tck) * 1000) / clk_tck,
12496 p[0]);
12497 } while (*(p += 2));
12498
Eric Andersencb57d552001-06-28 07:25:16 +000012499 return 0;
12500}
12501
Eric Andersend35c5df2002-01-09 15:37:36 +000012502#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012503static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012504dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012505{
Eric Andersened9ecf72004-06-22 08:29:45 +000012506 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012507 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012508
Eric Andersenc470f442003-07-28 09:56:35 +000012509 INTOFF;
12510 result = arith(s, &errcode);
12511 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012512 if (errcode == -3)
12513 error("exponent less than 0");
12514 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012515 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012516 else if (errcode == -5)
12517 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012518 else
12519 synerror(s);
12520 }
12521 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012522
Eric Andersenc470f442003-07-28 09:56:35 +000012523 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012524}
Eric Andersenc470f442003-07-28 09:56:35 +000012525
12526
12527/*
Eric Andersen90898442003-08-06 11:20:52 +000012528 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12529 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12530 *
12531 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012532 */
Eric Andersen90898442003-08-06 11:20:52 +000012533
Eric Andersenc470f442003-07-28 09:56:35 +000012534static int
Eric Andersen90898442003-08-06 11:20:52 +000012535letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012536{
Eric Andersenc470f442003-07-28 09:56:35 +000012537 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012538 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012539
Eric Andersen90898442003-08-06 11:20:52 +000012540 ap = argv + 1;
12541 if(!*ap)
12542 error("expression expected");
12543 for (ap = argv + 1; *ap; ap++) {
12544 i = dash_arith(*ap);
12545 }
Eric Andersenc470f442003-07-28 09:56:35 +000012546
Eric Andersen90898442003-08-06 11:20:52 +000012547 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012548}
12549#endif /* CONFIG_ASH_MATH_SUPPORT */
12550
12551/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12552
12553/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012554 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012555 */
12556
12557#undef rflag
12558
12559#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012560#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012561typedef enum __rlimit_resource rlim_t;
12562#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012563#endif
12564
12565
Eric Andersenc470f442003-07-28 09:56:35 +000012566/*
12567 * The read builtin. The -e option causes backslashes to escape the
12568 * following character.
12569 *
12570 * This uses unbuffered input, which may be avoidable in some cases.
12571 */
12572
12573static int
12574readcmd(int argc, char **argv)
12575{
12576 char **ap;
12577 int backslash;
12578 char c;
12579 int rflag;
12580 char *prompt;
12581 const char *ifs;
12582 char *p;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012583#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012584 fd_set set;
12585 int timeout;
12586 struct timeval timeout_struct;
12587 struct termios tty, old_tty;
12588#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012589 int startword;
12590 int status;
12591 int i;
12592
12593 rflag = 0;
12594 prompt = NULL;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012595#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012596 timeout = 0;
12597
12598 while ((i = nextopt("p:rt:")) != '\0')
12599#else
12600 while ((i = nextopt("p:r")) != '\0')
12601#endif
12602 {
Eric Andersenc470f442003-07-28 09:56:35 +000012603 if (i == 'p')
12604 prompt = optionarg;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012605 else if (i == 'r')
Eric Andersenc470f442003-07-28 09:56:35 +000012606 rflag = 1;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012607#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012608 else
12609 timeout = atoi(optionarg);
12610#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012611 }
12612 if (prompt && isatty(0)) {
12613 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012614 }
12615 if (*(ap = argptr) == NULL)
12616 error("arg count");
12617 if ((ifs = bltinlookup("IFS")) == NULL)
12618 ifs = defifs;
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012619#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012620 c = 0;
12621#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012622 status = 0;
12623 startword = 1;
12624 backslash = 0;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012625
Eric Andersenc470f442003-07-28 09:56:35 +000012626 STARTSTACKSTR(p);
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012627#if defined(CONFIG_ASH_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012628 if (timeout > 0) {
12629 tcgetattr(0, &tty);
12630 old_tty = tty;
12631
12632 /* cfmakeraw(...) disables too much; we just do this instead. */
12633 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
12634 tcsetattr(0, TCSANOW, &tty);
12635
12636 FD_ZERO (&set);
12637 FD_SET (0, &set);
12638
12639 timeout_struct.tv_sec = timeout;
12640 timeout_struct.tv_usec = 0;
12641
Ned Luddd1e3cbd2005-02-10 00:44:31 +000012642 if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012643 {
12644 read(0, &c, 1);
12645 if(c == '\n' || c == 4) /* Handle newlines and EOF */
12646 i = 0; /* Don't read further... */
12647 else
12648 STPUTC(c, p); /* Keep reading... */
12649 }
12650 tcsetattr(0, TCSANOW, &old_tty);
12651
12652 /* Echo the character so the user knows it was read...
12653 Yes, this can be done by setting the ECHO flag, but that
12654 echoes ^D and other control characters at this state */
12655 if(c != 0)
12656 write(1, &c, 1);
12657
12658 } else
12659 i = 1;
12660
12661 for (;i == 1;)
12662#else
12663 for (;;)
12664#endif
12665 {
Eric Andersenc470f442003-07-28 09:56:35 +000012666 if (read(0, &c, 1) != 1) {
12667 status = 1;
12668 break;
12669 }
12670 if (c == '\0')
12671 continue;
12672 if (backslash) {
12673 backslash = 0;
12674 if (c != '\n')
12675 goto put;
12676 continue;
12677 }
12678 if (!rflag && c == '\\') {
12679 backslash++;
12680 continue;
12681 }
12682 if (c == '\n')
12683 break;
12684 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12685 continue;
12686 }
12687 startword = 0;
12688 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12689 STACKSTRNUL(p);
12690 setvar(*ap, stackblock(), 0);
12691 ap++;
12692 startword = 1;
12693 STARTSTACKSTR(p);
12694 } else {
12695put:
12696 STPUTC(c, p);
12697 }
12698 }
12699 STACKSTRNUL(p);
12700 /* Remove trailing blanks */
12701 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12702 *p = '\0';
12703 setvar(*ap, stackblock(), 0);
12704 while (*++ap != NULL)
12705 setvar(*ap, nullstr, 0);
12706 return status;
12707}
12708
12709
12710static int umaskcmd(int argc, char **argv)
12711{
12712 static const char permuser[3] = "ugo";
12713 static const char permmode[3] = "rwx";
12714 static const short int permmask[] = {
12715 S_IRUSR, S_IWUSR, S_IXUSR,
12716 S_IRGRP, S_IWGRP, S_IXGRP,
12717 S_IROTH, S_IWOTH, S_IXOTH
12718 };
12719
12720 char *ap;
12721 mode_t mask;
12722 int i;
12723 int symbolic_mode = 0;
12724
12725 while (nextopt("S") != '\0') {
12726 symbolic_mode = 1;
12727 }
12728
12729 INTOFF;
12730 mask = umask(0);
12731 umask(mask);
12732 INTON;
12733
12734 if ((ap = *argptr) == NULL) {
12735 if (symbolic_mode) {
12736 char buf[18];
12737 char *p = buf;
12738
12739 for (i = 0; i < 3; i++) {
12740 int j;
12741
12742 *p++ = permuser[i];
12743 *p++ = '=';
12744 for (j = 0; j < 3; j++) {
12745 if ((mask & permmask[3 * i + j]) == 0) {
12746 *p++ = permmode[j];
12747 }
12748 }
12749 *p++ = ',';
12750 }
12751 *--p = 0;
12752 puts(buf);
12753 } else {
12754 out1fmt("%.4o\n", mask);
12755 }
12756 } else {
12757 if (is_digit((unsigned char) *ap)) {
12758 mask = 0;
12759 do {
12760 if (*ap >= '8' || *ap < '0')
12761 error(illnum, argv[1]);
12762 mask = (mask << 3) + (*ap - '0');
12763 } while (*++ap != '\0');
12764 umask(mask);
12765 } else {
12766 mask = ~mask & 0777;
12767 if (!bb_parse_mode(ap, &mask)) {
12768 error("Illegal mode: %s", ap);
12769 }
12770 umask(~mask & 0777);
12771 }
12772 }
12773 return 0;
12774}
12775
12776/*
12777 * ulimit builtin
12778 *
12779 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12780 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12781 * ash by J.T. Conklin.
12782 *
12783 * Public domain.
12784 */
12785
12786struct limits {
12787 const char *name;
12788 int cmd;
12789 int factor; /* multiply by to get rlim_{cur,max} values */
12790 char option;
12791};
12792
12793static const struct limits limits[] = {
12794#ifdef RLIMIT_CPU
12795 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12796#endif
12797#ifdef RLIMIT_FSIZE
12798 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12799#endif
12800#ifdef RLIMIT_DATA
12801 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12802#endif
12803#ifdef RLIMIT_STACK
12804 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12805#endif
12806#ifdef RLIMIT_CORE
12807 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12808#endif
12809#ifdef RLIMIT_RSS
12810 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12811#endif
12812#ifdef RLIMIT_MEMLOCK
12813 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12814#endif
12815#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012816 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012817#endif
12818#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012819 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012820#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012821#ifdef RLIMIT_AS
12822 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012823#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012824#ifdef RLIMIT_LOCKS
12825 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012826#endif
12827 { (char *) 0, 0, 0, '\0' }
12828};
12829
Glenn L McGrath76620622004-01-13 10:19:37 +000012830enum limtype { SOFT = 0x1, HARD = 0x2 };
12831
12832static void printlim(enum limtype how, const struct rlimit *limit,
12833 const struct limits *l)
12834{
12835 rlim_t val;
12836
12837 val = limit->rlim_max;
12838 if (how & SOFT)
12839 val = limit->rlim_cur;
12840
12841 if (val == RLIM_INFINITY)
12842 out1fmt("unlimited\n");
12843 else {
12844 val /= l->factor;
12845 out1fmt("%lld\n", (long long) val);
12846 }
12847}
12848
Eric Andersenc470f442003-07-28 09:56:35 +000012849int
12850ulimitcmd(int argc, char **argv)
12851{
12852 int c;
12853 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012854 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012855 const struct limits *l;
12856 int set, all = 0;
12857 int optc, what;
12858 struct rlimit limit;
12859
12860 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012861 while ((optc = nextopt("HSa"
12862#ifdef RLIMIT_CPU
12863 "t"
12864#endif
12865#ifdef RLIMIT_FSIZE
12866 "f"
12867#endif
12868#ifdef RLIMIT_DATA
12869 "d"
12870#endif
12871#ifdef RLIMIT_STACK
12872 "s"
12873#endif
12874#ifdef RLIMIT_CORE
12875 "c"
12876#endif
12877#ifdef RLIMIT_RSS
12878 "m"
12879#endif
12880#ifdef RLIMIT_MEMLOCK
12881 "l"
12882#endif
12883#ifdef RLIMIT_NPROC
12884 "p"
12885#endif
12886#ifdef RLIMIT_NOFILE
12887 "n"
12888#endif
12889#ifdef RLIMIT_AS
12890 "v"
12891#endif
12892#ifdef RLIMIT_LOCKS
12893 "w"
12894#endif
12895 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012896 switch (optc) {
12897 case 'H':
12898 how = HARD;
12899 break;
12900 case 'S':
12901 how = SOFT;
12902 break;
12903 case 'a':
12904 all = 1;
12905 break;
12906 default:
12907 what = optc;
12908 }
12909
Glenn L McGrath76620622004-01-13 10:19:37 +000012910 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012911 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012912
12913 set = *argptr ? 1 : 0;
12914 if (set) {
12915 char *p = *argptr;
12916
12917 if (all || argptr[1])
12918 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012919 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012920 val = RLIM_INFINITY;
12921 else {
12922 val = (rlim_t) 0;
12923
12924 while ((c = *p++) >= '0' && c <= '9')
12925 {
12926 val = (val * 10) + (long)(c - '0');
12927 if (val < (rlim_t) 0)
12928 break;
12929 }
12930 if (c)
12931 error("bad number");
12932 val *= l->factor;
12933 }
12934 }
12935 if (all) {
12936 for (l = limits; l->name; l++) {
12937 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000012938 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000012939 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012940 }
12941 return 0;
12942 }
12943
12944 getrlimit(l->cmd, &limit);
12945 if (set) {
12946 if (how & HARD)
12947 limit.rlim_max = val;
12948 if (how & SOFT)
12949 limit.rlim_cur = val;
12950 if (setrlimit(l->cmd, &limit) < 0)
12951 error("error setting limit (%m)");
12952 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000012953 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000012954 }
12955 return 0;
12956}
12957
Eric Andersen90898442003-08-06 11:20:52 +000012958
12959#ifdef CONFIG_ASH_MATH_SUPPORT
12960
12961/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12962
12963 Permission is hereby granted, free of charge, to any person obtaining
12964 a copy of this software and associated documentation files (the
12965 "Software"), to deal in the Software without restriction, including
12966 without limitation the rights to use, copy, modify, merge, publish,
12967 distribute, sublicense, and/or sell copies of the Software, and to
12968 permit persons to whom the Software is furnished to do so, subject to
12969 the following conditions:
12970
12971 The above copyright notice and this permission notice shall be
12972 included in all copies or substantial portions of the Software.
12973
12974 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12975 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12976 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12977 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12978 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12979 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12980 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12981*/
12982
12983/* This is my infix parser/evaluator. It is optimized for size, intended
12984 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000012985 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000012986 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000012987 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000012988 * be that which POSIX specifies for shells. */
12989
12990/* The code uses a simple two-stack algorithm. See
12991 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000012992 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000012993 * this is based (this code differs in that it applies operators immediately
12994 * to the stack instead of adding them to a queue to end up with an
12995 * expression). */
12996
12997/* To use the routine, call it with an expression string and error return
12998 * pointer */
12999
13000/*
13001 * Aug 24, 2001 Manuel Novoa III
13002 *
13003 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13004 *
13005 * 1) In arith_apply():
13006 * a) Cached values of *numptr and &(numptr[-1]).
13007 * b) Removed redundant test for zero denominator.
13008 *
13009 * 2) In arith():
13010 * a) Eliminated redundant code for processing operator tokens by moving
13011 * to a table-based implementation. Also folded handling of parens
13012 * into the table.
13013 * b) Combined all 3 loops which called arith_apply to reduce generated
13014 * code size at the cost of speed.
13015 *
13016 * 3) The following expressions were treated as valid by the original code:
13017 * 1() , 0! , 1 ( *3 ) .
13018 * These bugs have been fixed by internally enclosing the expression in
13019 * parens and then checking that all binary ops and right parens are
13020 * preceded by a valid expression (NUM_TOKEN).
13021 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013022 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013023 * ctype's isspace() if it is used by another busybox applet or if additional
13024 * whitespace chars should be considered. Look below the "#include"s for a
13025 * precompiler test.
13026 */
13027
13028/*
13029 * Aug 26, 2001 Manuel Novoa III
13030 *
13031 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13032 *
13033 * Merge in Aaron's comments previously posted to the busybox list,
13034 * modified slightly to take account of my changes to the code.
13035 *
13036 */
13037
13038/*
13039 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13040 *
13041 * - allow access to variable,
13042 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13043 * - realize assign syntax (VAR=expr, +=, *= etc)
13044 * - realize exponentiation (** operator)
13045 * - realize comma separated - expr, expr
13046 * - realise ++expr --expr expr++ expr--
13047 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013048 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013049 * - was restored loses XOR operator
13050 * - remove one goto label, added three ;-)
13051 * - protect $((num num)) as true zero expr (Manuel`s error)
13052 * - always use special isspace(), see comment from bash ;-)
13053 */
13054
13055
13056#define arith_isspace(arithval) \
13057 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13058
13059
13060typedef unsigned char operator;
13061
13062/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013063 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013064 * precedence. The ID portion is so that multiple operators can have the
13065 * same precedence, ensuring that the leftmost one is evaluated first.
13066 * Consider * and /. */
13067
13068#define tok_decl(prec,id) (((id)<<5)|(prec))
13069#define PREC(op) ((op) & 0x1F)
13070
13071#define TOK_LPAREN tok_decl(0,0)
13072
13073#define TOK_COMMA tok_decl(1,0)
13074
13075#define TOK_ASSIGN tok_decl(2,0)
13076#define TOK_AND_ASSIGN tok_decl(2,1)
13077#define TOK_OR_ASSIGN tok_decl(2,2)
13078#define TOK_XOR_ASSIGN tok_decl(2,3)
13079#define TOK_PLUS_ASSIGN tok_decl(2,4)
13080#define TOK_MINUS_ASSIGN tok_decl(2,5)
13081#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13082#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13083
13084#define TOK_MUL_ASSIGN tok_decl(3,0)
13085#define TOK_DIV_ASSIGN tok_decl(3,1)
13086#define TOK_REM_ASSIGN tok_decl(3,2)
13087
13088/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13089#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13090
13091/* conditional is right associativity too */
13092#define TOK_CONDITIONAL tok_decl(4,0)
13093#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13094
13095#define TOK_OR tok_decl(5,0)
13096
13097#define TOK_AND tok_decl(6,0)
13098
13099#define TOK_BOR tok_decl(7,0)
13100
13101#define TOK_BXOR tok_decl(8,0)
13102
13103#define TOK_BAND tok_decl(9,0)
13104
13105#define TOK_EQ tok_decl(10,0)
13106#define TOK_NE tok_decl(10,1)
13107
13108#define TOK_LT tok_decl(11,0)
13109#define TOK_GT tok_decl(11,1)
13110#define TOK_GE tok_decl(11,2)
13111#define TOK_LE tok_decl(11,3)
13112
13113#define TOK_LSHIFT tok_decl(12,0)
13114#define TOK_RSHIFT tok_decl(12,1)
13115
13116#define TOK_ADD tok_decl(13,0)
13117#define TOK_SUB tok_decl(13,1)
13118
13119#define TOK_MUL tok_decl(14,0)
13120#define TOK_DIV tok_decl(14,1)
13121#define TOK_REM tok_decl(14,2)
13122
13123/* exponent is right associativity */
13124#define TOK_EXPONENT tok_decl(15,1)
13125
13126/* For now unary operators. */
13127#define UNARYPREC 16
13128#define TOK_BNOT tok_decl(UNARYPREC,0)
13129#define TOK_NOT tok_decl(UNARYPREC,1)
13130
13131#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13132#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13133
13134#define PREC_PRE (UNARYPREC+2)
13135
13136#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13137#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13138
13139#define PREC_POST (UNARYPREC+3)
13140
13141#define TOK_POST_INC tok_decl(PREC_POST, 0)
13142#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13143
13144#define SPEC_PREC (UNARYPREC+4)
13145
13146#define TOK_NUM tok_decl(SPEC_PREC, 0)
13147#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13148
13149#define NUMPTR (*numstackptr)
13150
13151static inline int tok_have_assign(operator op)
13152{
13153 operator prec = PREC(op);
13154
13155 convert_prec_is_assing(prec);
13156 return (prec == PREC(TOK_ASSIGN) ||
13157 prec == PREC_PRE || prec == PREC_POST);
13158}
13159
13160static inline int is_right_associativity(operator prec)
13161{
13162 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13163 prec == PREC(TOK_CONDITIONAL));
13164}
13165
13166
13167typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013168 arith_t val;
13169 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013170 char contidional_second_val_initialized;
13171 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013172 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013173} v_n_t;
13174
13175
13176typedef struct CHK_VAR_RECURSIVE_LOOPED {
13177 const char *var;
13178 struct CHK_VAR_RECURSIVE_LOOPED *next;
13179} chk_var_recursive_looped_t;
13180
13181static chk_var_recursive_looped_t *prev_chk_var_recursive;
13182
13183
13184static int arith_lookup_val(v_n_t *t)
13185{
13186 if(t->var) {
13187 const char * p = lookupvar(t->var);
13188
13189 if(p) {
13190 int errcode;
13191
13192 /* recursive try as expression */
13193 chk_var_recursive_looped_t *cur;
13194 chk_var_recursive_looped_t cur_save;
13195
13196 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13197 if(strcmp(cur->var, t->var) == 0) {
13198 /* expression recursion loop detected */
13199 return -5;
13200 }
13201 }
13202 /* save current lookuped var name */
13203 cur = prev_chk_var_recursive;
13204 cur_save.var = t->var;
13205 cur_save.next = cur;
13206 prev_chk_var_recursive = &cur_save;
13207
13208 t->val = arith (p, &errcode);
13209 /* restore previous ptr after recursiving */
13210 prev_chk_var_recursive = cur;
13211 return errcode;
13212 } else {
13213 /* allow undefined var as 0 */
13214 t->val = 0;
13215 }
13216 }
13217 return 0;
13218}
13219
13220/* "applying" a token means performing it on the top elements on the integer
13221 * stack. For a unary operator it will only change the top element, but a
13222 * binary operator will pop two arguments and push a result */
13223static inline int
13224arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13225{
Eric Andersen90898442003-08-06 11:20:52 +000013226 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013227 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013228 int ret_arith_lookup_val;
13229
13230 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13231 without arguments */
13232 numptr_m1 = NUMPTR - 1;
13233
13234 /* check operand is var with noninteger value */
13235 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13236 if(ret_arith_lookup_val)
13237 return ret_arith_lookup_val;
13238
13239 rez = numptr_m1->val;
13240 if (op == TOK_UMINUS)
13241 rez *= -1;
13242 else if (op == TOK_NOT)
13243 rez = !rez;
13244 else if (op == TOK_BNOT)
13245 rez = ~rez;
13246 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13247 rez++;
13248 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13249 rez--;
13250 else if (op != TOK_UPLUS) {
13251 /* Binary operators */
13252
13253 /* check and binary operators need two arguments */
13254 if (numptr_m1 == numstack) goto err;
13255
13256 /* ... and they pop one */
13257 --NUMPTR;
13258 numptr_val = rez;
13259 if (op == TOK_CONDITIONAL) {
13260 if(! numptr_m1->contidional_second_val_initialized) {
13261 /* protect $((expr1 ? expr2)) without ": expr" */
13262 goto err;
13263 }
13264 rez = numptr_m1->contidional_second_val;
13265 } else if(numptr_m1->contidional_second_val_initialized) {
13266 /* protect $((expr1 : expr2)) without "expr ? " */
13267 goto err;
13268 }
13269 numptr_m1 = NUMPTR - 1;
13270 if(op != TOK_ASSIGN) {
13271 /* check operand is var with noninteger value for not '=' */
13272 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13273 if(ret_arith_lookup_val)
13274 return ret_arith_lookup_val;
13275 }
13276 if (op == TOK_CONDITIONAL) {
13277 numptr_m1->contidional_second_val = rez;
13278 }
13279 rez = numptr_m1->val;
13280 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13281 rez |= numptr_val;
13282 else if (op == TOK_OR)
13283 rez = numptr_val || rez;
13284 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13285 rez &= numptr_val;
13286 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13287 rez ^= numptr_val;
13288 else if (op == TOK_AND)
13289 rez = rez && numptr_val;
13290 else if (op == TOK_EQ)
13291 rez = (rez == numptr_val);
13292 else if (op == TOK_NE)
13293 rez = (rez != numptr_val);
13294 else if (op == TOK_GE)
13295 rez = (rez >= numptr_val);
13296 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13297 rez >>= numptr_val;
13298 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13299 rez <<= numptr_val;
13300 else if (op == TOK_GT)
13301 rez = (rez > numptr_val);
13302 else if (op == TOK_LT)
13303 rez = (rez < numptr_val);
13304 else if (op == TOK_LE)
13305 rez = (rez <= numptr_val);
13306 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13307 rez *= numptr_val;
13308 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13309 rez += numptr_val;
13310 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13311 rez -= numptr_val;
13312 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13313 rez = numptr_val;
13314 else if (op == TOK_CONDITIONAL_SEP) {
13315 if (numptr_m1 == numstack) {
13316 /* protect $((expr : expr)) without "expr ? " */
13317 goto err;
13318 }
13319 numptr_m1->contidional_second_val_initialized = op;
13320 numptr_m1->contidional_second_val = numptr_val;
13321 }
13322 else if (op == TOK_CONDITIONAL) {
13323 rez = rez ?
13324 numptr_val : numptr_m1->contidional_second_val;
13325 }
13326 else if(op == TOK_EXPONENT) {
13327 if(numptr_val < 0)
13328 return -3; /* exponent less than 0 */
13329 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013330 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013331
13332 if(numptr_val)
13333 while(numptr_val--)
13334 c *= rez;
13335 rez = c;
13336 }
13337 }
13338 else if(numptr_val==0) /* zero divisor check */
13339 return -2;
13340 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13341 rez /= numptr_val;
13342 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13343 rez %= numptr_val;
13344 }
13345 if(tok_have_assign(op)) {
13346 char buf[32];
13347
13348 if(numptr_m1->var == NULL) {
13349 /* Hmm, 1=2 ? */
13350 goto err;
13351 }
13352 /* save to shell variable */
Eric Andersenad63cb22004-10-08 09:43:34 +000013353 snprintf(buf, sizeof(buf), "%lld", (long long) rez);
Eric Andersen90898442003-08-06 11:20:52 +000013354 setvar(numptr_m1->var, buf, 0);
13355 /* after saving, make previous value for v++ or v-- */
13356 if(op == TOK_POST_INC)
13357 rez--;
13358 else if(op == TOK_POST_DEC)
13359 rez++;
13360 }
13361 numptr_m1->val = rez;
13362 /* protect geting var value, is number now */
13363 numptr_m1->var = NULL;
13364 return 0;
13365err: return(-1);
13366}
13367
13368/* longest must first */
13369static const char op_tokens[] = {
13370 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13371 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13372 '<','<', 0, TOK_LSHIFT,
13373 '>','>', 0, TOK_RSHIFT,
13374 '|','|', 0, TOK_OR,
13375 '&','&', 0, TOK_AND,
13376 '!','=', 0, TOK_NE,
13377 '<','=', 0, TOK_LE,
13378 '>','=', 0, TOK_GE,
13379 '=','=', 0, TOK_EQ,
13380 '|','=', 0, TOK_OR_ASSIGN,
13381 '&','=', 0, TOK_AND_ASSIGN,
13382 '*','=', 0, TOK_MUL_ASSIGN,
13383 '/','=', 0, TOK_DIV_ASSIGN,
13384 '%','=', 0, TOK_REM_ASSIGN,
13385 '+','=', 0, TOK_PLUS_ASSIGN,
13386 '-','=', 0, TOK_MINUS_ASSIGN,
13387 '-','-', 0, TOK_POST_DEC,
13388 '^','=', 0, TOK_XOR_ASSIGN,
13389 '+','+', 0, TOK_POST_INC,
13390 '*','*', 0, TOK_EXPONENT,
13391 '!', 0, TOK_NOT,
13392 '<', 0, TOK_LT,
13393 '>', 0, TOK_GT,
13394 '=', 0, TOK_ASSIGN,
13395 '|', 0, TOK_BOR,
13396 '&', 0, TOK_BAND,
13397 '*', 0, TOK_MUL,
13398 '/', 0, TOK_DIV,
13399 '%', 0, TOK_REM,
13400 '+', 0, TOK_ADD,
13401 '-', 0, TOK_SUB,
13402 '^', 0, TOK_BXOR,
13403 /* uniq */
13404 '~', 0, TOK_BNOT,
13405 ',', 0, TOK_COMMA,
13406 '?', 0, TOK_CONDITIONAL,
13407 ':', 0, TOK_CONDITIONAL_SEP,
13408 ')', 0, TOK_RPAREN,
13409 '(', 0, TOK_LPAREN,
13410 0
13411};
13412/* ptr to ")" */
13413#define endexpression &op_tokens[sizeof(op_tokens)-7]
13414
13415
Eric Andersened9ecf72004-06-22 08:29:45 +000013416static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013417{
13418 register char arithval; /* Current character under analysis */
13419 operator lasttok, op;
13420 operator prec;
13421
13422 const char *p = endexpression;
13423 int errcode;
13424
13425 size_t datasizes = strlen(expr) + 2;
13426
13427 /* Stack of integers */
13428 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013429 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013430 * the reader. */
13431 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13432 *numstackptr = numstack;
13433 /* Stack of operator tokens */
13434 operator *stack = alloca((datasizes) * sizeof(operator)),
13435 *stackptr = stack;
13436
13437 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13438 *perrcode = errcode = 0;
13439
13440 while(1) {
13441 if ((arithval = *expr) == 0) {
13442 if (p == endexpression) {
13443 /* Null expression. */
13444 return 0;
13445 }
13446
13447 /* This is only reached after all tokens have been extracted from the
13448 * input stream. If there are still tokens on the operator stack, they
13449 * are to be applied in order. At the end, there should be a final
13450 * result on the integer stack */
13451
13452 if (expr != endexpression + 1) {
13453 /* If we haven't done so already, */
13454 /* append a closing right paren */
13455 expr = endexpression;
13456 /* and let the loop process it. */
13457 continue;
13458 }
13459 /* At this point, we're done with the expression. */
13460 if (numstackptr != numstack+1) {
13461 /* ... but if there isn't, it's bad */
13462 err:
13463 return (*perrcode = -1);
13464 }
13465 if(numstack->var) {
13466 /* expression is $((var)) only, lookup now */
13467 errcode = arith_lookup_val(numstack);
13468 }
13469 ret:
13470 *perrcode = errcode;
13471 return numstack->val;
13472 } else {
13473 /* Continue processing the expression. */
13474 if (arith_isspace(arithval)) {
13475 /* Skip whitespace */
13476 goto prologue;
13477 }
13478 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013479 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013480
13481 numstackptr->var = alloca(var_name_size);
13482 safe_strncpy(numstackptr->var, expr, var_name_size);
13483 expr = p;
13484 num:
13485 numstackptr->contidional_second_val_initialized = 0;
13486 numstackptr++;
13487 lasttok = TOK_NUM;
13488 continue;
13489 } else if (is_digit(arithval)) {
13490 numstackptr->var = NULL;
Eric Andersenad63cb22004-10-08 09:43:34 +000013491 numstackptr->val = strtoll(expr, (char **) &expr, 0);
Eric Andersen90898442003-08-06 11:20:52 +000013492 goto num;
13493 }
13494 for(p = op_tokens; ; p++) {
13495 const char *o;
13496
13497 if(*p == 0) {
13498 /* strange operator not found */
13499 goto err;
13500 }
13501 for(o = expr; *p && *o == *p; p++)
13502 o++;
13503 if(! *p) {
13504 /* found */
13505 expr = o - 1;
13506 break;
13507 }
13508 /* skip tail uncompared token */
13509 while(*p)
13510 p++;
13511 /* skip zero delim */
13512 p++;
13513 }
13514 op = p[1];
13515
13516 /* post grammar: a++ reduce to num */
13517 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13518 lasttok = TOK_NUM;
13519
13520 /* Plus and minus are binary (not unary) _only_ if the last
13521 * token was as number, or a right paren (which pretends to be
13522 * a number, since it evaluates to one). Think about it.
13523 * It makes sense. */
13524 if (lasttok != TOK_NUM) {
13525 switch(op) {
13526 case TOK_ADD:
13527 op = TOK_UPLUS;
13528 break;
13529 case TOK_SUB:
13530 op = TOK_UMINUS;
13531 break;
13532 case TOK_POST_INC:
13533 op = TOK_PRE_INC;
13534 break;
13535 case TOK_POST_DEC:
13536 op = TOK_PRE_DEC;
13537 break;
13538 }
13539 }
13540 /* We don't want a unary operator to cause recursive descent on the
13541 * stack, because there can be many in a row and it could cause an
13542 * operator to be evaluated before its argument is pushed onto the
13543 * integer stack. */
13544 /* But for binary operators, "apply" everything on the operator
13545 * stack until we find an operator with a lesser priority than the
13546 * one we have just extracted. */
13547 /* Left paren is given the lowest priority so it will never be
13548 * "applied" in this way.
13549 * if associativity is right and priority eq, applied also skip
13550 */
13551 prec = PREC(op);
13552 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13553 /* not left paren or unary */
13554 if (lasttok != TOK_NUM) {
13555 /* binary op must be preceded by a num */
13556 goto err;
13557 }
13558 while (stackptr != stack) {
13559 if (op == TOK_RPAREN) {
13560 /* The algorithm employed here is simple: while we don't
13561 * hit an open paren nor the bottom of the stack, pop
13562 * tokens and apply them */
13563 if (stackptr[-1] == TOK_LPAREN) {
13564 --stackptr;
13565 /* Any operator directly after a */
13566 lasttok = TOK_NUM;
13567 /* close paren should consider itself binary */
13568 goto prologue;
13569 }
13570 } else {
13571 operator prev_prec = PREC(stackptr[-1]);
13572
13573 convert_prec_is_assing(prec);
13574 convert_prec_is_assing(prev_prec);
13575 if (prev_prec < prec)
13576 break;
13577 /* check right assoc */
13578 if(prev_prec == prec && is_right_associativity(prec))
13579 break;
13580 }
13581 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13582 if(errcode) goto ret;
13583 }
13584 if (op == TOK_RPAREN) {
13585 goto err;
13586 }
13587 }
13588
13589 /* Push this operator to the stack and remember it. */
13590 *stackptr++ = lasttok = op;
13591
13592 prologue:
13593 ++expr;
13594 }
13595 }
13596}
13597#endif /* CONFIG_ASH_MATH_SUPPORT */
13598
13599
Eric Andersenc470f442003-07-28 09:56:35 +000013600#ifdef DEBUG
13601const char *bb_applet_name = "debug stuff usage";
13602int main(int argc, char **argv)
13603{
13604 return ash_main(argc, argv);
13605}
13606#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013607
Eric Andersendf82f612001-06-28 07:46:40 +000013608/*-
13609 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013610 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013611 *
13612 * This code is derived from software contributed to Berkeley by
13613 * Kenneth Almquist.
13614 *
13615 * Redistribution and use in source and binary forms, with or without
13616 * modification, are permitted provided that the following conditions
13617 * are met:
13618 * 1. Redistributions of source code must retain the above copyright
13619 * notice, this list of conditions and the following disclaimer.
13620 * 2. Redistributions in binary form must reproduce the above copyright
13621 * notice, this list of conditions and the following disclaimer in the
13622 * documentation and/or other materials provided with the distribution.
13623 *
Eric Andersen2870d962001-07-02 17:27:21 +000013624 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13625 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013626 *
13627 * 4. Neither the name of the University nor the names of its contributors
13628 * may be used to endorse or promote products derived from this software
13629 * without specific prior written permission.
13630 *
13631 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13632 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13633 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13634 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13635 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13636 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13637 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13638 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13639 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13640 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13641 * SUCH DAMAGE.
13642 */