blob: 6edc48421448b025428d3e4df7e51ad5bee4b380 [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
Paul Fox02eb9342005-09-07 16:56:02 +0000108#if JOBS || defined(CONFIG_ASH_READ_NCHARS)
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
Eric Andersenc470f442003-07-28 09:56:35 +0000279/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000280
281struct strlist {
282 struct strlist *next;
283 char *text;
284};
285
286
287struct arglist {
288 struct strlist *list;
289 struct strlist **lastp;
290};
291
Eric Andersenc470f442003-07-28 09:56:35 +0000292/*
293 * expandarg() flags
294 */
295#define EXP_FULL 0x1 /* perform word splitting & file globbing */
296#define EXP_TILDE 0x2 /* do normal tilde expansion */
297#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
298#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
299#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
300#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
301#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
302#define EXP_WORD 0x80 /* expand word in parameter expansion */
303#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
304
305
306union node;
307static void expandarg(union node *, struct arglist *, int);
308#define rmescapes(p) _rmescapes((p), 0)
309static char *_rmescapes(char *, int);
310static int casematch(union node *, char *);
311
312#ifdef CONFIG_ASH_MATH_SUPPORT
313static void expari(int);
Eric Andersen2870d962001-07-02 17:27:21 +0000314#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000315
Eric Andersenc470f442003-07-28 09:56:35 +0000316/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +0000317
Eric Andersenc470f442003-07-28 09:56:35 +0000318static char *commandname; /* currently executing command */
319static struct strlist *cmdenviron; /* environment for builtin command */
320static int exitstatus; /* exit status of last command */
321static int back_exitstatus; /* exit status of backquoted command */
Eric Andersen2870d962001-07-02 17:27:21 +0000322
Eric Andersenc470f442003-07-28 09:56:35 +0000323
324struct backcmd { /* result of evalbackcmd */
325 int fd; /* file descriptor to read from */
326 char *buf; /* buffer */
327 int nleft; /* number of chars in buffer */
328 struct job *jp; /* job structure for command */
Eric Andersen2870d962001-07-02 17:27:21 +0000329};
330
Eric Andersen62483552001-07-10 06:09:16 +0000331/*
Eric Andersenc470f442003-07-28 09:56:35 +0000332 * This file was generated by the mknodes program.
Eric Andersen62483552001-07-10 06:09:16 +0000333 */
Eric Andersenc470f442003-07-28 09:56:35 +0000334
335#define NCMD 0
336#define NPIPE 1
337#define NREDIR 2
338#define NBACKGND 3
339#define NSUBSHELL 4
340#define NAND 5
341#define NOR 6
342#define NSEMI 7
343#define NIF 8
344#define NWHILE 9
345#define NUNTIL 10
346#define NFOR 11
347#define NCASE 12
348#define NCLIST 13
349#define NDEFUN 14
350#define NARG 15
351#define NTO 16
352#define NCLOBBER 17
353#define NFROM 18
354#define NFROMTO 19
355#define NAPPEND 20
356#define NTOFD 21
357#define NFROMFD 22
358#define NHERE 23
359#define NXHERE 24
360#define NNOT 25
Eric Andersen62483552001-07-10 06:09:16 +0000361
362
363
Eric Andersenc470f442003-07-28 09:56:35 +0000364struct ncmd {
365 int type;
366 union node *assign;
367 union node *args;
368 union node *redirect;
Eric Andersen62483552001-07-10 06:09:16 +0000369};
370
371
Eric Andersenc470f442003-07-28 09:56:35 +0000372struct npipe {
373 int type;
374 int backgnd;
375 struct nodelist *cmdlist;
376};
Eric Andersen62483552001-07-10 06:09:16 +0000377
378
Eric Andersenc470f442003-07-28 09:56:35 +0000379struct nredir {
380 int type;
381 union node *n;
382 union node *redirect;
383};
Eric Andersen62483552001-07-10 06:09:16 +0000384
385
Eric Andersenc470f442003-07-28 09:56:35 +0000386struct nbinary {
387 int type;
388 union node *ch1;
389 union node *ch2;
390};
Eric Andersen2870d962001-07-02 17:27:21 +0000391
Eric Andersen2870d962001-07-02 17:27:21 +0000392
Eric Andersenc470f442003-07-28 09:56:35 +0000393struct nif {
394 int type;
395 union node *test;
396 union node *ifpart;
397 union node *elsepart;
398};
399
400
401struct nfor {
402 int type;
403 union node *args;
404 union node *body;
405 char *var;
406};
407
408
409struct ncase {
410 int type;
411 union node *expr;
412 union node *cases;
413};
414
415
416struct nclist {
417 int type;
418 union node *next;
419 union node *pattern;
420 union node *body;
421};
422
423
424struct narg {
425 int type;
426 union node *next;
427 char *text;
428 struct nodelist *backquote;
429};
430
431
432struct nfile {
433 int type;
434 union node *next;
435 int fd;
436 union node *fname;
437 char *expfname;
438};
439
440
441struct ndup {
442 int type;
443 union node *next;
444 int fd;
445 int dupfd;
446 union node *vname;
447};
448
449
450struct nhere {
451 int type;
452 union node *next;
453 int fd;
454 union node *doc;
455};
456
457
458struct nnot {
459 int type;
460 union node *com;
461};
462
463
464union node {
465 int type;
466 struct ncmd ncmd;
467 struct npipe npipe;
468 struct nredir nredir;
469 struct nbinary nbinary;
470 struct nif nif;
471 struct nfor nfor;
472 struct ncase ncase;
473 struct nclist nclist;
474 struct narg narg;
475 struct nfile nfile;
476 struct ndup ndup;
477 struct nhere nhere;
478 struct nnot nnot;
479};
480
481
482struct nodelist {
483 struct nodelist *next;
484 union node *n;
485};
486
487
488struct funcnode {
489 int count;
490 union node n;
491};
492
493
494static void freefunc(struct funcnode *);
495/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
496
497/* control characters in argument strings */
498#define CTL_FIRST '\201' /* first 'special' character */
499#define CTLESC '\201' /* escape next character */
500#define CTLVAR '\202' /* variable defn */
501#define CTLENDVAR '\203'
502#define CTLBACKQ '\204'
503#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
504/* CTLBACKQ | CTLQUOTE == '\205' */
505#define CTLARI '\206' /* arithmetic expression */
506#define CTLENDARI '\207'
507#define CTLQUOTEMARK '\210'
508#define CTL_LAST '\210' /* last 'special' character */
509
510/* variable substitution byte (follows CTLVAR) */
511#define VSTYPE 0x0f /* type of variable substitution */
512#define VSNUL 0x10 /* colon--treat the empty string as unset */
513#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
514
515/* values of VSTYPE field */
516#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
517#define VSMINUS 0x2 /* ${var-text} */
518#define VSPLUS 0x3 /* ${var+text} */
519#define VSQUESTION 0x4 /* ${var?message} */
520#define VSASSIGN 0x5 /* ${var=text} */
521#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
522#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
523#define VSTRIMLEFT 0x8 /* ${var#pattern} */
524#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
525#define VSLENGTH 0xa /* ${#var} */
526
527/* values of checkkwd variable */
528#define CHKALIAS 0x1
529#define CHKKWD 0x2
530#define CHKNL 0x4
531
532#define IBUFSIZ (BUFSIZ + 1)
533
534/*
535 * NEOF is returned by parsecmd when it encounters an end of file. It
536 * must be distinct from NULL, so we use the address of a variable that
537 * happens to be handy.
538 */
539static int plinno = 1; /* input line number */
540
541/* number of characters left in input buffer */
542static int parsenleft; /* copy of parsefile->nleft */
543static int parselleft; /* copy of parsefile->lleft */
544
545/* next character in input buffer */
Eric Andersen90898442003-08-06 11:20:52 +0000546static char *parsenextc; /* copy of parsefile->nextc */
Glenn L McGrathd3612172003-09-17 00:22:26 +0000547
548struct strpush {
549 struct strpush *prev; /* preceding string on stack */
550 char *prevstring;
551 int prevnleft;
552#ifdef CONFIG_ASH_ALIAS
553 struct alias *ap; /* if push was associated with an alias */
554#endif
555 char *string; /* remember the string since it may change */
556};
557
558struct parsefile {
559 struct parsefile *prev; /* preceding file on stack */
560 int linno; /* current line */
561 int fd; /* file descriptor (or -1 if string) */
562 int nleft; /* number of chars left in this line */
563 int lleft; /* number of chars left in this buffer */
564 char *nextc; /* next char in buffer */
565 char *buf; /* input buffer */
566 struct strpush *strpush; /* for pushing strings at this level */
567 struct strpush basestrpush; /* so pushing one is fast */
568};
569
Eric Andersenc470f442003-07-28 09:56:35 +0000570static struct parsefile basepf; /* top level input file */
"Vladimir N. Oleynik"6f347ef2005-10-15 10:23:55 +0000571#define basebuf bb_common_bufsiz1 /* buffer for top level input file */
Eric Andersenc470f442003-07-28 09:56:35 +0000572static struct parsefile *parsefile = &basepf; /* current input file */
573
574
575static int tokpushback; /* last token pushed back */
576#define NEOF ((union node *)&tokpushback)
577static int parsebackquote; /* nonzero if we are inside backquotes */
578static int doprompt; /* if set, prompt the user */
579static int needprompt; /* true if interactive and at start of line */
580static int lasttoken; /* last token read */
581static char *wordtext; /* text of last word returned by readtoken */
582static int checkkwd;
583static struct nodelist *backquotelist;
584static union node *redirnode;
585static struct heredoc *heredoc;
586static int quoteflag; /* set if (part of) last token was quoted */
587static int startlinno; /* line # where last token started */
588
589static union node *parsecmd(int);
590static void fixredir(union node *, const char *, int);
591static const char *const *findkwd(const char *);
592static char *endofname(const char *);
593
594/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
595
596typedef void *pointer;
597
598static char nullstr[1]; /* zero length string */
599static const char spcstr[] = " ";
600static const char snlfmt[] = "%s\n";
601static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
602static const char illnum[] = "Illegal number: %s";
603static const char homestr[] = "HOME";
604
605#ifdef DEBUG
606#define TRACE(param) trace param
607#define TRACEV(param) tracev param
Eric Andersen62483552001-07-10 06:09:16 +0000608#else
Eric Andersenc470f442003-07-28 09:56:35 +0000609#define TRACE(param)
610#define TRACEV(param)
Eric Andersen62483552001-07-10 06:09:16 +0000611#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000612
Eric Andersenc470f442003-07-28 09:56:35 +0000613#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
614#define __builtin_expect(x, expected_value) (x)
615#endif
616
Glenn L McGrath2f325a02004-08-06 01:49:04 +0000617#define xlikely(x) __builtin_expect((x),1)
Eric Andersen90898442003-08-06 11:20:52 +0000618
Eric Andersenc470f442003-07-28 09:56:35 +0000619
620#define TEOF 0
621#define TNL 1
622#define TREDIR 2
623#define TWORD 3
624#define TSEMI 4
625#define TBACKGND 5
626#define TAND 6
627#define TOR 7
628#define TPIPE 8
629#define TLP 9
630#define TRP 10
631#define TENDCASE 11
632#define TENDBQUOTE 12
633#define TNOT 13
634#define TCASE 14
635#define TDO 15
636#define TDONE 16
637#define TELIF 17
638#define TELSE 18
639#define TESAC 19
640#define TFI 20
641#define TFOR 21
642#define TIF 22
643#define TIN 23
644#define TTHEN 24
645#define TUNTIL 25
646#define TWHILE 26
647#define TBEGIN 27
648#define TEND 28
649
650/* first char is indicating which tokens mark the end of a list */
651static const char *const tokname_array[] = {
652 "\1end of file",
653 "\0newline",
654 "\0redirection",
655 "\0word",
656 "\0;",
657 "\0&",
658 "\0&&",
659 "\0||",
660 "\0|",
661 "\0(",
662 "\1)",
663 "\1;;",
664 "\1`",
665#define KWDOFFSET 13
666 /* the following are keywords */
667 "\0!",
668 "\0case",
669 "\1do",
670 "\1done",
671 "\1elif",
672 "\1else",
673 "\1esac",
674 "\1fi",
675 "\0for",
676 "\0if",
677 "\0in",
678 "\1then",
679 "\0until",
680 "\0while",
681 "\0{",
682 "\1}",
683};
684
685static const char *tokname(int tok)
686{
687 static char buf[16];
688
689 if (tok >= TSEMI)
690 buf[0] = '"';
691 sprintf(buf + (tok >= TSEMI), "%s%c",
692 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
693 return buf;
694}
695
696/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
697
698/*
699 * Most machines require the value returned from malloc to be aligned
700 * in some way. The following macro will get this right on many machines.
701 */
702
703#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
704/*
705 * It appears that grabstackstr() will barf with such alignments
706 * because stalloc() will return a string allocated in a new stackblock.
707 */
708#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
709
710/*
711 * This file was generated by the mksyntax program.
712 */
713
714
715/* Syntax classes */
716#define CWORD 0 /* character is nothing special */
717#define CNL 1 /* newline character */
718#define CBACK 2 /* a backslash character */
719#define CSQUOTE 3 /* single quote */
720#define CDQUOTE 4 /* double quote */
721#define CENDQUOTE 5 /* a terminating quote */
722#define CBQUOTE 6 /* backwards single quote */
723#define CVAR 7 /* a dollar sign */
724#define CENDVAR 8 /* a '}' character */
725#define CLP 9 /* a left paren in arithmetic */
726#define CRP 10 /* a right paren in arithmetic */
727#define CENDFILE 11 /* end of file */
728#define CCTL 12 /* like CWORD, except it must be escaped */
729#define CSPCL 13 /* these terminate a word */
730#define CIGN 14 /* character should be ignored */
731
732#ifdef CONFIG_ASH_ALIAS
733#define SYNBASE 130
734#define PEOF -130
735#define PEOA -129
736#define PEOA_OR_PEOF PEOA
737#else
738#define SYNBASE 129
739#define PEOF -129
740#define PEOA_OR_PEOF PEOF
741#endif
742
743#define is_digit(c) ((unsigned)((c) - '0') <= 9)
744#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
745#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
746
747/*
748 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
749 * (assuming ascii char codes, as the original implementation did)
750 */
751#define is_special(c) \
752 ( (((unsigned int)c) - 33 < 32) \
753 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
754
755#define digit_val(c) ((c) - '0')
756
757/*
758 * This file was generated by the mksyntax program.
759 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000760
Eric Andersend35c5df2002-01-09 15:37:36 +0000761#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000762#define USE_SIT_FUNCTION
763#endif
764
765/* number syntax index */
Eric Andersenc470f442003-07-28 09:56:35 +0000766#define BASESYNTAX 0 /* not in quotes */
767#define DQSYNTAX 1 /* in double quotes */
768#define SQSYNTAX 2 /* in single quotes */
769#define ARISYNTAX 3 /* in arithmetic */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000770
Eric Andersenc470f442003-07-28 09:56:35 +0000771#ifdef CONFIG_ASH_MATH_SUPPORT
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000772static const char S_I_T[][4] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000773#ifdef CONFIG_ASH_ALIAS
774 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
775#endif
776 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
777 {CNL, CNL, CNL, CNL}, /* 2, \n */
778 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
779 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
780 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
781 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
782 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
783 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
784 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
785 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
786 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000787#ifndef USE_SIT_FUNCTION
Eric Andersenc470f442003-07-28 09:56:35 +0000788 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
789 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
790 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000791#endif
Eric Andersen2870d962001-07-02 17:27:21 +0000792};
Eric Andersenc470f442003-07-28 09:56:35 +0000793#else
794static const char S_I_T[][3] = {
795#ifdef CONFIG_ASH_ALIAS
796 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
797#endif
798 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
799 {CNL, CNL, CNL}, /* 2, \n */
800 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
801 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
802 {CVAR, CVAR, CWORD}, /* 5, $ */
803 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
804 {CSPCL, CWORD, CWORD}, /* 7, ( */
805 {CSPCL, CWORD, CWORD}, /* 8, ) */
806 {CBACK, CBACK, CCTL}, /* 9, \ */
807 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
808 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
809#ifndef USE_SIT_FUNCTION
810 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
811 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
812 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
813#endif
814};
815#endif /* CONFIG_ASH_MATH_SUPPORT */
Eric Andersen2870d962001-07-02 17:27:21 +0000816
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000817#ifdef USE_SIT_FUNCTION
818
819#define U_C(c) ((unsigned char)(c))
820
821static int SIT(int c, int syntax)
822{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000823 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Eric Andersenc470f442003-07-28 09:56:35 +0000824#ifdef CONFIG_ASH_ALIAS
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000825 static const char syntax_index_table[] = {
Eric Andersenc470f442003-07-28 09:56:35 +0000826 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
827 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
828 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
829 11, 3 /* "}~" */
830 };
831#else
832 static const char syntax_index_table[] = {
833 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
834 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
835 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
836 10, 2 /* "}~" */
837 };
838#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000839 const char *s;
840 int indx;
841
Eric Andersenc470f442003-07-28 09:56:35 +0000842 if (c == PEOF) /* 2^8+2 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000843 return CENDFILE;
Eric Andersenc470f442003-07-28 09:56:35 +0000844#ifdef CONFIG_ASH_ALIAS
845 if (c == PEOA) /* 2^8+1 */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000846 indx = 0;
Eric Andersenc470f442003-07-28 09:56:35 +0000847 else
848#endif
849 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
850 return CCTL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000851 else {
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000852 s = strchr(spec_symbls, c);
Eric Andersenc470f442003-07-28 09:56:35 +0000853 if (s == 0 || *s == 0)
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000854 return CWORD;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000855 indx = syntax_index_table[(s - spec_symbls)];
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000856 }
857 return S_I_T[indx][syntax];
858}
859
Eric Andersenc470f442003-07-28 09:56:35 +0000860#else /* USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000861
862#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
863
Eric Andersenc470f442003-07-28 09:56:35 +0000864#ifdef CONFIG_ASH_ALIAS
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000865#define CSPCL_CIGN_CIGN_CIGN 0
866#define CSPCL_CWORD_CWORD_CWORD 1
867#define CNL_CNL_CNL_CNL 2
868#define CWORD_CCTL_CCTL_CWORD 3
Eric Andersenc470f442003-07-28 09:56:35 +0000869#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000870#define CVAR_CVAR_CWORD_CVAR 5
Eric Andersenc470f442003-07-28 09:56:35 +0000871#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000872#define CSPCL_CWORD_CWORD_CLP 7
873#define CSPCL_CWORD_CWORD_CRP 8
874#define CBACK_CBACK_CCTL_CBACK 9
875#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
876#define CENDVAR_CENDVAR_CWORD_CENDVAR 11
877#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
878#define CWORD_CWORD_CWORD_CWORD 13
879#define CCTL_CCTL_CCTL_CCTL 14
Eric Andersenc470f442003-07-28 09:56:35 +0000880#else
881#define CSPCL_CWORD_CWORD_CWORD 0
882#define CNL_CNL_CNL_CNL 1
883#define CWORD_CCTL_CCTL_CWORD 2
884#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
885#define CVAR_CVAR_CWORD_CVAR 4
886#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
887#define CSPCL_CWORD_CWORD_CLP 6
888#define CSPCL_CWORD_CWORD_CRP 7
889#define CBACK_CBACK_CCTL_CBACK 8
890#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
891#define CENDVAR_CENDVAR_CWORD_CENDVAR 10
892#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
893#define CWORD_CWORD_CWORD_CWORD 12
894#define CCTL_CCTL_CCTL_CCTL 13
895#endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +0000896
897static const char syntax_index_table[258] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000898 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Eric Andersenc470f442003-07-28 09:56:35 +0000899 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
900#ifdef CONFIG_ASH_ALIAS
901 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
902#endif
903 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
904 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
905 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
906 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
907 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
908 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
909 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
910 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
911 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000912 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
913 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
914 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
915 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
916 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
917 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
918 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
919 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
920 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
921 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
922 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
923 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
924 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
925 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
926 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
927 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
928 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
929 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
930 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
931 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
932 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
933 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
934 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
935 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
936 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
937 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
938 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
939 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
940 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
941 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
942 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
943 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
944 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
945 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
946 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
947 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
948 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
949 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
950 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
951 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
952 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
953 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
954 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
955 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
956 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
957 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
958 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
959 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
960 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
961 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
962 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
963 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
964 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
965 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
966 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
967 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
968 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
969 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
970 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
971 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
972 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
973 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
974 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
975 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
976 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
977 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
978 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
979 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
980 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
981 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
982 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
983 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
984 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
985 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
986 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
987 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
988 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
989 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
990 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
991 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
992 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
993 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
994 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
995 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
996 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
997 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
998 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
999 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1041 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1042 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1051 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1052 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1053 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1054 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1055 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1056 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1057 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1058 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1059 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1060 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1061 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1062 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1063 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1064 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001065 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001066 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1068 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
Eric Andersenc470f442003-07-28 09:56:35 +00001070 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001071 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1072 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1073 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1074 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1075 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1076 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1077 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1078 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1079 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1090 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1091 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1092 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1093 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1094 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1095 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1123 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1124 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1125 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1128 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1143 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1144 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1145 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1146 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1147 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1148 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1149 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1150 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1151 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1152 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1153 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1154 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1155 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1156 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1157 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1158 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
Eric Andersen2870d962001-07-02 17:27:21 +00001159};
1160
Eric Andersenc470f442003-07-28 09:56:35 +00001161#endif /* USE_SIT_FUNCTION */
1162
1163/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001164
Eric Andersen2870d962001-07-02 17:27:21 +00001165
Eric Andersenc470f442003-07-28 09:56:35 +00001166#define ATABSIZE 39
1167
1168static int funcblocksize; /* size of structures in function */
1169static int funcstringsize; /* size of strings in node */
1170static pointer funcblock; /* block to allocate function from */
1171static char *funcstring; /* block to allocate strings from */
1172
1173static const short nodesize[26] = {
1174 SHELL_ALIGN(sizeof (struct ncmd)),
1175 SHELL_ALIGN(sizeof (struct npipe)),
1176 SHELL_ALIGN(sizeof (struct nredir)),
1177 SHELL_ALIGN(sizeof (struct nredir)),
1178 SHELL_ALIGN(sizeof (struct nredir)),
1179 SHELL_ALIGN(sizeof (struct nbinary)),
1180 SHELL_ALIGN(sizeof (struct nbinary)),
1181 SHELL_ALIGN(sizeof (struct nbinary)),
1182 SHELL_ALIGN(sizeof (struct nif)),
1183 SHELL_ALIGN(sizeof (struct nbinary)),
1184 SHELL_ALIGN(sizeof (struct nbinary)),
1185 SHELL_ALIGN(sizeof (struct nfor)),
1186 SHELL_ALIGN(sizeof (struct ncase)),
1187 SHELL_ALIGN(sizeof (struct nclist)),
1188 SHELL_ALIGN(sizeof (struct narg)),
1189 SHELL_ALIGN(sizeof (struct narg)),
1190 SHELL_ALIGN(sizeof (struct nfile)),
1191 SHELL_ALIGN(sizeof (struct nfile)),
1192 SHELL_ALIGN(sizeof (struct nfile)),
1193 SHELL_ALIGN(sizeof (struct nfile)),
1194 SHELL_ALIGN(sizeof (struct nfile)),
1195 SHELL_ALIGN(sizeof (struct ndup)),
1196 SHELL_ALIGN(sizeof (struct ndup)),
1197 SHELL_ALIGN(sizeof (struct nhere)),
1198 SHELL_ALIGN(sizeof (struct nhere)),
1199 SHELL_ALIGN(sizeof (struct nnot)),
Eric Andersen2870d962001-07-02 17:27:21 +00001200};
1201
Manuel Novoa III 16815d42001-08-10 19:36:07 +00001202
Eric Andersenc470f442003-07-28 09:56:35 +00001203static void calcsize(union node *);
1204static void sizenodelist(struct nodelist *);
1205static union node *copynode(union node *);
1206static struct nodelist *copynodelist(struct nodelist *);
1207static char *nodesavestr(char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001208
1209
Eric Andersen2870d962001-07-02 17:27:21 +00001210
Glenn L McGrath76620622004-01-13 10:19:37 +00001211static void evalstring(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001212union node; /* BLETCH for ansi C */
1213static void evaltree(union node *, int);
1214static void evalbackcmd(union node *, struct backcmd *);
Eric Andersen2870d962001-07-02 17:27:21 +00001215
Eric Andersenc470f442003-07-28 09:56:35 +00001216/* in_function returns nonzero if we are currently evaluating a function */
1217#define in_function() funcnest
1218static int evalskip; /* set if we are skipping commands */
1219static int skipcount; /* number of levels to skip */
1220static int funcnest; /* depth of function calls */
Eric Andersen2870d962001-07-02 17:27:21 +00001221
1222/* reasons for skipping commands (see comment on breakcmd routine) */
1223#define SKIPBREAK 1
1224#define SKIPCONT 2
1225#define SKIPFUNC 3
1226#define SKIPFILE 4
1227
Eric Andersenc470f442003-07-28 09:56:35 +00001228/*
1229 * This file was generated by the mkbuiltins program.
1230 */
Eric Andersen2870d962001-07-02 17:27:21 +00001231
Eric Andersenc470f442003-07-28 09:56:35 +00001232#ifdef JOBS
1233static int bgcmd(int, char **);
1234#endif
1235static int breakcmd(int, char **);
1236static int cdcmd(int, char **);
1237#ifdef CONFIG_ASH_CMDCMD
1238static int commandcmd(int, char **);
1239#endif
1240static int dotcmd(int, char **);
1241static int evalcmd(int, char **);
Paul Fox0b621582005-08-09 19:38:05 +00001242#ifdef CONFIG_ASH_BUILTIN_ECHO
1243static int echocmd(int, char **);
1244#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001245static int execcmd(int, char **);
1246static int exitcmd(int, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00001247static int exportcmd(int, char **);
1248static int falsecmd(int, char **);
1249#ifdef JOBS
1250static int fgcmd(int, char **);
1251#endif
1252#ifdef CONFIG_ASH_GETOPTS
1253static int getoptscmd(int, char **);
1254#endif
1255static int hashcmd(int, char **);
1256#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1257static int helpcmd(int argc, char **argv);
1258#endif
1259#ifdef JOBS
1260static int jobscmd(int, char **);
1261#endif
Eric Andersen90898442003-08-06 11:20:52 +00001262#ifdef CONFIG_ASH_MATH_SUPPORT
1263static int letcmd(int, char **);
1264#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001265static int localcmd(int, char **);
1266static int pwdcmd(int, char **);
1267static int readcmd(int, char **);
1268static int returncmd(int, char **);
1269static int setcmd(int, char **);
1270static int shiftcmd(int, char **);
1271static int timescmd(int, char **);
1272static int trapcmd(int, char **);
1273static int truecmd(int, char **);
1274static int typecmd(int, char **);
1275static int umaskcmd(int, char **);
1276static int unsetcmd(int, char **);
1277static int waitcmd(int, char **);
1278static int ulimitcmd(int, char **);
1279#ifdef JOBS
1280static int killcmd(int, char **);
1281#endif
1282
1283/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1284
1285#ifdef CONFIG_ASH_MAIL
1286static void chkmail(void);
1287static void changemail(const char *);
1288#endif
1289
1290/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1291
1292/* values of cmdtype */
1293#define CMDUNKNOWN -1 /* no entry in table for command */
1294#define CMDNORMAL 0 /* command is an executable program */
1295#define CMDFUNCTION 1 /* command is a shell function */
1296#define CMDBUILTIN 2 /* command is a shell builtin */
1297
1298struct builtincmd {
1299 const char *name;
1300 int (*builtin)(int, char **);
1301 /* unsigned flags; */
1302};
1303
Paul Fox0b621582005-08-09 19:38:05 +00001304
1305#define COMMANDCMD (builtincmd + 5 + \
1306 ENABLE_ASH_ALIAS + ENABLE_ASH_JOB_CONTROL)
1307#define EXECCMD (builtincmd + 7 + \
1308 ENABLE_ASH_CMDCMD + ENABLE_ASH_ALIAS + \
1309 ENABLE_ASH_BUILTIN_ECHO + ENABLE_ASH_JOB_CONTROL)
Eric Andersenc470f442003-07-28 09:56:35 +00001310
1311#define BUILTIN_NOSPEC "0"
1312#define BUILTIN_SPECIAL "1"
1313#define BUILTIN_REGULAR "2"
1314#define BUILTIN_SPEC_REG "3"
1315#define BUILTIN_ASSIGN "4"
1316#define BUILTIN_SPEC_ASSG "5"
1317#define BUILTIN_REG_ASSG "6"
1318#define BUILTIN_SPEC_REG_ASSG "7"
1319
1320#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1321#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
Paul Foxc3850c82005-07-20 18:23:39 +00001322#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001323
1324static const struct builtincmd builtincmd[] = {
1325 { BUILTIN_SPEC_REG ".", dotcmd },
1326 { BUILTIN_SPEC_REG ":", truecmd },
1327#ifdef CONFIG_ASH_ALIAS
1328 { BUILTIN_REG_ASSG "alias", aliascmd },
1329#endif
1330#ifdef JOBS
1331 { BUILTIN_REGULAR "bg", bgcmd },
1332#endif
1333 { BUILTIN_SPEC_REG "break", breakcmd },
1334 { BUILTIN_REGULAR "cd", cdcmd },
1335 { BUILTIN_NOSPEC "chdir", cdcmd },
1336#ifdef CONFIG_ASH_CMDCMD
1337 { BUILTIN_REGULAR "command", commandcmd },
1338#endif
1339 { BUILTIN_SPEC_REG "continue", breakcmd },
Paul Fox0b621582005-08-09 19:38:05 +00001340#ifdef CONFIG_ASH_BUILTIN_ECHO
1341 { BUILTIN_REGULAR "echo", echocmd },
1342#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001343 { BUILTIN_SPEC_REG "eval", evalcmd },
1344 { BUILTIN_SPEC_REG "exec", execcmd },
1345 { BUILTIN_SPEC_REG "exit", exitcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001346 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1347 { BUILTIN_REGULAR "false", falsecmd },
1348#ifdef JOBS
1349 { BUILTIN_REGULAR "fg", fgcmd },
1350#endif
1351#ifdef CONFIG_ASH_GETOPTS
1352 { BUILTIN_REGULAR "getopts", getoptscmd },
1353#endif
1354 { BUILTIN_NOSPEC "hash", hashcmd },
1355#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1356 { BUILTIN_NOSPEC "help", helpcmd },
1357#endif
1358#ifdef JOBS
1359 { BUILTIN_REGULAR "jobs", jobscmd },
1360 { BUILTIN_REGULAR "kill", killcmd },
1361#endif
1362#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersen90898442003-08-06 11:20:52 +00001363 { BUILTIN_NOSPEC "let", letcmd },
Eric Andersenc470f442003-07-28 09:56:35 +00001364#endif
1365 { BUILTIN_ASSIGN "local", localcmd },
1366 { BUILTIN_NOSPEC "pwd", pwdcmd },
1367 { BUILTIN_REGULAR "read", readcmd },
1368 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1369 { BUILTIN_SPEC_REG "return", returncmd },
1370 { BUILTIN_SPEC_REG "set", setcmd },
1371 { BUILTIN_SPEC_REG "shift", shiftcmd },
1372 { BUILTIN_SPEC_REG "times", timescmd },
1373 { BUILTIN_SPEC_REG "trap", trapcmd },
1374 { BUILTIN_REGULAR "true", truecmd },
1375 { BUILTIN_NOSPEC "type", typecmd },
1376 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1377 { BUILTIN_REGULAR "umask", umaskcmd },
1378#ifdef CONFIG_ASH_ALIAS
1379 { BUILTIN_REGULAR "unalias", unaliascmd },
1380#endif
1381 { BUILTIN_SPEC_REG "unset", unsetcmd },
1382 { BUILTIN_REGULAR "wait", waitcmd },
1383};
1384
1385#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1386
1387
1388
1389struct cmdentry {
1390 int cmdtype;
1391 union param {
1392 int index;
1393 const struct builtincmd *cmd;
1394 struct funcnode *func;
1395 } u;
1396};
1397
1398
1399/* action to find_command() */
1400#define DO_ERR 0x01 /* prints errors */
1401#define DO_ABS 0x02 /* checks absolute paths */
1402#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1403#define DO_ALTPATH 0x08 /* using alternate path */
1404#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1405
1406static const char *pathopt; /* set by padvance */
1407
1408static void shellexec(char **, const char *, int)
1409 __attribute__((__noreturn__));
1410static char *padvance(const char **, const char *);
1411static void find_command(char *, struct cmdentry *, int, const char *);
1412static struct builtincmd *find_builtin(const char *);
1413static void hashcd(void);
1414static void changepath(const char *);
1415static void defun(char *, union node *);
1416static void unsetfunc(const char *);
1417
Eric Andersened9ecf72004-06-22 08:29:45 +00001418#ifdef CONFIG_ASH_MATH_SUPPORT_64
1419typedef int64_t arith_t;
1420#else
1421typedef long arith_t;
1422#endif
Glenn L McGrath5f2a23c2004-06-25 07:05:13 +00001423
1424#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +00001425static arith_t dash_arith(const char *);
1426static arith_t arith(const char *expr, int *perrcode);
Eric Andersenc470f442003-07-28 09:56:35 +00001427#endif
1428
Eric Andersen16767e22004-03-16 05:14:10 +00001429#ifdef CONFIG_ASH_RANDOM_SUPPORT
1430static unsigned long rseed;
1431static void change_random(const char *);
1432# ifndef DYNAMIC_VAR
1433# define DYNAMIC_VAR
1434# endif
1435#endif
1436
Eric Andersenc470f442003-07-28 09:56:35 +00001437/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1438
1439static void reset(void);
1440
1441/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00001442
1443/*
1444 * Shell variables.
1445 */
1446
1447/* flags */
Eric Andersenc470f442003-07-28 09:56:35 +00001448#define VEXPORT 0x01 /* variable is exported */
1449#define VREADONLY 0x02 /* variable cannot be modified */
1450#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1451#define VTEXTFIXED 0x08 /* text is statically allocated */
1452#define VSTACK 0x10 /* text is allocated on the stack */
1453#define VUNSET 0x20 /* the variable is not set */
1454#define VNOFUNC 0x40 /* don't call the callback function */
1455#define VNOSET 0x80 /* do not set variable - just readonly test */
1456#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Eric Andersen16767e22004-03-16 05:14:10 +00001457#ifdef DYNAMIC_VAR
1458# define VDYNAMIC 0x200 /* dynamic variable */
1459# else
1460# define VDYNAMIC 0
1461#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001462
1463struct var {
Eric Andersenc470f442003-07-28 09:56:35 +00001464 struct var *next; /* next entry in hash list */
1465 int flags; /* flags are defined above */
1466 const char *text; /* name=value */
Eric Andersen16767e22004-03-16 05:14:10 +00001467 void (*func)(const char *); /* function to be called when */
Eric Andersenc470f442003-07-28 09:56:35 +00001468 /* the variable gets set/unset */
Eric Andersen2870d962001-07-02 17:27:21 +00001469};
1470
1471struct localvar {
Eric Andersenc470f442003-07-28 09:56:35 +00001472 struct localvar *next; /* next local variable in list */
1473 struct var *vp; /* the variable that was made local */
1474 int flags; /* saved flags */
1475 const char *text; /* saved text */
Eric Andersen2870d962001-07-02 17:27:21 +00001476};
1477
1478
Eric Andersen2870d962001-07-02 17:27:21 +00001479static struct localvar *localvars;
1480
Eric Andersenc470f442003-07-28 09:56:35 +00001481/*
1482 * Shell variables.
1483 */
1484
1485#ifdef CONFIG_ASH_GETOPTS
1486static void getoptsreset(const char *);
1487#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001488
Eric Andersenbdfd0d72001-10-24 05:00:29 +00001489#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +00001490#include <locale.h>
1491static void change_lc_all(const char *value);
1492static void change_lc_ctype(const char *value);
Eric Andersen2870d962001-07-02 17:27:21 +00001493#endif
1494
Eric Andersenef02f822004-03-11 13:34:24 +00001495
Eric Andersen2870d962001-07-02 17:27:21 +00001496#define VTABSIZE 39
1497
Eric Andersen90898442003-08-06 11:20:52 +00001498static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
Eric Andersenc470f442003-07-28 09:56:35 +00001499#ifdef IFS_BROKEN
1500static const char defifsvar[] = "IFS= \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001501#define defifs (defifsvar + 4)
1502#else
Eric Andersenc470f442003-07-28 09:56:35 +00001503static const char defifs[] = " \t\n";
Eric Andersen81fe1232003-07-29 06:38:40 +00001504#endif
1505
Eric Andersenc470f442003-07-28 09:56:35 +00001506
1507static struct var varinit[] = {
1508#ifdef IFS_BROKEN
Eric Andersen16767e22004-03-16 05:14:10 +00001509 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001510#else
Eric Andersen16767e22004-03-16 05:14:10 +00001511 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001512#endif
1513
1514#ifdef CONFIG_ASH_MAIL
Eric Andersen16767e22004-03-16 05:14:10 +00001515 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1516 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
Eric Andersenc470f442003-07-28 09:56:35 +00001517#endif
1518
Eric Andersen16767e22004-03-16 05:14:10 +00001519 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1520 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1521 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1522 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
Eric Andersenc470f442003-07-28 09:56:35 +00001523#ifdef CONFIG_ASH_GETOPTS
Eric Andersen16767e22004-03-16 05:14:10 +00001524 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1525#endif
1526#ifdef CONFIG_ASH_RANDOM_SUPPORT
1527 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
Eric Andersenc470f442003-07-28 09:56:35 +00001528#endif
1529#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen16767e22004-03-16 05:14:10 +00001530 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1531 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
Eric Andersenc470f442003-07-28 09:56:35 +00001532#endif
1533#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Eric Andersen16767e22004-03-16 05:14:10 +00001534 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
Eric Andersenc470f442003-07-28 09:56:35 +00001535#endif
1536};
1537
1538#define vifs varinit[0]
1539#ifdef CONFIG_ASH_MAIL
1540#define vmail (&vifs)[1]
1541#define vmpath (&vmail)[1]
1542#else
1543#define vmpath vifs
1544#endif
1545#define vpath (&vmpath)[1]
1546#define vps1 (&vpath)[1]
1547#define vps2 (&vps1)[1]
1548#define vps4 (&vps2)[1]
1549#define voptind (&vps4)[1]
Eric Andersen16767e22004-03-16 05:14:10 +00001550#ifdef CONFIG_ASH_GETOPTS
1551#define vrandom (&voptind)[1]
1552#else
1553#define vrandom (&vps4)[1]
1554#endif
Eric Andersenc470f442003-07-28 09:56:35 +00001555#define defpath (defpathvar + 5)
Eric Andersen2870d962001-07-02 17:27:21 +00001556
1557/*
1558 * The following macros access the values of the above variables.
1559 * They have to skip over the name. They return the null string
1560 * for unset variables.
1561 */
1562
1563#define ifsval() (vifs.text + 4)
1564#define ifsset() ((vifs.flags & VUNSET) == 0)
1565#define mailval() (vmail.text + 5)
1566#define mpathval() (vmpath.text + 9)
1567#define pathval() (vpath.text + 5)
1568#define ps1val() (vps1.text + 4)
1569#define ps2val() (vps2.text + 4)
Eric Andersenc470f442003-07-28 09:56:35 +00001570#define ps4val() (vps4.text + 4)
Eric Andersen2870d962001-07-02 17:27:21 +00001571#define optindval() (voptind.text + 7)
1572
1573#define mpathset() ((vmpath.flags & VUNSET) == 0)
1574
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001575static void setvar(const char *, const char *, int);
1576static void setvareq(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00001577static void listsetvar(struct strlist *, int);
1578static char *lookupvar(const char *);
1579static char *bltinlookup(const char *);
1580static char **listvars(int, int, char ***);
1581#define environment() listvars(VEXPORT, VUNSET, 0)
1582static int showvars(const char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00001583static void poplocalvars(void);
1584static int unsetvar(const char *);
Eric Andersenc470f442003-07-28 09:56:35 +00001585#ifdef CONFIG_ASH_GETOPTS
1586static int setvarsafe(const char *, const char *, int);
1587#endif
1588static int varcmp(const char *, const char *);
1589static struct var **hashvar(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00001590
1591
Eric Andersenc470f442003-07-28 09:56:35 +00001592static inline int varequal(const char *a, const char *b) {
1593 return !varcmp(a, b);
1594}
Eric Andersen2870d962001-07-02 17:27:21 +00001595
1596
Eric Andersenc470f442003-07-28 09:56:35 +00001597static int loopnest; /* current loop nesting level */
1598
Eric Andersenc470f442003-07-28 09:56:35 +00001599/*
1600 * The parsefile structure pointed to by the global variable parsefile
1601 * contains information about the current file being read.
1602 */
1603
1604
1605struct redirtab {
1606 struct redirtab *next;
1607 int renamed[10];
1608 int nullredirs;
1609};
1610
1611static struct redirtab *redirlist;
1612static int nullredirs;
1613
1614extern char **environ;
1615
1616/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1617
1618
1619static void outstr(const char *, FILE *);
1620static void outcslow(int, FILE *);
1621static void flushall(void);
Eric Andersen16767e22004-03-16 05:14:10 +00001622static void flusherr(void);
Eric Andersenc470f442003-07-28 09:56:35 +00001623static int out1fmt(const char *, ...)
1624 __attribute__((__format__(__printf__,1,2)));
1625static int fmtstr(char *, size_t, const char *, ...)
1626 __attribute__((__format__(__printf__,3,4)));
Eric Andersenc470f442003-07-28 09:56:35 +00001627
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001628static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
Eric Andersenc470f442003-07-28 09:56:35 +00001629
Eric Andersenc470f442003-07-28 09:56:35 +00001630
1631static void out1str(const char *p)
1632{
1633 outstr(p, stdout);
1634}
1635
1636static void out2str(const char *p)
1637{
1638 outstr(p, stderr);
Eric Andersen16767e22004-03-16 05:14:10 +00001639 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00001640}
1641
1642/*
1643 * Initialization code.
1644 */
1645
1646/*
1647 * This routine initializes the builtin variables.
1648 */
1649
1650static inline void
1651initvar(void)
1652{
1653 struct var *vp;
1654 struct var *end;
1655 struct var **vpp;
1656
1657 /*
1658 * PS1 depends on uid
1659 */
1660#if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1661 vps1.text = "PS1=\\w \\$ ";
1662#else
1663 if (!geteuid())
1664 vps1.text = "PS1=# ";
1665#endif
1666 vp = varinit;
1667 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1668 do {
1669 vpp = hashvar(vp->text);
1670 vp->next = *vpp;
1671 *vpp = vp;
1672 } while (++vp < end);
1673}
1674
1675static inline void
1676init(void)
1677{
1678
1679 /* from input.c: */
1680 {
1681 basepf.nextc = basepf.buf = basebuf;
1682 }
1683
1684 /* from trap.c: */
1685 {
1686 signal(SIGCHLD, SIG_DFL);
1687 }
1688
1689 /* from var.c: */
1690 {
1691 char **envp;
1692 char ppid[32];
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001693 const char *p;
1694 struct stat st1, st2;
Eric Andersenc470f442003-07-28 09:56:35 +00001695
1696 initvar();
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001697 for (envp = environ ; envp && *envp ; envp++) {
Eric Andersenc470f442003-07-28 09:56:35 +00001698 if (strchr(*envp, '=')) {
1699 setvareq(*envp, VEXPORT|VTEXTFIXED);
1700 }
1701 }
1702
1703 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1704 setvar("PPID", ppid, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00001705
1706 p = lookupvar("PWD");
1707 if (p)
1708 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1709 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1710 p = 0;
1711 setpwd(p, 0);
Eric Andersenc470f442003-07-28 09:56:35 +00001712 }
1713}
1714
1715/* PEOF (the end of file marker) */
1716
1717/*
1718 * The input line number. Input.c just defines this variable, and saves
1719 * and restores it when files are pushed and popped. The user of this
1720 * package must set its value.
1721 */
1722
1723static int pgetc(void);
1724static int pgetc2(void);
1725static int preadbuffer(void);
1726static void pungetc(void);
1727static void pushstring(char *, void *);
1728static void popstring(void);
1729static void setinputfile(const char *, int);
1730static void setinputfd(int, int);
1731static void setinputstring(char *);
1732static void popfile(void);
1733static void popallfiles(void);
1734static void closescript(void);
1735
1736
1737/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1738
1739
1740/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1741#define FORK_FG 0
1742#define FORK_BG 1
1743#define FORK_NOJOB 2
1744
1745/* mode flags for showjob(s) */
1746#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1747#define SHOW_PID 0x04 /* include process pid */
1748#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1749
1750
1751/*
1752 * A job structure contains information about a job. A job is either a
1753 * single process or a set of processes contained in a pipeline. In the
1754 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1755 * array of pids.
1756 */
1757
1758struct procstat {
1759 pid_t pid; /* process id */
1760 int status; /* last process status from wait() */
1761 char *cmd; /* text of command being run */
1762};
1763
1764struct job {
1765 struct procstat ps0; /* status of process */
1766 struct procstat *ps; /* status or processes when more than one */
1767#if JOBS
1768 int stopstatus; /* status of a stopped job */
1769#endif
1770 uint32_t
1771 nprocs: 16, /* number of processes */
1772 state: 8,
1773#define JOBRUNNING 0 /* at least one proc running */
1774#define JOBSTOPPED 1 /* all procs are stopped */
1775#define JOBDONE 2 /* all procs are completed */
1776#if JOBS
1777 sigint: 1, /* job was killed by SIGINT */
1778 jobctl: 1, /* job running under job control */
1779#endif
1780 waited: 1, /* true if this entry has been waited for */
1781 used: 1, /* true if this entry is in used */
1782 changed: 1; /* true if status has changed */
1783 struct job *prev_job; /* previous job */
1784};
1785
1786static pid_t backgndpid; /* pid of last background process */
1787static int job_warning; /* user was warned about stopped jobs */
1788#if JOBS
1789static int jobctl; /* true if doing job control */
1790#endif
1791
1792static struct job *makejob(union node *, int);
1793static int forkshell(struct job *, union node *, int);
1794static int waitforjob(struct job *);
1795static int stoppedjobs(void);
1796
1797#if ! JOBS
1798#define setjobctl(on) /* do nothing */
1799#else
1800static void setjobctl(int);
1801static void showjobs(FILE *, int);
1802#endif
1803
1804/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1805
1806
1807/* pid of main shell */
1808static int rootpid;
1809/* true if we aren't a child of the main shell */
1810static int rootshell;
1811
1812static void readcmdfile(char *);
1813static void cmdloop(int);
1814
1815/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1816
1817
1818struct stackmark {
1819 struct stack_block *stackp;
1820 char *stacknxt;
1821 size_t stacknleft;
1822 struct stackmark *marknext;
1823};
1824
1825/* minimum size of a block */
1826#define MINSIZE SHELL_ALIGN(504)
1827
1828struct stack_block {
1829 struct stack_block *prev;
1830 char space[MINSIZE];
1831};
1832
1833static struct stack_block stackbase;
1834static struct stack_block *stackp = &stackbase;
1835static struct stackmark *markp;
1836static char *stacknxt = stackbase.space;
1837static size_t stacknleft = MINSIZE;
1838static char *sstrend = stackbase.space + MINSIZE;
1839static int herefd = -1;
1840
1841
1842static pointer ckmalloc(size_t);
1843static pointer ckrealloc(pointer, size_t);
1844static char *savestr(const char *);
1845static pointer stalloc(size_t);
1846static void stunalloc(pointer);
1847static void setstackmark(struct stackmark *);
1848static void popstackmark(struct stackmark *);
1849static void growstackblock(void);
1850static void *growstackstr(void);
1851static char *makestrspace(size_t, char *);
1852static char *stnputs(const char *, size_t, char *);
1853static char *stputs(const char *, char *);
1854
1855
1856static inline char *_STPUTC(char c, char *p) {
1857 if (p == sstrend)
1858 p = growstackstr();
1859 *p++ = c;
1860 return p;
1861}
1862
1863#define stackblock() ((void *)stacknxt)
1864#define stackblocksize() stacknleft
1865#define STARTSTACKSTR(p) ((p) = stackblock())
1866#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1867#define CHECKSTRSPACE(n, p) \
1868 ({ \
1869 char *q = (p); \
1870 size_t l = (n); \
1871 size_t m = sstrend - q; \
1872 if (l > m) \
1873 (p) = makestrspace(l, q); \
1874 0; \
1875 })
1876#define USTPUTC(c, p) (*p++ = (c))
1877#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1878#define STUNPUTC(p) (--p)
1879#define STTOPC(p) p[-1]
1880#define STADJUST(amount, p) (p += (amount))
1881
1882#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1883#define ungrabstackstr(s, p) stunalloc((s))
1884#define stackstrend() ((void *)sstrend)
1885
1886#define ckfree(p) free((pointer)(p))
1887
1888/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1889
1890
1891#define DOLATSTRLEN 4
1892
1893static char *prefix(const char *, const char *);
1894static int number(const char *);
1895static int is_number(const char *);
1896static char *single_quote(const char *);
1897static char *sstrdup(const char *);
1898
1899#define equal(s1, s2) (strcmp(s1, s2) == 0)
1900#define scopy(s1, s2) ((void)strcpy(s2, s1))
1901
1902/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1903
1904struct shparam {
1905 int nparam; /* # of positional parameters (without $0) */
1906 unsigned char malloc; /* if parameter list dynamically allocated */
1907 char **p; /* parameter list */
1908#ifdef CONFIG_ASH_GETOPTS
1909 int optind; /* next parameter to be processed by getopts */
1910 int optoff; /* used by getopts */
1911#endif
1912};
1913
1914
1915#define eflag optlist[0]
1916#define fflag optlist[1]
1917#define Iflag optlist[2]
1918#define iflag optlist[3]
1919#define mflag optlist[4]
1920#define nflag optlist[5]
1921#define sflag optlist[6]
1922#define xflag optlist[7]
1923#define vflag optlist[8]
1924#define Cflag optlist[9]
1925#define aflag optlist[10]
1926#define bflag optlist[11]
1927#define uflag optlist[12]
1928#define qflag optlist[13]
Paul Fox3f11b1b2005-08-04 19:04:46 +00001929#define viflag optlist[14]
Eric Andersenc470f442003-07-28 09:56:35 +00001930
1931#ifdef DEBUG
Paul Fox3f11b1b2005-08-04 19:04:46 +00001932#define nolog optlist[15]
1933#define debug optlist[16]
1934#endif
1935
1936#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1937#define setvimode(on) viflag = 0 /* forcibly keep the option off */
Eric Andersenc470f442003-07-28 09:56:35 +00001938#endif
1939
1940/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1941
1942
Paul Fox3f11b1b2005-08-04 19:04:46 +00001943static const char *const optletters_optnames[] = {
Eric Andersenc470f442003-07-28 09:56:35 +00001944 "e" "errexit",
1945 "f" "noglob",
1946 "I" "ignoreeof",
1947 "i" "interactive",
1948 "m" "monitor",
1949 "n" "noexec",
1950 "s" "stdin",
1951 "x" "xtrace",
1952 "v" "verbose",
1953 "C" "noclobber",
1954 "a" "allexport",
1955 "b" "notify",
1956 "u" "nounset",
1957 "q" "quietprofile",
Paul Fox3f11b1b2005-08-04 19:04:46 +00001958 "\0" "vi",
Eric Andersenc470f442003-07-28 09:56:35 +00001959#ifdef DEBUG
1960 "\0" "nolog",
1961 "\0" "debug",
1962#endif
1963};
1964
1965#define optletters(n) optletters_optnames[(n)][0]
1966#define optnames(n) (&optletters_optnames[(n)][1])
1967
Paul Fox3f11b1b2005-08-04 19:04:46 +00001968#define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
Eric Andersenc470f442003-07-28 09:56:35 +00001969
1970static char optlist[NOPTS];
1971
1972
1973static char *arg0; /* value of $0 */
1974static struct shparam shellparam; /* $@ current positional parameters */
1975static char **argptr; /* argument list for builtin commands */
1976static char *optionarg; /* set by nextopt (like getopt) */
1977static char *optptr; /* used by nextopt */
1978
1979static char *minusc; /* argument to -c option */
1980
1981
1982static void procargs(int, char **);
1983static void optschanged(void);
1984static void setparam(char **);
1985static void freeparam(volatile struct shparam *);
1986static int shiftcmd(int, char **);
1987static int setcmd(int, char **);
1988static int nextopt(const char *);
1989
1990/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1991
1992/* flags passed to redirect */
1993#define REDIR_PUSH 01 /* save previous values of file descriptors */
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00001994#define REDIR_SAVEFD2 03 /* set preverrout */
Eric Andersenc470f442003-07-28 09:56:35 +00001995
1996union node;
1997static void redirect(union node *, int);
1998static void popredir(int);
1999static void clearredir(int);
2000static int copyfd(int, int);
2001static int redirectsafe(union node *, int);
2002
2003/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2004
2005
2006#ifdef DEBUG
2007static void showtree(union node *);
2008static void trace(const char *, ...);
2009static void tracev(const char *, va_list);
2010static void trargs(char **);
2011static void trputc(int);
2012static void trputs(const char *);
2013static void opentrace(void);
2014#endif
2015
2016/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2017
2018
2019/* trap handler commands */
2020static char *trap[NSIG];
2021/* current value of signal */
2022static char sigmode[NSIG - 1];
2023/* indicates specified signal received */
2024static char gotsig[NSIG - 1];
2025
2026static void clear_traps(void);
2027static void setsignal(int);
2028static void ignoresig(int);
2029static void onsig(int);
2030static void dotrap(void);
2031static void setinteractive(int);
2032static void exitshell(void) __attribute__((__noreturn__));
2033static int decode_signal(const char *, int);
2034
2035/*
2036 * This routine is called when an error or an interrupt occurs in an
2037 * interactive shell and control is returned to the main command loop.
2038 */
2039
2040static void
2041reset(void)
2042{
2043 /* from eval.c: */
2044 {
2045 evalskip = 0;
2046 loopnest = 0;
2047 funcnest = 0;
2048 }
2049
2050 /* from input.c: */
2051 {
2052 parselleft = parsenleft = 0; /* clear input buffer */
2053 popallfiles();
2054 }
2055
2056 /* from parser.c: */
2057 {
2058 tokpushback = 0;
2059 checkkwd = 0;
2060 }
2061
2062 /* from redir.c: */
2063 {
2064 clearredir(0);
2065 }
2066
2067}
2068
2069#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00002070static struct alias *atab[ATABSIZE];
2071
Eric Andersenc470f442003-07-28 09:56:35 +00002072static void setalias(const char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002073static struct alias *freealias(struct alias *);
2074static struct alias **__lookupalias(const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00002075
Eric Andersenc470f442003-07-28 09:56:35 +00002076static void
2077setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00002078{
2079 struct alias *ap, **app;
2080
2081 app = __lookupalias(name);
2082 ap = *app;
2083 INTOFF;
2084 if (ap) {
2085 if (!(ap->flag & ALIASINUSE)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002086 ckfree(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00002087 }
Eric Andersenc470f442003-07-28 09:56:35 +00002088 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002089 ap->flag &= ~ALIASDEAD;
2090 } else {
2091 /* not found */
Eric Andersenc470f442003-07-28 09:56:35 +00002092 ap = ckmalloc(sizeof (struct alias));
2093 ap->name = savestr(name);
2094 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00002095 ap->flag = 0;
2096 ap->next = 0;
2097 *app = ap;
2098 }
2099 INTON;
2100}
2101
Eric Andersenc470f442003-07-28 09:56:35 +00002102static int
2103unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00002104{
Eric Andersencb57d552001-06-28 07:25:16 +00002105 struct alias **app;
2106
2107 app = __lookupalias(name);
2108
2109 if (*app) {
2110 INTOFF;
2111 *app = freealias(*app);
2112 INTON;
2113 return (0);
2114 }
2115
2116 return (1);
2117}
2118
Eric Andersenc470f442003-07-28 09:56:35 +00002119static void
2120rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00002121{
Eric Andersencb57d552001-06-28 07:25:16 +00002122 struct alias *ap, **app;
2123 int i;
2124
2125 INTOFF;
2126 for (i = 0; i < ATABSIZE; i++) {
2127 app = &atab[i];
2128 for (ap = *app; ap; ap = *app) {
2129 *app = freealias(*app);
2130 if (ap == *app) {
2131 app = &ap->next;
2132 }
2133 }
2134 }
2135 INTON;
2136}
2137
Eric Andersenc470f442003-07-28 09:56:35 +00002138static struct alias *
2139lookupalias(const char *name, int check)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002140{
Eric Andersenc470f442003-07-28 09:56:35 +00002141 struct alias *ap = *__lookupalias(name);
Eric Andersen2870d962001-07-02 17:27:21 +00002142
Eric Andersenc470f442003-07-28 09:56:35 +00002143 if (check && ap && (ap->flag & ALIASINUSE))
2144 return (NULL);
2145 return (ap);
Eric Andersen2870d962001-07-02 17:27:21 +00002146}
2147
Eric Andersencb57d552001-06-28 07:25:16 +00002148/*
2149 * TODO - sort output
2150 */
Eric Andersenc470f442003-07-28 09:56:35 +00002151static int
2152aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002153{
2154 char *n, *v;
2155 int ret = 0;
2156 struct alias *ap;
2157
2158 if (argc == 1) {
2159 int i;
2160
2161 for (i = 0; i < ATABSIZE; i++)
2162 for (ap = atab[i]; ap; ap = ap->next) {
2163 printalias(ap);
2164 }
2165 return (0);
2166 }
2167 while ((n = *++argv) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002168 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
Eric Andersencb57d552001-06-28 07:25:16 +00002169 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00002170 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00002171 ret = 1;
2172 } else
2173 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002174 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00002175 *v++ = '\0';
2176 setalias(n, v);
2177 }
2178 }
2179
2180 return (ret);
2181}
2182
Eric Andersenc470f442003-07-28 09:56:35 +00002183static int
2184unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002185{
2186 int i;
2187
2188 while ((i = nextopt("a")) != '\0') {
2189 if (i == 'a') {
2190 rmaliases();
2191 return (0);
2192 }
2193 }
2194 for (i = 0; *argptr; argptr++) {
2195 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002196 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00002197 i = 1;
2198 }
2199 }
2200
2201 return (i);
2202}
2203
Eric Andersenc470f442003-07-28 09:56:35 +00002204static struct alias *
2205freealias(struct alias *ap) {
Eric Andersencb57d552001-06-28 07:25:16 +00002206 struct alias *next;
2207
2208 if (ap->flag & ALIASINUSE) {
2209 ap->flag |= ALIASDEAD;
2210 return ap;
2211 }
2212
2213 next = ap->next;
Eric Andersenc470f442003-07-28 09:56:35 +00002214 ckfree(ap->name);
2215 ckfree(ap->val);
2216 ckfree(ap);
Eric Andersencb57d552001-06-28 07:25:16 +00002217 return next;
2218}
2219
Eric Andersenc470f442003-07-28 09:56:35 +00002220static void
2221printalias(const struct alias *ap) {
2222 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2223}
Eric Andersencb57d552001-06-28 07:25:16 +00002224
Eric Andersenc470f442003-07-28 09:56:35 +00002225static struct alias **
2226__lookupalias(const char *name) {
2227 unsigned int hashval;
2228 struct alias **app;
2229 const char *p;
2230 unsigned int ch;
2231
2232 p = name;
2233
2234 ch = (unsigned char)*p;
2235 hashval = ch << 4;
2236 while (ch) {
2237 hashval += ch;
2238 ch = (unsigned char)*++p;
2239 }
2240 app = &atab[hashval % ATABSIZE];
Eric Andersencb57d552001-06-28 07:25:16 +00002241
2242 for (; *app; app = &(*app)->next) {
2243 if (equal(name, (*app)->name)) {
2244 break;
2245 }
2246 }
2247
2248 return app;
2249}
Eric Andersenc470f442003-07-28 09:56:35 +00002250#endif /* CONFIG_ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00002251
Eric Andersencb57d552001-06-28 07:25:16 +00002252
Eric Andersenc470f442003-07-28 09:56:35 +00002253/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
Eric Andersen2870d962001-07-02 17:27:21 +00002254
Eric Andersencb57d552001-06-28 07:25:16 +00002255/*
Eric Andersenc470f442003-07-28 09:56:35 +00002256 * The cd and pwd commands.
Eric Andersencb57d552001-06-28 07:25:16 +00002257 */
2258
Eric Andersenc470f442003-07-28 09:56:35 +00002259#define CD_PHYSICAL 1
2260#define CD_PRINT 2
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002261
Eric Andersenc470f442003-07-28 09:56:35 +00002262static int docd(const char *, int);
2263static int cdopt(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002264
Eric Andersenc470f442003-07-28 09:56:35 +00002265static char *curdir = nullstr; /* current working directory */
2266static char *physdir = nullstr; /* physical working directory */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002267
Eric Andersenc470f442003-07-28 09:56:35 +00002268static int
2269cdopt(void)
2270{
2271 int flags = 0;
2272 int i, j;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002273
Eric Andersenc470f442003-07-28 09:56:35 +00002274 j = 'L';
2275 while ((i = nextopt("LP"))) {
2276 if (i != j) {
2277 flags ^= CD_PHYSICAL;
2278 j = i;
2279 }
2280 }
Eric Andersencb57d552001-06-28 07:25:16 +00002281
Eric Andersenc470f442003-07-28 09:56:35 +00002282 return flags;
2283}
Eric Andersen2870d962001-07-02 17:27:21 +00002284
Eric Andersenc470f442003-07-28 09:56:35 +00002285static int
2286cdcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002287{
2288 const char *dest;
2289 const char *path;
Eric Andersenc470f442003-07-28 09:56:35 +00002290 const char *p;
2291 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00002292 struct stat statb;
Eric Andersenc470f442003-07-28 09:56:35 +00002293 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +00002294
Eric Andersenc470f442003-07-28 09:56:35 +00002295 flags = cdopt();
2296 dest = *argptr;
2297 if (!dest)
2298 dest = bltinlookup(homestr);
2299 else if (dest[0] == '-' && dest[1] == '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00002300 dest = bltinlookup("OLDPWD");
Eric Andersenc470f442003-07-28 09:56:35 +00002301 flags |= CD_PRINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002302 }
Eric Andersenc470f442003-07-28 09:56:35 +00002303 if (!dest)
2304 dest = nullstr;
2305 if (*dest == '/')
2306 goto step7;
2307 if (*dest == '.') {
2308 c = dest[1];
2309dotdot:
2310 switch (c) {
2311 case '\0':
2312 case '/':
2313 goto step6;
2314 case '.':
2315 c = dest[2];
2316 if (c != '.')
2317 goto dotdot;
2318 }
2319 }
2320 if (!*dest)
2321 dest = ".";
2322 if (!(path = bltinlookup("CDPATH"))) {
2323step6:
2324step7:
2325 p = dest;
2326 goto docd;
2327 }
2328 do {
2329 c = *path;
2330 p = padvance(&path, dest);
Eric Andersencb57d552001-06-28 07:25:16 +00002331 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
Eric Andersenc470f442003-07-28 09:56:35 +00002332 if (c && c != ':')
2333 flags |= CD_PRINT;
2334docd:
2335 if (!docd(p, flags))
2336 goto out;
2337 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002338 }
Eric Andersenc470f442003-07-28 09:56:35 +00002339 } while (path);
Eric Andersencb57d552001-06-28 07:25:16 +00002340 error("can't cd to %s", dest);
2341 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00002342out:
2343 if (flags & CD_PRINT)
2344 out1fmt(snlfmt, curdir);
2345 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00002346}
2347
2348
2349/*
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002350 * Update curdir (the name of the current directory) in response to a
Eric Andersenc470f442003-07-28 09:56:35 +00002351 * cd command.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002352 */
2353
Eric Andersenc470f442003-07-28 09:56:35 +00002354static inline const char *
2355updatepwd(const char *dir)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002356{
Eric Andersenc470f442003-07-28 09:56:35 +00002357 char *new;
2358 char *p;
2359 char *cdcomppath;
2360 const char *lim;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002361
Eric Andersenc470f442003-07-28 09:56:35 +00002362 cdcomppath = sstrdup(dir);
2363 STARTSTACKSTR(new);
2364 if (*dir != '/') {
2365 if (curdir == nullstr)
2366 return 0;
2367 new = stputs(curdir, new);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002368 }
Eric Andersenc470f442003-07-28 09:56:35 +00002369 new = makestrspace(strlen(dir) + 2, new);
2370 lim = stackblock() + 1;
2371 if (*dir != '/') {
2372 if (new[-1] != '/')
2373 USTPUTC('/', new);
2374 if (new > lim && *lim == '/')
2375 lim++;
2376 } else {
2377 USTPUTC('/', new);
2378 cdcomppath++;
2379 if (dir[1] == '/' && dir[2] != '/') {
2380 USTPUTC('/', new);
2381 cdcomppath++;
2382 lim++;
2383 }
2384 }
2385 p = strtok(cdcomppath, "/");
2386 while (p) {
2387 switch(*p) {
2388 case '.':
2389 if (p[1] == '.' && p[2] == '\0') {
2390 while (new > lim) {
2391 STUNPUTC(new);
2392 if (new[-1] == '/')
2393 break;
2394 }
2395 break;
2396 } else if (p[1] == '\0')
2397 break;
2398 /* fall through */
2399 default:
2400 new = stputs(p, new);
2401 USTPUTC('/', new);
2402 }
2403 p = strtok(0, "/");
2404 }
2405 if (new > lim)
2406 STUNPUTC(new);
2407 *new = 0;
2408 return stackblock();
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002409}
2410
2411/*
Eric Andersenc470f442003-07-28 09:56:35 +00002412 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2413 * know that the current directory has changed.
Eric Andersencb57d552001-06-28 07:25:16 +00002414 */
2415
Eric Andersenc470f442003-07-28 09:56:35 +00002416static int
2417docd(const char *dest, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002418{
Eric Andersenc470f442003-07-28 09:56:35 +00002419 const char *dir = 0;
2420 int err;
2421
2422 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2423
Eric Andersencb57d552001-06-28 07:25:16 +00002424 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002425 if (!(flags & CD_PHYSICAL)) {
2426 dir = updatepwd(dest);
2427 if (dir)
2428 dest = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002429 }
Eric Andersenc470f442003-07-28 09:56:35 +00002430 err = chdir(dest);
2431 if (err)
2432 goto out;
2433 setpwd(dir, 1);
2434 hashcd();
2435out:
Eric Andersencb57d552001-06-28 07:25:16 +00002436 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002437 return err;
2438}
2439
2440/*
2441 * Find out what the current directory is. If we already know the current
2442 * directory, this routine returns immediately.
2443 */
2444static inline char *
2445getpwd(void)
2446{
2447 char *dir = getcwd(0, 0);
2448 return dir ? dir : nullstr;
2449}
2450
2451static int
2452pwdcmd(int argc, char **argv)
2453{
2454 int flags;
2455 const char *dir = curdir;
2456
2457 flags = cdopt();
2458 if (flags) {
2459 if (physdir == nullstr)
2460 setpwd(dir, 0);
2461 dir = physdir;
2462 }
2463 out1fmt(snlfmt, dir);
Eric Andersencb57d552001-06-28 07:25:16 +00002464 return 0;
2465}
2466
Eric Andersenc470f442003-07-28 09:56:35 +00002467static void
2468setpwd(const char *val, int setold)
Eric Andersencb57d552001-06-28 07:25:16 +00002469{
Eric Andersenc470f442003-07-28 09:56:35 +00002470 char *oldcur, *dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002471
Eric Andersenc470f442003-07-28 09:56:35 +00002472 oldcur = dir = curdir;
Eric Andersena3483db2001-10-24 08:01:06 +00002473
Eric Andersencb57d552001-06-28 07:25:16 +00002474 if (setold) {
Eric Andersenc470f442003-07-28 09:56:35 +00002475 setvar("OLDPWD", oldcur, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002476 }
2477 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00002478 if (physdir != nullstr) {
2479 if (physdir != oldcur)
2480 free(physdir);
2481 physdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002482 }
Eric Andersenc470f442003-07-28 09:56:35 +00002483 if (oldcur == val || !val) {
2484 char *s = getpwd();
2485 physdir = s;
2486 if (!val)
2487 dir = s;
2488 } else
2489 dir = savestr(val);
2490 if (oldcur != dir && oldcur != nullstr) {
2491 free(oldcur);
2492 }
2493 curdir = dir;
Eric Andersencb57d552001-06-28 07:25:16 +00002494 INTON;
Eric Andersenc470f442003-07-28 09:56:35 +00002495 setvar("PWD", dir, VEXPORT);
Eric Andersencb57d552001-06-28 07:25:16 +00002496}
2497
Eric Andersenc470f442003-07-28 09:56:35 +00002498/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2499
Eric Andersencb57d552001-06-28 07:25:16 +00002500/*
2501 * Errors and exceptions.
2502 */
2503
2504/*
2505 * Code to handle exceptions in C.
2506 */
2507
Eric Andersen2870d962001-07-02 17:27:21 +00002508
Eric Andersencb57d552001-06-28 07:25:16 +00002509
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002510static void exverror(int, const char *, va_list)
Eric Andersenc470f442003-07-28 09:56:35 +00002511 __attribute__((__noreturn__));
Eric Andersencb57d552001-06-28 07:25:16 +00002512
2513/*
2514 * Called to raise an exception. Since C doesn't include exceptions, we
2515 * just do a longjmp to the exception handler. The type of exception is
2516 * stored in the global variable "exception".
2517 */
2518
Eric Andersenc470f442003-07-28 09:56:35 +00002519static void
2520exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002521{
2522#ifdef DEBUG
2523 if (handler == NULL)
2524 abort();
2525#endif
Eric Andersenc470f442003-07-28 09:56:35 +00002526 INTOFF;
2527
Eric Andersencb57d552001-06-28 07:25:16 +00002528 exception = e;
2529 longjmp(handler->loc, 1);
2530}
2531
2532
2533/*
2534 * Called from trap.c when a SIGINT is received. (If the user specifies
2535 * that SIGINT is to be trapped or ignored using the trap builtin, then
2536 * this routine is not called.) Suppressint is nonzero when interrupts
Eric Andersenc470f442003-07-28 09:56:35 +00002537 * are held using the INTOFF macro. (The test for iflag is just
2538 * defensive programming.)
Eric Andersencb57d552001-06-28 07:25:16 +00002539 */
2540
Eric Andersenc470f442003-07-28 09:56:35 +00002541static void
2542onint(void) {
2543 int i;
Eric Andersencb57d552001-06-28 07:25:16 +00002544
Eric Andersencb57d552001-06-28 07:25:16 +00002545 intpending = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00002546 sigsetmask(0);
2547 i = EXSIG;
2548 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2549 if (!(rootshell && iflag)) {
2550 signal(SIGINT, SIG_DFL);
2551 raise(SIGINT);
2552 }
2553 i = EXINT;
Eric Andersencb57d552001-06-28 07:25:16 +00002554 }
Eric Andersenc470f442003-07-28 09:56:35 +00002555 exraise(i);
Eric Andersencb57d552001-06-28 07:25:16 +00002556 /* NOTREACHED */
2557}
2558
Eric Andersenc470f442003-07-28 09:56:35 +00002559static void
2560exvwarning(const char *msg, va_list ap)
2561{
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002562 FILE *errs;
Eric Andersencb57d552001-06-28 07:25:16 +00002563
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00002564 errs = stderr;
2565 fprintf(errs, "%s: ", arg0);
2566 if (commandname) {
2567 const char *fmt = (!iflag || parsefile->fd) ?
2568 "%s: %d: " : "%s: ";
2569 fprintf(errs, fmt, commandname, startlinno);
2570 }
2571 vfprintf(errs, msg, ap);
2572 outcslow('\n', errs);
Eric Andersenc470f442003-07-28 09:56:35 +00002573}
Eric Andersen2870d962001-07-02 17:27:21 +00002574
Eric Andersencb57d552001-06-28 07:25:16 +00002575/*
Eric Andersenc470f442003-07-28 09:56:35 +00002576 * Exverror is called to raise the error exception. If the second argument
Eric Andersencb57d552001-06-28 07:25:16 +00002577 * is not NULL then error prints an error message using printf style
2578 * formatting. It then raises the error exception.
2579 */
Eric Andersenc470f442003-07-28 09:56:35 +00002580static void
2581exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002582{
Eric Andersencb57d552001-06-28 07:25:16 +00002583#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +00002584 if (msg) {
Eric Andersenc470f442003-07-28 09:56:35 +00002585 TRACE(("exverror(%d, \"", cond));
2586 TRACEV((msg, ap));
2587 TRACE(("\") pid=%d\n", getpid()));
2588 } else
2589 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2590 if (msg)
2591#endif
2592 exvwarning(msg, ap);
2593
2594 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00002595 exraise(cond);
2596 /* NOTREACHED */
2597}
2598
2599
Eric Andersenc470f442003-07-28 09:56:35 +00002600static void
2601error(const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002602{
Eric Andersencb57d552001-06-28 07:25:16 +00002603 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002604
Eric Andersencb57d552001-06-28 07:25:16 +00002605 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002606 exverror(EXERROR, msg, ap);
2607 /* NOTREACHED */
2608 va_end(ap);
2609}
2610
2611
Eric Andersenc470f442003-07-28 09:56:35 +00002612static void
2613exerror(int cond, const char *msg, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00002614{
Eric Andersencb57d552001-06-28 07:25:16 +00002615 va_list ap;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002616
Eric Andersencb57d552001-06-28 07:25:16 +00002617 va_start(ap, msg);
Eric Andersencb57d552001-06-28 07:25:16 +00002618 exverror(cond, msg, ap);
2619 /* NOTREACHED */
2620 va_end(ap);
2621}
2622
Eric Andersencb57d552001-06-28 07:25:16 +00002623/*
Eric Andersenc470f442003-07-28 09:56:35 +00002624 * error/warning routines for external builtins
Eric Andersencb57d552001-06-28 07:25:16 +00002625 */
2626
Eric Andersenc470f442003-07-28 09:56:35 +00002627static void
2628sh_warnx(const char *fmt, ...)
2629{
2630 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002631
Eric Andersenc470f442003-07-28 09:56:35 +00002632 va_start(ap, fmt);
2633 exvwarning(fmt, ap);
2634 va_end(ap);
2635}
Eric Andersen2870d962001-07-02 17:27:21 +00002636
Eric Andersencb57d552001-06-28 07:25:16 +00002637
2638/*
2639 * Return a string describing an error. The returned string may be a
2640 * pointer to a static buffer that will be overwritten on the next call.
2641 * Action describes the operation that got the error.
2642 */
2643
Eric Andersenc470f442003-07-28 09:56:35 +00002644static const char *
2645errmsg(int e, const char *em)
Eric Andersencb57d552001-06-28 07:25:16 +00002646{
Eric Andersenc470f442003-07-28 09:56:35 +00002647 if(e == ENOENT || e == ENOTDIR) {
Eric Andersencb57d552001-06-28 07:25:16 +00002648
Eric Andersenc470f442003-07-28 09:56:35 +00002649 return em;
Eric Andersencb57d552001-06-28 07:25:16 +00002650 }
Eric Andersenc470f442003-07-28 09:56:35 +00002651 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002652}
2653
2654
Eric Andersenc470f442003-07-28 09:56:35 +00002655/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2656
2657/*
2658 * Evaluate a command.
2659 */
Eric Andersencb57d552001-06-28 07:25:16 +00002660
2661/* flags in argument to evaltree */
Eric Andersenc470f442003-07-28 09:56:35 +00002662#define EV_EXIT 01 /* exit after evaluating tree */
2663#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2664#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002665
2666
Eric Andersenc470f442003-07-28 09:56:35 +00002667static void evalloop(union node *, int);
2668static void evalfor(union node *, int);
2669static void evalcase(union node *, int);
2670static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002671static void expredir(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002672static void evalpipe(union node *, int);
2673static void evalcommand(union node *, int);
2674static int evalbltin(const struct builtincmd *, int, char **);
2675static int evalfun(struct funcnode *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002676static void prehash(union node *);
Eric Andersenc470f442003-07-28 09:56:35 +00002677static int bltincmd(int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00002678
Eric Andersenc470f442003-07-28 09:56:35 +00002679
2680static const struct builtincmd bltin = {
2681 "\0\0", bltincmd
2682};
2683
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002684
Eric Andersencb57d552001-06-28 07:25:16 +00002685/*
2686 * Called to reset things after an exception.
2687 */
2688
Eric Andersencb57d552001-06-28 07:25:16 +00002689/*
Eric Andersenaff114c2004-04-14 17:51:38 +00002690 * The eval command.
Eric Andersencb57d552001-06-28 07:25:16 +00002691 */
2692
Eric Andersenc470f442003-07-28 09:56:35 +00002693static int
2694evalcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00002695{
Eric Andersen2870d962001-07-02 17:27:21 +00002696 char *p;
2697 char *concat;
2698 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002699
Eric Andersen2870d962001-07-02 17:27:21 +00002700 if (argc > 1) {
2701 p = argv[1];
2702 if (argc > 2) {
2703 STARTSTACKSTR(concat);
2704 ap = argv + 2;
2705 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002706 concat = stputs(p, concat);
Eric Andersen2870d962001-07-02 17:27:21 +00002707 if ((p = *ap++) == NULL)
2708 break;
2709 STPUTC(' ', concat);
2710 }
2711 STPUTC('\0', concat);
2712 p = grabstackstr(concat);
2713 }
Glenn L McGrath76620622004-01-13 10:19:37 +00002714 evalstring(p);
Eric Andersen2870d962001-07-02 17:27:21 +00002715 }
2716 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002717}
2718
Eric Andersenc470f442003-07-28 09:56:35 +00002719
Eric Andersencb57d552001-06-28 07:25:16 +00002720/*
2721 * Execute a command or commands contained in a string.
2722 */
2723
Eric Andersenc470f442003-07-28 09:56:35 +00002724static void
Glenn L McGrath76620622004-01-13 10:19:37 +00002725evalstring(char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00002726{
Eric Andersencb57d552001-06-28 07:25:16 +00002727 union node *n;
2728 struct stackmark smark;
2729
2730 setstackmark(&smark);
2731 setinputstring(s);
Eric Andersenc470f442003-07-28 09:56:35 +00002732
Eric Andersencb57d552001-06-28 07:25:16 +00002733 while ((n = parsecmd(0)) != NEOF) {
Glenn L McGrath76620622004-01-13 10:19:37 +00002734 evaltree(n, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00002735 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00002736 if (evalskip)
2737 break;
Eric Andersencb57d552001-06-28 07:25:16 +00002738 }
2739 popfile();
2740 popstackmark(&smark);
2741}
2742
Eric Andersenc470f442003-07-28 09:56:35 +00002743
Eric Andersen62483552001-07-10 06:09:16 +00002744
2745/*
Eric Andersenc470f442003-07-28 09:56:35 +00002746 * Evaluate a parse tree. The value is left in the global variable
2747 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00002748 */
2749
Eric Andersenc470f442003-07-28 09:56:35 +00002750static void
2751evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00002752{
Eric Andersenc470f442003-07-28 09:56:35 +00002753 int checkexit = 0;
2754 void (*evalfn)(union node *, int);
2755 unsigned isor;
2756 int status;
2757 if (n == NULL) {
2758 TRACE(("evaltree(NULL) called\n"));
2759 goto out;
Eric Andersen62483552001-07-10 06:09:16 +00002760 }
Eric Andersenc470f442003-07-28 09:56:35 +00002761 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2762 getpid(), n, n->type, flags));
2763 switch (n->type) {
2764 default:
2765#ifdef DEBUG
2766 out1fmt("Node type = %d\n", n->type);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00002767 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00002768 break;
2769#endif
2770 case NNOT:
2771 evaltree(n->nnot.com, EV_TESTED);
2772 status = !exitstatus;
2773 goto setstatus;
2774 case NREDIR:
2775 expredir(n->nredir.redirect);
2776 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2777 if (!status) {
2778 evaltree(n->nredir.n, flags & EV_TESTED);
2779 status = exitstatus;
2780 }
2781 popredir(0);
2782 goto setstatus;
2783 case NCMD:
2784 evalfn = evalcommand;
2785checkexit:
2786 if (eflag && !(flags & EV_TESTED))
2787 checkexit = ~0;
2788 goto calleval;
2789 case NFOR:
2790 evalfn = evalfor;
2791 goto calleval;
2792 case NWHILE:
2793 case NUNTIL:
2794 evalfn = evalloop;
2795 goto calleval;
2796 case NSUBSHELL:
2797 case NBACKGND:
2798 evalfn = evalsubshell;
2799 goto calleval;
2800 case NPIPE:
2801 evalfn = evalpipe;
2802 goto checkexit;
2803 case NCASE:
2804 evalfn = evalcase;
2805 goto calleval;
2806 case NAND:
2807 case NOR:
2808 case NSEMI:
2809#if NAND + 1 != NOR
2810#error NAND + 1 != NOR
2811#endif
2812#if NOR + 1 != NSEMI
2813#error NOR + 1 != NSEMI
2814#endif
2815 isor = n->type - NAND;
2816 evaltree(
2817 n->nbinary.ch1,
2818 (flags | ((isor >> 1) - 1)) & EV_TESTED
2819 );
2820 if (!exitstatus == isor)
2821 break;
2822 if (!evalskip) {
2823 n = n->nbinary.ch2;
2824evaln:
2825 evalfn = evaltree;
2826calleval:
2827 evalfn(n, flags);
2828 break;
2829 }
2830 break;
2831 case NIF:
2832 evaltree(n->nif.test, EV_TESTED);
2833 if (evalskip)
2834 break;
2835 if (exitstatus == 0) {
2836 n = n->nif.ifpart;
2837 goto evaln;
2838 } else if (n->nif.elsepart) {
2839 n = n->nif.elsepart;
2840 goto evaln;
2841 }
2842 goto success;
2843 case NDEFUN:
2844 defun(n->narg.text, n->narg.next);
2845success:
2846 status = 0;
2847setstatus:
2848 exitstatus = status;
2849 break;
2850 }
2851out:
2852 if (pendingsigs)
2853 dotrap();
2854 if (flags & EV_EXIT || checkexit & exitstatus)
2855 exraise(EXEXIT);
Eric Andersen62483552001-07-10 06:09:16 +00002856}
2857
Eric Andersenc470f442003-07-28 09:56:35 +00002858
2859#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2860static
2861#endif
2862void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2863
2864
2865static void
2866evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002867{
2868 int status;
2869
2870 loopnest++;
2871 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002872 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00002873 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00002874 int i;
2875
Eric Andersencb57d552001-06-28 07:25:16 +00002876 evaltree(n->nbinary.ch1, EV_TESTED);
2877 if (evalskip) {
Eric Andersenc470f442003-07-28 09:56:35 +00002878skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002879 evalskip = 0;
2880 continue;
2881 }
2882 if (evalskip == SKIPBREAK && --skipcount <= 0)
2883 evalskip = 0;
2884 break;
2885 }
Eric Andersenc470f442003-07-28 09:56:35 +00002886 i = exitstatus;
2887 if (n->type != NWHILE)
2888 i = !i;
2889 if (i != 0)
2890 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002891 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002892 status = exitstatus;
2893 if (evalskip)
2894 goto skipping;
2895 }
2896 loopnest--;
2897 exitstatus = status;
2898}
2899
Eric Andersenc470f442003-07-28 09:56:35 +00002900
2901
2902static void
2903evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002904{
2905 struct arglist arglist;
2906 union node *argp;
2907 struct strlist *sp;
2908 struct stackmark smark;
2909
2910 setstackmark(&smark);
2911 arglist.lastp = &arglist.list;
Eric Andersenc470f442003-07-28 09:56:35 +00002912 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002913 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00002914 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00002915 if (evalskip)
2916 goto out;
2917 }
2918 *arglist.lastp = NULL;
2919
2920 exitstatus = 0;
2921 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002922 flags &= EV_TESTED;
Eric Andersenc470f442003-07-28 09:56:35 +00002923 for (sp = arglist.list ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002924 setvar(n->nfor.var, sp->text, 0);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00002925 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002926 if (evalskip) {
2927 if (evalskip == SKIPCONT && --skipcount <= 0) {
2928 evalskip = 0;
2929 continue;
2930 }
2931 if (evalskip == SKIPBREAK && --skipcount <= 0)
2932 evalskip = 0;
2933 break;
2934 }
2935 }
2936 loopnest--;
Eric Andersenc470f442003-07-28 09:56:35 +00002937out:
Eric Andersencb57d552001-06-28 07:25:16 +00002938 popstackmark(&smark);
2939}
2940
Eric Andersenc470f442003-07-28 09:56:35 +00002941
2942
2943static void
2944evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002945{
2946 union node *cp;
2947 union node *patp;
2948 struct arglist arglist;
2949 struct stackmark smark;
2950
2951 setstackmark(&smark);
2952 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00002953 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00002954 exitstatus = 0;
2955 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2956 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00002957 if (casematch(patp, arglist.list->text)) {
2958 if (evalskip == 0) {
2959 evaltree(cp->nclist.body, flags);
2960 }
2961 goto out;
2962 }
2963 }
2964 }
Eric Andersenc470f442003-07-28 09:56:35 +00002965out:
Eric Andersencb57d552001-06-28 07:25:16 +00002966 popstackmark(&smark);
2967}
2968
Eric Andersenc470f442003-07-28 09:56:35 +00002969
2970
2971/*
2972 * Kick off a subshell to evaluate a tree.
2973 */
2974
2975static void
2976evalsubshell(union node *n, int flags)
2977{
2978 struct job *jp;
2979 int backgnd = (n->type == NBACKGND);
2980 int status;
2981
2982 expredir(n->nredir.redirect);
2983 if (!backgnd && flags & EV_EXIT && !trap[0])
2984 goto nofork;
2985 INTOFF;
2986 jp = makejob(n, 1);
2987 if (forkshell(jp, n, backgnd) == 0) {
2988 INTON;
2989 flags |= EV_EXIT;
2990 if (backgnd)
2991 flags &=~ EV_TESTED;
2992nofork:
2993 redirect(n->nredir.redirect, 0);
2994 evaltreenr(n->nredir.n, flags);
2995 /* never returns */
2996 }
2997 status = 0;
2998 if (! backgnd)
2999 status = waitforjob(jp);
3000 exitstatus = status;
3001 INTON;
3002}
3003
3004
3005
3006/*
3007 * Compute the names of the files in a redirection list.
3008 */
3009
3010static void
3011expredir(union node *n)
3012{
3013 union node *redir;
3014
3015 for (redir = n ; redir ; redir = redir->nfile.next) {
3016 struct arglist fn;
3017 fn.lastp = &fn.list;
3018 switch (redir->type) {
3019 case NFROMTO:
3020 case NFROM:
3021 case NTO:
3022 case NCLOBBER:
3023 case NAPPEND:
3024 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3025 redir->nfile.expfname = fn.list->text;
3026 break;
3027 case NFROMFD:
3028 case NTOFD:
3029 if (redir->ndup.vname) {
3030 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3031 fixredir(redir, fn.list->text, 1);
3032 }
3033 break;
3034 }
3035 }
3036}
3037
3038
3039
Eric Andersencb57d552001-06-28 07:25:16 +00003040/*
Eric Andersencb57d552001-06-28 07:25:16 +00003041 * Evaluate a pipeline. All the processes in the pipeline are children
3042 * of the process creating the pipeline. (This differs from some versions
3043 * of the shell, which make the last process in a pipeline the parent
3044 * of all the rest.)
3045 */
3046
Eric Andersenc470f442003-07-28 09:56:35 +00003047static void
3048evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00003049{
3050 struct job *jp;
3051 struct nodelist *lp;
3052 int pipelen;
3053 int prevfd;
3054 int pip[2];
3055
Eric Andersenc470f442003-07-28 09:56:35 +00003056 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00003057 pipelen = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003058 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00003059 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003060 flags |= EV_EXIT;
Eric Andersencb57d552001-06-28 07:25:16 +00003061 INTOFF;
3062 jp = makejob(n, pipelen);
3063 prevfd = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003064 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003065 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00003066 pip[1] = -1;
3067 if (lp->next) {
3068 if (pipe(pip) < 0) {
3069 close(prevfd);
3070 error("Pipe call failed");
3071 }
3072 }
3073 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3074 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003075 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003076 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003077 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003078 if (prevfd > 0) {
3079 dup2(prevfd, 0);
3080 close(prevfd);
3081 }
3082 if (pip[1] > 1) {
3083 dup2(pip[1], 1);
3084 close(pip[1]);
3085 }
Eric Andersenc470f442003-07-28 09:56:35 +00003086 evaltreenr(lp->n, flags);
3087 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00003088 }
3089 if (prevfd >= 0)
3090 close(prevfd);
3091 prevfd = pip[0];
3092 close(pip[1]);
3093 }
Eric Andersencb57d552001-06-28 07:25:16 +00003094 if (n->npipe.backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003095 exitstatus = waitforjob(jp);
3096 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00003097 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003098 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003099}
3100
Eric Andersen62483552001-07-10 06:09:16 +00003101
3102
3103/*
3104 * Execute a command inside back quotes. If it's a builtin command, we
3105 * want to save its output in a block obtained from malloc. Otherwise
3106 * we fork off a subprocess and get the output of the command via a pipe.
3107 * Should be called with interrupts off.
3108 */
3109
Eric Andersenc470f442003-07-28 09:56:35 +00003110static void
3111evalbackcmd(union node *n, struct backcmd *result)
Eric Andersen62483552001-07-10 06:09:16 +00003112{
Eric Andersenc470f442003-07-28 09:56:35 +00003113 int saveherefd;
Eric Andersen62483552001-07-10 06:09:16 +00003114
Eric Andersen62483552001-07-10 06:09:16 +00003115 result->fd = -1;
3116 result->buf = NULL;
3117 result->nleft = 0;
3118 result->jp = NULL;
3119 if (n == NULL) {
Eric Andersen62483552001-07-10 06:09:16 +00003120 goto out;
3121 }
Eric Andersenc470f442003-07-28 09:56:35 +00003122
3123 saveherefd = herefd;
3124 herefd = -1;
3125
3126 {
3127 int pip[2];
3128 struct job *jp;
3129
3130 if (pipe(pip) < 0)
3131 error("Pipe call failed");
3132 jp = makejob(n, 1);
3133 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3134 FORCEINTON;
3135 close(pip[0]);
3136 if (pip[1] != 1) {
3137 close(1);
3138 copyfd(pip[1], 1);
3139 close(pip[1]);
3140 }
3141 eflag = 0;
3142 evaltreenr(n, EV_EXIT);
3143 /* NOTREACHED */
Eric Andersen62483552001-07-10 06:09:16 +00003144 }
Eric Andersenc470f442003-07-28 09:56:35 +00003145 close(pip[1]);
3146 result->fd = pip[0];
3147 result->jp = jp;
Eric Andersen62483552001-07-10 06:09:16 +00003148 }
Eric Andersenc470f442003-07-28 09:56:35 +00003149 herefd = saveherefd;
3150out:
Eric Andersen62483552001-07-10 06:09:16 +00003151 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
Eric Andersenc470f442003-07-28 09:56:35 +00003152 result->fd, result->buf, result->nleft, result->jp));
Eric Andersen62483552001-07-10 06:09:16 +00003153}
3154
Eric Andersenc470f442003-07-28 09:56:35 +00003155#ifdef CONFIG_ASH_CMDCMD
3156static inline char **
3157parse_command_args(char **argv, const char **path)
3158{
3159 char *cp, c;
3160
3161 for (;;) {
3162 cp = *++argv;
3163 if (!cp)
3164 return 0;
3165 if (*cp++ != '-')
3166 break;
3167 if (!(c = *cp++))
3168 break;
3169 if (c == '-' && !*cp) {
3170 argv++;
3171 break;
3172 }
3173 do {
3174 switch (c) {
3175 case 'p':
3176 *path = defpath;
3177 break;
3178 default:
3179 /* run 'typecmd' for other options */
3180 return 0;
3181 }
3182 } while ((c = *cp++));
3183 }
3184 return argv;
3185}
3186#endif
3187
Paul Foxc3850c82005-07-20 18:23:39 +00003188static inline int
3189isassignment(const char *p)
3190{
3191 const char *q = endofname(p);
3192 if (p == q)
3193 return 0;
3194 return *q == '=';
3195}
Eric Andersen62483552001-07-10 06:09:16 +00003196
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003197#ifdef CONFIG_ASH_EXPAND_PRMT
3198static const char *expandstr(const char *ps);
3199#else
3200#define expandstr(s) s
3201#endif
3202
Eric Andersen62483552001-07-10 06:09:16 +00003203/*
3204 * Execute a simple command.
3205 */
Eric Andersencb57d552001-06-28 07:25:16 +00003206
Eric Andersenc470f442003-07-28 09:56:35 +00003207static void
3208evalcommand(union node *cmd, int flags)
3209{
3210 struct stackmark smark;
3211 union node *argp;
3212 struct arglist arglist;
3213 struct arglist varlist;
3214 char **argv;
3215 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003216 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00003217 struct cmdentry cmdentry;
3218 struct job *jp;
3219 char *lastarg;
3220 const char *path;
3221 int spclbltin;
3222 int cmd_is_exec;
3223 int status;
3224 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00003225 struct builtincmd *bcmd;
3226 int pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003227
3228 /* First expand the arguments. */
3229 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3230 setstackmark(&smark);
3231 back_exitstatus = 0;
3232
3233 cmdentry.cmdtype = CMDBUILTIN;
3234 cmdentry.u.cmd = &bltin;
3235 varlist.lastp = &varlist.list;
3236 *varlist.lastp = NULL;
3237 arglist.lastp = &arglist.list;
3238 *arglist.lastp = NULL;
3239
3240 argc = 0;
Paul Foxc3850c82005-07-20 18:23:39 +00003241 if (cmd->ncmd.args)
3242 {
3243 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3244 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3245 }
3246
Eric Andersenc470f442003-07-28 09:56:35 +00003247 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3248 struct strlist **spp;
3249
3250 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003251 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00003252 expandarg(argp, &arglist, EXP_VARTILDE);
3253 else
3254 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3255
Eric Andersenc470f442003-07-28 09:56:35 +00003256 for (sp = *spp; sp; sp = sp->next)
3257 argc++;
3258 }
3259
3260 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3261 for (sp = arglist.list ; sp ; sp = sp->next) {
3262 TRACE(("evalcommand arg: %s\n", sp->text));
3263 *nargv++ = sp->text;
3264 }
3265 *nargv = NULL;
3266
3267 lastarg = NULL;
3268 if (iflag && funcnest == 0 && argc > 0)
3269 lastarg = nargv[-1];
3270
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003271 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00003272 expredir(cmd->ncmd.redirect);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003273 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00003274
3275 path = vpath.text;
3276 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3277 struct strlist **spp;
3278 char *p;
3279
3280 spp = varlist.lastp;
3281 expandarg(argp, &varlist, EXP_VARTILDE);
3282
3283 /*
3284 * Modify the command lookup path, if a PATH= assignment
3285 * is present
3286 */
3287 p = (*spp)->text;
3288 if (varequal(p, path))
3289 path = p;
3290 }
3291
3292 /* Print the command if xflag is set. */
3293 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003294 int n;
3295 const char *p = " %s";
Eric Andersenc470f442003-07-28 09:56:35 +00003296
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003297 p++;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00003298 dprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003299
3300 sp = varlist.list;
3301 for(n = 0; n < 2; n++) {
3302 while (sp) {
3303 dprintf(preverrout_fd, p, sp->text);
3304 sp = sp->next;
3305 if(*p == '%') {
3306 p--;
3307 }
3308 }
3309 sp = arglist.list;
3310 }
Eric Andersen16767e22004-03-16 05:14:10 +00003311 bb_full_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00003312 }
3313
3314 cmd_is_exec = 0;
3315 spclbltin = -1;
3316
3317 /* Now locate the command. */
3318 if (argc) {
3319 const char *oldpath;
3320 int cmd_flag = DO_ERR;
3321
3322 path += 5;
3323 oldpath = path;
3324 for (;;) {
3325 find_command(argv[0], &cmdentry, cmd_flag, path);
3326 if (cmdentry.cmdtype == CMDUNKNOWN) {
3327 status = 127;
Eric Andersen16767e22004-03-16 05:14:10 +00003328 flusherr();
Eric Andersenc470f442003-07-28 09:56:35 +00003329 goto bail;
3330 }
3331
3332 /* implement bltin and command here */
3333 if (cmdentry.cmdtype != CMDBUILTIN)
3334 break;
3335 if (spclbltin < 0)
3336 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3337 if (cmdentry.u.cmd == EXECCMD)
3338 cmd_is_exec++;
3339#ifdef CONFIG_ASH_CMDCMD
3340 if (cmdentry.u.cmd == COMMANDCMD) {
3341
3342 path = oldpath;
3343 nargv = parse_command_args(argv, &path);
3344 if (!nargv)
3345 break;
3346 argc -= nargv - argv;
3347 argv = nargv;
3348 cmd_flag |= DO_NOFUNC;
3349 } else
3350#endif
3351 break;
3352 }
3353 }
3354
3355 if (status) {
3356 /* We have a redirection error. */
3357 if (spclbltin > 0)
3358 exraise(EXERROR);
3359bail:
3360 exitstatus = status;
3361 goto out;
3362 }
3363
3364 /* Execute the command. */
3365 switch (cmdentry.cmdtype) {
3366 default:
3367 /* Fork off a child process if necessary. */
3368 if (!(flags & EV_EXIT) || trap[0]) {
3369 INTOFF;
3370 jp = makejob(cmd, 1);
3371 if (forkshell(jp, cmd, FORK_FG) != 0) {
3372 exitstatus = waitforjob(jp);
3373 INTON;
3374 break;
3375 }
3376 FORCEINTON;
3377 }
3378 listsetvar(varlist.list, VEXPORT|VSTACK);
3379 shellexec(argv, path, cmdentry.u.index);
3380 /* NOTREACHED */
3381
3382 case CMDBUILTIN:
3383 cmdenviron = varlist.list;
3384 if (cmdenviron) {
3385 struct strlist *list = cmdenviron;
3386 int i = VNOSET;
3387 if (spclbltin > 0 || argc == 0) {
3388 i = 0;
3389 if (cmd_is_exec && argc > 1)
3390 i = VEXPORT;
3391 }
3392 listsetvar(list, i);
3393 }
3394 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3395 int exit_status;
3396 int i, j;
3397
3398 i = exception;
3399 if (i == EXEXIT)
3400 goto raise;
3401
3402 exit_status = 2;
3403 j = 0;
3404 if (i == EXINT)
3405 j = SIGINT;
3406 if (i == EXSIG)
3407 j = pendingsigs;
3408 if (j)
3409 exit_status = j + 128;
3410 exitstatus = exit_status;
3411
3412 if (i == EXINT || spclbltin > 0) {
3413raise:
3414 longjmp(handler->loc, 1);
3415 }
3416 FORCEINTON;
3417 }
3418 break;
3419
3420 case CMDFUNCTION:
3421 listsetvar(varlist.list, 0);
3422 if (evalfun(cmdentry.u.func, argc, argv, flags))
3423 goto raise;
3424 break;
3425 }
3426
3427out:
3428 popredir(cmd_is_exec);
3429 if (lastarg)
3430 /* dsl: I think this is intended to be used to support
3431 * '_' in 'vi' command mode during line editing...
3432 * However I implemented that within libedit itself.
3433 */
3434 setvar("_", lastarg, 0);
3435 popstackmark(&smark);
3436}
3437
3438static int
3439evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3440 char *volatile savecmdname;
3441 struct jmploc *volatile savehandler;
3442 struct jmploc jmploc;
3443 int i;
3444
3445 savecmdname = commandname;
3446 if ((i = setjmp(jmploc.loc)))
3447 goto cmddone;
3448 savehandler = handler;
3449 handler = &jmploc;
3450 commandname = argv[0];
3451 argptr = argv + 1;
3452 optptr = NULL; /* initialize nextopt */
3453 exitstatus = (*cmd->builtin)(argc, argv);
3454 flushall();
3455cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003456 exitstatus |= ferror(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00003457 commandname = savecmdname;
3458 exsig = 0;
3459 handler = savehandler;
3460
3461 return i;
3462}
3463
3464static int
3465evalfun(struct funcnode *func, int argc, char **argv, int flags)
3466{
3467 volatile struct shparam saveparam;
3468 struct localvar *volatile savelocalvars;
3469 struct jmploc *volatile savehandler;
3470 struct jmploc jmploc;
3471 int e;
3472
3473 saveparam = shellparam;
3474 savelocalvars = localvars;
3475 if ((e = setjmp(jmploc.loc))) {
3476 goto funcdone;
3477 }
3478 INTOFF;
3479 savehandler = handler;
3480 handler = &jmploc;
3481 localvars = NULL;
3482 shellparam.malloc = 0;
3483 func->count++;
3484 INTON;
3485 shellparam.nparam = argc - 1;
3486 shellparam.p = argv + 1;
3487#ifdef CONFIG_ASH_GETOPTS
3488 shellparam.optind = 1;
3489 shellparam.optoff = -1;
3490#endif
3491 funcnest++;
3492 evaltree(&func->n, flags & EV_TESTED);
3493 funcnest--;
3494funcdone:
3495 INTOFF;
3496 freefunc(func);
3497 poplocalvars();
3498 localvars = savelocalvars;
3499 freeparam(&shellparam);
3500 shellparam = saveparam;
3501 handler = savehandler;
3502 INTON;
3503 if (evalskip == SKIPFUNC) {
3504 evalskip = 0;
3505 skipcount = 0;
3506 }
3507 return e;
3508}
3509
3510
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003511static inline int
3512goodname(const char *p)
3513{
3514 return !*endofname(p);
3515}
3516
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003517/*
3518 * Search for a command. This is called before we fork so that the
3519 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003520 * the child. The check for "goodname" is an overly conservative
3521 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003522 */
3523
Eric Andersenc470f442003-07-28 09:56:35 +00003524static void
3525prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003526{
3527 struct cmdentry entry;
3528
3529 if (n->type == NCMD && n->ncmd.args)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00003530 if (goodname(n->ncmd.args->narg.text))
3531 find_command(n->ncmd.args->narg.text, &entry, 0,
3532 pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003533}
3534
Eric Andersencb57d552001-06-28 07:25:16 +00003535
Eric Andersenc470f442003-07-28 09:56:35 +00003536
Eric Andersencb57d552001-06-28 07:25:16 +00003537/*
3538 * Builtin commands. Builtin commands whose functions are closely
3539 * tied to evaluation are implemented here.
3540 */
3541
3542/*
Eric Andersenc470f442003-07-28 09:56:35 +00003543 * No command given.
Eric Andersencb57d552001-06-28 07:25:16 +00003544 */
3545
Eric Andersenc470f442003-07-28 09:56:35 +00003546static int
3547bltincmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003548{
3549 /*
3550 * Preserve exitstatus of a previous possible redirection
3551 * as POSIX mandates
3552 */
Eric Andersenc470f442003-07-28 09:56:35 +00003553 return back_exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003554}
3555
3556
3557/*
3558 * Handle break and continue commands. Break, continue, and return are
3559 * all handled by setting the evalskip flag. The evaluation routines
3560 * above all check this flag, and if it is set they start skipping
3561 * commands rather than executing them. The variable skipcount is
3562 * the number of loops to break/continue, or the number of function
3563 * levels to return. (The latter is always 1.) It should probably
3564 * be an error to break out of more loops than exist, but it isn't
3565 * in the standard shell so we don't make it one here.
3566 */
3567
Eric Andersenc470f442003-07-28 09:56:35 +00003568static int
3569breakcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003570{
3571 int n = argc > 1 ? number(argv[1]) : 1;
3572
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00003573 if (n <= 0)
Eric Andersenc470f442003-07-28 09:56:35 +00003574 error(illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00003575 if (n > loopnest)
3576 n = loopnest;
3577 if (n > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003578 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00003579 skipcount = n;
3580 }
3581 return 0;
3582}
3583
3584
3585/*
3586 * The return command.
3587 */
3588
Eric Andersenc470f442003-07-28 09:56:35 +00003589static int
3590returncmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003591{
Eric Andersenc470f442003-07-28 09:56:35 +00003592 int ret = argc > 1 ? number(argv[1]) : exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00003593
3594 if (funcnest) {
3595 evalskip = SKIPFUNC;
3596 skipcount = 1;
3597 return ret;
Eric Andersenc470f442003-07-28 09:56:35 +00003598 }
3599 else {
Eric Andersencb57d552001-06-28 07:25:16 +00003600 /* Do what ksh does; skip the rest of the file */
3601 evalskip = SKIPFILE;
3602 skipcount = 1;
3603 return ret;
3604 }
3605}
3606
3607
Eric Andersenc470f442003-07-28 09:56:35 +00003608static int
3609falsecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003610{
3611 return 1;
3612}
3613
Eric Andersenc470f442003-07-28 09:56:35 +00003614
3615static int
3616truecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003617{
3618 return 0;
3619}
Eric Andersen2870d962001-07-02 17:27:21 +00003620
Eric Andersencb57d552001-06-28 07:25:16 +00003621
Eric Andersenc470f442003-07-28 09:56:35 +00003622static int
3623execcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003624{
3625 if (argc > 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00003626 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003627 mflag = 0;
3628 optschanged();
Eric Andersenc470f442003-07-28 09:56:35 +00003629 shellexec(argv + 1, pathval(), 0);
Eric Andersencb57d552001-06-28 07:25:16 +00003630 }
3631 return 0;
3632}
3633
Eric Andersenc470f442003-07-28 09:56:35 +00003634
Eric Andersenc470f442003-07-28 09:56:35 +00003635/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3636
3637/*
3638 * When commands are first encountered, they are entered in a hash table.
3639 * This ensures that a full path search will not have to be done for them
3640 * on each invocation.
3641 *
3642 * We should investigate converting to a linear search, even though that
3643 * would make the command name "hash" a misnomer.
3644 */
3645
3646#define CMDTABLESIZE 31 /* should be prime */
3647#define ARB 1 /* actual size determined at run time */
3648
3649
3650
3651struct tblentry {
3652 struct tblentry *next; /* next entry in hash chain */
3653 union param param; /* definition of builtin function */
3654 short cmdtype; /* index identifying command */
3655 char rehash; /* if set, cd done since entry created */
3656 char cmdname[ARB]; /* name of command */
3657};
3658
3659
3660static struct tblentry *cmdtable[CMDTABLESIZE];
3661static int builtinloc = -1; /* index in path of %builtin, or -1 */
3662
3663
3664static void tryexec(char *, char **, char **);
Eric Andersenc470f442003-07-28 09:56:35 +00003665static void clearcmdentry(int);
3666static struct tblentry *cmdlookup(const char *, int);
3667static void delete_cmd_entry(void);
3668
Eric Andersencb57d552001-06-28 07:25:16 +00003669
3670/*
3671 * Exec a program. Never returns. If you change this routine, you may
3672 * have to change the find_command routine as well.
3673 */
3674
Eric Andersenc470f442003-07-28 09:56:35 +00003675static void
3676shellexec(char **argv, const char *path, int idx)
Eric Andersencb57d552001-06-28 07:25:16 +00003677{
3678 char *cmdname;
3679 int e;
Eric Andersenc470f442003-07-28 09:56:35 +00003680 char **envp;
Eric Andersencb57d552001-06-28 07:25:16 +00003681
Eric Andersenc470f442003-07-28 09:56:35 +00003682 clearredir(1);
3683 envp = environment();
Eric Andersenbf8bf102002-09-17 08:41:08 +00003684 if (strchr(argv[0], '/') != NULL
3685#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3686 || find_applet_by_name(argv[0])
Eric Andersenc470f442003-07-28 09:56:35 +00003687#endif
3688 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00003689 tryexec(argv[0], argv, envp);
3690 e = errno;
3691 } else {
3692 e = ENOENT;
3693 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3694 if (--idx < 0 && pathopt == NULL) {
3695 tryexec(cmdname, argv, envp);
3696 if (errno != ENOENT && errno != ENOTDIR)
3697 e = errno;
3698 }
3699 stunalloc(cmdname);
3700 }
3701 }
3702
3703 /* Map to POSIX errors */
3704 switch (e) {
3705 case EACCES:
3706 exerrno = 126;
3707 break;
3708 case ENOENT:
3709 exerrno = 127;
3710 break;
3711 default:
3712 exerrno = 2;
3713 break;
3714 }
Eric Andersenc470f442003-07-28 09:56:35 +00003715 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3716 argv[0], e, suppressint ));
Eric Andersencb57d552001-06-28 07:25:16 +00003717 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3718 /* NOTREACHED */
3719}
3720
Eric Andersen2870d962001-07-02 17:27:21 +00003721
Eric Andersenc470f442003-07-28 09:56:35 +00003722static void
3723tryexec(char *cmd, char **argv, char **envp)
Eric Andersen62483552001-07-10 06:09:16 +00003724{
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003725 int repeated = 0;
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003726#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Rob Landley0fcd9432005-05-07 08:27:34 +00003727 if(find_applet_by_name(cmd) != NULL) {
3728 /* re-exec ourselves with the new arguments */
3729 execve("/proc/self/exe",argv,envp);
3730 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3731 execve("/bin/busybox",argv,envp);
3732 /* If they called chroot or otherwise made the binary no longer
3733 * executable, fall through */
Glenn L McGrathc00c56e2002-12-23 10:23:10 +00003734 }
Eric Andersen3102ac42001-07-06 04:26:23 +00003735#endif
Eric Andersenc470f442003-07-28 09:56:35 +00003736
3737repeat:
3738#ifdef SYSV
3739 do {
3740 execve(cmd, argv, envp);
3741 } while (errno == EINTR);
3742#else
Eric Andersencb57d552001-06-28 07:25:16 +00003743 execve(cmd, argv, envp);
Eric Andersenc470f442003-07-28 09:56:35 +00003744#endif
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003745 if (repeated++) {
Eric Andersenc470f442003-07-28 09:56:35 +00003746 ckfree(argv);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003747 } else if (errno == ENOEXEC) {
3748 char **ap;
3749 char **new;
3750
Eric Andersenc470f442003-07-28 09:56:35 +00003751 for (ap = argv; *ap; ap++)
3752 ;
3753 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
Glenn L McGrath47e5ca12003-09-15 12:00:19 +00003754 ap[1] = cmd;
3755 *ap = cmd = (char *)DEFAULT_SHELL;
3756 ap += 2;
3757 argv++;
Eric Andersenc470f442003-07-28 09:56:35 +00003758 while ((*ap++ = *argv++))
3759 ;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00003760 argv = new;
3761 goto repeat;
Eric Andersencb57d552001-06-28 07:25:16 +00003762 }
Eric Andersencb57d552001-06-28 07:25:16 +00003763}
3764
Eric Andersenc470f442003-07-28 09:56:35 +00003765
Eric Andersencb57d552001-06-28 07:25:16 +00003766
3767/*
3768 * Do a path search. The variable path (passed by reference) should be
3769 * set to the start of the path before the first call; padvance will update
3770 * this value as it proceeds. Successive calls to padvance will return
3771 * the possible path expansions in sequence. If an option (indicated by
3772 * a percent sign) appears in the path entry then the global variable
3773 * pathopt will be set to point to it; otherwise pathopt will be set to
3774 * NULL.
3775 */
3776
Eric Andersenc470f442003-07-28 09:56:35 +00003777static char *
3778padvance(const char **path, const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003779{
Eric Andersencb57d552001-06-28 07:25:16 +00003780 const char *p;
3781 char *q;
3782 const char *start;
Eric Andersenc470f442003-07-28 09:56:35 +00003783 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00003784
3785 if (*path == NULL)
3786 return NULL;
3787 start = *path;
Eric Andersenc470f442003-07-28 09:56:35 +00003788 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3789 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003790 while (stackblocksize() < len)
3791 growstackblock();
3792 q = stackblock();
3793 if (p != start) {
3794 memcpy(q, start, p - start);
3795 q += p - start;
3796 *q++ = '/';
3797 }
3798 strcpy(q, name);
3799 pathopt = NULL;
3800 if (*p == '%') {
3801 pathopt = ++p;
Eric Andersenc470f442003-07-28 09:56:35 +00003802 while (*p && *p != ':') p++;
Eric Andersencb57d552001-06-28 07:25:16 +00003803 }
3804 if (*p == ':')
3805 *path = p + 1;
3806 else
3807 *path = NULL;
3808 return stalloc(len);
3809}
3810
3811
Eric Andersencb57d552001-06-28 07:25:16 +00003812/*** Command hashing code ***/
3813
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00003814static void
3815printentry(struct tblentry *cmdp)
3816{
3817 int idx;
3818 const char *path;
3819 char *name;
3820
3821 idx = cmdp->param.index;
3822 path = pathval();
3823 do {
3824 name = padvance(&path, cmdp->cmdname);
3825 stunalloc(name);
3826 } while (--idx >= 0);
3827 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3828}
3829
Eric Andersenc470f442003-07-28 09:56:35 +00003830
3831static int
3832hashcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003833{
3834 struct tblentry **pp;
3835 struct tblentry *cmdp;
3836 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00003837 struct cmdentry entry;
3838 char *name;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003839
Eric Andersenc470f442003-07-28 09:56:35 +00003840 while ((c = nextopt("r")) != '\0') {
3841 clearcmdentry(0);
3842 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003843 }
3844 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003845 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3846 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3847 if (cmdp->cmdtype == CMDNORMAL)
3848 printentry(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00003849 }
3850 }
3851 return 0;
3852 }
3853 c = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003854 while ((name = *argptr) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00003855 if ((cmdp = cmdlookup(name, 0)) != NULL
Eric Andersenc470f442003-07-28 09:56:35 +00003856 && (cmdp->cmdtype == CMDNORMAL
3857 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
Eric Andersencb57d552001-06-28 07:25:16 +00003858 delete_cmd_entry();
3859 find_command(name, &entry, DO_ERR, pathval());
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003860 if (entry.cmdtype == CMDUNKNOWN)
3861 c = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00003862 argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00003863 }
3864 return c;
3865}
3866
Eric Andersenc470f442003-07-28 09:56:35 +00003867
Eric Andersencb57d552001-06-28 07:25:16 +00003868/*
3869 * Resolve a command name. If you change this routine, you may have to
3870 * change the shellexec routine as well.
3871 */
3872
3873static void
Eric Andersenc470f442003-07-28 09:56:35 +00003874find_command(char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003875{
3876 struct tblentry *cmdp;
3877 int idx;
3878 int prev;
3879 char *fullname;
3880 struct stat statb;
3881 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003882 int updatetbl;
Eric Andersencb57d552001-06-28 07:25:16 +00003883 struct builtincmd *bcmd;
3884
Eric Andersenc470f442003-07-28 09:56:35 +00003885 /* If name contains a slash, don't use PATH or hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00003886 if (strchr(name, '/') != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003887 entry->u.index = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00003888 if (act & DO_ABS) {
3889 while (stat(name, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003890#ifdef SYSV
3891 if (errno == EINTR)
3892 continue;
3893#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003894 entry->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00003895 return;
3896 }
Eric Andersencb57d552001-06-28 07:25:16 +00003897 }
3898 entry->cmdtype = CMDNORMAL;
Eric Andersencb57d552001-06-28 07:25:16 +00003899 return;
3900 }
3901
Eric Andersenbf8bf102002-09-17 08:41:08 +00003902#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3903 if (find_applet_by_name(name)) {
3904 entry->cmdtype = CMDNORMAL;
3905 entry->u.index = -1;
3906 return;
3907 }
3908#endif
3909
Eric Andersenc470f442003-07-28 09:56:35 +00003910 updatetbl = (path == pathval());
3911 if (!updatetbl) {
3912 act |= DO_ALTPATH;
3913 if (strstr(path, "%builtin") != NULL)
3914 act |= DO_ALTBLTIN;
Eric Andersencb57d552001-06-28 07:25:16 +00003915 }
3916
Eric Andersenc470f442003-07-28 09:56:35 +00003917 /* If name is in the table, check answer will be ok */
3918 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3919 int bit;
Eric Andersencb57d552001-06-28 07:25:16 +00003920
Eric Andersenc470f442003-07-28 09:56:35 +00003921 switch (cmdp->cmdtype) {
3922 default:
3923#if DEBUG
3924 abort();
3925#endif
3926 case CMDNORMAL:
3927 bit = DO_ALTPATH;
3928 break;
3929 case CMDFUNCTION:
3930 bit = DO_NOFUNC;
3931 break;
3932 case CMDBUILTIN:
3933 bit = DO_ALTBLTIN;
3934 break;
Eric Andersencb57d552001-06-28 07:25:16 +00003935 }
Eric Andersenc470f442003-07-28 09:56:35 +00003936 if (act & bit) {
Eric Andersencb57d552001-06-28 07:25:16 +00003937 updatetbl = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00003938 cmdp = NULL;
3939 } else if (cmdp->rehash == 0)
3940 /* if not invalidated by cd, we're done */
3941 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003942 }
3943
3944 /* If %builtin not in path, check for builtin next */
Eric Andersenc470f442003-07-28 09:56:35 +00003945 bcmd = find_builtin(name);
3946 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3947 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3948 )))
3949 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003950
3951 /* We have to search path. */
Eric Andersenc470f442003-07-28 09:56:35 +00003952 prev = -1; /* where to start */
3953 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003954 if (cmdp->cmdtype == CMDBUILTIN)
3955 prev = builtinloc;
3956 else
3957 prev = cmdp->param.index;
3958 }
3959
3960 e = ENOENT;
3961 idx = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00003962loop:
Eric Andersencb57d552001-06-28 07:25:16 +00003963 while ((fullname = padvance(&path, name)) != NULL) {
3964 stunalloc(fullname);
3965 idx++;
Eric Andersencb57d552001-06-28 07:25:16 +00003966 if (pathopt) {
Eric Andersenc470f442003-07-28 09:56:35 +00003967 if (prefix(pathopt, "builtin")) {
3968 if (bcmd)
3969 goto builtin_success;
Eric Andersencb57d552001-06-28 07:25:16 +00003970 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003971 } else if (!(act & DO_NOFUNC) &&
3972 prefix(pathopt, "func")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003973 /* handled below */
3974 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00003975 /* ignore unimplemented options */
3976 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00003977 }
3978 }
3979 /* if rehash, don't redo absolute path names */
Eric Andersenc470f442003-07-28 09:56:35 +00003980 if (fullname[0] == '/' && idx <= prev) {
Eric Andersencb57d552001-06-28 07:25:16 +00003981 if (idx < prev)
3982 continue;
3983 TRACE(("searchexec \"%s\": no change\n", name));
3984 goto success;
3985 }
3986 while (stat(fullname, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00003987#ifdef SYSV
3988 if (errno == EINTR)
3989 continue;
3990#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003991 if (errno != ENOENT && errno != ENOTDIR)
3992 e = errno;
3993 goto loop;
3994 }
Eric Andersenc470f442003-07-28 09:56:35 +00003995 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003996 if (!S_ISREG(statb.st_mode))
3997 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00003998 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003999 stalloc(strlen(fullname) + 1);
4000 readcmdfile(fullname);
Eric Andersenc470f442003-07-28 09:56:35 +00004001 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4002 cmdp->cmdtype != CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004003 error("%s not defined in %s", name, fullname);
4004 stunalloc(fullname);
4005 goto success;
4006 }
Eric Andersencb57d552001-06-28 07:25:16 +00004007 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
Eric Andersencb57d552001-06-28 07:25:16 +00004008 if (!updatetbl) {
4009 entry->cmdtype = CMDNORMAL;
4010 entry->u.index = idx;
4011 return;
4012 }
4013 INTOFF;
4014 cmdp = cmdlookup(name, 1);
4015 cmdp->cmdtype = CMDNORMAL;
4016 cmdp->param.index = idx;
4017 INTON;
4018 goto success;
4019 }
4020
4021 /* We failed. If there was an entry for this command, delete it */
4022 if (cmdp && updatetbl)
4023 delete_cmd_entry();
4024 if (act & DO_ERR)
Eric Andersenc470f442003-07-28 09:56:35 +00004025 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004026 entry->cmdtype = CMDUNKNOWN;
4027 return;
4028
Eric Andersenc470f442003-07-28 09:56:35 +00004029builtin_success:
4030 if (!updatetbl) {
4031 entry->cmdtype = CMDBUILTIN;
4032 entry->u.cmd = bcmd;
4033 return;
4034 }
4035 INTOFF;
4036 cmdp = cmdlookup(name, 1);
4037 cmdp->cmdtype = CMDBUILTIN;
4038 cmdp->param.cmd = bcmd;
4039 INTON;
4040success:
Eric Andersencb57d552001-06-28 07:25:16 +00004041 cmdp->rehash = 0;
4042 entry->cmdtype = cmdp->cmdtype;
4043 entry->u = cmdp->param;
4044}
4045
4046
Eric Andersenc470f442003-07-28 09:56:35 +00004047/*
4048 * Wrapper around strcmp for qsort/bsearch/...
4049 */
4050static int pstrcmp(const void *a, const void *b)
4051{
4052 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4053}
Eric Andersencb57d552001-06-28 07:25:16 +00004054
4055/*
4056 * Search the table of builtin commands.
4057 */
4058
Eric Andersenc470f442003-07-28 09:56:35 +00004059static struct builtincmd *
4060find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004061{
4062 struct builtincmd *bp;
4063
Eric Andersenc470f442003-07-28 09:56:35 +00004064 bp = bsearch(
4065 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4066 pstrcmp
4067 );
Eric Andersencb57d552001-06-28 07:25:16 +00004068 return bp;
4069}
4070
4071
Eric Andersenc470f442003-07-28 09:56:35 +00004072
Eric Andersencb57d552001-06-28 07:25:16 +00004073/*
4074 * Called when a cd is done. Marks all commands so the next time they
4075 * are executed they will be rehashed.
4076 */
4077
Eric Andersenc470f442003-07-28 09:56:35 +00004078static void
4079hashcd(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004080{
Eric Andersencb57d552001-06-28 07:25:16 +00004081 struct tblentry **pp;
4082 struct tblentry *cmdp;
4083
Eric Andersenc470f442003-07-28 09:56:35 +00004084 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4085 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4086 if (cmdp->cmdtype == CMDNORMAL || (
4087 cmdp->cmdtype == CMDBUILTIN &&
4088 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4089 builtinloc > 0
4090 ))
Eric Andersencb57d552001-06-28 07:25:16 +00004091 cmdp->rehash = 1;
4092 }
4093 }
4094}
4095
4096
4097
4098/*
Eric Andersenc470f442003-07-28 09:56:35 +00004099 * Fix command hash table when PATH changed.
Eric Andersencb57d552001-06-28 07:25:16 +00004100 * Called before PATH is changed. The argument is the new value of PATH;
Eric Andersenc470f442003-07-28 09:56:35 +00004101 * pathval() still returns the old value at this point.
4102 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00004103 */
4104
Eric Andersenc470f442003-07-28 09:56:35 +00004105static void
4106changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004107{
Eric Andersenc470f442003-07-28 09:56:35 +00004108 const char *old, *new;
4109 int idx;
Eric Andersencb57d552001-06-28 07:25:16 +00004110 int firstchange;
Eric Andersenc470f442003-07-28 09:56:35 +00004111 int idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004112
Eric Andersenc470f442003-07-28 09:56:35 +00004113 old = pathval();
4114 new = newval;
4115 firstchange = 9999; /* assume no change */
4116 idx = 0;
4117 idx_bltin = -1;
4118 for (;;) {
4119 if (*old != *new) {
4120 firstchange = idx;
4121 if ((*old == '\0' && *new == ':')
4122 || (*old == ':' && *new == '\0'))
4123 firstchange++;
4124 old = new; /* ignore subsequent differences */
4125 }
4126 if (*new == '\0')
4127 break;
4128 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4129 idx_bltin = idx;
4130 if (*new == ':') {
4131 idx++;
4132 }
4133 new++, old++;
4134 }
4135 if (builtinloc < 0 && idx_bltin >= 0)
4136 builtinloc = idx_bltin; /* zap builtins */
4137 if (builtinloc >= 0 && idx_bltin < 0)
4138 firstchange = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00004139 clearcmdentry(firstchange);
Eric Andersenc470f442003-07-28 09:56:35 +00004140 builtinloc = idx_bltin;
Eric Andersencb57d552001-06-28 07:25:16 +00004141}
4142
4143
4144/*
4145 * Clear out command entries. The argument specifies the first entry in
4146 * PATH which has changed.
4147 */
4148
Eric Andersenc470f442003-07-28 09:56:35 +00004149static void
4150clearcmdentry(int firstchange)
Eric Andersencb57d552001-06-28 07:25:16 +00004151{
4152 struct tblentry **tblp;
4153 struct tblentry **pp;
4154 struct tblentry *cmdp;
4155
4156 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00004157 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00004158 pp = tblp;
4159 while ((cmdp = *pp) != NULL) {
4160 if ((cmdp->cmdtype == CMDNORMAL &&
Eric Andersenc470f442003-07-28 09:56:35 +00004161 cmdp->param.index >= firstchange)
4162 || (cmdp->cmdtype == CMDBUILTIN &&
4163 builtinloc >= firstchange)) {
Eric Andersencb57d552001-06-28 07:25:16 +00004164 *pp = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004165 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004166 } else {
4167 pp = &cmdp->next;
4168 }
4169 }
4170 }
4171 INTON;
4172}
4173
4174
Eric Andersenc470f442003-07-28 09:56:35 +00004175
Eric Andersencb57d552001-06-28 07:25:16 +00004176/*
Eric Andersencb57d552001-06-28 07:25:16 +00004177 * Locate a command in the command hash table. If "add" is nonzero,
4178 * add the command to the table if it is not already present. The
4179 * variable "lastcmdentry" is set to point to the address of the link
4180 * pointing to the entry, so that delete_cmd_entry can delete the
4181 * entry.
Eric Andersenc470f442003-07-28 09:56:35 +00004182 *
4183 * Interrupts must be off if called with add != 0.
Eric Andersencb57d552001-06-28 07:25:16 +00004184 */
4185
Eric Andersen2870d962001-07-02 17:27:21 +00004186static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004187
Eric Andersenc470f442003-07-28 09:56:35 +00004188
4189static struct tblentry *
4190cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004191{
Eric Andersenc470f442003-07-28 09:56:35 +00004192 unsigned int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004193 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004194 struct tblentry *cmdp;
4195 struct tblentry **pp;
4196
4197 p = name;
Eric Andersenc470f442003-07-28 09:56:35 +00004198 hashval = (unsigned char)*p << 4;
Eric Andersencb57d552001-06-28 07:25:16 +00004199 while (*p)
Eric Andersenc470f442003-07-28 09:56:35 +00004200 hashval += (unsigned char)*p++;
Eric Andersencb57d552001-06-28 07:25:16 +00004201 hashval &= 0x7FFF;
4202 pp = &cmdtable[hashval % CMDTABLESIZE];
Eric Andersenc470f442003-07-28 09:56:35 +00004203 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +00004204 if (equal(cmdp->cmdname, name))
4205 break;
4206 pp = &cmdp->next;
4207 }
4208 if (add && cmdp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004209 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4210 + strlen(name) + 1);
Eric Andersencb57d552001-06-28 07:25:16 +00004211 cmdp->next = NULL;
4212 cmdp->cmdtype = CMDUNKNOWN;
Eric Andersencb57d552001-06-28 07:25:16 +00004213 strcpy(cmdp->cmdname, name);
Eric Andersencb57d552001-06-28 07:25:16 +00004214 }
4215 lastcmdentry = pp;
4216 return cmdp;
4217}
4218
4219/*
4220 * Delete the command entry returned on the last lookup.
4221 */
4222
Eric Andersenc470f442003-07-28 09:56:35 +00004223static void
4224delete_cmd_entry(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00004225{
Eric Andersencb57d552001-06-28 07:25:16 +00004226 struct tblentry *cmdp;
4227
4228 INTOFF;
4229 cmdp = *lastcmdentry;
4230 *lastcmdentry = cmdp->next;
Eric Andersenc470f442003-07-28 09:56:35 +00004231 if (cmdp->cmdtype == CMDFUNCTION)
4232 freefunc(cmdp->param.func);
4233 ckfree(cmdp);
Eric Andersencb57d552001-06-28 07:25:16 +00004234 INTON;
4235}
4236
4237
Eric Andersenc470f442003-07-28 09:56:35 +00004238/*
4239 * Add a new command entry, replacing any existing command entry for
4240 * the same name - except special builtins.
4241 */
Eric Andersencb57d552001-06-28 07:25:16 +00004242
Eric Andersenc470f442003-07-28 09:56:35 +00004243static inline void
4244addcmdentry(char *name, struct cmdentry *entry)
4245{
4246 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +00004247
Eric Andersenc470f442003-07-28 09:56:35 +00004248 cmdp = cmdlookup(name, 1);
4249 if (cmdp->cmdtype == CMDFUNCTION) {
4250 freefunc(cmdp->param.func);
4251 }
4252 cmdp->cmdtype = entry->cmdtype;
4253 cmdp->param = entry->u;
4254 cmdp->rehash = 0;
4255}
Eric Andersencb57d552001-06-28 07:25:16 +00004256
Eric Andersenc470f442003-07-28 09:56:35 +00004257/*
4258 * Make a copy of a parse tree.
4259 */
Eric Andersencb57d552001-06-28 07:25:16 +00004260
Eric Andersenc470f442003-07-28 09:56:35 +00004261static inline struct funcnode *
4262copyfunc(union node *n)
4263{
4264 struct funcnode *f;
4265 size_t blocksize;
4266
4267 funcblocksize = offsetof(struct funcnode, n);
4268 funcstringsize = 0;
4269 calcsize(n);
4270 blocksize = funcblocksize;
4271 f = ckmalloc(blocksize + funcstringsize);
4272 funcblock = (char *) f + offsetof(struct funcnode, n);
4273 funcstring = (char *) f + blocksize;
4274 copynode(n);
4275 f->count = 0;
4276 return f;
4277}
4278
4279/*
4280 * Define a shell function.
4281 */
4282
4283static void
4284defun(char *name, union node *func)
4285{
4286 struct cmdentry entry;
4287
4288 INTOFF;
4289 entry.cmdtype = CMDFUNCTION;
4290 entry.u.func = copyfunc(func);
4291 addcmdentry(name, &entry);
4292 INTON;
4293}
Eric Andersencb57d552001-06-28 07:25:16 +00004294
4295
4296/*
4297 * Delete a function if it exists.
4298 */
4299
Eric Andersenc470f442003-07-28 09:56:35 +00004300static void
4301unsetfunc(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00004302{
Eric Andersencb57d552001-06-28 07:25:16 +00004303 struct tblentry *cmdp;
4304
Eric Andersenc470f442003-07-28 09:56:35 +00004305 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4306 cmdp->cmdtype == CMDFUNCTION)
Eric Andersencb57d552001-06-28 07:25:16 +00004307 delete_cmd_entry();
Eric Andersencb57d552001-06-28 07:25:16 +00004308}
4309
Eric Andersen2870d962001-07-02 17:27:21 +00004310/*
Eric Andersencb57d552001-06-28 07:25:16 +00004311 * Locate and print what a word is...
4312 */
4313
Eric Andersenc470f442003-07-28 09:56:35 +00004314
4315#ifdef CONFIG_ASH_CMDCMD
4316static int
4317describe_command(char *command, int describe_command_verbose)
4318#else
4319#define describe_command_verbose 1
4320static int
4321describe_command(char *command)
4322#endif
4323{
4324 struct cmdentry entry;
4325 struct tblentry *cmdp;
4326#ifdef CONFIG_ASH_ALIAS
4327 const struct alias *ap;
4328#endif
4329 const char *path = pathval();
4330
4331 if (describe_command_verbose) {
4332 out1str(command);
4333 }
4334
4335 /* First look at the keywords */
4336 if (findkwd(command)) {
4337 out1str(describe_command_verbose ? " is a shell keyword" : command);
4338 goto out;
4339 }
4340
4341#ifdef CONFIG_ASH_ALIAS
4342 /* Then look at the aliases */
4343 if ((ap = lookupalias(command, 0)) != NULL) {
4344 if (describe_command_verbose) {
4345 out1fmt(" is an alias for %s", ap->val);
4346 } else {
4347 out1str("alias ");
4348 printalias(ap);
4349 return 0;
4350 }
4351 goto out;
4352 }
4353#endif
4354 /* Then check if it is a tracked alias */
4355 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4356 entry.cmdtype = cmdp->cmdtype;
4357 entry.u = cmdp->param;
4358 } else {
4359 /* Finally use brute force */
4360 find_command(command, &entry, DO_ABS, path);
4361 }
4362
4363 switch (entry.cmdtype) {
4364 case CMDNORMAL: {
4365 int j = entry.u.index;
4366 char *p;
4367 if (j == -1) {
4368 p = command;
4369 } else {
4370 do {
4371 p = padvance(&path, command);
4372 stunalloc(p);
4373 } while (--j >= 0);
4374 }
4375 if (describe_command_verbose) {
4376 out1fmt(" is%s %s",
4377 (cmdp ? " a tracked alias for" : nullstr), p
4378 );
4379 } else {
4380 out1str(p);
4381 }
4382 break;
4383 }
4384
4385 case CMDFUNCTION:
4386 if (describe_command_verbose) {
4387 out1str(" is a shell function");
4388 } else {
4389 out1str(command);
4390 }
4391 break;
4392
4393 case CMDBUILTIN:
4394 if (describe_command_verbose) {
4395 out1fmt(" is a %sshell builtin",
4396 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4397 "special " : nullstr
4398 );
4399 } else {
4400 out1str(command);
4401 }
4402 break;
4403
4404 default:
4405 if (describe_command_verbose) {
4406 out1str(": not found\n");
4407 }
4408 return 127;
4409 }
4410
4411out:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00004412 outstr("\n", stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00004413 return 0;
4414}
4415
4416static int
4417typecmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004418{
4419 int i;
4420 int err = 0;
4421
4422 for (i = 1; i < argc; i++) {
Eric Andersenc470f442003-07-28 09:56:35 +00004423#ifdef CONFIG_ASH_CMDCMD
4424 err |= describe_command(argv[i], 1);
4425#else
4426 err |= describe_command(argv[i]);
4427#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004428 }
4429 return err;
4430}
4431
Eric Andersend35c5df2002-01-09 15:37:36 +00004432#ifdef CONFIG_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00004433static int
4434commandcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00004435{
4436 int c;
4437 int default_path = 0;
4438 int verify_only = 0;
4439 int verbose_verify_only = 0;
4440
4441 while ((c = nextopt("pvV")) != '\0')
4442 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00004443 default:
4444#ifdef DEBUG
4445 fprintf(stderr,
4446"command: nextopt returned character code 0%o\n", c);
4447 return EX_SOFTWARE;
4448#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004449 case 'p':
4450 default_path = 1;
4451 break;
4452 case 'v':
4453 verify_only = 1;
4454 break;
4455 case 'V':
4456 verbose_verify_only = 1;
4457 break;
Eric Andersencb57d552001-06-28 07:25:16 +00004458 }
4459
Eric Andersenc470f442003-07-28 09:56:35 +00004460 if (default_path + verify_only + verbose_verify_only > 1 ||
4461 !*argptr) {
4462 fprintf(stderr,
4463 "command [-p] command [arg ...]\n"
Eric Andersen62483552001-07-10 06:09:16 +00004464 "command {-v|-V} command\n");
Eric Andersenc470f442003-07-28 09:56:35 +00004465 return EX_USAGE;
Eric Andersencb57d552001-06-28 07:25:16 +00004466 }
4467
Eric Andersencb57d552001-06-28 07:25:16 +00004468 if (verify_only || verbose_verify_only) {
Eric Andersenc470f442003-07-28 09:56:35 +00004469 return describe_command(*argptr, verbose_verify_only);
Eric Andersencb57d552001-06-28 07:25:16 +00004470 }
Eric Andersencb57d552001-06-28 07:25:16 +00004471
4472 return 0;
4473}
Eric Andersen2870d962001-07-02 17:27:21 +00004474#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004475
Eric Andersenc470f442003-07-28 09:56:35 +00004476/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004477
Eric Andersencb57d552001-06-28 07:25:16 +00004478/*
4479 * Routines to expand arguments to commands. We have to deal with
4480 * backquotes, shell variables, and file metacharacters.
4481 */
Eric Andersenc470f442003-07-28 09:56:35 +00004482
Eric Andersencb57d552001-06-28 07:25:16 +00004483/*
4484 * _rmescape() flags
4485 */
Eric Andersenc470f442003-07-28 09:56:35 +00004486#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4487#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4488#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4489#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4490#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Eric Andersencb57d552001-06-28 07:25:16 +00004491
4492/*
4493 * Structure specifying which parts of the string should be searched
4494 * for IFS characters.
4495 */
4496
4497struct ifsregion {
Eric Andersenc470f442003-07-28 09:56:35 +00004498 struct ifsregion *next; /* next region in list */
4499 int begoff; /* offset of start of region */
4500 int endoff; /* offset of end of region */
4501 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004502};
4503
Eric Andersenc470f442003-07-28 09:56:35 +00004504/* output of current string */
4505static char *expdest;
4506/* list of back quote expressions */
4507static struct nodelist *argbackq;
4508/* first struct in list of ifs regions */
4509static struct ifsregion ifsfirst;
4510/* last struct in list */
4511static struct ifsregion *ifslastp;
4512/* holds expanded arg list */
4513static struct arglist exparg;
Eric Andersencb57d552001-06-28 07:25:16 +00004514
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004515static void argstr(char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004516static char *exptilde(char *, char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004517static void expbackq(union node *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004518static const char *subevalvar(char *, char *, int, int, int, int, int);
4519static char *evalvar(char *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004520static void strtodest(const char *, int, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004521static void memtodest(const char *p, size_t len, int syntax, int quotes);
Glenn L McGrath76620622004-01-13 10:19:37 +00004522static ssize_t varvalue(char *, int, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004523static void recordregion(int, int, int);
4524static void removerecordregions(int);
4525static void ifsbreakup(char *, struct arglist *);
4526static void ifsfree(void);
4527static void expandmeta(struct strlist *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00004528static int patmatch(char *, const char *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004529
Eric Andersened9ecf72004-06-22 08:29:45 +00004530static int cvtnum(arith_t);
Eric Andersenc470f442003-07-28 09:56:35 +00004531static size_t esclen(const char *, const char *);
4532static char *scanleft(char *, char *, char *, char *, int, int);
4533static char *scanright(char *, char *, char *, char *, int, int);
4534static void varunset(const char *, const char *, const char *, int)
4535 __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00004536
Eric Andersenc470f442003-07-28 09:56:35 +00004537
4538#define pmatch(a, b) !fnmatch((a), (b), 0)
4539/*
Eric Andersen90898442003-08-06 11:20:52 +00004540 * Prepare a pattern for a expmeta (internal glob(3)) call.
Eric Andersenc470f442003-07-28 09:56:35 +00004541 *
4542 * Returns an stalloced string.
4543 */
4544
4545static inline char *
4546preglob(const char *pattern, int quoted, int flag) {
4547 flag |= RMESCAPE_GLOB;
4548 if (quoted) {
4549 flag |= RMESCAPE_QUOTED;
4550 }
4551 return _rmescapes((char *)pattern, flag);
4552}
4553
4554
4555static size_t
4556esclen(const char *start, const char *p) {
4557 size_t esc = 0;
4558
4559 while (p > start && *--p == CTLESC) {
4560 esc++;
4561 }
4562 return esc;
4563}
4564
Eric Andersencb57d552001-06-28 07:25:16 +00004565
4566/*
4567 * Expand shell variables and backquotes inside a here document.
4568 */
4569
Eric Andersenc470f442003-07-28 09:56:35 +00004570static inline void
4571expandhere(union node *arg, int fd)
Eric Andersen2870d962001-07-02 17:27:21 +00004572{
Eric Andersencb57d552001-06-28 07:25:16 +00004573 herefd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +00004574 expandarg(arg, (struct arglist *)NULL, 0);
Eric Andersen16767e22004-03-16 05:14:10 +00004575 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
Eric Andersencb57d552001-06-28 07:25:16 +00004576}
4577
4578
4579/*
4580 * Perform variable substitution and command substitution on an argument,
4581 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4582 * perform splitting and file name expansion. When arglist is NULL, perform
4583 * here document expansion.
4584 */
4585
Eric Andersenc470f442003-07-28 09:56:35 +00004586void
4587expandarg(union node *arg, struct arglist *arglist, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004588{
4589 struct strlist *sp;
4590 char *p;
4591
4592 argbackq = arg->narg.backquote;
4593 STARTSTACKSTR(expdest);
4594 ifsfirst.next = NULL;
4595 ifslastp = NULL;
4596 argstr(arg->narg.text, flag);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004597 p = _STPUTC('\0', expdest);
4598 expdest = p - 1;
Eric Andersencb57d552001-06-28 07:25:16 +00004599 if (arglist == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00004600 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004601 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00004602 p = grabstackstr(p);
Eric Andersencb57d552001-06-28 07:25:16 +00004603 exparg.lastp = &exparg.list;
4604 /*
4605 * TODO - EXP_REDIR
4606 */
4607 if (flag & EXP_FULL) {
4608 ifsbreakup(p, &exparg);
4609 *exparg.lastp = NULL;
4610 exparg.lastp = &exparg.list;
4611 expandmeta(exparg.list, flag);
4612 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00004613 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
Eric Andersencb57d552001-06-28 07:25:16 +00004614 rmescapes(p);
Eric Andersenc470f442003-07-28 09:56:35 +00004615 sp = (struct strlist *)stalloc(sizeof (struct strlist));
Eric Andersencb57d552001-06-28 07:25:16 +00004616 sp->text = p;
4617 *exparg.lastp = sp;
4618 exparg.lastp = &sp->next;
4619 }
Eric Andersenc470f442003-07-28 09:56:35 +00004620 if (ifsfirst.next)
4621 ifsfree();
Eric Andersencb57d552001-06-28 07:25:16 +00004622 *exparg.lastp = NULL;
4623 if (exparg.list) {
4624 *arglist->lastp = exparg.list;
4625 arglist->lastp = exparg.lastp;
4626 }
4627}
4628
4629
Eric Andersenc470f442003-07-28 09:56:35 +00004630/*
4631 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4632 * characters to allow for further processing. Otherwise treat
4633 * $@ like $* since no splitting will be performed.
4634 */
4635
4636static void
4637argstr(char *p, int flag)
4638{
4639 static const char spclchars[] = {
4640 '=',
4641 ':',
4642 CTLQUOTEMARK,
4643 CTLENDVAR,
4644 CTLESC,
4645 CTLVAR,
4646 CTLBACKQ,
4647 CTLBACKQ | CTLQUOTE,
4648#ifdef CONFIG_ASH_MATH_SUPPORT
4649 CTLENDARI,
4650#endif
4651 0
4652 };
4653 const char *reject = spclchars;
4654 int c;
4655 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4656 int breakall = flag & EXP_WORD;
4657 int inquotes;
4658 size_t length;
4659 int startloc;
4660
4661 if (!(flag & EXP_VARTILDE)) {
4662 reject += 2;
4663 } else if (flag & EXP_VARTILDE2) {
4664 reject++;
4665 }
4666 inquotes = 0;
4667 length = 0;
4668 if (flag & EXP_TILDE) {
4669 char *q;
4670
4671 flag &= ~EXP_TILDE;
4672tilde:
4673 q = p;
4674 if (*q == CTLESC && (flag & EXP_QWORD))
4675 q++;
4676 if (*q == '~')
4677 p = exptilde(p, q, flag);
4678 }
4679start:
4680 startloc = expdest - (char *)stackblock();
4681 for (;;) {
4682 length += strcspn(p + length, reject);
4683 c = p[length];
4684 if (c && (!(c & 0x80)
4685#ifdef CONFIG_ASH_MATH_SUPPORT
4686 || c == CTLENDARI
4687#endif
4688 )) {
4689 /* c == '=' || c == ':' || c == CTLENDARI */
4690 length++;
4691 }
4692 if (length > 0) {
4693 int newloc;
4694 expdest = stnputs(p, length, expdest);
4695 newloc = expdest - (char *)stackblock();
4696 if (breakall && !inquotes && newloc > startloc) {
4697 recordregion(startloc, newloc, 0);
4698 }
4699 startloc = newloc;
4700 }
4701 p += length + 1;
4702 length = 0;
4703
4704 switch (c) {
4705 case '\0':
4706 goto breakloop;
4707 case '=':
4708 if (flag & EXP_VARTILDE2) {
4709 p--;
4710 continue;
4711 }
4712 flag |= EXP_VARTILDE2;
4713 reject++;
4714 /* fall through */
4715 case ':':
4716 /*
4717 * sort of a hack - expand tildes in variable
4718 * assignments (after the first '=' and after ':'s).
4719 */
4720 if (*--p == '~') {
4721 goto tilde;
4722 }
4723 continue;
4724 }
4725
4726 switch (c) {
4727 case CTLENDVAR: /* ??? */
4728 goto breakloop;
4729 case CTLQUOTEMARK:
4730 /* "$@" syntax adherence hack */
4731 if (
4732 !inquotes &&
4733 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4734 (p[4] == CTLQUOTEMARK || (
4735 p[4] == CTLENDVAR &&
4736 p[5] == CTLQUOTEMARK
4737 ))
4738 ) {
4739 p = evalvar(p + 1, flag) + 1;
4740 goto start;
4741 }
4742 inquotes = !inquotes;
4743addquote:
4744 if (quotes) {
4745 p--;
4746 length++;
4747 startloc++;
4748 }
4749 break;
4750 case CTLESC:
4751 startloc++;
4752 length++;
4753 goto addquote;
4754 case CTLVAR:
4755 p = evalvar(p, flag);
4756 goto start;
4757 case CTLBACKQ:
4758 c = 0;
4759 case CTLBACKQ|CTLQUOTE:
4760 expbackq(argbackq->n, c, quotes);
4761 argbackq = argbackq->next;
4762 goto start;
4763#ifdef CONFIG_ASH_MATH_SUPPORT
4764 case CTLENDARI:
4765 p--;
4766 expari(quotes);
4767 goto start;
4768#endif
4769 }
4770 }
4771breakloop:
4772 ;
4773}
4774
4775static char *
4776exptilde(char *startp, char *p, int flag)
4777{
4778 char c;
4779 char *name;
4780 struct passwd *pw;
4781 const char *home;
4782 int quotes = flag & (EXP_FULL | EXP_CASE);
4783 int startloc;
4784
4785 name = p + 1;
4786
4787 while ((c = *++p) != '\0') {
4788 switch(c) {
4789 case CTLESC:
4790 return (startp);
4791 case CTLQUOTEMARK:
4792 return (startp);
4793 case ':':
4794 if (flag & EXP_VARTILDE)
4795 goto done;
4796 break;
4797 case '/':
4798 case CTLENDVAR:
4799 goto done;
4800 }
4801 }
4802done:
4803 *p = '\0';
4804 if (*name == '\0') {
4805 if ((home = lookupvar(homestr)) == NULL)
4806 goto lose;
4807 } else {
4808 if ((pw = getpwnam(name)) == NULL)
4809 goto lose;
4810 home = pw->pw_dir;
4811 }
4812 if (*home == '\0')
4813 goto lose;
4814 *p = c;
4815 startloc = expdest - (char *)stackblock();
4816 strtodest(home, SQSYNTAX, quotes);
4817 recordregion(startloc, expdest - (char *)stackblock(), 0);
4818 return (p);
4819lose:
4820 *p = c;
4821 return (startp);
4822}
4823
4824
4825static void
4826removerecordregions(int endoff)
4827{
4828 if (ifslastp == NULL)
4829 return;
4830
4831 if (ifsfirst.endoff > endoff) {
4832 while (ifsfirst.next != NULL) {
4833 struct ifsregion *ifsp;
4834 INTOFF;
4835 ifsp = ifsfirst.next->next;
4836 ckfree(ifsfirst.next);
4837 ifsfirst.next = ifsp;
4838 INTON;
4839 }
4840 if (ifsfirst.begoff > endoff)
4841 ifslastp = NULL;
4842 else {
4843 ifslastp = &ifsfirst;
4844 ifsfirst.endoff = endoff;
4845 }
4846 return;
4847 }
4848
4849 ifslastp = &ifsfirst;
4850 while (ifslastp->next && ifslastp->next->begoff < endoff)
4851 ifslastp=ifslastp->next;
4852 while (ifslastp->next != NULL) {
4853 struct ifsregion *ifsp;
4854 INTOFF;
4855 ifsp = ifslastp->next->next;
4856 ckfree(ifslastp->next);
4857 ifslastp->next = ifsp;
4858 INTON;
4859 }
4860 if (ifslastp->endoff > endoff)
4861 ifslastp->endoff = endoff;
4862}
4863
4864
4865#ifdef CONFIG_ASH_MATH_SUPPORT
4866/*
4867 * Expand arithmetic expression. Backup to start of expression,
4868 * evaluate, place result in (backed up) result, adjust string position.
4869 */
4870void
4871expari(int quotes)
4872{
4873 char *p, *start;
4874 int begoff;
4875 int flag;
4876 int len;
4877
4878 /* ifsfree(); */
4879
4880 /*
4881 * This routine is slightly over-complicated for
4882 * efficiency. Next we scan backwards looking for the
4883 * start of arithmetic.
4884 */
4885 start = stackblock();
4886 p = expdest - 1;
4887 *p = '\0';
4888 p--;
4889 do {
4890 int esc;
4891
4892 while (*p != CTLARI) {
4893 p--;
4894#ifdef DEBUG
4895 if (p < start) {
4896 error("missing CTLARI (shouldn't happen)");
4897 }
4898#endif
4899 }
4900
4901 esc = esclen(start, p);
4902 if (!(esc % 2)) {
4903 break;
4904 }
4905
4906 p -= esc + 1;
4907 } while (1);
4908
4909 begoff = p - start;
4910
4911 removerecordregions(begoff);
4912
4913 flag = p[1];
4914
4915 expdest = p;
4916
4917 if (quotes)
4918 rmescapes(p + 2);
4919
4920 len = cvtnum(dash_arith(p + 2));
4921
4922 if (flag != '"')
4923 recordregion(begoff, begoff + len, 0);
4924}
4925#endif
4926
4927/*
4928 * Expand stuff in backwards quotes.
4929 */
4930
4931static void
4932expbackq(union node *cmd, int quoted, int quotes)
4933{
4934 struct backcmd in;
4935 int i;
4936 char buf[128];
4937 char *p;
4938 char *dest;
4939 int startloc;
4940 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4941 struct stackmark smark;
4942
4943 INTOFF;
4944 setstackmark(&smark);
4945 dest = expdest;
4946 startloc = dest - (char *)stackblock();
4947 grabstackstr(dest);
4948 evalbackcmd(cmd, (struct backcmd *) &in);
4949 popstackmark(&smark);
4950
4951 p = in.buf;
4952 i = in.nleft;
4953 if (i == 0)
4954 goto read;
4955 for (;;) {
4956 memtodest(p, i, syntax, quotes);
4957read:
4958 if (in.fd < 0)
4959 break;
4960 i = safe_read(in.fd, buf, sizeof buf);
4961 TRACE(("expbackq: read returns %d\n", i));
4962 if (i <= 0)
4963 break;
4964 p = buf;
4965 }
4966
4967 if (in.buf)
4968 ckfree(in.buf);
4969 if (in.fd >= 0) {
4970 close(in.fd);
4971 back_exitstatus = waitforjob(in.jp);
4972 }
4973 INTON;
4974
4975 /* Eat all trailing newlines */
4976 dest = expdest;
4977 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4978 STUNPUTC(dest);
4979 expdest = dest;
4980
4981 if (quoted == 0)
4982 recordregion(startloc, dest - (char *)stackblock(), 0);
4983 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4984 (dest - (char *)stackblock()) - startloc,
4985 (dest - (char *)stackblock()) - startloc,
4986 stackblock() + startloc));
4987}
4988
4989
4990static char *
Eric Andersen90898442003-08-06 11:20:52 +00004991scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4992 int zero)
4993{
Eric Andersenc470f442003-07-28 09:56:35 +00004994 char *loc;
4995 char *loc2;
4996 char c;
4997
4998 loc = startp;
4999 loc2 = rmesc;
5000 do {
5001 int match;
5002 const char *s = loc2;
5003 c = *loc2;
5004 if (zero) {
5005 *loc2 = '\0';
5006 s = rmesc;
5007 }
5008 match = pmatch(str, s);
5009 *loc2 = c;
5010 if (match)
5011 return loc;
5012 if (quotes && *loc == CTLESC)
5013 loc++;
5014 loc++;
5015 loc2++;
5016 } while (c);
5017 return 0;
5018}
5019
5020
5021static char *
Eric Andersen90898442003-08-06 11:20:52 +00005022scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5023 int zero)
5024{
Eric Andersenc470f442003-07-28 09:56:35 +00005025 int esc = 0;
5026 char *loc;
5027 char *loc2;
5028
5029 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5030 int match;
5031 char c = *loc2;
5032 const char *s = loc2;
5033 if (zero) {
5034 *loc2 = '\0';
5035 s = rmesc;
5036 }
5037 match = pmatch(str, s);
5038 *loc2 = c;
5039 if (match)
5040 return loc;
5041 loc--;
5042 if (quotes) {
5043 if (--esc < 0) {
5044 esc = esclen(startp, loc);
5045 }
5046 if (esc % 2) {
5047 esc--;
5048 loc--;
5049 }
5050 }
5051 }
5052 return 0;
5053}
5054
5055static const char *
5056subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5057{
5058 char *startp;
5059 char *loc;
5060 int saveherefd = herefd;
5061 struct nodelist *saveargbackq = argbackq;
5062 int amount;
5063 char *rmesc, *rmescend;
5064 int zero;
5065 char *(*scan)(char *, char *, char *, char *, int , int);
5066
5067 herefd = -1;
5068 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5069 STPUTC('\0', expdest);
5070 herefd = saveherefd;
5071 argbackq = saveargbackq;
5072 startp = stackblock() + startloc;
5073
5074 switch (subtype) {
5075 case VSASSIGN:
5076 setvar(str, startp, 0);
5077 amount = startp - expdest;
5078 STADJUST(amount, expdest);
5079 return startp;
5080
5081 case VSQUESTION:
5082 varunset(p, str, startp, varflags);
5083 /* NOTREACHED */
5084 }
5085
5086 subtype -= VSTRIMRIGHT;
5087#ifdef DEBUG
5088 if (subtype < 0 || subtype > 3)
5089 abort();
5090#endif
5091
5092 rmesc = startp;
5093 rmescend = stackblock() + strloc;
5094 if (quotes) {
5095 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5096 if (rmesc != startp) {
5097 rmescend = expdest;
5098 startp = stackblock() + startloc;
5099 }
5100 }
5101 rmescend--;
5102 str = stackblock() + strloc;
5103 preglob(str, varflags & VSQUOTE, 0);
5104
5105 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5106 zero = subtype >> 1;
5107 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5108 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5109
5110 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5111 if (loc) {
5112 if (zero) {
5113 memmove(startp, loc, str - loc);
5114 loc = startp + (str - loc) - 1;
5115 }
5116 *loc = '\0';
5117 amount = loc - expdest;
5118 STADJUST(amount, expdest);
5119 }
5120 return loc;
5121}
5122
5123
Eric Andersen62483552001-07-10 06:09:16 +00005124/*
5125 * Expand a variable, and return a pointer to the next character in the
5126 * input string.
5127 */
Eric Andersenc470f442003-07-28 09:56:35 +00005128static char *
5129evalvar(char *p, int flag)
Eric Andersen62483552001-07-10 06:09:16 +00005130{
5131 int subtype;
5132 int varflags;
5133 char *var;
Eric Andersen62483552001-07-10 06:09:16 +00005134 int patloc;
5135 int c;
Eric Andersen62483552001-07-10 06:09:16 +00005136 int startloc;
Glenn L McGrath76620622004-01-13 10:19:37 +00005137 ssize_t varlen;
Eric Andersen62483552001-07-10 06:09:16 +00005138 int easy;
Eric Andersenc470f442003-07-28 09:56:35 +00005139 int quotes;
5140 int quoted;
Eric Andersen62483552001-07-10 06:09:16 +00005141
Eric Andersenc470f442003-07-28 09:56:35 +00005142 quotes = flag & (EXP_FULL | EXP_CASE);
Eric Andersen62483552001-07-10 06:09:16 +00005143 varflags = *p++;
5144 subtype = varflags & VSTYPE;
Eric Andersenc470f442003-07-28 09:56:35 +00005145 quoted = varflags & VSQUOTE;
Eric Andersen62483552001-07-10 06:09:16 +00005146 var = p;
Eric Andersenc470f442003-07-28 09:56:35 +00005147 easy = (!quoted || (*var == '@' && shellparam.nparam));
Eric Andersenc470f442003-07-28 09:56:35 +00005148 startloc = expdest - (char *)stackblock();
5149 p = strchr(p, '=') + 1;
5150
Eric Andersenc470f442003-07-28 09:56:35 +00005151again:
Glenn L McGrath76620622004-01-13 10:19:37 +00005152 varlen = varvalue(var, varflags, flag);
5153 if (varflags & VSNUL)
5154 varlen--;
Eric Andersen62483552001-07-10 06:09:16 +00005155
Glenn L McGrath76620622004-01-13 10:19:37 +00005156 if (subtype == VSPLUS) {
5157 varlen = -1 - varlen;
5158 goto vsplus;
5159 }
Eric Andersen62483552001-07-10 06:09:16 +00005160
Eric Andersenc470f442003-07-28 09:56:35 +00005161 if (subtype == VSMINUS) {
5162vsplus:
Glenn L McGrath76620622004-01-13 10:19:37 +00005163 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005164 argstr(
5165 p, flag | EXP_TILDE |
5166 (quoted ? EXP_QWORD : EXP_WORD)
5167 );
5168 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005169 }
5170 if (easy)
5171 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005172 goto end;
5173 }
Eric Andersen62483552001-07-10 06:09:16 +00005174
Eric Andersenc470f442003-07-28 09:56:35 +00005175 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005176 if (varlen < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005177 if (subevalvar(p, var, 0, subtype, startloc,
5178 varflags, 0)) {
Eric Andersen62483552001-07-10 06:09:16 +00005179 varflags &= ~VSNUL;
5180 /*
5181 * Remove any recorded regions beyond
5182 * start of variable
5183 */
5184 removerecordregions(startloc);
5185 goto again;
5186 }
Eric Andersenc470f442003-07-28 09:56:35 +00005187 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005188 }
5189 if (easy)
5190 goto record;
Eric Andersenc470f442003-07-28 09:56:35 +00005191 goto end;
Eric Andersen62483552001-07-10 06:09:16 +00005192 }
5193
Glenn L McGrath76620622004-01-13 10:19:37 +00005194 if (varlen < 0 && uflag)
Eric Andersenc470f442003-07-28 09:56:35 +00005195 varunset(p, var, 0, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005196
Eric Andersenc470f442003-07-28 09:56:35 +00005197 if (subtype == VSLENGTH) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005198 cvtnum(varlen > 0 ? varlen : 0);
Eric Andersenc470f442003-07-28 09:56:35 +00005199 goto record;
5200 }
5201
5202 if (subtype == VSNORMAL) {
5203 if (!easy)
5204 goto end;
5205record:
5206 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5207 goto end;
5208 }
5209
5210#ifdef DEBUG
5211 switch (subtype) {
5212 case VSTRIMLEFT:
5213 case VSTRIMLEFTMAX:
5214 case VSTRIMRIGHT:
5215 case VSTRIMRIGHTMAX:
5216 break;
5217 default:
5218 abort();
5219 }
5220#endif
5221
Glenn L McGrath76620622004-01-13 10:19:37 +00005222 if (varlen >= 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005223 /*
5224 * Terminate the string and start recording the pattern
5225 * right after it
5226 */
5227 STPUTC('\0', expdest);
5228 patloc = expdest - (char *)stackblock();
5229 if (subevalvar(p, NULL, patloc, subtype,
5230 startloc, varflags, quotes) == 0) {
5231 int amount = expdest - (
5232 (char *)stackblock() + patloc - 1
5233 );
5234 STADJUST(-amount, expdest);
5235 }
5236 /* Remove any recorded regions beyond start of variable */
5237 removerecordregions(startloc);
5238 goto record;
5239 }
5240
5241end:
5242 if (subtype != VSNORMAL) { /* skip to end of alternative */
5243 int nesting = 1;
Eric Andersen62483552001-07-10 06:09:16 +00005244 for (;;) {
5245 if ((c = *p++) == CTLESC)
5246 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005247 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005248 if (varlen >= 0)
Eric Andersen62483552001-07-10 06:09:16 +00005249 argbackq = argbackq->next;
5250 } else if (c == CTLVAR) {
5251 if ((*p++ & VSTYPE) != VSNORMAL)
5252 nesting++;
5253 } else if (c == CTLENDVAR) {
5254 if (--nesting == 0)
5255 break;
5256 }
5257 }
5258 }
5259 return p;
5260}
5261
Eric Andersencb57d552001-06-28 07:25:16 +00005262
Eric Andersencb57d552001-06-28 07:25:16 +00005263/*
5264 * Put a string on the stack.
5265 */
5266
Eric Andersenc470f442003-07-28 09:56:35 +00005267static void
5268memtodest(const char *p, size_t len, int syntax, int quotes) {
5269 char *q = expdest;
5270
5271 q = makestrspace(len * 2, q);
5272
5273 while (len--) {
5274 int c = *p++;
5275 if (!c)
5276 continue;
5277 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5278 USTPUTC(CTLESC, q);
5279 USTPUTC(c, q);
Eric Andersencb57d552001-06-28 07:25:16 +00005280 }
Eric Andersenc470f442003-07-28 09:56:35 +00005281
5282 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005283}
5284
Eric Andersenc470f442003-07-28 09:56:35 +00005285
5286static void
5287strtodest(const char *p, int syntax, int quotes)
5288{
5289 memtodest(p, strlen(p), syntax, quotes);
5290}
5291
5292
Eric Andersencb57d552001-06-28 07:25:16 +00005293/*
5294 * Add the value of a specialized variable to the stack string.
5295 */
5296
Glenn L McGrath76620622004-01-13 10:19:37 +00005297static ssize_t
5298varvalue(char *name, int varflags, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00005299{
5300 int num;
5301 char *p;
5302 int i;
Glenn L McGrath76620622004-01-13 10:19:37 +00005303 int sep = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005304 int sepq = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +00005305 ssize_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00005306 char **ap;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00005307 int syntax;
Glenn L McGrath76620622004-01-13 10:19:37 +00005308 int quoted = varflags & VSQUOTE;
5309 int subtype = varflags & VSTYPE;
Eric Andersencb57d552001-06-28 07:25:16 +00005310 int quotes = flags & (EXP_FULL | EXP_CASE);
5311
Glenn L McGrath76620622004-01-13 10:19:37 +00005312 if (quoted && (flags & EXP_FULL))
5313 sep = 1 << CHAR_BIT;
5314
Eric Andersencb57d552001-06-28 07:25:16 +00005315 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5316 switch (*name) {
5317 case '$':
5318 num = rootpid;
5319 goto numvar;
5320 case '?':
Eric Andersenc470f442003-07-28 09:56:35 +00005321 num = exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00005322 goto numvar;
5323 case '#':
5324 num = shellparam.nparam;
5325 goto numvar;
5326 case '!':
5327 num = backgndpid;
Glenn L McGrath76620622004-01-13 10:19:37 +00005328 if (num == 0)
5329 return -1;
Eric Andersenc470f442003-07-28 09:56:35 +00005330numvar:
Glenn L McGrath76620622004-01-13 10:19:37 +00005331 len = cvtnum(num);
Eric Andersencb57d552001-06-28 07:25:16 +00005332 break;
5333 case '-':
Glenn L McGrath76620622004-01-13 10:19:37 +00005334 p = makestrspace(NOPTS, expdest);
5335 for (i = NOPTS - 1; i >= 0; i--) {
5336 if (optlist[i]) {
5337 USTPUTC(optletters(i), p);
5338 len++;
5339 }
Eric Andersencb57d552001-06-28 07:25:16 +00005340 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005341 expdest = p;
Eric Andersencb57d552001-06-28 07:25:16 +00005342 break;
5343 case '@':
Glenn L McGrath76620622004-01-13 10:19:37 +00005344 if (sep)
Eric Andersencb57d552001-06-28 07:25:16 +00005345 goto param;
Eric Andersencb57d552001-06-28 07:25:16 +00005346 /* fall through */
5347 case '*':
Eric Andersenc470f442003-07-28 09:56:35 +00005348 sep = ifsset() ? ifsval()[0] : ' ';
Glenn L McGrath76620622004-01-13 10:19:37 +00005349 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5350 sepq = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00005351param:
Glenn L McGrath76620622004-01-13 10:19:37 +00005352 if (!(ap = shellparam.p))
5353 return -1;
5354 while ((p = *ap++)) {
5355 size_t partlen;
5356
5357 partlen = strlen(p);
Glenn L McGrath76620622004-01-13 10:19:37 +00005358 len += partlen;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00005359
5360 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5361 memtodest(p, partlen, syntax, quotes);
5362
5363 if (*ap && sep) {
Glenn L McGrath76620622004-01-13 10:19:37 +00005364 char *q;
5365
5366 len++;
5367 if (subtype == VSPLUS || subtype == VSLENGTH) {
5368 continue;
5369 }
5370 q = expdest;
Eric Andersencb57d552001-06-28 07:25:16 +00005371 if (sepq)
Glenn L McGrath76620622004-01-13 10:19:37 +00005372 STPUTC(CTLESC, q);
5373 STPUTC(sep, q);
5374 expdest = q;
Eric Andersencb57d552001-06-28 07:25:16 +00005375 }
5376 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005377 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005378 case '0':
Glenn L McGrath76620622004-01-13 10:19:37 +00005379 case '1':
5380 case '2':
5381 case '3':
5382 case '4':
5383 case '5':
5384 case '6':
5385 case '7':
5386 case '8':
5387 case '9':
Eric Andersencb57d552001-06-28 07:25:16 +00005388 num = atoi(name);
Glenn L McGrath76620622004-01-13 10:19:37 +00005389 if (num < 0 || num > shellparam.nparam)
5390 return -1;
5391 p = num ? shellparam.p[num - 1] : arg0;
5392 goto value;
5393 default:
5394 p = lookupvar(name);
5395value:
5396 if (!p)
5397 return -1;
5398
5399 len = strlen(p);
5400 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5401 memtodest(p, len, syntax, quotes);
5402 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005403 }
Glenn L McGrath76620622004-01-13 10:19:37 +00005404
5405 if (subtype == VSPLUS || subtype == VSLENGTH)
5406 STADJUST(-len, expdest);
5407 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005408}
5409
5410
Eric Andersencb57d552001-06-28 07:25:16 +00005411/*
5412 * Record the fact that we have to scan this region of the
5413 * string for IFS characters.
5414 */
5415
Eric Andersenc470f442003-07-28 09:56:35 +00005416static void
5417recordregion(int start, int end, int nulonly)
Eric Andersencb57d552001-06-28 07:25:16 +00005418{
5419 struct ifsregion *ifsp;
5420
5421 if (ifslastp == NULL) {
5422 ifsp = &ifsfirst;
5423 } else {
5424 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005425 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
Eric Andersencb57d552001-06-28 07:25:16 +00005426 ifsp->next = NULL;
5427 ifslastp->next = ifsp;
5428 INTON;
5429 }
5430 ifslastp = ifsp;
5431 ifslastp->begoff = start;
5432 ifslastp->endoff = end;
5433 ifslastp->nulonly = nulonly;
5434}
5435
5436
Eric Andersencb57d552001-06-28 07:25:16 +00005437/*
5438 * Break the argument string into pieces based upon IFS and add the
5439 * strings to the argument list. The regions of the string to be
5440 * searched for IFS characters have been stored by recordregion.
5441 */
Eric Andersenc470f442003-07-28 09:56:35 +00005442static void
5443ifsbreakup(char *string, struct arglist *arglist)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005444{
Eric Andersencb57d552001-06-28 07:25:16 +00005445 struct ifsregion *ifsp;
5446 struct strlist *sp;
5447 char *start;
5448 char *p;
5449 char *q;
5450 const char *ifs, *realifs;
5451 int ifsspc;
5452 int nulonly;
5453
5454
5455 start = string;
Eric Andersencb57d552001-06-28 07:25:16 +00005456 if (ifslastp != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00005457 ifsspc = 0;
5458 nulonly = 0;
5459 realifs = ifsset() ? ifsval() : defifs;
Eric Andersencb57d552001-06-28 07:25:16 +00005460 ifsp = &ifsfirst;
5461 do {
5462 p = string + ifsp->begoff;
5463 nulonly = ifsp->nulonly;
5464 ifs = nulonly ? nullstr : realifs;
5465 ifsspc = 0;
5466 while (p < string + ifsp->endoff) {
5467 q = p;
5468 if (*p == CTLESC)
5469 p++;
5470 if (strchr(ifs, *p)) {
5471 if (!nulonly)
5472 ifsspc = (strchr(defifs, *p) != NULL);
5473 /* Ignore IFS whitespace at start */
5474 if (q == start && ifsspc) {
5475 p++;
5476 start = p;
5477 continue;
5478 }
5479 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005480 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005481 sp->text = start;
5482 *arglist->lastp = sp;
5483 arglist->lastp = &sp->next;
5484 p++;
5485 if (!nulonly) {
5486 for (;;) {
5487 if (p >= string + ifsp->endoff) {
5488 break;
5489 }
5490 q = p;
5491 if (*p == CTLESC)
5492 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005493 if (strchr(ifs, *p) == NULL ) {
Eric Andersencb57d552001-06-28 07:25:16 +00005494 p = q;
5495 break;
5496 } else if (strchr(defifs, *p) == NULL) {
5497 if (ifsspc) {
5498 p++;
5499 ifsspc = 0;
5500 } else {
5501 p = q;
5502 break;
5503 }
5504 } else
5505 p++;
5506 }
5507 }
5508 start = p;
5509 } else
5510 p++;
5511 }
5512 } while ((ifsp = ifsp->next) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00005513 if (nulonly)
5514 goto add;
Eric Andersencb57d552001-06-28 07:25:16 +00005515 }
5516
Eric Andersenc470f442003-07-28 09:56:35 +00005517 if (!*start)
5518 return;
5519
5520add:
5521 sp = (struct strlist *)stalloc(sizeof *sp);
Eric Andersencb57d552001-06-28 07:25:16 +00005522 sp->text = start;
5523 *arglist->lastp = sp;
5524 arglist->lastp = &sp->next;
5525}
5526
Eric Andersenc470f442003-07-28 09:56:35 +00005527static void
5528ifsfree(void)
Eric Andersencb57d552001-06-28 07:25:16 +00005529{
Eric Andersenc470f442003-07-28 09:56:35 +00005530 struct ifsregion *p;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005531
Eric Andersenc470f442003-07-28 09:56:35 +00005532 INTOFF;
5533 p = ifsfirst.next;
5534 do {
5535 struct ifsregion *ifsp;
5536 ifsp = p->next;
5537 ckfree(p);
5538 p = ifsp;
5539 } while (p);
Eric Andersencb57d552001-06-28 07:25:16 +00005540 ifslastp = NULL;
5541 ifsfirst.next = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00005542 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00005543}
5544
Eric Andersen90898442003-08-06 11:20:52 +00005545static void expmeta(char *, char *);
5546static struct strlist *expsort(struct strlist *);
5547static struct strlist *msort(struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00005548
Eric Andersen90898442003-08-06 11:20:52 +00005549static char *expdir;
Eric Andersencb57d552001-06-28 07:25:16 +00005550
Eric Andersencb57d552001-06-28 07:25:16 +00005551
Eric Andersenc470f442003-07-28 09:56:35 +00005552static void
Eric Andersen90898442003-08-06 11:20:52 +00005553expandmeta(struct strlist *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005554{
Eric Andersen90898442003-08-06 11:20:52 +00005555 static const char metachars[] = {
5556 '*', '?', '[', 0
5557 };
Eric Andersencb57d552001-06-28 07:25:16 +00005558 /* TODO - EXP_REDIR */
5559
5560 while (str) {
Eric Andersen90898442003-08-06 11:20:52 +00005561 struct strlist **savelastp;
5562 struct strlist *sp;
5563 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +00005564
Eric Andersencb57d552001-06-28 07:25:16 +00005565 if (fflag)
5566 goto nometa;
Eric Andersen90898442003-08-06 11:20:52 +00005567 if (!strpbrk(str->text, metachars))
5568 goto nometa;
5569 savelastp = exparg.lastp;
5570
Eric Andersencb57d552001-06-28 07:25:16 +00005571 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00005572 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Eric Andersen90898442003-08-06 11:20:52 +00005573 {
5574 int i = strlen(str->text);
5575 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5576 }
5577
5578 expmeta(expdir, p);
5579 ckfree(expdir);
Eric Andersenc470f442003-07-28 09:56:35 +00005580 if (p != str->text)
5581 ckfree(p);
Eric Andersen90898442003-08-06 11:20:52 +00005582 INTON;
5583 if (exparg.lastp == savelastp) {
5584 /*
5585 * no matches
5586 */
Eric Andersenc470f442003-07-28 09:56:35 +00005587nometa:
Eric Andersencb57d552001-06-28 07:25:16 +00005588 *exparg.lastp = str;
5589 rmescapes(str->text);
5590 exparg.lastp = &str->next;
Eric Andersen90898442003-08-06 11:20:52 +00005591 } else {
5592 *exparg.lastp = NULL;
5593 *savelastp = sp = expsort(*savelastp);
5594 while (sp->next != NULL)
5595 sp = sp->next;
5596 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005597 }
5598 str = str->next;
5599 }
5600}
5601
Eric Andersencb57d552001-06-28 07:25:16 +00005602/*
Eric Andersenc470f442003-07-28 09:56:35 +00005603 * Add a file name to the list.
Eric Andersencb57d552001-06-28 07:25:16 +00005604 */
5605
Eric Andersenc470f442003-07-28 09:56:35 +00005606static void
Eric Andersen90898442003-08-06 11:20:52 +00005607addfname(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005608{
Eric Andersencb57d552001-06-28 07:25:16 +00005609 struct strlist *sp;
5610
Eric Andersenc470f442003-07-28 09:56:35 +00005611 sp = (struct strlist *)stalloc(sizeof *sp);
5612 sp->text = sstrdup(name);
5613 *exparg.lastp = sp;
5614 exparg.lastp = &sp->next;
Eric Andersencb57d552001-06-28 07:25:16 +00005615}
5616
5617
Eric Andersencb57d552001-06-28 07:25:16 +00005618/*
Eric Andersen90898442003-08-06 11:20:52 +00005619 * Do metacharacter (i.e. *, ?, [...]) expansion.
5620 */
5621
5622static void
5623expmeta(char *enddir, char *name)
5624{
5625 char *p;
5626 const char *cp;
5627 char *start;
5628 char *endname;
5629 int metaflag;
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005630 struct stat statb;
Eric Andersen90898442003-08-06 11:20:52 +00005631 DIR *dirp;
5632 struct dirent *dp;
5633 int atend;
5634 int matchdot;
5635
5636 metaflag = 0;
5637 start = name;
5638 for (p = name; *p; p++) {
5639 if (*p == '*' || *p == '?')
5640 metaflag = 1;
5641 else if (*p == '[') {
5642 char *q = p + 1;
5643 if (*q == '!')
5644 q++;
5645 for (;;) {
5646 if (*q == '\\')
5647 q++;
5648 if (*q == '/' || *q == '\0')
5649 break;
5650 if (*++q == ']') {
5651 metaflag = 1;
5652 break;
5653 }
5654 }
5655 } else if (*p == '\\')
5656 p++;
5657 else if (*p == '/') {
5658 if (metaflag)
5659 goto out;
5660 start = p + 1;
5661 }
5662 }
5663out:
5664 if (metaflag == 0) { /* we've reached the end of the file name */
5665 if (enddir != expdir)
5666 metaflag++;
5667 p = name;
5668 do {
5669 if (*p == '\\')
5670 p++;
5671 *enddir++ = *p;
5672 } while (*p++);
Glenn L McGrath005f83a2003-09-01 08:53:32 +00005673 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
Eric Andersen90898442003-08-06 11:20:52 +00005674 addfname(expdir);
5675 return;
5676 }
5677 endname = p;
5678 if (name < start) {
5679 p = name;
5680 do {
5681 if (*p == '\\')
5682 p++;
5683 *enddir++ = *p++;
5684 } while (p < start);
5685 }
5686 if (enddir == expdir) {
5687 cp = ".";
5688 } else if (enddir == expdir + 1 && *expdir == '/') {
5689 cp = "/";
5690 } else {
5691 cp = expdir;
5692 enddir[-1] = '\0';
5693 }
5694 if ((dirp = opendir(cp)) == NULL)
5695 return;
5696 if (enddir != expdir)
5697 enddir[-1] = '/';
5698 if (*endname == 0) {
5699 atend = 1;
5700 } else {
5701 atend = 0;
5702 *endname++ = '\0';
5703 }
5704 matchdot = 0;
5705 p = start;
5706 if (*p == '\\')
5707 p++;
5708 if (*p == '.')
5709 matchdot++;
5710 while (! intpending && (dp = readdir(dirp)) != NULL) {
5711 if (dp->d_name[0] == '.' && ! matchdot)
5712 continue;
5713 if (pmatch(start, dp->d_name)) {
5714 if (atend) {
5715 scopy(dp->d_name, enddir);
5716 addfname(expdir);
5717 } else {
5718 for (p = enddir, cp = dp->d_name;
5719 (*p++ = *cp++) != '\0';)
5720 continue;
5721 p[-1] = '/';
5722 expmeta(p, endname);
5723 }
5724 }
5725 }
5726 closedir(dirp);
5727 if (! atend)
5728 endname[-1] = '/';
5729}
5730
5731/*
5732 * Sort the results of file name expansion. It calculates the number of
5733 * strings to sort and then calls msort (short for merge sort) to do the
5734 * work.
5735 */
5736
5737static struct strlist *
5738expsort(struct strlist *str)
5739{
5740 int len;
5741 struct strlist *sp;
5742
5743 len = 0;
5744 for (sp = str ; sp ; sp = sp->next)
5745 len++;
5746 return msort(str, len);
5747}
5748
5749
5750static struct strlist *
5751msort(struct strlist *list, int len)
5752{
5753 struct strlist *p, *q = NULL;
5754 struct strlist **lpp;
5755 int half;
5756 int n;
5757
5758 if (len <= 1)
5759 return list;
5760 half = len >> 1;
5761 p = list;
5762 for (n = half ; --n >= 0 ; ) {
5763 q = p;
5764 p = p->next;
5765 }
5766 q->next = NULL; /* terminate first half of list */
5767 q = msort(list, half); /* sort first half of list */
5768 p = msort(p, len - half); /* sort second half */
5769 lpp = &list;
5770 for (;;) {
5771#ifdef CONFIG_LOCALE_SUPPORT
5772 if (strcoll(p->text, q->text) < 0)
5773#else
5774 if (strcmp(p->text, q->text) < 0)
5775#endif
5776 {
5777 *lpp = p;
5778 lpp = &p->next;
5779 if ((p = *lpp) == NULL) {
5780 *lpp = q;
5781 break;
5782 }
5783 } else {
5784 *lpp = q;
5785 lpp = &q->next;
5786 if ((q = *lpp) == NULL) {
5787 *lpp = p;
5788 break;
5789 }
5790 }
5791 }
5792 return list;
5793}
5794
5795
5796/*
Eric Andersencb57d552001-06-28 07:25:16 +00005797 * Returns true if the pattern matches the string.
5798 */
5799
Eric Andersenc470f442003-07-28 09:56:35 +00005800static inline int
5801patmatch(char *pattern, const char *string)
Eric Andersen2870d962001-07-02 17:27:21 +00005802{
Eric Andersenc470f442003-07-28 09:56:35 +00005803 return pmatch(preglob(pattern, 0, 0), string);
Eric Andersencb57d552001-06-28 07:25:16 +00005804}
5805
5806
Eric Andersencb57d552001-06-28 07:25:16 +00005807/*
5808 * Remove any CTLESC characters from a string.
5809 */
5810
Eric Andersenc470f442003-07-28 09:56:35 +00005811static char *
5812_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005813{
5814 char *p, *q, *r;
5815 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
Eric Andersenc470f442003-07-28 09:56:35 +00005816 unsigned inquotes;
5817 int notescaped;
5818 int globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005819
5820 p = strpbrk(str, qchars);
5821 if (!p) {
5822 return str;
5823 }
5824 q = p;
5825 r = str;
5826 if (flag & RMESCAPE_ALLOC) {
5827 size_t len = p - str;
Eric Andersenc470f442003-07-28 09:56:35 +00005828 size_t fulllen = len + strlen(p) + 1;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005829
Eric Andersenc470f442003-07-28 09:56:35 +00005830 if (flag & RMESCAPE_GROW) {
5831 r = makestrspace(fulllen, expdest);
5832 } else if (flag & RMESCAPE_HEAP) {
5833 r = ckmalloc(fulllen);
5834 } else {
5835 r = stalloc(fulllen);
5836 }
5837 q = r;
Eric Andersencb57d552001-06-28 07:25:16 +00005838 if (len > 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00005839 q = mempcpy(q, str, len);
Eric Andersencb57d552001-06-28 07:25:16 +00005840 }
5841 }
Eric Andersenc470f442003-07-28 09:56:35 +00005842 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5843 globbing = flag & RMESCAPE_GLOB;
5844 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005845 while (*p) {
5846 if (*p == CTLQUOTEMARK) {
Eric Andersenc470f442003-07-28 09:56:35 +00005847 inquotes = ~inquotes;
Eric Andersencb57d552001-06-28 07:25:16 +00005848 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005849 notescaped = globbing;
Eric Andersencb57d552001-06-28 07:25:16 +00005850 continue;
5851 }
Eric Andersenc470f442003-07-28 09:56:35 +00005852 if (*p == '\\') {
5853 /* naked back slash */
5854 notescaped = 0;
5855 goto copy;
5856 }
Eric Andersencb57d552001-06-28 07:25:16 +00005857 if (*p == CTLESC) {
5858 p++;
Eric Andersenc470f442003-07-28 09:56:35 +00005859 if (notescaped && inquotes && *p != '/') {
Eric Andersencb57d552001-06-28 07:25:16 +00005860 *q++ = '\\';
5861 }
5862 }
Eric Andersenc470f442003-07-28 09:56:35 +00005863 notescaped = globbing;
5864copy:
Eric Andersencb57d552001-06-28 07:25:16 +00005865 *q++ = *p++;
5866 }
5867 *q = '\0';
Eric Andersenc470f442003-07-28 09:56:35 +00005868 if (flag & RMESCAPE_GROW) {
5869 expdest = r;
5870 STADJUST(q - r + 1, expdest);
5871 }
Eric Andersencb57d552001-06-28 07:25:16 +00005872 return r;
5873}
Eric Andersencb57d552001-06-28 07:25:16 +00005874
5875
Eric Andersencb57d552001-06-28 07:25:16 +00005876/*
5877 * See if a pattern matches in a case statement.
5878 */
5879
Eric Andersenc470f442003-07-28 09:56:35 +00005880int
5881casematch(union node *pattern, char *val)
Eric Andersen2870d962001-07-02 17:27:21 +00005882{
Eric Andersencb57d552001-06-28 07:25:16 +00005883 struct stackmark smark;
5884 int result;
Eric Andersencb57d552001-06-28 07:25:16 +00005885
5886 setstackmark(&smark);
5887 argbackq = pattern->narg.backquote;
5888 STARTSTACKSTR(expdest);
5889 ifslastp = NULL;
5890 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
Eric Andersenc470f442003-07-28 09:56:35 +00005891 STACKSTRNUL(expdest);
5892 result = patmatch(stackblock(), val);
Eric Andersencb57d552001-06-28 07:25:16 +00005893 popstackmark(&smark);
5894 return result;
5895}
5896
5897/*
5898 * Our own itoa().
5899 */
5900
Eric Andersenc470f442003-07-28 09:56:35 +00005901static int
Eric Andersened9ecf72004-06-22 08:29:45 +00005902cvtnum(arith_t num)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00005903{
Eric Andersencb57d552001-06-28 07:25:16 +00005904 int len;
5905
Eric Andersenc470f442003-07-28 09:56:35 +00005906 expdest = makestrspace(32, expdest);
Eric Andersened9ecf72004-06-22 08:29:45 +00005907#ifdef CONFIG_ASH_MATH_SUPPORT_64
5908 len = fmtstr(expdest, 32, "%lld", (long long) num);
5909#else
Eric Andersenc470f442003-07-28 09:56:35 +00005910 len = fmtstr(expdest, 32, "%ld", num);
Eric Andersened9ecf72004-06-22 08:29:45 +00005911#endif
Eric Andersenc470f442003-07-28 09:56:35 +00005912 STADJUST(len, expdest);
5913 return len;
Eric Andersencb57d552001-06-28 07:25:16 +00005914}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00005915
Eric Andersenc470f442003-07-28 09:56:35 +00005916static void
5917varunset(const char *end, const char *var, const char *umsg, int varflags)
Eric Andersencb57d552001-06-28 07:25:16 +00005918{
Eric Andersenc470f442003-07-28 09:56:35 +00005919 const char *msg;
5920 const char *tail;
5921
5922 tail = nullstr;
5923 msg = "parameter not set";
5924 if (umsg) {
5925 if (*end == CTLENDVAR) {
5926 if (varflags & VSNUL)
5927 tail = " or null";
5928 } else
5929 msg = umsg;
5930 }
5931 error("%.*s: %s%s", end - var - 1, var, msg, tail);
Eric Andersencb57d552001-06-28 07:25:16 +00005932}
Eric Andersen90898442003-08-06 11:20:52 +00005933
5934
Eric Andersenc470f442003-07-28 09:56:35 +00005935/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +00005936
Eric Andersencb57d552001-06-28 07:25:16 +00005937/*
Eric Andersen90898442003-08-06 11:20:52 +00005938 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00005939 */
5940
Eric Andersenc470f442003-07-28 09:56:35 +00005941#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00005942
Eric Andersenc470f442003-07-28 09:56:35 +00005943static void pushfile(void);
Eric Andersencb57d552001-06-28 07:25:16 +00005944
Eric Andersencb57d552001-06-28 07:25:16 +00005945/*
Eric Andersenc470f442003-07-28 09:56:35 +00005946 * Read a character from the script, returning PEOF on end of file.
5947 * Nul characters in the input are silently discarded.
5948 */
5949
5950#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5951
5952#ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5953#define pgetc_macro() pgetc()
5954static int
5955pgetc(void)
5956{
5957 return pgetc_as_macro();
5958}
5959#else
5960#define pgetc_macro() pgetc_as_macro()
5961static int
5962pgetc(void)
5963{
5964 return pgetc_macro();
5965}
5966#endif
5967
5968
5969/*
5970 * Same as pgetc(), but ignores PEOA.
5971 */
5972#ifdef CONFIG_ASH_ALIAS
5973static int pgetc2(void)
5974{
5975 int c;
5976
5977 do {
5978 c = pgetc_macro();
5979 } while (c == PEOA);
5980 return c;
5981}
5982#else
5983static inline int pgetc2(void)
5984{
5985 return pgetc_macro();
5986}
5987#endif
5988
Glenn L McGrath28939ad2004-07-21 10:20:19 +00005989/*
5990 * Read a line from the script.
5991 */
5992
5993static inline char *
5994pfgets(char *line, int len)
5995{
5996 char *p = line;
5997 int nleft = len;
5998 int c;
5999
6000 while (--nleft > 0) {
6001 c = pgetc2();
6002 if (c == PEOF) {
6003 if (p == line)
6004 return NULL;
6005 break;
6006 }
6007 *p++ = c;
6008 if (c == '\n')
6009 break;
6010 }
6011 *p = '\0';
6012 return line;
6013}
6014
6015
Eric Andersenc470f442003-07-28 09:56:35 +00006016
6017#ifdef CONFIG_FEATURE_COMMAND_EDITING
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006018#ifdef CONFIG_ASH_EXPAND_PRMT
6019static char *cmdedit_prompt;
6020#else
Eric Andersenc470f442003-07-28 09:56:35 +00006021static const char *cmdedit_prompt;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006022#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006023static inline void putprompt(const char *s)
6024{
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006025#ifdef CONFIG_ASH_EXPAND_PRMT
6026 free(cmdedit_prompt);
6027 cmdedit_prompt = bb_xstrdup(s);
6028#else
Eric Andersenc470f442003-07-28 09:56:35 +00006029 cmdedit_prompt = s;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +00006030#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006031}
6032#else
6033static inline void putprompt(const char *s)
6034{
6035 out2str(s);
6036}
6037#endif
6038
6039static inline int
6040preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006041{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006042 int nr;
Eric Andersenc470f442003-07-28 09:56:35 +00006043 char *buf = parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006044 parsenextc = buf;
6045
Eric Andersenc470f442003-07-28 09:56:35 +00006046retry:
Eric Andersenbdfd0d72001-10-24 05:00:29 +00006047#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersenc470f442003-07-28 09:56:35 +00006048 if (!iflag || parsefile->fd)
6049 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6050 else {
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006051#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
Eric Andersenfa06a772004-02-06 10:33:19 +00006052 cmdedit_path_lookup = pathval();
Eric Andersen4a79c0e2004-09-08 10:01:07 +00006053#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006054 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6055 if(nr == 0) {
6056 /* Ctrl+C presend */
Glenn L McGrath16e45d72004-02-04 08:24:39 +00006057 if(trap[SIGINT]) {
6058 buf[0] = '\n';
6059 buf[1] = 0;
6060 raise(SIGINT);
6061 return 1;
6062 }
Eric Andersenc470f442003-07-28 09:56:35 +00006063 goto retry;
6064 }
Eric Andersencb01bb12004-08-19 18:22:13 +00006065 if(nr < 0 && errno == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006066 /* Ctrl+D presend */
6067 nr = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006068 }
Eric Andersencb57d552001-06-28 07:25:16 +00006069 }
6070#else
Eric Andersen7467c8d2001-07-12 20:26:32 +00006071 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006072#endif
6073
6074 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006075 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6076 int flags = fcntl(0, F_GETFL, 0);
6077 if (flags >= 0 && flags & O_NONBLOCK) {
Eric Andersenc470f442003-07-28 09:56:35 +00006078 flags &=~ O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00006079 if (fcntl(0, F_SETFL, flags) >= 0) {
6080 out2str("sh: turning off NDELAY mode\n");
6081 goto retry;
6082 }
6083 }
6084 }
6085 }
6086 return nr;
6087}
6088
6089/*
6090 * Refill the input buffer and return the next input character:
6091 *
6092 * 1) If a string was pushed back on the input, pop it;
6093 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6094 * from a string so we can't refill the buffer, return EOF.
6095 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6096 * 4) Process input up to the next newline, deleting nul characters.
6097 */
6098
Eric Andersenc470f442003-07-28 09:56:35 +00006099int
6100preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006101{
6102 char *p, *q;
6103 int more;
6104 char savec;
6105
6106 while (parsefile->strpush) {
Eric Andersend35c5df2002-01-09 15:37:36 +00006107#ifdef CONFIG_ASH_ALIAS
Eric Andersen2870d962001-07-02 17:27:21 +00006108 if (parsenleft == -1 && parsefile->strpush->ap &&
6109 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006110 return PEOA;
6111 }
Eric Andersen2870d962001-07-02 17:27:21 +00006112#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006113 popstring();
6114 if (--parsenleft >= 0)
6115 return (*parsenextc++);
6116 }
6117 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6118 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006119 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006120
Eric Andersenc470f442003-07-28 09:56:35 +00006121again:
Eric Andersencb57d552001-06-28 07:25:16 +00006122 if (parselleft <= 0) {
6123 if ((parselleft = preadfd()) <= 0) {
6124 parselleft = parsenleft = EOF_NLEFT;
6125 return PEOF;
6126 }
6127 }
6128
6129 q = p = parsenextc;
6130
6131 /* delete nul characters */
6132 for (more = 1; more;) {
6133 switch (*p) {
6134 case '\0':
Eric Andersenc470f442003-07-28 09:56:35 +00006135 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006136 goto check;
6137
Eric Andersencb57d552001-06-28 07:25:16 +00006138 case '\n':
6139 parsenleft = q - parsenextc;
Eric Andersenc470f442003-07-28 09:56:35 +00006140 more = 0; /* Stop processing here */
Eric Andersencb57d552001-06-28 07:25:16 +00006141 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006142
Eric Andersencb57d552001-06-28 07:25:16 +00006143 }
6144
6145 *q++ = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00006146check:
Eric Andersencb57d552001-06-28 07:25:16 +00006147 if (--parselleft <= 0 && more) {
6148 parsenleft = q - parsenextc - 1;
6149 if (parsenleft < 0)
6150 goto again;
6151 more = 0;
6152 }
6153 }
6154
6155 savec = *q;
6156 *q = '\0';
6157
6158 if (vflag) {
6159 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006160 }
6161
6162 *q = savec;
6163
6164 return *parsenextc++;
6165}
6166
Eric Andersenc470f442003-07-28 09:56:35 +00006167/*
6168 * Undo the last call to pgetc. Only one character may be pushed back.
6169 * PEOF may be pushed back.
6170 */
6171
6172void
6173pungetc(void)
6174{
6175 parsenleft++;
6176 parsenextc--;
6177}
Eric Andersencb57d552001-06-28 07:25:16 +00006178
6179/*
6180 * Push a string back onto the input at this current parsefile level.
6181 * We handle aliases this way.
6182 */
Eric Andersenc470f442003-07-28 09:56:35 +00006183void
6184pushstring(char *s, void *ap)
Eric Andersen2870d962001-07-02 17:27:21 +00006185{
Eric Andersencb57d552001-06-28 07:25:16 +00006186 struct strpush *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00006187 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00006188
Eric Andersenc470f442003-07-28 09:56:35 +00006189 len = strlen(s);
Eric Andersencb57d552001-06-28 07:25:16 +00006190 INTOFF;
6191/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6192 if (parsefile->strpush) {
Eric Andersenc470f442003-07-28 09:56:35 +00006193 sp = ckmalloc(sizeof (struct strpush));
Eric Andersencb57d552001-06-28 07:25:16 +00006194 sp->prev = parsefile->strpush;
6195 parsefile->strpush = sp;
6196 } else
6197 sp = parsefile->strpush = &(parsefile->basestrpush);
6198 sp->prevstring = parsenextc;
6199 sp->prevnleft = parsenleft;
Eric Andersend35c5df2002-01-09 15:37:36 +00006200#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00006201 sp->ap = (struct alias *)ap;
Eric Andersencb57d552001-06-28 07:25:16 +00006202 if (ap) {
Eric Andersenc470f442003-07-28 09:56:35 +00006203 ((struct alias *)ap)->flag |= ALIASINUSE;
Eric Andersencb57d552001-06-28 07:25:16 +00006204 sp->string = s;
6205 }
Eric Andersen2870d962001-07-02 17:27:21 +00006206#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006207 parsenextc = s;
6208 parsenleft = len;
6209 INTON;
6210}
6211
Eric Andersenc470f442003-07-28 09:56:35 +00006212void
6213popstring(void)
6214{
6215 struct strpush *sp = parsefile->strpush;
6216
6217 INTOFF;
6218#ifdef CONFIG_ASH_ALIAS
6219 if (sp->ap) {
6220 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6221 checkkwd |= CHKALIAS;
6222 }
6223 if (sp->string != sp->ap->val) {
6224 ckfree(sp->string);
6225 }
6226 sp->ap->flag &= ~ALIASINUSE;
6227 if (sp->ap->flag & ALIASDEAD) {
6228 unalias(sp->ap->name);
6229 }
6230 }
6231#endif
6232 parsenextc = sp->prevstring;
6233 parsenleft = sp->prevnleft;
6234/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6235 parsefile->strpush = sp->prev;
6236 if (sp != &(parsefile->basestrpush))
6237 ckfree(sp);
6238 INTON;
6239}
6240
6241/*
6242 * Set the input to take input from a file. If push is set, push the
6243 * old input onto the stack first.
6244 */
6245
6246void
6247setinputfile(const char *fname, int push)
6248{
6249 int fd;
6250 int fd2;
6251
6252 INTOFF;
6253 if ((fd = open(fname, O_RDONLY)) < 0)
6254 error("Can't open %s", fname);
6255 if (fd < 10) {
6256 fd2 = copyfd(fd, 10);
6257 close(fd);
6258 if (fd2 < 0)
6259 error("Out of file descriptors");
6260 fd = fd2;
6261 }
6262 setinputfd(fd, push);
6263 INTON;
6264}
6265
6266
6267/*
6268 * Like setinputfile, but takes an open file descriptor. Call this with
6269 * interrupts off.
6270 */
6271
6272static void
6273setinputfd(int fd, int push)
6274{
6275 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6276 if (push) {
6277 pushfile();
6278 parsefile->buf = 0;
6279 }
6280 parsefile->fd = fd;
6281 if (parsefile->buf == NULL)
6282 parsefile->buf = ckmalloc(IBUFSIZ);
6283 parselleft = parsenleft = 0;
6284 plinno = 1;
6285}
6286
Eric Andersencb57d552001-06-28 07:25:16 +00006287
Eric Andersencb57d552001-06-28 07:25:16 +00006288/*
6289 * Like setinputfile, but takes input from a string.
6290 */
6291
Eric Andersenc470f442003-07-28 09:56:35 +00006292static void
6293setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +00006294{
Eric Andersencb57d552001-06-28 07:25:16 +00006295 INTOFF;
6296 pushfile();
6297 parsenextc = string;
6298 parsenleft = strlen(string);
6299 parsefile->buf = NULL;
6300 plinno = 1;
6301 INTON;
6302}
6303
6304
Eric Andersencb57d552001-06-28 07:25:16 +00006305/*
6306 * To handle the "." command, a stack of input files is used. Pushfile
6307 * adds a new entry to the stack and popfile restores the previous level.
6308 */
6309
Eric Andersenc470f442003-07-28 09:56:35 +00006310static void
6311pushfile(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +00006312{
Eric Andersencb57d552001-06-28 07:25:16 +00006313 struct parsefile *pf;
6314
6315 parsefile->nleft = parsenleft;
6316 parsefile->lleft = parselleft;
6317 parsefile->nextc = parsenextc;
6318 parsefile->linno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +00006319 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
Eric Andersencb57d552001-06-28 07:25:16 +00006320 pf->prev = parsefile;
6321 pf->fd = -1;
6322 pf->strpush = NULL;
6323 pf->basestrpush.prev = NULL;
6324 parsefile = pf;
6325}
6326
Eric Andersenc470f442003-07-28 09:56:35 +00006327
6328static void
6329popfile(void)
6330{
6331 struct parsefile *pf = parsefile;
6332
6333 INTOFF;
6334 if (pf->fd >= 0)
6335 close(pf->fd);
6336 if (pf->buf)
6337 ckfree(pf->buf);
6338 while (pf->strpush)
6339 popstring();
6340 parsefile = pf->prev;
6341 ckfree(pf);
6342 parsenleft = parsefile->nleft;
6343 parselleft = parsefile->lleft;
6344 parsenextc = parsefile->nextc;
6345 plinno = parsefile->linno;
6346 INTON;
6347}
Eric Andersencb57d552001-06-28 07:25:16 +00006348
6349
Eric Andersen2870d962001-07-02 17:27:21 +00006350/*
Eric Andersenc470f442003-07-28 09:56:35 +00006351 * Return to top level.
6352 */
Eric Andersen2870d962001-07-02 17:27:21 +00006353
Eric Andersenc470f442003-07-28 09:56:35 +00006354static void
6355popallfiles(void)
Eric Andersen74400cc2001-10-18 04:11:39 +00006356{
Eric Andersenc470f442003-07-28 09:56:35 +00006357 while (parsefile != &basepf)
6358 popfile();
Eric Andersen2870d962001-07-02 17:27:21 +00006359}
6360
Eric Andersen2870d962001-07-02 17:27:21 +00006361
Eric Andersenc470f442003-07-28 09:56:35 +00006362/*
6363 * Close the file(s) that the shell is reading commands from. Called
6364 * after a fork is done.
6365 */
6366
6367static void
6368closescript(void)
6369{
6370 popallfiles();
6371 if (parsefile->fd > 0) {
6372 close(parsefile->fd);
6373 parsefile->fd = 0;
6374 }
6375}
Eric Andersenc470f442003-07-28 09:56:35 +00006376
Eric Andersen90898442003-08-06 11:20:52 +00006377/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
Eric Andersenc470f442003-07-28 09:56:35 +00006378
6379/* mode flags for set_curjob */
6380#define CUR_DELETE 2
6381#define CUR_RUNNING 1
6382#define CUR_STOPPED 0
6383
6384/* mode flags for dowait */
6385#define DOWAIT_NORMAL 0
6386#define DOWAIT_BLOCK 1
6387
6388/* array of jobs */
6389static struct job *jobtab;
6390/* size of array */
6391static unsigned njobs;
6392#if JOBS
6393/* pgrp of shell on invocation */
6394static int initialpgrp;
6395static int ttyfd = -1;
6396#endif
6397/* current job */
6398static struct job *curjob;
6399/* number of presumed living untracked jobs */
6400static int jobless;
6401
6402static void set_curjob(struct job *, unsigned);
6403#if JOBS
6404static int restartjob(struct job *, int);
6405static void xtcsetpgrp(int, pid_t);
6406static char *commandtext(union node *);
6407static void cmdlist(union node *, int);
6408static void cmdtxt(union node *);
6409static void cmdputs(const char *);
6410static void showpipe(struct job *, FILE *);
6411#endif
6412static int sprint_status(char *, int, int);
6413static void freejob(struct job *);
6414static struct job *getjob(const char *, int);
6415static struct job *growjobtab(void);
6416static void forkchild(struct job *, union node *, int);
6417static void forkparent(struct job *, union node *, int, pid_t);
6418static int dowait(int, struct job *);
6419static int getstatus(struct job *);
6420
6421static void
6422set_curjob(struct job *jp, unsigned mode)
6423{
6424 struct job *jp1;
6425 struct job **jpp, **curp;
6426
6427 /* first remove from list */
6428 jpp = curp = &curjob;
6429 do {
6430 jp1 = *jpp;
6431 if (jp1 == jp)
6432 break;
6433 jpp = &jp1->prev_job;
6434 } while (1);
6435 *jpp = jp1->prev_job;
6436
6437 /* Then re-insert in correct position */
6438 jpp = curp;
6439 switch (mode) {
6440 default:
6441#ifdef DEBUG
6442 abort();
6443#endif
6444 case CUR_DELETE:
6445 /* job being deleted */
6446 break;
6447 case CUR_RUNNING:
6448 /* newly created job or backgrounded job,
6449 put after all stopped jobs. */
6450 do {
6451 jp1 = *jpp;
6452#ifdef JOBS
6453 if (!jp1 || jp1->state != JOBSTOPPED)
6454#endif
6455 break;
6456 jpp = &jp1->prev_job;
6457 } while (1);
6458 /* FALLTHROUGH */
6459#ifdef JOBS
6460 case CUR_STOPPED:
6461#endif
6462 /* newly stopped job - becomes curjob */
6463 jp->prev_job = *jpp;
6464 *jpp = jp;
6465 break;
6466 }
6467}
6468
6469#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006470/*
6471 * Turn job control on and off.
6472 *
6473 * Note: This code assumes that the third arg to ioctl is a character
6474 * pointer, which is true on Berkeley systems but not System V. Since
6475 * System V doesn't have job control yet, this isn't a problem now.
Eric Andersenc470f442003-07-28 09:56:35 +00006476 *
6477 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00006478 */
6479
Eric Andersenc470f442003-07-28 09:56:35 +00006480void
6481setjobctl(int on)
Eric Andersencb57d552001-06-28 07:25:16 +00006482{
Eric Andersenc470f442003-07-28 09:56:35 +00006483 int fd;
6484 int pgrp;
6485
6486 if (on == jobctl || rootshell == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00006487 return;
Eric Andersenc470f442003-07-28 09:56:35 +00006488 if (on) {
6489 int ofd;
6490 ofd = fd = open(_PATH_TTY, O_RDWR);
6491 if (fd < 0) {
6492 fd += 3;
6493 while (!isatty(fd) && --fd >= 0)
6494 ;
6495 }
6496 fd = fcntl(fd, F_DUPFD, 10);
6497 close(ofd);
6498 if (fd < 0)
6499 goto out;
6500 fcntl(fd, F_SETFD, FD_CLOEXEC);
6501 do { /* while we are in the background */
6502 if ((pgrp = tcgetpgrp(fd)) < 0) {
6503out:
6504 sh_warnx("can't access tty; job control turned off");
6505 mflag = on = 0;
6506 goto close;
Eric Andersencb57d552001-06-28 07:25:16 +00006507 }
Eric Andersenc470f442003-07-28 09:56:35 +00006508 if (pgrp == getpgrp())
Glenn L McGrath7040ecc2003-01-06 16:27:07 +00006509 break;
6510 killpg(0, SIGTTIN);
6511 } while (1);
Eric Andersenc470f442003-07-28 09:56:35 +00006512 initialpgrp = pgrp;
6513
Eric Andersencb57d552001-06-28 07:25:16 +00006514 setsignal(SIGTSTP);
6515 setsignal(SIGTTOU);
6516 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006517 pgrp = rootpid;
6518 setpgid(0, pgrp);
6519 xtcsetpgrp(fd, pgrp);
6520 } else {
6521 /* turning job control off */
6522 fd = ttyfd;
6523 pgrp = initialpgrp;
6524 xtcsetpgrp(fd, pgrp);
6525 setpgid(0, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006526 setsignal(SIGTSTP);
6527 setsignal(SIGTTOU);
6528 setsignal(SIGTTIN);
Eric Andersenc470f442003-07-28 09:56:35 +00006529close:
6530 close(fd);
6531 fd = -1;
Eric Andersencb57d552001-06-28 07:25:16 +00006532 }
Eric Andersenc470f442003-07-28 09:56:35 +00006533 ttyfd = fd;
6534 jobctl = on;
Eric Andersencb57d552001-06-28 07:25:16 +00006535}
Eric Andersencb57d552001-06-28 07:25:16 +00006536
Eric Andersenc470f442003-07-28 09:56:35 +00006537static int
Eric Andersen90898442003-08-06 11:20:52 +00006538killcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006539{
6540 int signo = -1;
6541 int list = 0;
6542 int i;
6543 pid_t pid;
6544 struct job *jp;
6545
6546 if (argc <= 1) {
Eric Andersenc470f442003-07-28 09:56:35 +00006547usage:
6548 error(
6549"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6550"kill -l [exitstatus]"
6551 );
Eric Andersencb57d552001-06-28 07:25:16 +00006552 }
6553
Eric Andersenc470f442003-07-28 09:56:35 +00006554 if (**++argv == '-') {
6555 signo = decode_signal(*argv + 1, 1);
Eric Andersencb57d552001-06-28 07:25:16 +00006556 if (signo < 0) {
6557 int c;
6558
6559 while ((c = nextopt("ls:")) != '\0')
6560 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +00006561 default:
6562#ifdef DEBUG
6563 abort();
6564#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006565 case 'l':
6566 list = 1;
6567 break;
6568 case 's':
6569 signo = decode_signal(optionarg, 1);
6570 if (signo < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00006571 error(
6572 "invalid signal number or name: %s",
6573 optionarg
6574 );
Eric Andersencb57d552001-06-28 07:25:16 +00006575 }
Eric Andersen2870d962001-07-02 17:27:21 +00006576 break;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006577 }
Eric Andersenc470f442003-07-28 09:56:35 +00006578 argv = argptr;
Eric Andersencb57d552001-06-28 07:25:16 +00006579 } else
Eric Andersenc470f442003-07-28 09:56:35 +00006580 argv++;
Eric Andersencb57d552001-06-28 07:25:16 +00006581 }
6582
6583 if (!list && signo < 0)
6584 signo = SIGTERM;
6585
Eric Andersenc470f442003-07-28 09:56:35 +00006586 if ((signo < 0 || !*argv) ^ list) {
Eric Andersencb57d552001-06-28 07:25:16 +00006587 goto usage;
6588 }
6589
6590 if (list) {
Eric Andersen34506362001-08-02 05:02:46 +00006591 const char *name;
6592
Eric Andersenc470f442003-07-28 09:56:35 +00006593 if (!*argv) {
Eric Andersencb57d552001-06-28 07:25:16 +00006594 for (i = 1; i < NSIG; i++) {
Eric Andersen34506362001-08-02 05:02:46 +00006595 name = u_signal_names(0, &i, 1);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006596 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006597 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006598 }
6599 return 0;
6600 }
Eric Andersen34506362001-08-02 05:02:46 +00006601 name = u_signal_names(*argptr, &signo, -1);
6602 if (name)
Eric Andersenc470f442003-07-28 09:56:35 +00006603 out1fmt(snlfmt, name);
Eric Andersencb57d552001-06-28 07:25:16 +00006604 else
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006605 error("invalid signal number or exit status: %s", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006606 return 0;
6607 }
6608
Eric Andersenc470f442003-07-28 09:56:35 +00006609 i = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00006610 do {
Eric Andersenc470f442003-07-28 09:56:35 +00006611 if (**argv == '%') {
6612 jp = getjob(*argv, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006613 pid = -jp->ps[0].pid;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006614 } else {
6615 pid = **argv == '-' ?
6616 -number(*argv + 1) : number(*argv);
6617 }
Eric Andersenc470f442003-07-28 09:56:35 +00006618 if (kill(pid, signo) != 0) {
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00006619 sh_warnx("(%d) - %m", pid);
Eric Andersenc470f442003-07-28 09:56:35 +00006620 i = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006621 }
Eric Andersenc470f442003-07-28 09:56:35 +00006622 } while (*++argv);
6623
6624 return i;
6625}
6626#endif /* JOBS */
6627
6628#if defined(JOBS) || defined(DEBUG)
6629static int
6630jobno(const struct job *jp)
6631{
6632 return jp - jobtab + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00006633}
6634#endif
6635
Eric Andersenc470f442003-07-28 09:56:35 +00006636#ifdef JOBS
6637static int
6638fgcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006639{
Eric Andersenc470f442003-07-28 09:56:35 +00006640 struct job *jp;
6641 FILE *out;
6642 int mode;
6643 int retval;
6644
6645 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6646 nextopt(nullstr);
6647 argv = argptr;
6648 out = stdout;
6649 do {
6650 jp = getjob(*argv, 1);
6651 if (mode == FORK_BG) {
6652 set_curjob(jp, CUR_RUNNING);
6653 fprintf(out, "[%d] ", jobno(jp));
6654 }
6655 outstr(jp->ps->cmd, out);
6656 showpipe(jp, out);
6657 retval = restartjob(jp, mode);
6658 } while (*argv && *++argv);
6659 return retval;
6660}
6661
6662static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6663
6664
6665static int
6666restartjob(struct job *jp, int mode)
6667{
6668 struct procstat *ps;
6669 int i;
6670 int status;
6671 pid_t pgid;
6672
6673 INTOFF;
6674 if (jp->state == JOBDONE)
6675 goto out;
6676 jp->state = JOBRUNNING;
6677 pgid = jp->ps->pid;
6678 if (mode == FORK_FG)
6679 xtcsetpgrp(ttyfd, pgid);
6680 killpg(pgid, SIGCONT);
6681 ps = jp->ps;
6682 i = jp->nprocs;
6683 do {
6684 if (WIFSTOPPED(ps->status)) {
6685 ps->status = -1;
6686 }
6687 } while (ps++, --i);
6688out:
6689 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6690 INTON;
6691 return status;
6692}
6693#endif
6694
6695static int
6696sprint_status(char *s, int status, int sigonly)
6697{
6698 int col;
6699 int st;
6700
6701 col = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006702 if (!WIFEXITED(status)) {
Eric Andersenc470f442003-07-28 09:56:35 +00006703#if JOBS
Glenn L McGratha3822de2003-09-15 14:42:39 +00006704 if (WIFSTOPPED(status))
6705 st = WSTOPSIG(status);
Eric Andersena48b0a32003-10-22 10:56:47 +00006706 else
Eric Andersenc470f442003-07-28 09:56:35 +00006707#endif
Eric Andersena48b0a32003-10-22 10:56:47 +00006708 st = WTERMSIG(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006709 if (sigonly) {
Glenn L McGrath4ddddd12003-11-25 20:45:38 +00006710 if (st == SIGINT || st == SIGPIPE)
Eric Andersena48b0a32003-10-22 10:56:47 +00006711 goto out;
6712#if JOBS
Eric Andersenc470f442003-07-28 09:56:35 +00006713 if (WIFSTOPPED(status))
6714 goto out;
Eric Andersena48b0a32003-10-22 10:56:47 +00006715#endif
Eric Andersenc470f442003-07-28 09:56:35 +00006716 }
6717 st &= 0x7f;
Glenn L McGrath5c2c8ec2003-11-14 21:01:26 +00006718 col = fmtstr(s, 32, strsignal(st));
Eric Andersenc470f442003-07-28 09:56:35 +00006719 if (WCOREDUMP(status)) {
6720 col += fmtstr(s + col, 16, " (core dumped)");
6721 }
6722 } else if (!sigonly) {
Eric Andersena48b0a32003-10-22 10:56:47 +00006723 st = WEXITSTATUS(status);
Eric Andersenc470f442003-07-28 09:56:35 +00006724 if (st)
6725 col = fmtstr(s, 16, "Done(%d)", st);
6726 else
6727 col = fmtstr(s, 16, "Done");
6728 }
6729
6730out:
6731 return col;
6732}
6733
6734#if JOBS
6735static void
6736showjob(FILE *out, struct job *jp, int mode)
6737{
6738 struct procstat *ps;
6739 struct procstat *psend;
6740 int col;
6741 int indent;
6742 char s[80];
6743
6744 ps = jp->ps;
6745
6746 if (mode & SHOW_PGID) {
6747 /* just output process (group) id of pipeline */
6748 fprintf(out, "%d\n", ps->pid);
6749 return;
6750 }
6751
6752 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6753 indent = col;
6754
6755 if (jp == curjob)
6756 s[col - 2] = '+';
6757 else if (curjob && jp == curjob->prev_job)
6758 s[col - 2] = '-';
6759
6760 if (mode & SHOW_PID)
6761 col += fmtstr(s + col, 16, "%d ", ps->pid);
6762
6763 psend = ps + jp->nprocs;
6764
6765 if (jp->state == JOBRUNNING) {
6766 scopy("Running", s + col);
6767 col += strlen("Running");
6768 } else {
6769 int status = psend[-1].status;
6770#if JOBS
6771 if (jp->state == JOBSTOPPED)
6772 status = jp->stopstatus;
6773#endif
6774 col += sprint_status(s + col, status, 0);
6775 }
6776
6777 goto start;
6778
6779 do {
6780 /* for each process */
6781 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6782
6783start:
Eric Andersen90898442003-08-06 11:20:52 +00006784 fprintf(out, "%s%*c%s",
Eric Andersenc470f442003-07-28 09:56:35 +00006785 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6786 );
6787 if (!(mode & SHOW_PID)) {
6788 showpipe(jp, out);
6789 break;
6790 }
6791 if (++ps == psend) {
6792 outcslow('\n', out);
6793 break;
6794 }
6795 } while (1);
6796
6797 jp->changed = 0;
6798
6799 if (jp->state == JOBDONE) {
6800 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6801 freejob(jp);
6802 }
6803}
6804
6805
6806static int
6807jobscmd(int argc, char **argv)
6808{
6809 int mode, m;
6810 FILE *out;
6811
6812 mode = 0;
6813 while ((m = nextopt("lp")))
6814 if (m == 'l')
6815 mode = SHOW_PID;
6816 else
6817 mode = SHOW_PGID;
6818
6819 out = stdout;
6820 argv = argptr;
6821 if (*argv)
6822 do
6823 showjob(out, getjob(*argv,0), mode);
6824 while (*++argv);
6825 else
6826 showjobs(out, mode);
6827
Eric Andersencb57d552001-06-28 07:25:16 +00006828 return 0;
6829}
6830
6831
6832/*
6833 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6834 * statuses have changed since the last call to showjobs.
Eric Andersencb57d552001-06-28 07:25:16 +00006835 */
6836
Eric Andersenc470f442003-07-28 09:56:35 +00006837static void
6838showjobs(FILE *out, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00006839{
Eric Andersencb57d552001-06-28 07:25:16 +00006840 struct job *jp;
Eric Andersencb57d552001-06-28 07:25:16 +00006841
Eric Andersenc470f442003-07-28 09:56:35 +00006842 TRACE(("showjobs(%x) called\n", mode));
6843
6844 /* If not even one one job changed, there is nothing to do */
6845 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6846 continue;
6847
6848 for (jp = curjob; jp; jp = jp->prev_job) {
6849 if (!(mode & SHOW_CHANGED) || jp->changed)
6850 showjob(out, jp, mode);
Eric Andersencb57d552001-06-28 07:25:16 +00006851 }
6852}
Eric Andersenc470f442003-07-28 09:56:35 +00006853#endif /* JOBS */
Eric Andersencb57d552001-06-28 07:25:16 +00006854
6855/*
6856 * Mark a job structure as unused.
6857 */
6858
Eric Andersenc470f442003-07-28 09:56:35 +00006859static void
6860freejob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00006861{
Eric Andersenc470f442003-07-28 09:56:35 +00006862 struct procstat *ps;
Eric Andersencb57d552001-06-28 07:25:16 +00006863 int i;
6864
6865 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +00006866 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
Eric Andersencb57d552001-06-28 07:25:16 +00006867 if (ps->cmd != nullstr)
Eric Andersenc470f442003-07-28 09:56:35 +00006868 ckfree(ps->cmd);
Eric Andersencb57d552001-06-28 07:25:16 +00006869 }
6870 if (jp->ps != &jp->ps0)
Eric Andersenc470f442003-07-28 09:56:35 +00006871 ckfree(jp->ps);
Eric Andersencb57d552001-06-28 07:25:16 +00006872 jp->used = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00006873 set_curjob(jp, CUR_DELETE);
Eric Andersencb57d552001-06-28 07:25:16 +00006874 INTON;
6875}
6876
6877
Eric Andersenc470f442003-07-28 09:56:35 +00006878static int
6879waitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00006880{
6881 struct job *job;
Eric Andersenc470f442003-07-28 09:56:35 +00006882 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006883 struct job *jp;
6884
Eric Andersenc470f442003-07-28 09:56:35 +00006885 EXSIGON();
6886
6887 nextopt(nullstr);
6888 retval = 0;
6889
6890 argv = argptr;
6891 if (!*argv) {
6892 /* wait for all jobs */
6893 for (;;) {
6894 jp = curjob;
6895 while (1) {
6896 if (!jp) {
6897 /* no running procs */
6898 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00006899 }
Eric Andersenc470f442003-07-28 09:56:35 +00006900 if (jp->state == JOBRUNNING)
Eric Andersencb57d552001-06-28 07:25:16 +00006901 break;
Eric Andersenc470f442003-07-28 09:56:35 +00006902 jp->waited = 1;
6903 jp = jp->prev_job;
Eric Andersencb57d552001-06-28 07:25:16 +00006904 }
Eric Andersenc470f442003-07-28 09:56:35 +00006905 dowait(DOWAIT_BLOCK, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006906 }
6907 }
Eric Andersenc470f442003-07-28 09:56:35 +00006908
6909 retval = 127;
6910 do {
6911 if (**argv != '%') {
6912 pid_t pid = number(*argv);
6913 job = curjob;
6914 goto start;
6915 do {
6916 if (job->ps[job->nprocs - 1].pid == pid)
6917 break;
6918 job = job->prev_job;
6919start:
6920 if (!job)
6921 goto repeat;
6922 } while (1);
6923 } else
6924 job = getjob(*argv, 0);
6925 /* loop until process terminated or stopped */
6926 while (job->state == JOBRUNNING)
6927 dowait(DOWAIT_BLOCK, 0);
6928 job->waited = 1;
6929 retval = getstatus(job);
6930repeat:
6931 ;
6932 } while (*++argv);
6933
6934out:
6935 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00006936}
6937
6938
Eric Andersencb57d552001-06-28 07:25:16 +00006939/*
6940 * Convert a job name to a job structure.
6941 */
6942
Eric Andersenc470f442003-07-28 09:56:35 +00006943static struct job *
6944getjob(const char *name, int getctl)
Eric Andersen2870d962001-07-02 17:27:21 +00006945{
Eric Andersencb57d552001-06-28 07:25:16 +00006946 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00006947 struct job *found;
6948 const char *err_msg = "No such job: %s";
6949 unsigned num;
6950 int c;
6951 const char *p;
6952 char *(*match)(const char *, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00006953
Eric Andersenc470f442003-07-28 09:56:35 +00006954 jp = curjob;
6955 p = name;
6956 if (!p)
6957 goto currentjob;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00006958
Eric Andersenc470f442003-07-28 09:56:35 +00006959 if (*p != '%')
6960 goto err;
6961
6962 c = *++p;
6963 if (!c)
6964 goto currentjob;
6965
6966 if (!p[1]) {
6967 if (c == '+' || c == '%') {
6968currentjob:
6969 err_msg = "No current job";
6970 goto check;
6971 } else if (c == '-') {
6972 if (jp)
6973 jp = jp->prev_job;
6974 err_msg = "No previous job";
6975check:
6976 if (!jp)
6977 goto err;
6978 goto gotit;
Eric Andersencb57d552001-06-28 07:25:16 +00006979 }
6980 }
Eric Andersenc470f442003-07-28 09:56:35 +00006981
6982 if (is_number(p)) {
6983 num = atoi(p);
6984 if (num < njobs) {
6985 jp = jobtab + num - 1;
6986 if (jp->used)
6987 goto gotit;
6988 goto err;
6989 }
6990 }
6991
6992 match = prefix;
6993 if (*p == '?') {
6994 match = strstr;
6995 p++;
6996 }
6997
6998 found = 0;
6999 while (1) {
7000 if (!jp)
7001 goto err;
7002 if (match(jp->ps[0].cmd, p)) {
7003 if (found)
7004 goto err;
7005 found = jp;
7006 err_msg = "%s: ambiguous";
7007 }
7008 jp = jp->prev_job;
7009 }
7010
7011gotit:
7012#if JOBS
7013 err_msg = "job %s not created under job control";
7014 if (getctl && jp->jobctl == 0)
7015 goto err;
7016#endif
7017 return jp;
7018err:
7019 error(err_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00007020}
7021
7022
Eric Andersencb57d552001-06-28 07:25:16 +00007023/*
Eric Andersenc470f442003-07-28 09:56:35 +00007024 * Return a new job structure.
7025 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007026 */
7027
Eric Andersenc470f442003-07-28 09:56:35 +00007028static struct job *
7029makejob(union node *node, int nprocs)
Eric Andersencb57d552001-06-28 07:25:16 +00007030{
7031 int i;
7032 struct job *jp;
7033
Eric Andersenc470f442003-07-28 09:56:35 +00007034 for (i = njobs, jp = jobtab ; ; jp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007035 if (--i < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +00007036 jp = growjobtab();
Eric Andersencb57d552001-06-28 07:25:16 +00007037 break;
7038 }
7039 if (jp->used == 0)
7040 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007041 if (jp->state != JOBDONE || !jp->waited)
7042 continue;
7043#if JOBS
7044 if (jobctl)
7045 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007046#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007047 freejob(jp);
7048 break;
Eric Andersencb57d552001-06-28 07:25:16 +00007049 }
Eric Andersenc470f442003-07-28 09:56:35 +00007050 memset(jp, 0, sizeof(*jp));
7051#if JOBS
7052 if (jobctl)
7053 jp->jobctl = 1;
7054#endif
7055 jp->prev_job = curjob;
7056 curjob = jp;
7057 jp->used = 1;
7058 jp->ps = &jp->ps0;
7059 if (nprocs > 1) {
7060 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7061 }
7062 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7063 jobno(jp)));
7064 return jp;
7065}
7066
7067static struct job *
7068growjobtab(void)
7069{
7070 size_t len;
7071 ptrdiff_t offset;
7072 struct job *jp, *jq;
7073
7074 len = njobs * sizeof(*jp);
7075 jq = jobtab;
7076 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7077
7078 offset = (char *)jp - (char *)jq;
7079 if (offset) {
7080 /* Relocate pointers */
7081 size_t l = len;
7082
7083 jq = (struct job *)((char *)jq + l);
7084 while (l) {
7085 l -= sizeof(*jp);
7086 jq--;
7087#define joff(p) ((struct job *)((char *)(p) + l))
7088#define jmove(p) (p) = (void *)((char *)(p) + offset)
Glenn L McGrath2f325a02004-08-06 01:49:04 +00007089 if (xlikely(joff(jp)->ps == &jq->ps0))
Eric Andersenc470f442003-07-28 09:56:35 +00007090 jmove(joff(jp)->ps);
7091 if (joff(jp)->prev_job)
7092 jmove(joff(jp)->prev_job);
7093 }
7094 if (curjob)
7095 jmove(curjob);
7096#undef joff
7097#undef jmove
7098 }
7099
7100 njobs += 4;
7101 jobtab = jp;
7102 jp = (struct job *)((char *)jp + len);
7103 jq = jp + 3;
7104 do {
7105 jq->used = 0;
7106 } while (--jq >= jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007107 return jp;
7108}
7109
7110
7111/*
Eric Andersenc470f442003-07-28 09:56:35 +00007112 * Fork off a subshell. If we are doing job control, give the subshell its
Eric Andersencb57d552001-06-28 07:25:16 +00007113 * own process group. Jp is a job structure that the job is to be added to.
7114 * N is the command that will be evaluated by the child. Both jp and n may
7115 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007116 * FORK_FG - Fork off a foreground process.
7117 * FORK_BG - Fork off a background process.
7118 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7119 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007120 *
7121 * When job control is turned off, background processes have their standard
7122 * input redirected to /dev/null (except for the second and later processes
7123 * in a pipeline).
Eric Andersenc470f442003-07-28 09:56:35 +00007124 *
7125 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007126 */
7127
Eric Andersenc470f442003-07-28 09:56:35 +00007128static inline void
7129forkchild(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007130{
Eric Andersenc470f442003-07-28 09:56:35 +00007131 int wasroot;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007132
Eric Andersenc470f442003-07-28 09:56:35 +00007133 TRACE(("Child shell %d\n", getpid()));
7134 wasroot = rootshell;
7135 rootshell = 0;
7136
7137 closescript();
7138 clear_traps();
7139#if JOBS
7140 /* do job control only in root shell */
7141 jobctl = 0;
7142 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7143 pid_t pgrp;
7144
7145 if (jp->nprocs == 0)
7146 pgrp = getpid();
7147 else
7148 pgrp = jp->ps[0].pid;
7149 /* This can fail because we are doing it in the parent also */
7150 (void)setpgid(0, pgrp);
7151 if (mode == FORK_FG)
7152 xtcsetpgrp(ttyfd, pgrp);
7153 setsignal(SIGTSTP);
7154 setsignal(SIGTTOU);
7155 } else
Eric Andersen62483552001-07-10 06:09:16 +00007156#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007157 if (mode == FORK_BG) {
7158 ignoresig(SIGINT);
7159 ignoresig(SIGQUIT);
7160 if (jp->nprocs == 0) {
7161 close(0);
7162 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7163 error("Can't open %s", _PATH_DEVNULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007164 }
Eric Andersencb57d552001-06-28 07:25:16 +00007165 }
Eric Andersenc470f442003-07-28 09:56:35 +00007166 if (wasroot && iflag) {
7167 setsignal(SIGINT);
7168 setsignal(SIGQUIT);
7169 setsignal(SIGTERM);
7170 }
7171 for (jp = curjob; jp; jp = jp->prev_job)
7172 freejob(jp);
7173 jobless = 0;
7174}
7175
7176static inline void
7177forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7178{
7179 TRACE(("In parent shell: child = %d\n", pid));
7180 if (!jp) {
7181 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7182 jobless++;
7183 return;
7184 }
7185#if JOBS
7186 if (mode != FORK_NOJOB && jp->jobctl) {
7187 int pgrp;
7188
7189 if (jp->nprocs == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007190 pgrp = pid;
7191 else
7192 pgrp = jp->ps[0].pid;
Eric Andersenc470f442003-07-28 09:56:35 +00007193 /* This can fail because we are doing it in the child also */
7194 (void)setpgid(pid, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00007195 }
Eric Andersen62483552001-07-10 06:09:16 +00007196#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007197 if (mode == FORK_BG) {
7198 backgndpid = pid; /* set $! */
7199 set_curjob(jp, CUR_RUNNING);
7200 }
Eric Andersencb57d552001-06-28 07:25:16 +00007201 if (jp) {
7202 struct procstat *ps = &jp->ps[jp->nprocs++];
7203 ps->pid = pid;
7204 ps->status = -1;
7205 ps->cmd = nullstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007206#if JOBS
7207 if (jobctl && n)
Eric Andersencb57d552001-06-28 07:25:16 +00007208 ps->cmd = commandtext(n);
Eric Andersenc470f442003-07-28 09:56:35 +00007209#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007210 }
Eric Andersencb57d552001-06-28 07:25:16 +00007211}
7212
Eric Andersenc470f442003-07-28 09:56:35 +00007213static int
7214forkshell(struct job *jp, union node *n, int mode)
7215{
7216 int pid;
Eric Andersencb57d552001-06-28 07:25:16 +00007217
Eric Andersenc470f442003-07-28 09:56:35 +00007218 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7219 pid = fork();
7220 if (pid < 0) {
7221 TRACE(("Fork failed, errno=%d", errno));
7222 if (jp)
7223 freejob(jp);
7224 error("Cannot fork");
7225 }
7226 if (pid == 0)
7227 forkchild(jp, n, mode);
7228 else
7229 forkparent(jp, n, mode, pid);
7230 return pid;
7231}
Eric Andersencb57d552001-06-28 07:25:16 +00007232
7233/*
7234 * Wait for job to finish.
7235 *
7236 * Under job control we have the problem that while a child process is
7237 * running interrupts generated by the user are sent to the child but not
7238 * to the shell. This means that an infinite loop started by an inter-
7239 * active user may be hard to kill. With job control turned off, an
7240 * interactive user may place an interactive program inside a loop. If
7241 * the interactive program catches interrupts, the user doesn't want
7242 * these interrupts to also abort the loop. The approach we take here
7243 * is to have the shell ignore interrupt signals while waiting for a
Eric Andersenaff114c2004-04-14 17:51:38 +00007244 * foreground process to terminate, and then send itself an interrupt
Eric Andersencb57d552001-06-28 07:25:16 +00007245 * signal if the child process was terminated by an interrupt signal.
7246 * Unfortunately, some programs want to do a bit of cleanup and then
7247 * exit on interrupt; unless these processes terminate themselves by
7248 * sending a signal to themselves (instead of calling exit) they will
7249 * confuse this approach.
Eric Andersenc470f442003-07-28 09:56:35 +00007250 *
7251 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +00007252 */
7253
Eric Andersenc470f442003-07-28 09:56:35 +00007254int
7255waitforjob(struct job *jp)
Eric Andersen62483552001-07-10 06:09:16 +00007256{
Eric Andersencb57d552001-06-28 07:25:16 +00007257 int st;
Eric Andersencb57d552001-06-28 07:25:16 +00007258
Eric Andersenc470f442003-07-28 09:56:35 +00007259 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7260 while (jp->state == JOBRUNNING) {
7261 dowait(DOWAIT_BLOCK, jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007262 }
Eric Andersenc470f442003-07-28 09:56:35 +00007263 st = getstatus(jp);
7264#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007265 if (jp->jobctl) {
Eric Andersenc470f442003-07-28 09:56:35 +00007266 xtcsetpgrp(ttyfd, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00007267 /*
7268 * This is truly gross.
7269 * If we're doing job control, then we did a TIOCSPGRP which
7270 * caused us (the shell) to no longer be in the controlling
7271 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7272 * intuit from the subprocess exit status whether a SIGINT
Eric Andersenc470f442003-07-28 09:56:35 +00007273 * occurred, and if so interrupt ourselves. Yuck. - mycroft
Eric Andersencb57d552001-06-28 07:25:16 +00007274 */
Eric Andersenc470f442003-07-28 09:56:35 +00007275 if (jp->sigint)
Eric Andersencb57d552001-06-28 07:25:16 +00007276 raise(SIGINT);
7277 }
Eric Andersen2870d962001-07-02 17:27:21 +00007278 if (jp->state == JOBDONE)
Eric Andersencb57d552001-06-28 07:25:16 +00007279#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007280 freejob(jp);
Eric Andersencb57d552001-06-28 07:25:16 +00007281 return st;
7282}
7283
7284
Eric Andersen62483552001-07-10 06:09:16 +00007285/*
7286 * Do a wait system call. If job control is compiled in, we accept
7287 * stopped processes. If block is zero, we return a value of zero
7288 * rather than blocking.
7289 *
7290 * System V doesn't have a non-blocking wait system call. It does
7291 * have a SIGCLD signal that is sent to a process when one of it's
7292 * children dies. The obvious way to use SIGCLD would be to install
7293 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7294 * was received, and have waitproc bump another counter when it got
7295 * the status of a process. Waitproc would then know that a wait
7296 * system call would not block if the two counters were different.
7297 * This approach doesn't work because if a process has children that
7298 * have not been waited for, System V will send it a SIGCLD when it
7299 * installs a signal handler for SIGCLD. What this means is that when
7300 * a child exits, the shell will be sent SIGCLD signals continuously
7301 * until is runs out of stack space, unless it does a wait call before
7302 * restoring the signal handler. The code below takes advantage of
7303 * this (mis)feature by installing a signal handler for SIGCLD and
7304 * then checking to see whether it was called. If there are any
7305 * children to be waited for, it will be.
7306 *
Eric Andersenc470f442003-07-28 09:56:35 +00007307 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7308 * waits at all. In this case, the user will not be informed when
7309 * a background process until the next time she runs a real program
7310 * (as opposed to running a builtin command or just typing return),
7311 * and the jobs command may give out of date information.
Eric Andersen62483552001-07-10 06:09:16 +00007312 */
7313
Eric Andersenc470f442003-07-28 09:56:35 +00007314static inline int
7315waitproc(int block, int *status)
Eric Andersen62483552001-07-10 06:09:16 +00007316{
Eric Andersenc470f442003-07-28 09:56:35 +00007317 int flags = 0;
Eric Andersen62483552001-07-10 06:09:16 +00007318
Eric Andersenc470f442003-07-28 09:56:35 +00007319#if JOBS
Eric Andersen62483552001-07-10 06:09:16 +00007320 if (jobctl)
7321 flags |= WUNTRACED;
7322#endif
7323 if (block == 0)
7324 flags |= WNOHANG;
Eric Andersenc470f442003-07-28 09:56:35 +00007325 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersen62483552001-07-10 06:09:16 +00007326}
7327
Eric Andersenc470f442003-07-28 09:56:35 +00007328/*
7329 * Wait for a process to terminate.
7330 */
7331
7332static int
7333dowait(int block, struct job *job)
Eric Andersencb57d552001-06-28 07:25:16 +00007334{
7335 int pid;
7336 int status;
Eric Andersencb57d552001-06-28 07:25:16 +00007337 struct job *jp;
7338 struct job *thisjob;
Eric Andersenc470f442003-07-28 09:56:35 +00007339 int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007340
7341 TRACE(("dowait(%d) called\n", block));
Eric Andersenc470f442003-07-28 09:56:35 +00007342 pid = waitproc(block, &status);
7343 TRACE(("wait returns pid %d, status=%d\n", pid, status));
Eric Andersencb57d552001-06-28 07:25:16 +00007344 if (pid <= 0)
7345 return pid;
7346 INTOFF;
7347 thisjob = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00007348 for (jp = curjob; jp; jp = jp->prev_job) {
7349 struct procstat *sp;
7350 struct procstat *spend;
7351 if (jp->state == JOBDONE)
7352 continue;
7353 state = JOBDONE;
7354 spend = jp->ps + jp->nprocs;
7355 sp = jp->ps;
7356 do {
7357 if (sp->pid == pid) {
7358 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7359 sp->status = status;
7360 thisjob = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00007361 }
Eric Andersenc470f442003-07-28 09:56:35 +00007362 if (sp->status == -1)
7363 state = JOBRUNNING;
7364#ifdef JOBS
7365 if (state == JOBRUNNING)
7366 continue;
7367 if (WIFSTOPPED(sp->status)) {
7368 jp->stopstatus = sp->status;
7369 state = JOBSTOPPED;
7370 }
Eric Andersencb57d552001-06-28 07:25:16 +00007371#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007372 } while (++sp < spend);
7373 if (thisjob)
7374 goto gotjob;
7375 }
7376#ifdef JOBS
7377 if (!WIFSTOPPED(status))
7378#endif
7379
7380 jobless--;
7381 goto out;
7382
7383gotjob:
7384 if (state != JOBRUNNING) {
7385 thisjob->changed = 1;
7386
7387 if (thisjob->state != state) {
7388 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7389 thisjob->state = state;
7390#ifdef JOBS
7391 if (state == JOBSTOPPED) {
7392 set_curjob(thisjob, CUR_STOPPED);
Eric Andersencb57d552001-06-28 07:25:16 +00007393 }
Eric Andersenc470f442003-07-28 09:56:35 +00007394#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007395 }
7396 }
Eric Andersencb57d552001-06-28 07:25:16 +00007397
Eric Andersenc470f442003-07-28 09:56:35 +00007398out:
7399 INTON;
7400
7401 if (thisjob && thisjob == job) {
7402 char s[48 + 1];
7403 int len;
7404
7405 len = sprint_status(s, status, 1);
7406 if (len) {
7407 s[len] = '\n';
7408 s[len + 1] = 0;
7409 out2str(s);
Eric Andersencb57d552001-06-28 07:25:16 +00007410 }
Eric Andersencb57d552001-06-28 07:25:16 +00007411 }
7412 return pid;
7413}
7414
7415
Eric Andersencb57d552001-06-28 07:25:16 +00007416/*
7417 * return 1 if there are stopped jobs, otherwise 0
7418 */
Eric Andersen90898442003-08-06 11:20:52 +00007419
Eric Andersenc470f442003-07-28 09:56:35 +00007420int
7421stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007422{
Eric Andersencb57d552001-06-28 07:25:16 +00007423 struct job *jp;
Eric Andersenc470f442003-07-28 09:56:35 +00007424 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007425
Eric Andersenc470f442003-07-28 09:56:35 +00007426 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007427 if (job_warning)
Eric Andersenc470f442003-07-28 09:56:35 +00007428 goto out;
7429 jp = curjob;
7430 if (jp && jp->state == JOBSTOPPED) {
7431 out2str("You have stopped jobs.\n");
7432 job_warning = 2;
7433 retval++;
Eric Andersencb57d552001-06-28 07:25:16 +00007434 }
7435
Eric Andersenc470f442003-07-28 09:56:35 +00007436out:
7437 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +00007438}
7439
7440/*
7441 * Return a string identifying a command (to be printed by the
Eric Andersenc470f442003-07-28 09:56:35 +00007442 * jobs command).
Eric Andersencb57d552001-06-28 07:25:16 +00007443 */
7444
Eric Andersenc470f442003-07-28 09:56:35 +00007445#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007446static char *cmdnextc;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007447
Eric Andersenc470f442003-07-28 09:56:35 +00007448static char *
7449commandtext(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007450{
Eric Andersenc470f442003-07-28 09:56:35 +00007451 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007452
Eric Andersenc470f442003-07-28 09:56:35 +00007453 STARTSTACKSTR(cmdnextc);
7454 cmdtxt(n);
7455 name = stackblock();
7456 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7457 name, cmdnextc, cmdnextc));
7458 return savestr(name);
Eric Andersencb57d552001-06-28 07:25:16 +00007459}
7460
Eric Andersenc470f442003-07-28 09:56:35 +00007461static void
7462cmdtxt(union node *n)
Eric Andersen2870d962001-07-02 17:27:21 +00007463{
Eric Andersencb57d552001-06-28 07:25:16 +00007464 union node *np;
7465 struct nodelist *lp;
7466 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00007467 char s[2];
7468
Glenn L McGrath16e45d72004-02-04 08:24:39 +00007469 if (!n)
7470 return;
Eric Andersencb57d552001-06-28 07:25:16 +00007471 switch (n->type) {
Eric Andersenc470f442003-07-28 09:56:35 +00007472 default:
7473#if DEBUG
7474 abort();
7475#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007476 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +00007477 lp = n->npipe.cmdlist;
7478 for (;;) {
Eric Andersencb57d552001-06-28 07:25:16 +00007479 cmdtxt(lp->n);
Eric Andersenc470f442003-07-28 09:56:35 +00007480 lp = lp->next;
7481 if (!lp)
7482 break;
7483 cmdputs(" | ");
Eric Andersencb57d552001-06-28 07:25:16 +00007484 }
7485 break;
Eric Andersenc470f442003-07-28 09:56:35 +00007486 case NSEMI:
7487 p = "; ";
7488 goto binop;
7489 case NAND:
7490 p = " && ";
7491 goto binop;
7492 case NOR:
7493 p = " || ";
7494binop:
7495 cmdtxt(n->nbinary.ch1);
7496 cmdputs(p);
7497 n = n->nbinary.ch2;
7498 goto donode;
Eric Andersencb57d552001-06-28 07:25:16 +00007499 case NREDIR:
7500 case NBACKGND:
Eric Andersenc470f442003-07-28 09:56:35 +00007501 n = n->nredir.n;
7502 goto donode;
7503 case NNOT:
7504 cmdputs("!");
7505 n = n->nnot.com;
7506donode:
7507 cmdtxt(n);
Eric Andersencb57d552001-06-28 07:25:16 +00007508 break;
7509 case NIF:
7510 cmdputs("if ");
7511 cmdtxt(n->nif.test);
7512 cmdputs("; then ");
Eric Andersenc470f442003-07-28 09:56:35 +00007513 n = n->nif.ifpart;
7514 if (n->nif.elsepart) {
7515 cmdtxt(n);
7516 cmdputs("; else ");
7517 n = n->nif.elsepart;
7518 }
7519 p = "; fi";
7520 goto dotail;
7521 case NSUBSHELL:
7522 cmdputs("(");
7523 n = n->nredir.n;
7524 p = ")";
7525 goto dotail;
Eric Andersencb57d552001-06-28 07:25:16 +00007526 case NWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00007527 p = "while ";
Eric Andersencb57d552001-06-28 07:25:16 +00007528 goto until;
7529 case NUNTIL:
Eric Andersenc470f442003-07-28 09:56:35 +00007530 p = "until ";
7531until:
7532 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007533 cmdtxt(n->nbinary.ch1);
Eric Andersenc470f442003-07-28 09:56:35 +00007534 n = n->nbinary.ch2;
7535 p = "; done";
7536dodo:
Eric Andersencb57d552001-06-28 07:25:16 +00007537 cmdputs("; do ");
Eric Andersenc470f442003-07-28 09:56:35 +00007538dotail:
7539 cmdtxt(n);
7540 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007541 case NFOR:
7542 cmdputs("for ");
7543 cmdputs(n->nfor.var);
Eric Andersenc470f442003-07-28 09:56:35 +00007544 cmdputs(" in ");
7545 cmdlist(n->nfor.args, 1);
7546 n = n->nfor.body;
7547 p = "; done";
7548 goto dodo;
Eric Andersencb57d552001-06-28 07:25:16 +00007549 case NDEFUN:
7550 cmdputs(n->narg.text);
Eric Andersenc470f442003-07-28 09:56:35 +00007551 p = "() { ... }";
7552 goto dotail2;
Eric Andersencb57d552001-06-28 07:25:16 +00007553 case NCMD:
Eric Andersenc470f442003-07-28 09:56:35 +00007554 cmdlist(n->ncmd.args, 1);
7555 cmdlist(n->ncmd.redirect, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00007556 break;
7557 case NARG:
Eric Andersenc470f442003-07-28 09:56:35 +00007558 p = n->narg.text;
7559dotail2:
Eric Andersencb57d552001-06-28 07:25:16 +00007560 cmdputs(p);
Eric Andersencb57d552001-06-28 07:25:16 +00007561 break;
7562 case NHERE:
7563 case NXHERE:
Eric Andersenc470f442003-07-28 09:56:35 +00007564 p = "<<...";
7565 goto dotail2;
7566 case NCASE:
7567 cmdputs("case ");
7568 cmdputs(n->ncase.expr->narg.text);
7569 cmdputs(" in ");
7570 for (np = n->ncase.cases; np; np = np->nclist.next) {
7571 cmdtxt(np->nclist.pattern);
7572 cmdputs(") ");
7573 cmdtxt(np->nclist.body);
7574 cmdputs(";; ");
7575 }
7576 p = "esac";
7577 goto dotail2;
7578 case NTO:
7579 p = ">";
7580 goto redir;
7581 case NCLOBBER:
7582 p = ">|";
7583 goto redir;
7584 case NAPPEND:
7585 p = ">>";
7586 goto redir;
7587 case NTOFD:
7588 p = ">&";
7589 goto redir;
7590 case NFROM:
7591 p = "<";
7592 goto redir;
7593 case NFROMFD:
7594 p = "<&";
7595 goto redir;
7596 case NFROMTO:
7597 p = "<>";
7598redir:
7599 s[0] = n->nfile.fd + '0';
7600 s[1] = '\0';
7601 cmdputs(s);
7602 cmdputs(p);
7603 if (n->type == NTOFD || n->type == NFROMFD) {
7604 s[0] = n->ndup.dupfd + '0';
7605 p = s;
7606 goto dotail2;
7607 } else {
7608 n = n->nfile.fname;
7609 goto donode;
7610 }
Eric Andersencb57d552001-06-28 07:25:16 +00007611 }
7612}
Eric Andersencb57d552001-06-28 07:25:16 +00007613
Eric Andersenc470f442003-07-28 09:56:35 +00007614static void
7615cmdlist(union node *np, int sep)
Eric Andersen2870d962001-07-02 17:27:21 +00007616{
Eric Andersenc470f442003-07-28 09:56:35 +00007617 for (; np; np = np->narg.next) {
7618 if (!sep)
7619 cmdputs(spcstr);
7620 cmdtxt(np);
7621 if (sep && np->narg.next)
7622 cmdputs(spcstr);
7623 }
Eric Andersencb57d552001-06-28 07:25:16 +00007624}
7625
Eric Andersenc470f442003-07-28 09:56:35 +00007626static void
7627cmdputs(const char *s)
7628{
7629 const char *p, *str;
7630 char c, cc[2] = " ";
7631 char *nextc;
7632 int subtype = 0;
7633 int quoted = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007634 static const char vstype[VSTYPE + 1][4] = {
7635 "", "}", "-", "+", "?", "=",
7636 "%", "%%", "#", "##"
Eric Andersenc470f442003-07-28 09:56:35 +00007637 };
Eric Andersenc470f442003-07-28 09:56:35 +00007638 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7639 p = s;
7640 while ((c = *p++) != 0) {
7641 str = 0;
7642 switch (c) {
7643 case CTLESC:
7644 c = *p++;
7645 break;
7646 case CTLVAR:
7647 subtype = *p++;
7648 if ((subtype & VSTYPE) == VSLENGTH)
7649 str = "${#";
7650 else
7651 str = "${";
7652 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7653 quoted ^= 1;
7654 c = '"';
7655 } else
7656 goto dostr;
7657 break;
7658 case CTLENDVAR:
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007659 str = "\"}" + !(quoted & 1);
Eric Andersenc470f442003-07-28 09:56:35 +00007660 quoted >>= 1;
7661 subtype = 0;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007662 goto dostr;
Eric Andersenc470f442003-07-28 09:56:35 +00007663 case CTLBACKQ:
7664 str = "$(...)";
7665 goto dostr;
7666 case CTLBACKQ+CTLQUOTE:
7667 str = "\"$(...)\"";
7668 goto dostr;
7669#ifdef CONFIG_ASH_MATH_SUPPORT
7670 case CTLARI:
7671 str = "$((";
7672 goto dostr;
7673 case CTLENDARI:
7674 str = "))";
7675 goto dostr;
7676#endif
7677 case CTLQUOTEMARK:
7678 quoted ^= 1;
7679 c = '"';
7680 break;
7681 case '=':
7682 if (subtype == 0)
7683 break;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007684 if ((subtype & VSTYPE) != VSNORMAL)
7685 quoted <<= 1;
Eric Andersenc470f442003-07-28 09:56:35 +00007686 str = vstype[subtype & VSTYPE];
7687 if (subtype & VSNUL)
7688 c = ':';
7689 else
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007690 goto checkstr;
Eric Andersenc470f442003-07-28 09:56:35 +00007691 break;
7692 case '\'':
7693 case '\\':
7694 case '"':
7695 case '$':
7696 /* These can only happen inside quotes */
7697 cc[0] = c;
7698 str = cc;
7699 c = '\\';
7700 break;
7701 default:
7702 break;
7703 }
7704 USTPUTC(c, nextc);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00007705checkstr:
Eric Andersenc470f442003-07-28 09:56:35 +00007706 if (!str)
7707 continue;
7708dostr:
7709 while ((c = *str++)) {
7710 USTPUTC(c, nextc);
7711 }
7712 }
7713 if (quoted & 1) {
7714 USTPUTC('"', nextc);
7715 }
7716 *nextc = 0;
7717 cmdnextc = nextc;
7718}
7719
7720
7721static void
7722showpipe(struct job *jp, FILE *out)
7723{
7724 struct procstat *sp;
7725 struct procstat *spend;
7726
7727 spend = jp->ps + jp->nprocs;
7728 for (sp = jp->ps + 1; sp < spend; sp++)
7729 fprintf(out, " | %s", sp->cmd);
7730 outcslow('\n', out);
7731 flushall();
7732}
7733
7734static void
7735xtcsetpgrp(int fd, pid_t pgrp)
7736{
7737 if (tcsetpgrp(fd, pgrp))
7738 error("Cannot set tty process group (%m)");
7739}
7740#endif /* JOBS */
7741
7742static int
7743getstatus(struct job *job) {
7744 int status;
7745 int retval;
7746
7747 status = job->ps[job->nprocs - 1].status;
7748 retval = WEXITSTATUS(status);
7749 if (!WIFEXITED(status)) {
7750#if JOBS
7751 retval = WSTOPSIG(status);
7752 if (!WIFSTOPPED(status))
7753#endif
7754 {
7755 /* XXX: limits number of signals */
7756 retval = WTERMSIG(status);
7757#if JOBS
7758 if (retval == SIGINT)
7759 job->sigint = 1;
7760#endif
7761 }
7762 retval += 128;
7763 }
7764 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7765 jobno(job), job->nprocs, status, retval));
7766 return retval;
7767}
7768
Eric Andersend35c5df2002-01-09 15:37:36 +00007769#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00007770/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
Eric Andersenec074692001-10-31 11:05:49 +00007771
Eric Andersencb57d552001-06-28 07:25:16 +00007772/*
Eric Andersenc470f442003-07-28 09:56:35 +00007773 * Routines to check for mail. (Perhaps make part of main.c?)
Eric Andersencb57d552001-06-28 07:25:16 +00007774 */
7775
Eric Andersencb57d552001-06-28 07:25:16 +00007776#define MAXMBOXES 10
7777
Eric Andersenc470f442003-07-28 09:56:35 +00007778/* times of mailboxes */
7779static time_t mailtime[MAXMBOXES];
7780/* Set if MAIL or MAILPATH is changed. */
7781static int mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +00007782
7783
7784
7785/*
Eric Andersenc470f442003-07-28 09:56:35 +00007786 * Print appropriate message(s) if mail has arrived.
7787 * If mail_var_path_changed is set,
7788 * then the value of MAIL has mail_var_path_changed,
7789 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +00007790 */
7791
Eric Andersenc470f442003-07-28 09:56:35 +00007792static void
7793chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007794{
Eric Andersencb57d552001-06-28 07:25:16 +00007795 const char *mpath;
7796 char *p;
7797 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +00007798 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +00007799 struct stackmark smark;
7800 struct stat statb;
7801
Eric Andersencb57d552001-06-28 07:25:16 +00007802 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007803 mpath = mpathset() ? mpathval() : mailval();
7804 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Eric Andersencb57d552001-06-28 07:25:16 +00007805 p = padvance(&mpath, nullstr);
7806 if (p == NULL)
7807 break;
7808 if (*p == '\0')
7809 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00007810 for (q = p ; *q ; q++);
Eric Andersencb57d552001-06-28 07:25:16 +00007811#ifdef DEBUG
7812 if (q[-1] != '/')
7813 abort();
7814#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007815 q[-1] = '\0'; /* delete trailing '/' */
7816 if (stat(p, &statb) < 0) {
7817 *mtp = 0;
7818 continue;
Eric Andersencb57d552001-06-28 07:25:16 +00007819 }
Eric Andersenc470f442003-07-28 09:56:35 +00007820 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7821 fprintf(
7822 stderr, snlfmt,
7823 pathopt ? pathopt : "you have mail"
7824 );
7825 }
7826 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +00007827 }
Eric Andersenc470f442003-07-28 09:56:35 +00007828 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007829 popstackmark(&smark);
7830}
Eric Andersencb57d552001-06-28 07:25:16 +00007831
Eric Andersenec074692001-10-31 11:05:49 +00007832
Eric Andersenc470f442003-07-28 09:56:35 +00007833static void
7834changemail(const char *val)
7835{
7836 mail_var_path_changed++;
7837}
7838
7839#endif /* CONFIG_ASH_MAIL */
7840
7841/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7842
Eric Andersencb57d552001-06-28 07:25:16 +00007843
Eric Andersencb57d552001-06-28 07:25:16 +00007844#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007845static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007846extern int etext();
7847#endif
7848
Eric Andersenc470f442003-07-28 09:56:35 +00007849static int isloginsh;
Robert Griebl64f70cc2002-05-14 23:22:06 +00007850
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00007851static void read_profile(const char *);
Eric Andersen2870d962001-07-02 17:27:21 +00007852
Eric Andersencb57d552001-06-28 07:25:16 +00007853/*
7854 * Main routine. We initialize things, parse the arguments, execute
7855 * profiles if we're a login shell, and then call cmdloop to execute
7856 * commands. The setjmp call sets up the location to jump to when an
7857 * exception occurs. When an exception occurs the variable "state"
7858 * is used to figure out how far we had gotten.
7859 */
7860
Eric Andersenc470f442003-07-28 09:56:35 +00007861int
7862ash_main(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00007863{
Eric Andersenc470f442003-07-28 09:56:35 +00007864 char *shinit;
7865 volatile int state;
Eric Andersencb57d552001-06-28 07:25:16 +00007866 struct jmploc jmploc;
7867 struct stackmark smark;
Eric Andersencb57d552001-06-28 07:25:16 +00007868
Eric Andersenc470f442003-07-28 09:56:35 +00007869#ifdef __GLIBC__
7870 dash_errno = __errno_location();
Eric Andersen1c039232001-07-07 00:05:55 +00007871#endif
7872
Eric Andersencb57d552001-06-28 07:25:16 +00007873#if PROFILE
7874 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7875#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007876 state = 0;
7877 if (setjmp(jmploc.loc)) {
Eric Andersenc470f442003-07-28 09:56:35 +00007878 int status;
7879 int e;
7880
Eric Andersencb57d552001-06-28 07:25:16 +00007881 reset();
Eric Andersenc470f442003-07-28 09:56:35 +00007882
7883 e = exception;
7884 switch (exception) {
7885 case EXEXEC:
7886 status = exerrno;
7887 break;
7888
7889 case EXERROR:
7890 status = 2;
7891 break;
7892
7893 default:
7894 status = exitstatus;
7895 break;
7896 }
7897 exitstatus = status;
7898
7899 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7900 exitshell();
7901
Eric Andersen90898442003-08-06 11:20:52 +00007902 if (e == EXINT) {
Eric Andersenc470f442003-07-28 09:56:35 +00007903 outcslow('\n', stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00007904 }
7905 popstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +00007906 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007907 if (state == 1)
7908 goto state1;
7909 else if (state == 2)
7910 goto state2;
7911 else if (state == 3)
7912 goto state3;
7913 else
7914 goto state4;
7915 }
7916 handler = &jmploc;
7917#ifdef DEBUG
7918 opentrace();
Eric Andersenc470f442003-07-28 09:56:35 +00007919 trputs("Shell args: "); trargs(argv);
Eric Andersencb57d552001-06-28 07:25:16 +00007920#endif
7921 rootpid = getpid();
Eric Andersen16767e22004-03-16 05:14:10 +00007922
7923#ifdef CONFIG_ASH_RANDOM_SUPPORT
7924 rseed = rootpid + ((time_t)time((time_t *)0));
7925#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007926 rootshell = 1;
7927 init();
7928 setstackmark(&smark);
7929 procargs(argc, argv);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007930#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7931 if ( iflag ) {
7932 const char *hp = lookupvar("HISTFILE");
7933
7934 if(hp == NULL ) {
7935 hp = lookupvar("HOME");
7936 if(hp != NULL) {
7937 char *defhp = concat_path_file(hp, ".ash_history");
7938 setvar("HISTFILE", defhp, 0);
7939 free(defhp);
7940 }
7941 }
7942 }
7943#endif
Robert Griebl64f70cc2002-05-14 23:22:06 +00007944 if (argv[0] && argv[0][0] == '-')
7945 isloginsh = 1;
7946 if (isloginsh) {
Eric Andersencb57d552001-06-28 07:25:16 +00007947 state = 1;
7948 read_profile("/etc/profile");
Eric Andersenc470f442003-07-28 09:56:35 +00007949state1:
Eric Andersencb57d552001-06-28 07:25:16 +00007950 state = 2;
7951 read_profile(".profile");
7952 }
Eric Andersenc470f442003-07-28 09:56:35 +00007953state2:
Eric Andersencb57d552001-06-28 07:25:16 +00007954 state = 3;
Eric Andersenc470f442003-07-28 09:56:35 +00007955 if (
Eric Andersencb57d552001-06-28 07:25:16 +00007956#ifndef linux
Eric Andersenc470f442003-07-28 09:56:35 +00007957 getuid() == geteuid() && getgid() == getegid() &&
Eric Andersencb57d552001-06-28 07:25:16 +00007958#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007959 iflag
7960 ) {
Eric Andersencb57d552001-06-28 07:25:16 +00007961 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
Eric Andersencb57d552001-06-28 07:25:16 +00007962 read_profile(shinit);
7963 }
Eric Andersencb57d552001-06-28 07:25:16 +00007964 }
Eric Andersenc470f442003-07-28 09:56:35 +00007965state3:
Eric Andersencb57d552001-06-28 07:25:16 +00007966 state = 4;
Eric Andersencb57d552001-06-28 07:25:16 +00007967 if (minusc)
Glenn L McGrath76620622004-01-13 10:19:37 +00007968 evalstring(minusc);
Eric Andersencb57d552001-06-28 07:25:16 +00007969
7970 if (sflag || minusc == NULL) {
Robert Griebl350d26b2002-12-03 22:45:46 +00007971#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
Glenn L McGrathfdbbb042002-12-09 11:10:40 +00007972 if ( iflag ) {
7973 const char *hp = lookupvar("HISTFILE");
7974
7975 if(hp != NULL )
7976 load_history ( hp );
7977 }
Robert Griebl350d26b2002-12-03 22:45:46 +00007978#endif
Eric Andersen90898442003-08-06 11:20:52 +00007979state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007980 cmdloop(1);
7981 }
7982#if PROFILE
7983 monitor(0);
7984#endif
Eric Andersenc470f442003-07-28 09:56:35 +00007985#if GPROF
7986 {
7987 extern void _mcleanup(void);
7988 _mcleanup();
7989 }
7990#endif
7991 exitshell();
Eric Andersencb57d552001-06-28 07:25:16 +00007992 /* NOTREACHED */
7993}
7994
7995
7996/*
7997 * Read and execute commands. "Top" is nonzero for the top level command
7998 * loop; it turns on prompting if the shell is interactive.
7999 */
8000
Eric Andersenc470f442003-07-28 09:56:35 +00008001static void
8002cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008003{
8004 union node *n;
8005 struct stackmark smark;
8006 int inter;
8007 int numeof = 0;
8008
8009 TRACE(("cmdloop(%d) called\n", top));
Eric Andersencb57d552001-06-28 07:25:16 +00008010 for (;;) {
Glenn L McGrath76620622004-01-13 10:19:37 +00008011 setstackmark(&smark);
Eric Andersencb57d552001-06-28 07:25:16 +00008012 if (pendingsigs)
8013 dotrap();
Eric Andersenc470f442003-07-28 09:56:35 +00008014#if JOBS
8015 if (jobctl)
8016 showjobs(stderr, SHOW_CHANGED);
8017#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008018 inter = 0;
8019 if (iflag && top) {
8020 inter++;
Eric Andersend35c5df2002-01-09 15:37:36 +00008021#ifdef CONFIG_ASH_MAIL
Eric Andersenc470f442003-07-28 09:56:35 +00008022 chkmail();
Eric Andersenec074692001-10-31 11:05:49 +00008023#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008024 }
8025 n = parsecmd(inter);
8026 /* showtree(n); DEBUG */
8027 if (n == NEOF) {
8028 if (!top || numeof >= 50)
8029 break;
8030 if (!stoppedjobs()) {
8031 if (!Iflag)
8032 break;
8033 out2str("\nUse \"exit\" to leave shell.\n");
8034 }
8035 numeof++;
8036 } else if (n != NULL && nflag == 0) {
8037 job_warning = (job_warning == 2) ? 1 : 0;
8038 numeof = 0;
8039 evaltree(n, 0);
8040 }
8041 popstackmark(&smark);
Glenn L McGrath76620622004-01-13 10:19:37 +00008042 if (evalskip) {
Eric Andersencb57d552001-06-28 07:25:16 +00008043 evalskip = 0;
8044 break;
8045 }
8046 }
Eric Andersencb57d552001-06-28 07:25:16 +00008047}
8048
8049
Eric Andersencb57d552001-06-28 07:25:16 +00008050/*
8051 * Read /etc/profile or .profile. Return on error.
8052 */
8053
Eric Andersenc470f442003-07-28 09:56:35 +00008054static void
8055read_profile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008056{
8057 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +00008058 int xflag_set = 0;
8059 int vflag_set = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008060
8061 INTOFF;
8062 if ((fd = open(name, O_RDONLY)) >= 0)
8063 setinputfd(fd, 1);
8064 INTON;
8065 if (fd < 0)
8066 return;
8067 /* -q turns off -x and -v just when executing init files */
Eric Andersenc470f442003-07-28 09:56:35 +00008068 if (qflag) {
8069 if (xflag)
8070 xflag = 0, xflag_set = 1;
8071 if (vflag)
8072 vflag = 0, vflag_set = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008073 }
8074 cmdloop(0);
Eric Andersenc470f442003-07-28 09:56:35 +00008075 if (qflag) {
8076 if (xflag_set)
8077 xflag = 1;
8078 if (vflag_set)
8079 vflag = 1;
8080 }
Eric Andersencb57d552001-06-28 07:25:16 +00008081 popfile();
8082}
8083
8084
Eric Andersencb57d552001-06-28 07:25:16 +00008085/*
8086 * Read a file containing shell functions.
8087 */
8088
Eric Andersenc470f442003-07-28 09:56:35 +00008089static void
8090readcmdfile(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008091{
8092 int fd;
8093
8094 INTOFF;
8095 if ((fd = open(name, O_RDONLY)) >= 0)
8096 setinputfd(fd, 1);
8097 else
8098 error("Can't open %s", name);
8099 INTON;
8100 cmdloop(0);
8101 popfile();
8102}
8103
8104
Eric Andersencb57d552001-06-28 07:25:16 +00008105/*
Eric Andersenc470f442003-07-28 09:56:35 +00008106 * Take commands from a file. To be compatible we should do a path
Eric Andersencb57d552001-06-28 07:25:16 +00008107 * search for the file, which is necessary to find sub-commands.
8108 */
8109
Eric Andersenc470f442003-07-28 09:56:35 +00008110static inline char *
8111find_dot_file(char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008112{
8113 char *fullname;
8114 const char *path = pathval();
8115 struct stat statb;
8116
8117 /* don't try this for absolute or relative paths */
Eric Andersenc470f442003-07-28 09:56:35 +00008118 if (strchr(name, '/'))
8119 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00008120
Eric Andersenc470f442003-07-28 09:56:35 +00008121 while ((fullname = padvance(&path, name)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00008122 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8123 /*
8124 * Don't bother freeing here, since it will
8125 * be freed by the caller.
8126 */
8127 return fullname;
8128 }
8129 stunalloc(fullname);
8130 }
8131
8132 /* not found in the PATH */
Eric Andersenc470f442003-07-28 09:56:35 +00008133 error(not_found_msg, name);
Eric Andersencb57d552001-06-28 07:25:16 +00008134 /* NOTREACHED */
8135}
8136
Eric Andersen1e6aba92004-04-12 19:12:13 +00008137static int dotcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008138{
Eric Andersen1e6aba92004-04-12 19:12:13 +00008139 struct strlist *sp;
8140 volatile struct shparam saveparam;
8141
Eric Andersencb57d552001-06-28 07:25:16 +00008142 exitstatus = 0;
8143
Eric Andersen1e6aba92004-04-12 19:12:13 +00008144 for (sp = cmdenviron; sp; sp = sp->next)
8145 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8146
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00008147 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008148 char *fullname;
8149 struct stackmark smark;
8150
8151 setstackmark(&smark);
8152 fullname = find_dot_file(argv[1]);
Eric Andersen1e6aba92004-04-12 19:12:13 +00008153
8154 if (argc > 2) {
8155 saveparam = shellparam;
8156 shellparam.malloc = 0;
8157 shellparam.nparam = argc - 2;
8158 shellparam.p = argv + 2;
8159 };
8160
Eric Andersencb57d552001-06-28 07:25:16 +00008161 setinputfile(fullname, 1);
8162 commandname = fullname;
8163 cmdloop(0);
8164 popfile();
Eric Andersen1e6aba92004-04-12 19:12:13 +00008165
8166 if (argc > 2) {
8167 freeparam(&shellparam);
8168 shellparam = saveparam;
8169 };
8170
Eric Andersencb57d552001-06-28 07:25:16 +00008171 popstackmark(&smark);
8172 }
8173 return exitstatus;
8174}
8175
8176
Eric Andersenc470f442003-07-28 09:56:35 +00008177static int
8178exitcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008179{
8180 if (stoppedjobs())
8181 return 0;
8182 if (argc > 1)
8183 exitstatus = number(argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +00008184 exraise(EXEXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00008185 /* NOTREACHED */
8186}
Eric Andersen62483552001-07-10 06:09:16 +00008187
Paul Fox0b621582005-08-09 19:38:05 +00008188#ifdef CONFIG_ASH_BUILTIN_ECHO
8189static int
8190echocmd(int argc, char **argv)
8191{
8192 return bb_echo(argc, argv);
8193}
8194#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008195/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8196
8197/*
Eric Andersen90898442003-08-06 11:20:52 +00008198 * Same for malloc, realloc, but returns an error when out of space.
Eric Andersenc470f442003-07-28 09:56:35 +00008199 */
8200
8201static pointer
8202ckrealloc(pointer p, size_t nbytes)
8203{
8204 p = realloc(p, nbytes);
8205 if (p == NULL)
8206 error(bb_msg_memory_exhausted);
8207 return p;
8208}
8209
Eric Andersen90898442003-08-06 11:20:52 +00008210static pointer
8211ckmalloc(size_t nbytes)
8212{
8213 return ckrealloc(NULL, nbytes);
8214}
Eric Andersenc470f442003-07-28 09:56:35 +00008215
8216/*
8217 * Make a copy of a string in safe storage.
8218 */
8219
8220static char *
8221savestr(const char *s)
8222{
8223 char *p = strdup(s);
8224 if (!p)
8225 error(bb_msg_memory_exhausted);
8226 return p;
8227}
8228
8229
8230/*
8231 * Parse trees for commands are allocated in lifo order, so we use a stack
8232 * to make this more efficient, and also to avoid all sorts of exception
8233 * handling code to handle interrupts in the middle of a parse.
8234 *
8235 * The size 504 was chosen because the Ultrix malloc handles that size
8236 * well.
8237 */
8238
8239
8240static pointer
8241stalloc(size_t nbytes)
8242{
8243 char *p;
8244 size_t aligned;
8245
8246 aligned = SHELL_ALIGN(nbytes);
8247 if (aligned > stacknleft) {
8248 size_t len;
8249 size_t blocksize;
8250 struct stack_block *sp;
8251
8252 blocksize = aligned;
8253 if (blocksize < MINSIZE)
8254 blocksize = MINSIZE;
8255 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8256 if (len < blocksize)
8257 error(bb_msg_memory_exhausted);
8258 INTOFF;
8259 sp = ckmalloc(len);
8260 sp->prev = stackp;
8261 stacknxt = sp->space;
8262 stacknleft = blocksize;
8263 sstrend = stacknxt + blocksize;
8264 stackp = sp;
8265 INTON;
8266 }
8267 p = stacknxt;
8268 stacknxt += aligned;
8269 stacknleft -= aligned;
8270 return p;
8271}
8272
8273
8274void
8275stunalloc(pointer p)
Eric Andersen2870d962001-07-02 17:27:21 +00008276{
Eric Andersencb57d552001-06-28 07:25:16 +00008277#ifdef DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008278 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
Eric Andersencb57d552001-06-28 07:25:16 +00008279 write(2, "stunalloc\n", 10);
8280 abort();
8281 }
8282#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008283 stacknleft += stacknxt - (char *)p;
Eric Andersencb57d552001-06-28 07:25:16 +00008284 stacknxt = p;
8285}
8286
8287
Eric Andersenc470f442003-07-28 09:56:35 +00008288void
8289setstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008290{
Eric Andersencb57d552001-06-28 07:25:16 +00008291 mark->stackp = stackp;
8292 mark->stacknxt = stacknxt;
8293 mark->stacknleft = stacknleft;
8294 mark->marknext = markp;
8295 markp = mark;
8296}
8297
8298
Eric Andersenc470f442003-07-28 09:56:35 +00008299void
8300popstackmark(struct stackmark *mark)
Eric Andersen2870d962001-07-02 17:27:21 +00008301{
Eric Andersencb57d552001-06-28 07:25:16 +00008302 struct stack_block *sp;
8303
8304 INTOFF;
8305 markp = mark->marknext;
8306 while (stackp != mark->stackp) {
8307 sp = stackp;
8308 stackp = sp->prev;
Eric Andersenc470f442003-07-28 09:56:35 +00008309 ckfree(sp);
Eric Andersencb57d552001-06-28 07:25:16 +00008310 }
8311 stacknxt = mark->stacknxt;
8312 stacknleft = mark->stacknleft;
Eric Andersenc470f442003-07-28 09:56:35 +00008313 sstrend = mark->stacknxt + mark->stacknleft;
Eric Andersencb57d552001-06-28 07:25:16 +00008314 INTON;
8315}
8316
8317
8318/*
8319 * When the parser reads in a string, it wants to stick the string on the
8320 * stack and only adjust the stack pointer when it knows how big the
8321 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8322 * of space on top of the stack and stackblocklen returns the length of
8323 * this block. Growstackblock will grow this space by at least one byte,
8324 * possibly moving it (like realloc). Grabstackblock actually allocates the
8325 * part of the block that has been used.
8326 */
8327
Eric Andersenc470f442003-07-28 09:56:35 +00008328void
8329growstackblock(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008330{
Eric Andersenc470f442003-07-28 09:56:35 +00008331 size_t newlen;
8332
8333 newlen = stacknleft * 2;
8334 if (newlen < stacknleft)
8335 error(bb_msg_memory_exhausted);
8336 if (newlen < 128)
8337 newlen += 128;
Eric Andersencb57d552001-06-28 07:25:16 +00008338
8339 if (stacknxt == stackp->space && stackp != &stackbase) {
Eric Andersenc470f442003-07-28 09:56:35 +00008340 struct stack_block *oldstackp;
8341 struct stackmark *xmark;
8342 struct stack_block *sp;
8343 struct stack_block *prevstackp;
8344 size_t grosslen;
8345
Eric Andersencb57d552001-06-28 07:25:16 +00008346 INTOFF;
8347 oldstackp = stackp;
8348 sp = stackp;
Eric Andersenc470f442003-07-28 09:56:35 +00008349 prevstackp = sp->prev;
8350 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8351 sp = ckrealloc((pointer)sp, grosslen);
8352 sp->prev = prevstackp;
Eric Andersencb57d552001-06-28 07:25:16 +00008353 stackp = sp;
8354 stacknxt = sp->space;
8355 stacknleft = newlen;
Eric Andersenc470f442003-07-28 09:56:35 +00008356 sstrend = sp->space + newlen;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008357
Eric Andersenc470f442003-07-28 09:56:35 +00008358 /*
8359 * Stack marks pointing to the start of the old block
8360 * must be relocated to point to the new block
8361 */
8362 xmark = markp;
8363 while (xmark != NULL && xmark->stackp == oldstackp) {
8364 xmark->stackp = stackp;
8365 xmark->stacknxt = stacknxt;
8366 xmark->stacknleft = stacknleft;
8367 xmark = xmark->marknext;
Eric Andersencb57d552001-06-28 07:25:16 +00008368 }
8369 INTON;
8370 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00008371 char *oldspace = stacknxt;
8372 int oldlen = stacknleft;
8373 char *p = stalloc(newlen);
8374
8375 /* free the space we just allocated */
8376 stacknxt = memcpy(p, oldspace, oldlen);
8377 stacknleft += newlen;
Eric Andersencb57d552001-06-28 07:25:16 +00008378 }
8379}
8380
Eric Andersenc470f442003-07-28 09:56:35 +00008381static inline void
8382grabstackblock(size_t len)
Eric Andersencb57d552001-06-28 07:25:16 +00008383{
Eric Andersenc470f442003-07-28 09:56:35 +00008384 len = SHELL_ALIGN(len);
Eric Andersencb57d552001-06-28 07:25:16 +00008385 stacknxt += len;
8386 stacknleft -= len;
8387}
8388
Eric Andersencb57d552001-06-28 07:25:16 +00008389/*
Eric Andersenc470f442003-07-28 09:56:35 +00008390 * The following routines are somewhat easier to use than the above.
Eric Andersencb57d552001-06-28 07:25:16 +00008391 * The user declares a variable of type STACKSTR, which may be declared
8392 * to be a register. The macro STARTSTACKSTR initializes things. Then
8393 * the user uses the macro STPUTC to add characters to the string. In
8394 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8395 * grown as necessary. When the user is done, she can just leave the
8396 * string there and refer to it using stackblock(). Or she can allocate
8397 * the space for it using grabstackstr(). If it is necessary to allow
8398 * someone else to use the stack temporarily and then continue to grow
8399 * the string, the user should use grabstack to allocate the space, and
8400 * then call ungrabstr(p) to return to the previous mode of operation.
8401 *
8402 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8403 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8404 * is space for at least one character.
8405 */
8406
Eric Andersenc470f442003-07-28 09:56:35 +00008407void *
8408growstackstr(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008409{
Eric Andersenc470f442003-07-28 09:56:35 +00008410 size_t len = stackblocksize();
Eric Andersencb57d552001-06-28 07:25:16 +00008411 if (herefd >= 0 && len >= 1024) {
Eric Andersen16767e22004-03-16 05:14:10 +00008412 bb_full_write(herefd, stackblock(), len);
Eric Andersencb57d552001-06-28 07:25:16 +00008413 return stackblock();
8414 }
8415 growstackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008416 return stackblock() + len;
8417}
8418
Eric Andersencb57d552001-06-28 07:25:16 +00008419/*
8420 * Called from CHECKSTRSPACE.
8421 */
8422
Eric Andersenc470f442003-07-28 09:56:35 +00008423char *
8424makestrspace(size_t newlen, char *p)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008425{
Eric Andersenc470f442003-07-28 09:56:35 +00008426 size_t len = p - stacknxt;
8427 size_t size = stackblocksize();
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008428
Eric Andersenc470f442003-07-28 09:56:35 +00008429 for (;;) {
8430 size_t nleft;
8431
8432 size = stackblocksize();
8433 nleft = size - len;
8434 if (nleft >= newlen)
8435 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008436 growstackblock();
Eric Andersenc470f442003-07-28 09:56:35 +00008437 }
Eric Andersencb57d552001-06-28 07:25:16 +00008438 return stackblock() + len;
8439}
8440
Eric Andersenc470f442003-07-28 09:56:35 +00008441char *
8442stnputs(const char *s, size_t n, char *p)
Eric Andersen2870d962001-07-02 17:27:21 +00008443{
Eric Andersenc470f442003-07-28 09:56:35 +00008444 p = makestrspace(n, p);
8445 p = mempcpy(p, s, n);
8446 return p;
Eric Andersencb57d552001-06-28 07:25:16 +00008447}
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008448
Eric Andersenc470f442003-07-28 09:56:35 +00008449char *
8450stputs(const char *s, char *p)
8451{
8452 return stnputs(s, strlen(s), p);
8453}
8454
8455/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8456
Eric Andersencb57d552001-06-28 07:25:16 +00008457/*
Eric Andersenc470f442003-07-28 09:56:35 +00008458 * String functions.
Eric Andersencb57d552001-06-28 07:25:16 +00008459 *
Eric Andersenc470f442003-07-28 09:56:35 +00008460 * number(s) Convert a string of digits to an integer.
8461 * is_number(s) Return true if s is a string of digits.
Eric Andersencb57d552001-06-28 07:25:16 +00008462 */
8463
Eric Andersencb57d552001-06-28 07:25:16 +00008464/*
8465 * prefix -- see if pfx is a prefix of string.
8466 */
8467
Eric Andersenc470f442003-07-28 09:56:35 +00008468char *
8469prefix(const char *string, const char *pfx)
Eric Andersen62483552001-07-10 06:09:16 +00008470{
Eric Andersencb57d552001-06-28 07:25:16 +00008471 while (*pfx) {
8472 if (*pfx++ != *string++)
8473 return 0;
8474 }
Eric Andersenc470f442003-07-28 09:56:35 +00008475 return (char *) string;
Eric Andersencb57d552001-06-28 07:25:16 +00008476}
8477
8478
8479/*
8480 * Convert a string of digits to an integer, printing an error message on
8481 * failure.
8482 */
8483
Eric Andersenc470f442003-07-28 09:56:35 +00008484int
8485number(const char *s)
Eric Andersen2870d962001-07-02 17:27:21 +00008486{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008487
Eric Andersenc470f442003-07-28 09:56:35 +00008488 if (! is_number(s))
8489 error(illnum, s);
8490 return atoi(s);
Eric Andersencb57d552001-06-28 07:25:16 +00008491}
8492
Eric Andersenc470f442003-07-28 09:56:35 +00008493
Eric Andersenc470f442003-07-28 09:56:35 +00008494/*
8495 * Check for a valid number. This should be elsewhere.
8496 */
8497
8498int
8499is_number(const char *p)
8500{
8501 do {
8502 if (! is_digit(*p))
8503 return 0;
8504 } while (*++p != '\0');
8505 return 1;
8506}
8507
8508
Eric Andersencb57d552001-06-28 07:25:16 +00008509/*
8510 * Produce a possibly single quoted string suitable as input to the shell.
8511 * The return string is allocated on the stack.
8512 */
8513
Eric Andersenc470f442003-07-28 09:56:35 +00008514char *
8515single_quote(const char *s) {
Eric Andersencb57d552001-06-28 07:25:16 +00008516 char *p;
8517
8518 STARTSTACKSTR(p);
8519
8520 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008521 char *q;
8522 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +00008523
Eric Andersenc470f442003-07-28 09:56:35 +00008524 len = strchrnul(s, '\'') - s;
Eric Andersencb57d552001-06-28 07:25:16 +00008525
Eric Andersenc470f442003-07-28 09:56:35 +00008526 q = p = makestrspace(len + 3, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008527
Eric Andersenc470f442003-07-28 09:56:35 +00008528 *q++ = '\'';
8529 q = mempcpy(q, s, len);
8530 *q++ = '\'';
8531 s += len;
Eric Andersencb57d552001-06-28 07:25:16 +00008532
Eric Andersenc470f442003-07-28 09:56:35 +00008533 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008534
Eric Andersenc470f442003-07-28 09:56:35 +00008535 len = strspn(s, "'");
8536 if (!len)
8537 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008538
Eric Andersenc470f442003-07-28 09:56:35 +00008539 q = p = makestrspace(len + 3, p);
8540
8541 *q++ = '"';
8542 q = mempcpy(q, s, len);
8543 *q++ = '"';
8544 s += len;
8545
8546 STADJUST(q - p, p);
Eric Andersencb57d552001-06-28 07:25:16 +00008547 } while (*s);
8548
8549 USTPUTC(0, p);
8550
Eric Andersenc470f442003-07-28 09:56:35 +00008551 return stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +00008552}
8553
8554/*
Eric Andersenc470f442003-07-28 09:56:35 +00008555 * Like strdup but works with the ash stack.
Eric Andersencb57d552001-06-28 07:25:16 +00008556 */
8557
Eric Andersenc470f442003-07-28 09:56:35 +00008558char *
8559sstrdup(const char *p)
Eric Andersencb57d552001-06-28 07:25:16 +00008560{
Eric Andersenc470f442003-07-28 09:56:35 +00008561 size_t len = strlen(p) + 1;
8562 return memcpy(stalloc(len), p, len);
Eric Andersencb57d552001-06-28 07:25:16 +00008563}
Eric Andersenc470f442003-07-28 09:56:35 +00008564
8565
8566static void
8567calcsize(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008568{
Eric Andersenc470f442003-07-28 09:56:35 +00008569 if (n == NULL)
8570 return;
8571 funcblocksize += nodesize[n->type];
8572 switch (n->type) {
8573 case NCMD:
8574 calcsize(n->ncmd.redirect);
8575 calcsize(n->ncmd.args);
8576 calcsize(n->ncmd.assign);
8577 break;
8578 case NPIPE:
8579 sizenodelist(n->npipe.cmdlist);
8580 break;
8581 case NREDIR:
8582 case NBACKGND:
8583 case NSUBSHELL:
8584 calcsize(n->nredir.redirect);
8585 calcsize(n->nredir.n);
8586 break;
8587 case NAND:
8588 case NOR:
8589 case NSEMI:
8590 case NWHILE:
8591 case NUNTIL:
8592 calcsize(n->nbinary.ch2);
8593 calcsize(n->nbinary.ch1);
8594 break;
8595 case NIF:
8596 calcsize(n->nif.elsepart);
8597 calcsize(n->nif.ifpart);
8598 calcsize(n->nif.test);
8599 break;
8600 case NFOR:
8601 funcstringsize += strlen(n->nfor.var) + 1;
8602 calcsize(n->nfor.body);
8603 calcsize(n->nfor.args);
8604 break;
8605 case NCASE:
8606 calcsize(n->ncase.cases);
8607 calcsize(n->ncase.expr);
8608 break;
8609 case NCLIST:
8610 calcsize(n->nclist.body);
8611 calcsize(n->nclist.pattern);
8612 calcsize(n->nclist.next);
8613 break;
8614 case NDEFUN:
8615 case NARG:
8616 sizenodelist(n->narg.backquote);
8617 funcstringsize += strlen(n->narg.text) + 1;
8618 calcsize(n->narg.next);
8619 break;
8620 case NTO:
8621 case NCLOBBER:
8622 case NFROM:
8623 case NFROMTO:
8624 case NAPPEND:
8625 calcsize(n->nfile.fname);
8626 calcsize(n->nfile.next);
8627 break;
8628 case NTOFD:
8629 case NFROMFD:
8630 calcsize(n->ndup.vname);
8631 calcsize(n->ndup.next);
8632 break;
8633 case NHERE:
8634 case NXHERE:
8635 calcsize(n->nhere.doc);
8636 calcsize(n->nhere.next);
8637 break;
8638 case NNOT:
8639 calcsize(n->nnot.com);
8640 break;
8641 };
Eric Andersencb57d552001-06-28 07:25:16 +00008642}
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008643
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008644
Eric Andersenc470f442003-07-28 09:56:35 +00008645static void
8646sizenodelist(struct nodelist *lp)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008647{
8648 while (lp) {
Eric Andersenc470f442003-07-28 09:56:35 +00008649 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Manuel Novoa III 16815d42001-08-10 19:36:07 +00008650 calcsize(lp->n);
8651 lp = lp->next;
8652 }
8653}
Eric Andersencb57d552001-06-28 07:25:16 +00008654
8655
Eric Andersenc470f442003-07-28 09:56:35 +00008656static union node *
8657copynode(union node *n)
8658{
8659 union node *new;
8660
8661 if (n == NULL)
8662 return NULL;
8663 new = funcblock;
8664 funcblock = (char *) funcblock + nodesize[n->type];
8665 switch (n->type) {
8666 case NCMD:
8667 new->ncmd.redirect = copynode(n->ncmd.redirect);
8668 new->ncmd.args = copynode(n->ncmd.args);
8669 new->ncmd.assign = copynode(n->ncmd.assign);
8670 break;
8671 case NPIPE:
8672 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8673 new->npipe.backgnd = n->npipe.backgnd;
8674 break;
8675 case NREDIR:
8676 case NBACKGND:
8677 case NSUBSHELL:
8678 new->nredir.redirect = copynode(n->nredir.redirect);
8679 new->nredir.n = copynode(n->nredir.n);
8680 break;
8681 case NAND:
8682 case NOR:
8683 case NSEMI:
8684 case NWHILE:
8685 case NUNTIL:
8686 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8687 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8688 break;
8689 case NIF:
8690 new->nif.elsepart = copynode(n->nif.elsepart);
8691 new->nif.ifpart = copynode(n->nif.ifpart);
8692 new->nif.test = copynode(n->nif.test);
8693 break;
8694 case NFOR:
8695 new->nfor.var = nodesavestr(n->nfor.var);
8696 new->nfor.body = copynode(n->nfor.body);
8697 new->nfor.args = copynode(n->nfor.args);
8698 break;
8699 case NCASE:
8700 new->ncase.cases = copynode(n->ncase.cases);
8701 new->ncase.expr = copynode(n->ncase.expr);
8702 break;
8703 case NCLIST:
8704 new->nclist.body = copynode(n->nclist.body);
8705 new->nclist.pattern = copynode(n->nclist.pattern);
8706 new->nclist.next = copynode(n->nclist.next);
8707 break;
8708 case NDEFUN:
8709 case NARG:
8710 new->narg.backquote = copynodelist(n->narg.backquote);
8711 new->narg.text = nodesavestr(n->narg.text);
8712 new->narg.next = copynode(n->narg.next);
8713 break;
8714 case NTO:
8715 case NCLOBBER:
8716 case NFROM:
8717 case NFROMTO:
8718 case NAPPEND:
8719 new->nfile.fname = copynode(n->nfile.fname);
8720 new->nfile.fd = n->nfile.fd;
8721 new->nfile.next = copynode(n->nfile.next);
8722 break;
8723 case NTOFD:
8724 case NFROMFD:
8725 new->ndup.vname = copynode(n->ndup.vname);
8726 new->ndup.dupfd = n->ndup.dupfd;
8727 new->ndup.fd = n->ndup.fd;
8728 new->ndup.next = copynode(n->ndup.next);
8729 break;
8730 case NHERE:
8731 case NXHERE:
8732 new->nhere.doc = copynode(n->nhere.doc);
8733 new->nhere.fd = n->nhere.fd;
8734 new->nhere.next = copynode(n->nhere.next);
8735 break;
8736 case NNOT:
8737 new->nnot.com = copynode(n->nnot.com);
8738 break;
8739 };
8740 new->type = n->type;
8741 return new;
8742}
8743
8744
8745static struct nodelist *
8746copynodelist(struct nodelist *lp)
Eric Andersencb57d552001-06-28 07:25:16 +00008747{
8748 struct nodelist *start;
8749 struct nodelist **lpp;
8750
8751 lpp = &start;
8752 while (lp) {
8753 *lpp = funcblock;
Eric Andersenc470f442003-07-28 09:56:35 +00008754 funcblock = (char *) funcblock +
8755 SHELL_ALIGN(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00008756 (*lpp)->n = copynode(lp->n);
8757 lp = lp->next;
8758 lpp = &(*lpp)->next;
8759 }
8760 *lpp = NULL;
8761 return start;
8762}
8763
8764
Eric Andersenc470f442003-07-28 09:56:35 +00008765static char *
8766nodesavestr(char *s)
8767{
8768 char *rtn = funcstring;
8769
8770 funcstring = stpcpy(funcstring, s) + 1;
Eric Andersencb57d552001-06-28 07:25:16 +00008771 return rtn;
Eric Andersencb57d552001-06-28 07:25:16 +00008772}
8773
Eric Andersenc470f442003-07-28 09:56:35 +00008774
Eric Andersenc470f442003-07-28 09:56:35 +00008775/*
8776 * Free a parse tree.
8777 */
8778
8779static void
8780freefunc(struct funcnode *f)
8781{
8782 if (f && --f->count < 0)
8783 ckfree(f);
8784}
8785
8786
8787static void options(int);
8788static void setoption(int, int);
8789
Eric Andersencb57d552001-06-28 07:25:16 +00008790
Eric Andersencb57d552001-06-28 07:25:16 +00008791/*
8792 * Process the shell command line arguments.
8793 */
8794
Eric Andersenc470f442003-07-28 09:56:35 +00008795void
8796procargs(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00008797{
8798 int i;
Eric Andersenc470f442003-07-28 09:56:35 +00008799 const char *xminusc;
8800 char **xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008801
Eric Andersenc470f442003-07-28 09:56:35 +00008802 xargv = argv;
8803 arg0 = xargv[0];
Eric Andersencb57d552001-06-28 07:25:16 +00008804 if (argc > 0)
Eric Andersenc470f442003-07-28 09:56:35 +00008805 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008806 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008807 optlist[i] = 2;
8808 argptr = xargv;
Eric Andersencb57d552001-06-28 07:25:16 +00008809 options(1);
Eric Andersenc470f442003-07-28 09:56:35 +00008810 xargv = argptr;
8811 xminusc = minusc;
8812 if (*xargv == NULL) {
8813 if (xminusc)
8814 error("-c requires an argument");
Eric Andersencb57d552001-06-28 07:25:16 +00008815 sflag = 1;
Eric Andersenc470f442003-07-28 09:56:35 +00008816 }
Eric Andersencb57d552001-06-28 07:25:16 +00008817 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8818 iflag = 1;
8819 if (mflag == 2)
8820 mflag = iflag;
8821 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008822 if (optlist[i] == 2)
8823 optlist[i] = 0;
8824#if DEBUG == 2
8825 debug = 1;
8826#endif
8827 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8828 if (xminusc) {
8829 minusc = *xargv++;
8830 if (*xargv)
8831 goto setarg0;
8832 } else if (!sflag) {
8833 setinputfile(*xargv, 0);
8834setarg0:
8835 arg0 = *xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008836 commandname = arg0;
8837 }
Eric Andersencb57d552001-06-28 07:25:16 +00008838
Eric Andersenc470f442003-07-28 09:56:35 +00008839 shellparam.p = xargv;
8840#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008841 shellparam.optind = 1;
8842 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008843#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008844 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
Eric Andersenc470f442003-07-28 09:56:35 +00008845 while (*xargv) {
Eric Andersencb57d552001-06-28 07:25:16 +00008846 shellparam.nparam++;
Eric Andersenc470f442003-07-28 09:56:35 +00008847 xargv++;
Eric Andersencb57d552001-06-28 07:25:16 +00008848 }
8849 optschanged();
8850}
8851
8852
Eric Andersenc470f442003-07-28 09:56:35 +00008853void
8854optschanged(void)
8855{
8856#ifdef DEBUG
8857 opentrace();
8858#endif
8859 setinteractive(iflag);
8860 setjobctl(mflag);
Paul Fox3f11b1b2005-08-04 19:04:46 +00008861 setvimode(viflag);
Eric Andersenc470f442003-07-28 09:56:35 +00008862}
Eric Andersencb57d552001-06-28 07:25:16 +00008863
Eric Andersenc470f442003-07-28 09:56:35 +00008864static inline void
8865minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +00008866{
8867 int i;
8868
8869 if (name == NULL) {
8870 out1str("Current option settings\n");
8871 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008872 out1fmt("%-16s%s\n", optnames(i),
8873 optlist[i] ? "on" : "off");
Eric Andersen62483552001-07-10 06:09:16 +00008874 } else {
8875 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008876 if (equal(name, optnames(i))) {
8877 optlist[i] = val;
Eric Andersen62483552001-07-10 06:09:16 +00008878 return;
8879 }
8880 error("Illegal option -o %s", name);
8881 }
8882}
8883
Eric Andersenc470f442003-07-28 09:56:35 +00008884/*
8885 * Process shell options. The global variable argptr contains a pointer
8886 * to the argument list; we advance it past the options.
8887 */
Eric Andersen62483552001-07-10 06:09:16 +00008888
Eric Andersenc470f442003-07-28 09:56:35 +00008889static void
8890options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +00008891{
8892 char *p;
8893 int val;
8894 int c;
8895
8896 if (cmdline)
8897 minusc = NULL;
8898 while ((p = *argptr) != NULL) {
8899 argptr++;
8900 if ((c = *p++) == '-') {
8901 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00008902 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8903 if (!cmdline) {
8904 /* "-" means turn off -x and -v */
8905 if (p[0] == '\0')
8906 xflag = vflag = 0;
8907 /* "--" means reset params */
8908 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00008909 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00008910 }
Eric Andersenc470f442003-07-28 09:56:35 +00008911 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00008912 }
8913 } else if (c == '+') {
8914 val = 0;
8915 } else {
8916 argptr--;
8917 break;
8918 }
8919 while ((c = *p++) != '\0') {
8920 if (c == 'c' && cmdline) {
Eric Andersenc470f442003-07-28 09:56:35 +00008921 minusc = p; /* command is after shell args*/
Eric Andersencb57d552001-06-28 07:25:16 +00008922 } else if (c == 'o') {
8923 minus_o(*argptr, val);
8924 if (*argptr)
8925 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00008926 } else if (cmdline && (c == '-')) { // long options
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008927 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +00008928 isloginsh = 1;
8929 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008930 } else {
8931 setoption(c, val);
8932 }
8933 }
8934 }
8935}
8936
Eric Andersencb57d552001-06-28 07:25:16 +00008937
Eric Andersenc470f442003-07-28 09:56:35 +00008938static void
8939setoption(int flag, int val)
Eric Andersen2870d962001-07-02 17:27:21 +00008940{
Eric Andersencb57d552001-06-28 07:25:16 +00008941 int i;
8942
8943 for (i = 0; i < NOPTS; i++)
Eric Andersenc470f442003-07-28 09:56:35 +00008944 if (optletters(i) == flag) {
8945 optlist[i] = val;
Eric Andersencb57d552001-06-28 07:25:16 +00008946 return;
8947 }
8948 error("Illegal option -%c", flag);
8949 /* NOTREACHED */
8950}
8951
8952
8953
Eric Andersencb57d552001-06-28 07:25:16 +00008954/*
8955 * Set the shell parameters.
8956 */
8957
Eric Andersenc470f442003-07-28 09:56:35 +00008958void
8959setparam(char **argv)
Eric Andersen2870d962001-07-02 17:27:21 +00008960{
Eric Andersencb57d552001-06-28 07:25:16 +00008961 char **newparam;
8962 char **ap;
8963 int nparam;
8964
Eric Andersenc470f442003-07-28 09:56:35 +00008965 for (nparam = 0 ; argv[nparam] ; nparam++);
8966 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
Eric Andersencb57d552001-06-28 07:25:16 +00008967 while (*argv) {
Eric Andersenc470f442003-07-28 09:56:35 +00008968 *ap++ = savestr(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +00008969 }
8970 *ap = NULL;
8971 freeparam(&shellparam);
8972 shellparam.malloc = 1;
8973 shellparam.nparam = nparam;
8974 shellparam.p = newparam;
Eric Andersenc470f442003-07-28 09:56:35 +00008975#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00008976 shellparam.optind = 1;
8977 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00008978#endif
Eric Andersencb57d552001-06-28 07:25:16 +00008979}
8980
8981
8982/*
8983 * Free the list of positional parameters.
8984 */
8985
Eric Andersenc470f442003-07-28 09:56:35 +00008986void
8987freeparam(volatile struct shparam *param)
Eric Andersen2870d962001-07-02 17:27:21 +00008988{
Eric Andersencb57d552001-06-28 07:25:16 +00008989 char **ap;
8990
8991 if (param->malloc) {
Eric Andersenc470f442003-07-28 09:56:35 +00008992 for (ap = param->p ; *ap ; ap++)
8993 ckfree(*ap);
8994 ckfree(param->p);
Eric Andersencb57d552001-06-28 07:25:16 +00008995 }
8996}
8997
8998
8999
9000/*
9001 * The shift builtin command.
9002 */
9003
Eric Andersenc470f442003-07-28 09:56:35 +00009004int
9005shiftcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009006{
9007 int n;
9008 char **ap1, **ap2;
9009
9010 n = 1;
9011 if (argc > 1)
9012 n = number(argv[1]);
9013 if (n > shellparam.nparam)
9014 error("can't shift that many");
9015 INTOFF;
9016 shellparam.nparam -= n;
Eric Andersenc470f442003-07-28 09:56:35 +00009017 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
Eric Andersencb57d552001-06-28 07:25:16 +00009018 if (shellparam.malloc)
Eric Andersenc470f442003-07-28 09:56:35 +00009019 ckfree(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +00009020 }
9021 ap2 = shellparam.p;
9022 while ((*ap2++ = *ap1++) != NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009023#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009024 shellparam.optind = 1;
9025 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009026#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009027 INTON;
9028 return 0;
9029}
9030
9031
9032
9033/*
9034 * The set command builtin.
9035 */
9036
Eric Andersenc470f442003-07-28 09:56:35 +00009037int
9038setcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009039{
9040 if (argc == 1)
Eric Andersenc470f442003-07-28 09:56:35 +00009041 return showvars(nullstr, 0, VUNSET);
Eric Andersencb57d552001-06-28 07:25:16 +00009042 INTOFF;
9043 options(0);
9044 optschanged();
9045 if (*argptr != NULL) {
9046 setparam(argptr);
9047 }
9048 INTON;
9049 return 0;
9050}
9051
9052
Eric Andersenc470f442003-07-28 09:56:35 +00009053#ifdef CONFIG_ASH_GETOPTS
9054static void
9055getoptsreset(value)
9056 const char *value;
Eric Andersencb57d552001-06-28 07:25:16 +00009057{
9058 shellparam.optind = number(value);
9059 shellparam.optoff = -1;
9060}
Eric Andersenc470f442003-07-28 09:56:35 +00009061#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009062
Eric Andersenbdfd0d72001-10-24 05:00:29 +00009063#ifdef CONFIG_LOCALE_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00009064static void change_lc_all(const char *value)
9065{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009066 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009067 setlocale(LC_ALL, value);
9068}
9069
9070static void change_lc_ctype(const char *value)
9071{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009072 if (value != 0 && *value != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00009073 setlocale(LC_CTYPE, value);
9074}
9075
9076#endif
9077
Eric Andersen16767e22004-03-16 05:14:10 +00009078#ifdef CONFIG_ASH_RANDOM_SUPPORT
Eric Andersenef02f822004-03-11 13:34:24 +00009079/* Roughly copied from bash.. */
Eric Andersenef02f822004-03-11 13:34:24 +00009080static void change_random(const char *value)
9081{
Eric Andersen16767e22004-03-16 05:14:10 +00009082 if(value == NULL) {
9083 /* "get", generate */
9084 char buf[16];
9085
9086 rseed = rseed * 1103515245 + 12345;
9087 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9088 /* set without recursion */
9089 setvar(vrandom.text, buf, VNOFUNC);
9090 vrandom.flags &= ~VNOFUNC;
9091 } else {
9092 /* set/reset */
9093 rseed = strtoul(value, (char **)NULL, 10);
9094 }
Eric Andersenef02f822004-03-11 13:34:24 +00009095}
Eric Andersen16767e22004-03-16 05:14:10 +00009096#endif
9097
Eric Andersenef02f822004-03-11 13:34:24 +00009098
Eric Andersend35c5df2002-01-09 15:37:36 +00009099#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +00009100static int
Eric Andersenc470f442003-07-28 09:56:35 +00009101getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009102{
9103 char *p, *q;
9104 char c = '?';
9105 int done = 0;
9106 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +00009107 char s[12];
9108 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +00009109
Eric Andersena48b0a32003-10-22 10:56:47 +00009110 if(*param_optind < 1)
9111 return 1;
9112 optnext = optfirst + *param_optind - 1;
9113
9114 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +00009115 p = NULL;
9116 else
Eric Andersena48b0a32003-10-22 10:56:47 +00009117 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +00009118 if (p == NULL || *p == '\0') {
9119 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +00009120 p = *optnext;
9121 if (p == NULL || *p != '-' || *++p == '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +00009122atend:
Eric Andersencb57d552001-06-28 07:25:16 +00009123 p = NULL;
9124 done = 1;
9125 goto out;
9126 }
9127 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009128 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009129 goto atend;
9130 }
9131
9132 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009133 for (q = optstr; *q != c; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009134 if (*q == '\0') {
9135 if (optstr[0] == ':') {
9136 s[0] = c;
9137 s[1] = '\0';
9138 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009139 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009140 fprintf(stderr, "Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009141 (void) unsetvar("OPTARG");
9142 }
9143 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +00009144 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009145 }
9146 if (*++q == ':')
9147 q++;
9148 }
9149
9150 if (*++q == ':') {
9151 if (*p == '\0' && (p = *optnext) == NULL) {
9152 if (optstr[0] == ':') {
9153 s[0] = c;
9154 s[1] = '\0';
9155 err |= setvarsafe("OPTARG", s, 0);
9156 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009157 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009158 fprintf(stderr, "No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009159 (void) unsetvar("OPTARG");
9160 c = '?';
9161 }
Eric Andersenc470f442003-07-28 09:56:35 +00009162 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009163 }
9164
9165 if (p == *optnext)
9166 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +00009167 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009168 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009169 } else
Eric Andersenc470f442003-07-28 09:56:35 +00009170 err |= setvarsafe("OPTARG", nullstr, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00009171
Eric Andersenc470f442003-07-28 09:56:35 +00009172out:
Eric Andersencb57d552001-06-28 07:25:16 +00009173 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009174 *param_optind = optnext - optfirst + 1;
9175 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +00009176 err |= setvarsafe("OPTIND", s, VNOFUNC);
9177 s[0] = c;
9178 s[1] = '\0';
9179 err |= setvarsafe(optvar, s, 0);
9180 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +00009181 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009182 *optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +00009183 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00009184 exraise(EXERROR);
9185 }
9186 return done;
9187}
Eric Andersenc470f442003-07-28 09:56:35 +00009188
9189/*
9190 * The getopts builtin. Shellparam.optnext points to the next argument
9191 * to be processed. Shellparam.optptr points to the next character to
9192 * be processed in the current argument. If shellparam.optnext is NULL,
9193 * then it's the first time getopts has been called.
9194 */
9195
9196int
9197getoptscmd(int argc, char **argv)
9198{
9199 char **optbase;
9200
9201 if (argc < 3)
9202 error("Usage: getopts optstring var [arg]");
9203 else if (argc == 3) {
9204 optbase = shellparam.p;
9205 if (shellparam.optind > shellparam.nparam + 1) {
9206 shellparam.optind = 1;
9207 shellparam.optoff = -1;
9208 }
9209 }
9210 else {
9211 optbase = &argv[3];
9212 if (shellparam.optind > argc - 2) {
9213 shellparam.optind = 1;
9214 shellparam.optoff = -1;
9215 }
9216 }
9217
9218 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9219 &shellparam.optoff);
9220}
9221#endif /* CONFIG_ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +00009222
9223/*
9224 * XXX - should get rid of. have all builtins use getopt(3). the
9225 * library getopt must have the BSD extension static variable "optreset"
9226 * otherwise it can't be used within the shell safely.
9227 *
9228 * Standard option processing (a la getopt) for builtin routines. The
9229 * only argument that is passed to nextopt is the option string; the
9230 * other arguments are unnecessary. It return the character, or '\0' on
9231 * end of input.
9232 */
9233
Eric Andersenc470f442003-07-28 09:56:35 +00009234static int
9235nextopt(const char *optstring)
Eric Andersen62483552001-07-10 06:09:16 +00009236{
Eric Andersencb57d552001-06-28 07:25:16 +00009237 char *p;
9238 const char *q;
9239 char c;
9240
9241 if ((p = optptr) == NULL || *p == '\0') {
9242 p = *argptr;
9243 if (p == NULL || *p != '-' || *++p == '\0')
9244 return '\0';
9245 argptr++;
Eric Andersenc470f442003-07-28 09:56:35 +00009246 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009247 return '\0';
9248 }
9249 c = *p++;
Eric Andersenc470f442003-07-28 09:56:35 +00009250 for (q = optstring ; *q != c ; ) {
Eric Andersencb57d552001-06-28 07:25:16 +00009251 if (*q == '\0')
9252 error("Illegal option -%c", c);
9253 if (*++q == ':')
9254 q++;
9255 }
9256 if (*++q == ':') {
9257 if (*p == '\0' && (p = *argptr++) == NULL)
9258 error("No arg for -%c option", c);
9259 optionarg = p;
9260 p = NULL;
9261 }
9262 optptr = p;
9263 return c;
9264}
9265
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009266
Eric Andersenc470f442003-07-28 09:56:35 +00009267/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9268
Eric Andersenc470f442003-07-28 09:56:35 +00009269void
9270outstr(const char *p, FILE *file)
9271{
9272 INTOFF;
9273 fputs(p, file);
9274 INTON;
9275}
9276
9277void
9278flushall(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009279{
Eric Andersencb57d552001-06-28 07:25:16 +00009280 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009281 fflush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009282 fflush(stderr);
Eric Andersencb57d552001-06-28 07:25:16 +00009283 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009284}
9285
Eric Andersenc470f442003-07-28 09:56:35 +00009286void
Eric Andersen16767e22004-03-16 05:14:10 +00009287flusherr(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009288{
9289 INTOFF;
Eric Andersen16767e22004-03-16 05:14:10 +00009290 fflush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00009291 INTON;
9292}
9293
9294static void
9295outcslow(int c, FILE *dest)
9296{
9297 INTOFF;
9298 putc(c, dest);
9299 fflush(dest);
9300 INTON;
9301}
9302
9303
9304static int
9305out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009306{
9307 va_list ap;
Eric Andersenc470f442003-07-28 09:56:35 +00009308 int r;
9309
9310 INTOFF;
9311 va_start(ap, fmt);
9312 r = vprintf(fmt, ap);
9313 va_end(ap);
9314 INTON;
9315 return r;
9316}
9317
9318
9319int
9320fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9321{
9322 va_list ap;
9323 int ret;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009324
Eric Andersencb57d552001-06-28 07:25:16 +00009325 va_start(ap, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +00009326 INTOFF;
9327 ret = vsnprintf(outbuf, length, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009328 va_end(ap);
Eric Andersenc470f442003-07-28 09:56:35 +00009329 INTON;
9330 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00009331}
9332
Eric Andersenc470f442003-07-28 09:56:35 +00009333
Eric Andersencb57d552001-06-28 07:25:16 +00009334
Eric Andersenc470f442003-07-28 09:56:35 +00009335/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9336
9337
Eric Andersencb57d552001-06-28 07:25:16 +00009338/*
9339 * Shell command parser.
9340 */
9341
9342#define EOFMARKLEN 79
9343
9344
Eric Andersencb57d552001-06-28 07:25:16 +00009345struct heredoc {
Eric Andersenc470f442003-07-28 09:56:35 +00009346 struct heredoc *next; /* next here document in list */
9347 union node *here; /* redirection node */
9348 char *eofmark; /* string indicating end of input */
9349 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009350};
9351
9352
9353
Eric Andersenc470f442003-07-28 09:56:35 +00009354static struct heredoc *heredoclist; /* list of here documents to read */
Eric Andersencb57d552001-06-28 07:25:16 +00009355
9356
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009357static union node *list(int);
9358static union node *andor(void);
9359static union node *pipeline(void);
9360static union node *command(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009361static union node *simplecmd(void);
9362static union node *makename(void);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009363static void parsefname(void);
9364static void parseheredoc(void);
9365static char peektoken(void);
9366static int readtoken(void);
9367static int xxreadtoken(void);
Eric Andersenc470f442003-07-28 09:56:35 +00009368static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009369static int noexpand(char *);
Eric Andersenc470f442003-07-28 09:56:35 +00009370static void synexpect(int) __attribute__((__noreturn__));
9371static void synerror(const char *) __attribute__((__noreturn__));
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009372static void setprompt(int);
Eric Andersencb57d552001-06-28 07:25:16 +00009373
9374
Eric Andersenc470f442003-07-28 09:56:35 +00009375
Eric Andersenc470f442003-07-28 09:56:35 +00009376
Eric Andersencb57d552001-06-28 07:25:16 +00009377/*
9378 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9379 * valid parse tree indicating a blank line.)
9380 */
9381
Eric Andersenc470f442003-07-28 09:56:35 +00009382union node *
9383parsecmd(int interact)
Eric Andersencb57d552001-06-28 07:25:16 +00009384{
9385 int t;
9386
9387 tokpushback = 0;
9388 doprompt = interact;
9389 if (doprompt)
Eric Andersenc470f442003-07-28 09:56:35 +00009390 setprompt(doprompt);
Eric Andersencb57d552001-06-28 07:25:16 +00009391 needprompt = 0;
9392 t = readtoken();
9393 if (t == TEOF)
9394 return NEOF;
9395 if (t == TNL)
9396 return NULL;
9397 tokpushback++;
9398 return list(1);
9399}
9400
9401
Eric Andersenc470f442003-07-28 09:56:35 +00009402static union node *
9403list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +00009404{
9405 union node *n1, *n2, *n3;
9406 int tok;
9407
Eric Andersenc470f442003-07-28 09:56:35 +00009408 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9409 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009410 return NULL;
9411 n1 = NULL;
9412 for (;;) {
9413 n2 = andor();
9414 tok = readtoken();
9415 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +00009416 if (n2->type == NPIPE) {
9417 n2->npipe.backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009418 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009419 if (n2->type != NREDIR) {
9420 n3 = stalloc(sizeof(struct nredir));
9421 n3->nredir.n = n2;
9422 n3->nredir.redirect = NULL;
9423 n2 = n3;
9424 }
9425 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +00009426 }
9427 }
9428 if (n1 == NULL) {
9429 n1 = n2;
Eric Andersenc470f442003-07-28 09:56:35 +00009430 }
9431 else {
9432 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009433 n3->type = NSEMI;
9434 n3->nbinary.ch1 = n1;
9435 n3->nbinary.ch2 = n2;
9436 n1 = n3;
9437 }
9438 switch (tok) {
9439 case TBACKGND:
9440 case TSEMI:
9441 tok = readtoken();
9442 /* fall through */
9443 case TNL:
9444 if (tok == TNL) {
9445 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +00009446 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009447 return n1;
9448 } else {
9449 tokpushback++;
9450 }
Eric Andersenc470f442003-07-28 09:56:35 +00009451 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009452 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +00009453 return n1;
9454 break;
9455 case TEOF:
9456 if (heredoclist)
9457 parseheredoc();
9458 else
Eric Andersenc470f442003-07-28 09:56:35 +00009459 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009460 return n1;
9461 default:
Eric Andersenc470f442003-07-28 09:56:35 +00009462 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +00009463 synexpect(-1);
9464 tokpushback++;
9465 return n1;
9466 }
9467 }
9468}
9469
9470
9471
Eric Andersenc470f442003-07-28 09:56:35 +00009472static union node *
9473andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009474{
Eric Andersencb57d552001-06-28 07:25:16 +00009475 union node *n1, *n2, *n3;
9476 int t;
9477
Eric Andersencb57d552001-06-28 07:25:16 +00009478 n1 = pipeline();
9479 for (;;) {
9480 if ((t = readtoken()) == TAND) {
9481 t = NAND;
9482 } else if (t == TOR) {
9483 t = NOR;
9484 } else {
9485 tokpushback++;
9486 return n1;
9487 }
Eric Andersenc470f442003-07-28 09:56:35 +00009488 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009489 n2 = pipeline();
Eric Andersenc470f442003-07-28 09:56:35 +00009490 n3 = (union node *)stalloc(sizeof (struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +00009491 n3->type = t;
9492 n3->nbinary.ch1 = n1;
9493 n3->nbinary.ch2 = n2;
9494 n1 = n3;
9495 }
9496}
9497
9498
9499
Eric Andersenc470f442003-07-28 09:56:35 +00009500static union node *
9501pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009502{
Eric Andersencb57d552001-06-28 07:25:16 +00009503 union node *n1, *n2, *pipenode;
9504 struct nodelist *lp, *prev;
9505 int negate;
9506
9507 negate = 0;
9508 TRACE(("pipeline: entered\n"));
9509 if (readtoken() == TNOT) {
9510 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +00009511 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009512 } else
9513 tokpushback++;
9514 n1 = command();
9515 if (readtoken() == TPIPE) {
Eric Andersenc470f442003-07-28 09:56:35 +00009516 pipenode = (union node *)stalloc(sizeof (struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +00009517 pipenode->type = NPIPE;
9518 pipenode->npipe.backgnd = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009519 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +00009520 pipenode->npipe.cmdlist = lp;
9521 lp->n = n1;
9522 do {
9523 prev = lp;
Eric Andersenc470f442003-07-28 09:56:35 +00009524 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9525 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009526 lp->n = command();
9527 prev->next = lp;
9528 } while (readtoken() == TPIPE);
9529 lp->next = NULL;
9530 n1 = pipenode;
9531 }
9532 tokpushback++;
9533 if (negate) {
Eric Andersenc470f442003-07-28 09:56:35 +00009534 n2 = (union node *)stalloc(sizeof (struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +00009535 n2->type = NNOT;
9536 n2->nnot.com = n1;
9537 return n2;
9538 } else
9539 return n1;
9540}
9541
9542
9543
Eric Andersenc470f442003-07-28 09:56:35 +00009544static union node *
9545command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009546{
Eric Andersencb57d552001-06-28 07:25:16 +00009547 union node *n1, *n2;
9548 union node *ap, **app;
9549 union node *cp, **cpp;
9550 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009551 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009552 int t;
9553
9554 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009555 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +00009556
Eric Andersencb57d552001-06-28 07:25:16 +00009557 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +00009558 default:
9559 synexpect(-1);
9560 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +00009561 case TIF:
Eric Andersenc470f442003-07-28 09:56:35 +00009562 n1 = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009563 n1->type = NIF;
9564 n1->nif.test = list(0);
9565 if (readtoken() != TTHEN)
9566 synexpect(TTHEN);
9567 n1->nif.ifpart = list(0);
9568 n2 = n1;
9569 while (readtoken() == TELIF) {
Eric Andersenc470f442003-07-28 09:56:35 +00009570 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +00009571 n2 = n2->nif.elsepart;
9572 n2->type = NIF;
9573 n2->nif.test = list(0);
9574 if (readtoken() != TTHEN)
9575 synexpect(TTHEN);
9576 n2->nif.ifpart = list(0);
9577 }
9578 if (lasttoken == TELSE)
9579 n2->nif.elsepart = list(0);
9580 else {
9581 n2->nif.elsepart = NULL;
9582 tokpushback++;
9583 }
Eric Andersenc470f442003-07-28 09:56:35 +00009584 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +00009585 break;
9586 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +00009587 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +00009588 int got;
Eric Andersenc470f442003-07-28 09:56:35 +00009589 n1 = (union node *)stalloc(sizeof (struct nbinary));
9590 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +00009591 n1->nbinary.ch1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009592 if ((got=readtoken()) != TDO) {
9593TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009594 synexpect(TDO);
9595 }
9596 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009597 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009598 break;
9599 }
9600 case TFOR:
Eric Andersenc470f442003-07-28 09:56:35 +00009601 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
Eric Andersencb57d552001-06-28 07:25:16 +00009602 synerror("Bad for loop variable");
Eric Andersenc470f442003-07-28 09:56:35 +00009603 n1 = (union node *)stalloc(sizeof (struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +00009604 n1->type = NFOR;
9605 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +00009606 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009607 if (readtoken() == TIN) {
9608 app = &ap;
9609 while (readtoken() == TWORD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009610 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009611 n2->type = NARG;
9612 n2->narg.text = wordtext;
9613 n2->narg.backquote = backquotelist;
9614 *app = n2;
9615 app = &n2->narg.next;
9616 }
9617 *app = NULL;
9618 n1->nfor.args = ap;
9619 if (lasttoken != TNL && lasttoken != TSEMI)
9620 synexpect(-1);
9621 } else {
Eric Andersenc470f442003-07-28 09:56:35 +00009622 n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009623 n2->type = NARG;
Eric Andersenc470f442003-07-28 09:56:35 +00009624 n2->narg.text = (char *)dolatstr;
Eric Andersencb57d552001-06-28 07:25:16 +00009625 n2->narg.backquote = NULL;
9626 n2->narg.next = NULL;
9627 n1->nfor.args = n2;
9628 /*
9629 * Newline or semicolon here is optional (but note
9630 * that the original Bourne shell only allowed NL).
9631 */
9632 if (lasttoken != TNL && lasttoken != TSEMI)
9633 tokpushback++;
9634 }
Eric Andersenc470f442003-07-28 09:56:35 +00009635 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009636 if (readtoken() != TDO)
9637 synexpect(TDO);
9638 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009639 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +00009640 break;
9641 case TCASE:
Eric Andersenc470f442003-07-28 09:56:35 +00009642 n1 = (union node *)stalloc(sizeof (struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +00009643 n1->type = NCASE;
9644 if (readtoken() != TWORD)
9645 synexpect(TWORD);
Eric Andersenc470f442003-07-28 09:56:35 +00009646 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009647 n2->type = NARG;
9648 n2->narg.text = wordtext;
9649 n2->narg.backquote = backquotelist;
9650 n2->narg.next = NULL;
9651 do {
Eric Andersenc470f442003-07-28 09:56:35 +00009652 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009653 } while (readtoken() == TNL);
9654 if (lasttoken != TIN)
Eric Andersenc470f442003-07-28 09:56:35 +00009655 synexpect(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +00009656 cpp = &n1->ncase.cases;
Eric Andersenc470f442003-07-28 09:56:35 +00009657next_case:
9658 checkkwd = CHKNL | CHKKWD;
9659 t = readtoken();
9660 while(t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +00009661 if (lasttoken == TLP)
9662 readtoken();
Eric Andersenc470f442003-07-28 09:56:35 +00009663 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +00009664 cp->type = NCLIST;
9665 app = &cp->nclist.pattern;
9666 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009667 *app = ap = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009668 ap->type = NARG;
9669 ap->narg.text = wordtext;
9670 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009671 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +00009672 break;
9673 app = &ap->narg.next;
9674 readtoken();
9675 }
9676 ap->narg.next = NULL;
9677 if (lasttoken != TRP)
9678 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009679 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009680
Eric Andersenc470f442003-07-28 09:56:35 +00009681 cpp = &cp->nclist.next;
9682
9683 checkkwd = CHKNL | CHKKWD;
Eric Andersencb57d552001-06-28 07:25:16 +00009684 if ((t = readtoken()) != TESAC) {
9685 if (t != TENDCASE)
9686 synexpect(TENDCASE);
9687 else
Eric Andersenc470f442003-07-28 09:56:35 +00009688 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +00009689 }
Eric Andersenc470f442003-07-28 09:56:35 +00009690 }
Eric Andersencb57d552001-06-28 07:25:16 +00009691 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009692 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +00009693 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009694 n1 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009695 n1->type = NSUBSHELL;
9696 n1->nredir.n = list(0);
9697 n1->nredir.redirect = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009698 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +00009699 break;
9700 case TBEGIN:
9701 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +00009702 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +00009703 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009704 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009705 case TREDIR:
Eric Andersencb57d552001-06-28 07:25:16 +00009706 tokpushback++;
Eric Andersenc470f442003-07-28 09:56:35 +00009707 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +00009708 }
9709
Eric Andersenc470f442003-07-28 09:56:35 +00009710 if (readtoken() != t)
9711 synexpect(t);
9712
9713redir:
Eric Andersencb57d552001-06-28 07:25:16 +00009714 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +00009715 checkkwd = CHKKWD | CHKALIAS;
9716 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +00009717 while (readtoken() == TREDIR) {
9718 *rpp = n2 = redirnode;
9719 rpp = &n2->nfile.next;
9720 parsefname();
9721 }
9722 tokpushback++;
9723 *rpp = NULL;
9724 if (redir) {
9725 if (n1->type != NSUBSHELL) {
Eric Andersenc470f442003-07-28 09:56:35 +00009726 n2 = (union node *)stalloc(sizeof (struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +00009727 n2->type = NREDIR;
9728 n2->nredir.n = n1;
9729 n1 = n2;
9730 }
9731 n1->nredir.redirect = redir;
9732 }
9733
9734 return n1;
9735}
9736
9737
Eric Andersenc470f442003-07-28 09:56:35 +00009738static union node *
9739simplecmd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00009740 union node *args, **app;
9741 union node *n = NULL;
9742 union node *vars, **vpp;
Eric Andersenc470f442003-07-28 09:56:35 +00009743 union node **rpp, *redir;
9744 int savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009745
9746 args = NULL;
9747 app = &args;
9748 vars = NULL;
9749 vpp = &vars;
Eric Andersenc470f442003-07-28 09:56:35 +00009750 redir = NULL;
9751 rpp = &redir;
Eric Andersena3483db2001-10-24 08:01:06 +00009752
Eric Andersenc470f442003-07-28 09:56:35 +00009753 savecheckkwd = CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009754 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00009755 checkkwd = savecheckkwd;
Eric Andersencb57d552001-06-28 07:25:16 +00009756 switch (readtoken()) {
9757 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +00009758 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009759 n->type = NARG;
9760 n->narg.text = wordtext;
9761 n->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +00009762 if (savecheckkwd && isassignment(wordtext)) {
Eric Andersencb57d552001-06-28 07:25:16 +00009763 *vpp = n;
9764 vpp = &n->narg.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009765 } else {
9766 *app = n;
9767 app = &n->narg.next;
9768 savecheckkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009769 }
9770 break;
9771 case TREDIR:
9772 *rpp = n = redirnode;
9773 rpp = &n->nfile.next;
Eric Andersenc470f442003-07-28 09:56:35 +00009774 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +00009775 break;
9776 case TLP:
Eric Andersenc470f442003-07-28 09:56:35 +00009777 if (
9778 args && app == &args->narg.next &&
9779 !vars && !redir
9780 ) {
9781 struct builtincmd *bcmd;
9782 const char *name;
9783
Eric Andersencb57d552001-06-28 07:25:16 +00009784 /* We have a function */
9785 if (readtoken() != TRP)
9786 synexpect(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +00009787 name = n->narg.text;
9788 if (
9789 !goodname(name) || (
9790 (bcmd = find_builtin(name)) &&
9791 IS_BUILTIN_SPECIAL(bcmd)
9792 )
9793 )
9794 synerror("Bad function name");
Eric Andersencb57d552001-06-28 07:25:16 +00009795 n->type = NDEFUN;
Eric Andersenc470f442003-07-28 09:56:35 +00009796 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +00009797 n->narg.next = command();
9798 return n;
9799 }
9800 /* fall through */
9801 default:
9802 tokpushback++;
9803 goto out;
9804 }
9805 }
Eric Andersenc470f442003-07-28 09:56:35 +00009806out:
Eric Andersencb57d552001-06-28 07:25:16 +00009807 *app = NULL;
9808 *vpp = NULL;
9809 *rpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009810 n = (union node *)stalloc(sizeof (struct ncmd));
Eric Andersencb57d552001-06-28 07:25:16 +00009811 n->type = NCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00009812 n->ncmd.args = args;
9813 n->ncmd.assign = vars;
9814 n->ncmd.redirect = redir;
9815 return n;
9816}
9817
Eric Andersenc470f442003-07-28 09:56:35 +00009818static union node *
9819makename(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009820{
Eric Andersencb57d552001-06-28 07:25:16 +00009821 union node *n;
9822
Eric Andersenc470f442003-07-28 09:56:35 +00009823 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009824 n->type = NARG;
9825 n->narg.next = NULL;
9826 n->narg.text = wordtext;
9827 n->narg.backquote = backquotelist;
9828 return n;
9829}
9830
Eric Andersenc470f442003-07-28 09:56:35 +00009831void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +00009832{
Eric Andersencb57d552001-06-28 07:25:16 +00009833 TRACE(("Fix redir %s %d\n", text, err));
9834 if (!err)
9835 n->ndup.vname = NULL;
9836
9837 if (is_digit(text[0]) && text[1] == '\0')
9838 n->ndup.dupfd = digit_val(text[0]);
9839 else if (text[0] == '-' && text[1] == '\0')
9840 n->ndup.dupfd = -1;
9841 else {
9842
9843 if (err)
9844 synerror("Bad fd number");
9845 else
9846 n->ndup.vname = makename();
9847 }
9848}
9849
9850
Eric Andersenc470f442003-07-28 09:56:35 +00009851static void
9852parsefname(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009853{
Eric Andersencb57d552001-06-28 07:25:16 +00009854 union node *n = redirnode;
9855
9856 if (readtoken() != TWORD)
9857 synexpect(-1);
9858 if (n->type == NHERE) {
9859 struct heredoc *here = heredoc;
9860 struct heredoc *p;
9861 int i;
9862
9863 if (quoteflag == 0)
9864 n->type = NXHERE;
9865 TRACE(("Here document %d\n", n->type));
Eric Andersenc470f442003-07-28 09:56:35 +00009866 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Eric Andersencb57d552001-06-28 07:25:16 +00009867 synerror("Illegal eof marker for << redirection");
9868 rmescapes(wordtext);
9869 here->eofmark = wordtext;
9870 here->next = NULL;
9871 if (heredoclist == NULL)
9872 heredoclist = here;
9873 else {
Eric Andersenc470f442003-07-28 09:56:35 +00009874 for (p = heredoclist ; p->next ; p = p->next);
Eric Andersencb57d552001-06-28 07:25:16 +00009875 p->next = here;
9876 }
9877 } else if (n->type == NTOFD || n->type == NFROMFD) {
9878 fixredir(n, wordtext, 0);
9879 } else {
9880 n->nfile.fname = makename();
9881 }
9882}
9883
9884
9885/*
9886 * Input any here documents.
9887 */
9888
Eric Andersenc470f442003-07-28 09:56:35 +00009889static void
9890parseheredoc(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009891{
Eric Andersencb57d552001-06-28 07:25:16 +00009892 struct heredoc *here;
9893 union node *n;
9894
Eric Andersenc470f442003-07-28 09:56:35 +00009895 here = heredoclist;
9896 heredoclist = 0;
9897
9898 while (here) {
Eric Andersencb57d552001-06-28 07:25:16 +00009899 if (needprompt) {
9900 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +00009901 }
Eric Andersenc470f442003-07-28 09:56:35 +00009902 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9903 here->eofmark, here->striptabs);
9904 n = (union node *)stalloc(sizeof (struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +00009905 n->narg.type = NARG;
9906 n->narg.next = NULL;
9907 n->narg.text = wordtext;
9908 n->narg.backquote = backquotelist;
9909 here->here->nhere.doc = n;
Eric Andersenc470f442003-07-28 09:56:35 +00009910 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +00009911 }
9912}
9913
Eric Andersenc470f442003-07-28 09:56:35 +00009914static char peektoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009915{
Eric Andersencb57d552001-06-28 07:25:16 +00009916 int t;
9917
9918 t = readtoken();
9919 tokpushback++;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00009920 return tokname_array[t][0];
Eric Andersencb57d552001-06-28 07:25:16 +00009921}
9922
Eric Andersenc470f442003-07-28 09:56:35 +00009923static int
9924readtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009925{
Eric Andersencb57d552001-06-28 07:25:16 +00009926 int t;
Eric Andersencb57d552001-06-28 07:25:16 +00009927#ifdef DEBUG
9928 int alreadyseen = tokpushback;
9929#endif
9930
Eric Andersend35c5df2002-01-09 15:37:36 +00009931#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009932top:
Eric Andersen2870d962001-07-02 17:27:21 +00009933#endif
9934
Eric Andersencb57d552001-06-28 07:25:16 +00009935 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +00009936
Eric Andersenc470f442003-07-28 09:56:35 +00009937 /*
9938 * eat newlines
9939 */
9940 if (checkkwd & CHKNL) {
9941 while (t == TNL) {
9942 parseheredoc();
9943 t = xxreadtoken();
Eric Andersencb57d552001-06-28 07:25:16 +00009944 }
9945 }
9946
Eric Andersenc470f442003-07-28 09:56:35 +00009947 if (t != TWORD || quoteflag) {
9948 goto out;
9949 }
Eric Andersen7467c8d2001-07-12 20:26:32 +00009950
Eric Andersenc470f442003-07-28 09:56:35 +00009951 /*
9952 * check for keywords
9953 */
9954 if (checkkwd & CHKKWD) {
9955 const char *const *pp;
9956
9957 if ((pp = findkwd(wordtext))) {
9958 lasttoken = t = pp - tokname_array;
9959 TRACE(("keyword %s recognized\n", tokname(t)));
9960 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +00009961 }
Eric Andersenc470f442003-07-28 09:56:35 +00009962 }
9963
9964 if (checkkwd & CHKALIAS) {
Eric Andersen8e139872002-07-04 00:19:46 +00009965#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +00009966 struct alias *ap;
9967 if ((ap = lookupalias(wordtext, 1)) != NULL) {
Eric Andersencb57d552001-06-28 07:25:16 +00009968 if (*ap->val) {
Eric Andersenc470f442003-07-28 09:56:35 +00009969 pushstring(ap->val, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009970 }
Eric Andersencb57d552001-06-28 07:25:16 +00009971 goto top;
9972 }
Eric Andersen2870d962001-07-02 17:27:21 +00009973#endif
Eric Andersen7467c8d2001-07-12 20:26:32 +00009974 }
Eric Andersenc470f442003-07-28 09:56:35 +00009975out:
9976 checkkwd = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009977#ifdef DEBUG
9978 if (!alreadyseen)
Eric Andersenc470f442003-07-28 09:56:35 +00009979 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009980 else
Eric Andersenc470f442003-07-28 09:56:35 +00009981 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
Eric Andersencb57d552001-06-28 07:25:16 +00009982#endif
9983 return (t);
9984}
9985
9986
9987/*
9988 * Read the next input token.
9989 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +00009990 * backquotes. We set quoteflag to true if any part of the word was
9991 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +00009992 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +00009993 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +00009994 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +00009995 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +00009996 *
9997 * [Change comment: here documents and internal procedures]
9998 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9999 * word parsing code into a separate routine. In this case, readtoken
10000 * doesn't need to have any internal procedures, but parseword does.
10001 * We could also make parseoperator in essence the main routine, and
10002 * have parseword (readtoken1?) handle both words and redirection.]
10003 */
10004
Eric Andersen81fe1232003-07-29 06:38:40 +000010005#define NEW_xxreadtoken
10006#ifdef NEW_xxreadtoken
10007
10008/* singles must be first! */
10009static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10010
10011static const char xxreadtoken_tokens[] = {
10012 TNL, TLP, TRP, /* only single occurrence allowed */
10013 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10014 TEOF, /* corresponds to trailing nul */
10015 TAND, TOR, TENDCASE, /* if double occurrence */
10016};
10017
10018#define xxreadtoken_doubles \
10019 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10020#define xxreadtoken_singles \
10021 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10022
10023static int xxreadtoken()
10024{
10025 int c;
10026
10027 if (tokpushback) {
10028 tokpushback = 0;
10029 return lasttoken;
10030 }
10031 if (needprompt) {
10032 setprompt(2);
Eric Andersen81fe1232003-07-29 06:38:40 +000010033 }
10034 startlinno = plinno;
10035 for (;;) { /* until token or start of word found */
10036 c = pgetc_macro();
10037
10038 if ((c != ' ') && (c != '\t')
10039#ifdef CONFIG_ASH_ALIAS
10040 && (c != PEOA)
10041#endif
10042 ) {
10043 if (c == '#') {
10044 while ((c = pgetc()) != '\n' && c != PEOF);
10045 pungetc();
10046 } else if (c == '\\') {
10047 if (pgetc() != '\n') {
10048 pungetc();
10049 goto READTOKEN1;
10050 }
10051 startlinno = ++plinno;
10052 if (doprompt)
10053 setprompt(2);
10054 } else {
10055 const char *p
10056 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10057
10058 if (c != PEOF) {
10059 if (c == '\n') {
10060 plinno++;
10061 needprompt = doprompt;
10062 }
10063
10064 p = strchr(xxreadtoken_chars, c);
10065 if (p == NULL) {
10066 READTOKEN1:
10067 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10068 }
10069
10070 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10071 if (pgetc() == *p) { /* double occurrence? */
10072 p += xxreadtoken_doubles + 1;
10073 } else {
10074 pungetc();
10075 }
10076 }
10077 }
10078
10079 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10080 }
10081 }
10082 }
10083}
10084
10085
10086#else
Eric Andersen2870d962001-07-02 17:27:21 +000010087#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010088
Eric Andersenc470f442003-07-28 09:56:35 +000010089static int
10090xxreadtoken(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010091{
Eric Andersencb57d552001-06-28 07:25:16 +000010092 int c;
10093
10094 if (tokpushback) {
10095 tokpushback = 0;
10096 return lasttoken;
10097 }
10098 if (needprompt) {
10099 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010100 }
10101 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010102 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010103 c = pgetc_macro();
10104 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000010105 case ' ': case '\t':
Eric Andersend35c5df2002-01-09 15:37:36 +000010106#ifdef CONFIG_ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010107 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010108#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010109 continue;
10110 case '#':
10111 while ((c = pgetc()) != '\n' && c != PEOF);
10112 pungetc();
10113 continue;
10114 case '\\':
10115 if (pgetc() == '\n') {
10116 startlinno = ++plinno;
10117 if (doprompt)
10118 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010119 continue;
10120 }
10121 pungetc();
10122 goto breakloop;
10123 case '\n':
10124 plinno++;
10125 needprompt = doprompt;
10126 RETURN(TNL);
10127 case PEOF:
10128 RETURN(TEOF);
10129 case '&':
10130 if (pgetc() == '&')
10131 RETURN(TAND);
10132 pungetc();
10133 RETURN(TBACKGND);
10134 case '|':
10135 if (pgetc() == '|')
10136 RETURN(TOR);
10137 pungetc();
10138 RETURN(TPIPE);
10139 case ';':
10140 if (pgetc() == ';')
10141 RETURN(TENDCASE);
10142 pungetc();
10143 RETURN(TSEMI);
10144 case '(':
10145 RETURN(TLP);
10146 case ')':
10147 RETURN(TRP);
10148 default:
10149 goto breakloop;
10150 }
10151 }
Eric Andersenc470f442003-07-28 09:56:35 +000010152breakloop:
10153 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010154#undef RETURN
10155}
Eric Andersen81fe1232003-07-29 06:38:40 +000010156#endif /* NEW_xxreadtoken */
Eric Andersenc470f442003-07-28 09:56:35 +000010157
Eric Andersencb57d552001-06-28 07:25:16 +000010158
Eric Andersencb57d552001-06-28 07:25:16 +000010159/*
10160 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10161 * is not NULL, read a here document. In the latter case, eofmark is the
10162 * word which marks the end of the document and striptabs is true if
10163 * leading tabs should be stripped from the document. The argument firstc
10164 * is the first character of the input token or document.
10165 *
10166 * Because C does not have internal subroutines, I have simulated them
10167 * using goto's to implement the subroutine linkage. The following macros
10168 * will run code that appears at the end of readtoken1.
10169 */
10170
Eric Andersen2870d962001-07-02 17:27:21 +000010171#define CHECKEND() {goto checkend; checkend_return:;}
10172#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10173#define PARSESUB() {goto parsesub; parsesub_return:;}
10174#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10175#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10176#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010177
10178static int
Eric Andersenc470f442003-07-28 09:56:35 +000010179readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010180{
Eric Andersencb57d552001-06-28 07:25:16 +000010181 int c = firstc;
10182 char *out;
10183 int len;
10184 char line[EOFMARKLEN + 1];
10185 struct nodelist *bqlist;
10186 int quotef;
10187 int dblquote;
Eric Andersenc470f442003-07-28 09:56:35 +000010188 int varnest; /* levels of variables expansion */
10189 int arinest; /* levels of arithmetic expansion */
10190 int parenlevel; /* levels of parens in arithmetic */
10191 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010192 int oldstyle;
Eric Andersenc470f442003-07-28 09:56:35 +000010193 int prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010194#if __GNUC__
10195 /* Avoid longjmp clobbering */
10196 (void) &out;
10197 (void) &quotef;
10198 (void) &dblquote;
10199 (void) &varnest;
10200 (void) &arinest;
10201 (void) &parenlevel;
10202 (void) &dqvarnest;
10203 (void) &oldstyle;
10204 (void) &prevsyntax;
10205 (void) &syntax;
10206#endif
10207
10208 startlinno = plinno;
10209 dblquote = 0;
10210 if (syntax == DQSYNTAX)
10211 dblquote = 1;
10212 quotef = 0;
10213 bqlist = NULL;
10214 varnest = 0;
10215 arinest = 0;
10216 parenlevel = 0;
10217 dqvarnest = 0;
10218
10219 STARTSTACKSTR(out);
Eric Andersenc470f442003-07-28 09:56:35 +000010220 loop: { /* for each line, until end of word */
10221 CHECKEND(); /* set c to PEOF if at end of here document */
10222 for (;;) { /* until end of line or end of word */
10223 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10224 switch(SIT(c, syntax)) {
10225 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010226 if (syntax == BASESYNTAX)
Eric Andersenc470f442003-07-28 09:56:35 +000010227 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010228 USTPUTC(c, out);
10229 plinno++;
10230 if (doprompt)
10231 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010232 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010233 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010234 case CWORD:
10235 USTPUTC(c, out);
10236 break;
10237 case CCTL:
Eric Andersenc470f442003-07-28 09:56:35 +000010238 if (eofmark == NULL || dblquote)
Eric Andersencb57d552001-06-28 07:25:16 +000010239 USTPUTC(CTLESC, out);
10240 USTPUTC(c, out);
10241 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010242 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010243 c = pgetc2();
10244 if (c == PEOF) {
Eric Andersenc470f442003-07-28 09:56:35 +000010245 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010246 USTPUTC('\\', out);
10247 pungetc();
10248 } else if (c == '\n') {
10249 if (doprompt)
10250 setprompt(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010251 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010252 if (
10253 dblquote &&
10254 c != '\\' && c != '`' &&
10255 c != '$' && (
10256 c != '"' ||
10257 eofmark != NULL
10258 )
10259 ) {
10260 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010261 USTPUTC('\\', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010262 }
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010263 if (SIT(c, SQSYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010264 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010265 USTPUTC(c, out);
10266 quotef++;
10267 }
10268 break;
10269 case CSQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010270 syntax = SQSYNTAX;
Eric Andersenc470f442003-07-28 09:56:35 +000010271quotemark:
10272 if (eofmark == NULL) {
10273 USTPUTC(CTLQUOTEMARK, out);
10274 }
Eric Andersencb57d552001-06-28 07:25:16 +000010275 break;
10276 case CDQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000010277 syntax = DQSYNTAX;
10278 dblquote = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010279 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010280 case CENDQUOTE:
Eric Andersenc470f442003-07-28 09:56:35 +000010281 if (eofmark != NULL && arinest == 0 &&
10282 varnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010283 USTPUTC(c, out);
10284 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010285 if (dqvarnest == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010286 syntax = BASESYNTAX;
10287 dblquote = 0;
10288 }
10289 quotef++;
Eric Andersenc470f442003-07-28 09:56:35 +000010290 goto quotemark;
Eric Andersencb57d552001-06-28 07:25:16 +000010291 }
10292 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010293 case CVAR: /* '$' */
10294 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010295 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010296 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010297 if (varnest > 0) {
10298 varnest--;
10299 if (dqvarnest > 0) {
10300 dqvarnest--;
10301 }
10302 USTPUTC(CTLENDVAR, out);
10303 } else {
10304 USTPUTC(c, out);
10305 }
10306 break;
Eric Andersend35c5df2002-01-09 15:37:36 +000010307#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000010308 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010309 parenlevel++;
10310 USTPUTC(c, out);
10311 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010312 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010313 if (parenlevel > 0) {
10314 USTPUTC(c, out);
10315 --parenlevel;
10316 } else {
10317 if (pgetc() == ')') {
10318 if (--arinest == 0) {
10319 USTPUTC(CTLENDARI, out);
10320 syntax = prevsyntax;
10321 if (syntax == DQSYNTAX)
10322 dblquote = 1;
10323 else
10324 dblquote = 0;
10325 } else
10326 USTPUTC(')', out);
10327 } else {
10328 /*
10329 * unbalanced parens
10330 * (don't 2nd guess - no error)
10331 */
10332 pungetc();
10333 USTPUTC(')', out);
10334 }
10335 }
10336 break;
10337#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010338 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010339 PARSEBACKQOLD();
10340 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010341 case CENDFILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010342 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010343 case CIGN:
10344 break;
10345 default:
10346 if (varnest == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010347 goto endword; /* exit outer loop */
Eric Andersend35c5df2002-01-09 15:37:36 +000010348#ifdef CONFIG_ASH_ALIAS
Eric Andersen3102ac42001-07-06 04:26:23 +000010349 if (c != PEOA)
10350#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010351 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010352
Eric Andersencb57d552001-06-28 07:25:16 +000010353 }
10354 c = pgetc_macro();
10355 }
10356 }
Eric Andersenc470f442003-07-28 09:56:35 +000010357endword:
10358#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010359 if (syntax == ARISYNTAX)
10360 synerror("Missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000010361#endif
10362 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010363 synerror("Unterminated quoted string");
10364 if (varnest != 0) {
10365 startlinno = plinno;
Eric Andersenc470f442003-07-28 09:56:35 +000010366 /* { */
Eric Andersencb57d552001-06-28 07:25:16 +000010367 synerror("Missing '}'");
10368 }
10369 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000010370 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000010371 out = stackblock();
10372 if (eofmark == NULL) {
10373 if ((c == '>' || c == '<')
Eric Andersenc470f442003-07-28 09:56:35 +000010374 && quotef == 0
10375 && len <= 2
10376 && (*out == '\0' || is_digit(*out))) {
Eric Andersencb57d552001-06-28 07:25:16 +000010377 PARSEREDIR();
10378 return lasttoken = TREDIR;
10379 } else {
10380 pungetc();
10381 }
10382 }
10383 quoteflag = quotef;
10384 backquotelist = bqlist;
10385 grabstackblock(len);
10386 wordtext = out;
10387 return lasttoken = TWORD;
10388/* end of readtoken routine */
10389
10390
10391
10392/*
10393 * Check to see whether we are at the end of the here document. When this
10394 * is called, c is set to the first character of the next input line. If
10395 * we are at the end of the here document, this routine sets the c to PEOF.
10396 */
10397
Eric Andersenc470f442003-07-28 09:56:35 +000010398checkend: {
10399 if (eofmark) {
Eric Andersend35c5df2002-01-09 15:37:36 +000010400#ifdef CONFIG_ASH_ALIAS
Eric Andersenc470f442003-07-28 09:56:35 +000010401 if (c == PEOA) {
10402 c = pgetc2();
10403 }
10404#endif
10405 if (striptabs) {
10406 while (c == '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +000010407 c = pgetc2();
10408 }
Eric Andersenc470f442003-07-28 09:56:35 +000010409 }
10410 if (c == *eofmark) {
10411 if (pfgets(line, sizeof line) != NULL) {
10412 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000010413
Eric Andersenc470f442003-07-28 09:56:35 +000010414 p = line;
10415 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10416 if (*p == '\n' && *q == '\0') {
10417 c = PEOF;
10418 plinno++;
10419 needprompt = doprompt;
10420 } else {
10421 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000010422 }
10423 }
10424 }
10425 }
Eric Andersenc470f442003-07-28 09:56:35 +000010426 goto checkend_return;
10427}
Eric Andersencb57d552001-06-28 07:25:16 +000010428
10429
10430/*
10431 * Parse a redirection operator. The variable "out" points to a string
10432 * specifying the fd to be redirected. The variable "c" contains the
10433 * first character of the redirection operator.
10434 */
10435
Eric Andersenc470f442003-07-28 09:56:35 +000010436parseredir: {
10437 char fd = *out;
10438 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000010439
Eric Andersenc470f442003-07-28 09:56:35 +000010440 np = (union node *)stalloc(sizeof (struct nfile));
10441 if (c == '>') {
10442 np->nfile.fd = 1;
10443 c = pgetc();
10444 if (c == '>')
10445 np->type = NAPPEND;
10446 else if (c == '|')
10447 np->type = NCLOBBER;
10448 else if (c == '&')
10449 np->type = NTOFD;
10450 else {
10451 np->type = NTO;
10452 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000010453 }
Eric Andersenc470f442003-07-28 09:56:35 +000010454 } else { /* c == '<' */
10455 np->nfile.fd = 0;
10456 switch (c = pgetc()) {
10457 case '<':
10458 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10459 np = (union node *)stalloc(sizeof (struct nhere));
10460 np->nfile.fd = 0;
10461 }
10462 np->type = NHERE;
10463 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10464 heredoc->here = np;
10465 if ((c = pgetc()) == '-') {
10466 heredoc->striptabs = 1;
10467 } else {
10468 heredoc->striptabs = 0;
10469 pungetc();
10470 }
10471 break;
10472
10473 case '&':
10474 np->type = NFROMFD;
10475 break;
10476
10477 case '>':
10478 np->type = NFROMTO;
10479 break;
10480
10481 default:
10482 np->type = NFROM;
10483 pungetc();
10484 break;
10485 }
Eric Andersencb57d552001-06-28 07:25:16 +000010486 }
Eric Andersenc470f442003-07-28 09:56:35 +000010487 if (fd != '\0')
10488 np->nfile.fd = digit_val(fd);
10489 redirnode = np;
10490 goto parseredir_return;
10491}
Eric Andersencb57d552001-06-28 07:25:16 +000010492
10493
10494/*
10495 * Parse a substitution. At this point, we have read the dollar sign
10496 * and nothing else.
10497 */
10498
Eric Andersenc470f442003-07-28 09:56:35 +000010499parsesub: {
10500 int subtype;
10501 int typeloc;
10502 int flags;
10503 char *p;
10504 static const char types[] = "}-+?=";
Eric Andersencb57d552001-06-28 07:25:16 +000010505
Eric Andersenc470f442003-07-28 09:56:35 +000010506 c = pgetc();
10507 if (
10508 c <= PEOA_OR_PEOF ||
10509 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10510 ) {
10511 USTPUTC('$', out);
10512 pungetc();
10513 } else if (c == '(') { /* $(command) or $((arith)) */
10514 if (pgetc() == '(') {
10515#ifdef CONFIG_ASH_MATH_SUPPORT
10516 PARSEARITH();
10517#else
10518 synerror("We unsupport $((arith))");
10519#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010520 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010521 pungetc();
10522 PARSEBACKQNEW();
10523 }
10524 } else {
10525 USTPUTC(CTLVAR, out);
10526 typeloc = out - (char *)stackblock();
10527 USTPUTC(VSNORMAL, out);
10528 subtype = VSNORMAL;
10529 if (c == '{') {
10530 c = pgetc();
10531 if (c == '#') {
10532 if ((c = pgetc()) == '}')
10533 c = '#';
10534 else
10535 subtype = VSLENGTH;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010536 }
Eric Andersenc470f442003-07-28 09:56:35 +000010537 else
10538 subtype = 0;
10539 }
10540 if (c > PEOA_OR_PEOF && is_name(c)) {
10541 do {
10542 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000010543 c = pgetc();
Eric Andersenc470f442003-07-28 09:56:35 +000010544 } while (c > PEOA_OR_PEOF && is_in_name(c));
10545 } else if (is_digit(c)) {
10546 do {
10547 STPUTC(c, out);
10548 c = pgetc();
10549 } while (is_digit(c));
10550 }
10551 else if (is_special(c)) {
10552 USTPUTC(c, out);
10553 c = pgetc();
10554 }
10555 else
10556badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010557
Eric Andersenc470f442003-07-28 09:56:35 +000010558 STPUTC('=', out);
10559 flags = 0;
10560 if (subtype == 0) {
10561 switch (c) {
10562 case ':':
10563 flags = VSNUL;
10564 c = pgetc();
10565 /*FALLTHROUGH*/
10566 default:
10567 p = strchr(types, c);
10568 if (p == NULL)
10569 goto badsub;
10570 subtype = p - types + VSNORMAL;
10571 break;
10572 case '%':
10573 case '#':
Eric Andersencb57d552001-06-28 07:25:16 +000010574 {
10575 int cc = c;
Eric Andersenc470f442003-07-28 09:56:35 +000010576 subtype = c == '#' ? VSTRIMLEFT :
10577 VSTRIMRIGHT;
Eric Andersencb57d552001-06-28 07:25:16 +000010578 c = pgetc();
10579 if (c == cc)
10580 subtype++;
10581 else
10582 pungetc();
10583 break;
10584 }
10585 }
Eric Andersenc470f442003-07-28 09:56:35 +000010586 } else {
10587 pungetc();
10588 }
10589 if (dblquote || arinest)
10590 flags |= VSQUOTE;
10591 *((char *)stackblock() + typeloc) = subtype | flags;
10592 if (subtype != VSNORMAL) {
10593 varnest++;
10594 if (dblquote || arinest) {
10595 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000010596 }
10597 }
10598 }
Eric Andersenc470f442003-07-28 09:56:35 +000010599 goto parsesub_return;
10600}
Eric Andersencb57d552001-06-28 07:25:16 +000010601
10602
10603/*
10604 * Called to parse command substitutions. Newstyle is set if the command
10605 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10606 * list of commands (passed by reference), and savelen is the number of
10607 * characters on the top of the stack which must be preserved.
10608 */
10609
Eric Andersenc470f442003-07-28 09:56:35 +000010610parsebackq: {
10611 struct nodelist **nlpp;
10612 int savepbq;
10613 union node *n;
10614 char *volatile str;
10615 struct jmploc jmploc;
10616 struct jmploc *volatile savehandler;
10617 size_t savelen;
10618 int saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010619#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000010620 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000010621#endif
10622
Eric Andersenc470f442003-07-28 09:56:35 +000010623 savepbq = parsebackquote;
10624 if (setjmp(jmploc.loc)) {
10625 if (str)
10626 ckfree(str);
10627 parsebackquote = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010628 handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000010629 longjmp(handler->loc, 1);
10630 }
10631 INTOFF;
10632 str = NULL;
10633 savelen = out - (char *)stackblock();
10634 if (savelen > 0) {
10635 str = ckmalloc(savelen);
10636 memcpy(str, stackblock(), savelen);
10637 }
10638 savehandler = handler;
10639 handler = &jmploc;
10640 INTON;
10641 if (oldstyle) {
10642 /* We must read until the closing backquote, giving special
10643 treatment to some slashes, and then push the string and
10644 reread it as input, interpreting it normally. */
10645 char *pout;
10646 int pc;
10647 size_t psavelen;
10648 char *pstr;
10649
10650
10651 STARTSTACKSTR(pout);
10652 for (;;) {
10653 if (needprompt) {
10654 setprompt(2);
Eric Andersenc470f442003-07-28 09:56:35 +000010655 }
10656 switch (pc = pgetc()) {
10657 case '`':
10658 goto done;
10659
10660 case '\\':
10661 if ((pc = pgetc()) == '\n') {
10662 plinno++;
10663 if (doprompt)
10664 setprompt(2);
10665 /*
10666 * If eating a newline, avoid putting
10667 * the newline into the new character
10668 * stream (via the STPUTC after the
10669 * switch).
10670 */
10671 continue;
10672 }
10673 if (pc != '\\' && pc != '`' && pc != '$'
10674 && (!dblquote || pc != '"'))
10675 STPUTC('\\', pout);
10676 if (pc > PEOA_OR_PEOF) {
10677 break;
10678 }
10679 /* fall through */
10680
10681 case PEOF:
10682#ifdef CONFIG_ASH_ALIAS
10683 case PEOA:
10684#endif
10685 startlinno = plinno;
10686 synerror("EOF in backquote substitution");
10687
10688 case '\n':
10689 plinno++;
10690 needprompt = doprompt;
10691 break;
10692
10693 default:
10694 break;
10695 }
10696 STPUTC(pc, pout);
10697 }
10698done:
10699 STPUTC('\0', pout);
10700 psavelen = pout - (char *)stackblock();
10701 if (psavelen > 0) {
10702 pstr = grabstackstr(pout);
10703 setinputstring(pstr);
10704 }
10705 }
10706 nlpp = &bqlist;
10707 while (*nlpp)
10708 nlpp = &(*nlpp)->next;
10709 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10710 (*nlpp)->next = NULL;
10711 parsebackquote = oldstyle;
10712
10713 if (oldstyle) {
10714 saveprompt = doprompt;
10715 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010716 }
10717
Eric Andersenc470f442003-07-28 09:56:35 +000010718 n = list(2);
10719
10720 if (oldstyle)
10721 doprompt = saveprompt;
10722 else {
10723 if (readtoken() != TRP)
10724 synexpect(TRP);
10725 }
10726
10727 (*nlpp)->n = n;
10728 if (oldstyle) {
10729 /*
10730 * Start reading from old file again, ignoring any pushed back
10731 * tokens left from the backquote parsing
10732 */
10733 popfile();
10734 tokpushback = 0;
10735 }
10736 while (stackblocksize() <= savelen)
10737 growstackblock();
10738 STARTSTACKSTR(out);
10739 if (str) {
10740 memcpy(out, str, savelen);
10741 STADJUST(savelen, out);
10742 INTOFF;
10743 ckfree(str);
10744 str = NULL;
10745 INTON;
10746 }
10747 parsebackquote = savepbq;
10748 handler = savehandler;
10749 if (arinest || dblquote)
10750 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10751 else
10752 USTPUTC(CTLBACKQ, out);
10753 if (oldstyle)
10754 goto parsebackq_oldreturn;
10755 else
10756 goto parsebackq_newreturn;
10757}
10758
10759#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000010760/*
10761 * Parse an arithmetic expansion (indicate start of one and set state)
10762 */
Eric Andersenc470f442003-07-28 09:56:35 +000010763parsearith: {
Eric Andersencb57d552001-06-28 07:25:16 +000010764
Eric Andersenc470f442003-07-28 09:56:35 +000010765 if (++arinest == 1) {
10766 prevsyntax = syntax;
10767 syntax = ARISYNTAX;
10768 USTPUTC(CTLARI, out);
10769 if (dblquote)
10770 USTPUTC('"',out);
10771 else
10772 USTPUTC(' ',out);
10773 } else {
10774 /*
10775 * we collapse embedded arithmetic expansion to
10776 * parenthesis, which should be equivalent
10777 */
10778 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000010779 }
Eric Andersenc470f442003-07-28 09:56:35 +000010780 goto parsearith_return;
10781}
10782#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010783
Eric Andersenc470f442003-07-28 09:56:35 +000010784} /* end of readtoken */
10785
Eric Andersencb57d552001-06-28 07:25:16 +000010786
10787
Eric Andersencb57d552001-06-28 07:25:16 +000010788/*
10789 * Returns true if the text contains nothing to expand (no dollar signs
10790 * or backquotes).
10791 */
10792
Eric Andersenc470f442003-07-28 09:56:35 +000010793static int
10794noexpand(char *text)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000010795{
Eric Andersencb57d552001-06-28 07:25:16 +000010796 char *p;
10797 char c;
10798
10799 p = text;
10800 while ((c = *p++) != '\0') {
10801 if (c == CTLQUOTEMARK)
10802 continue;
10803 if (c == CTLESC)
10804 p++;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010805 else if (SIT(c, BASESYNTAX) == CCTL)
Eric Andersencb57d552001-06-28 07:25:16 +000010806 return 0;
10807 }
10808 return 1;
10809}
10810
10811
10812/*
Eric Andersenc470f442003-07-28 09:56:35 +000010813 * Return of a legal variable name (a letter or underscore followed by zero or
10814 * more letters, underscores, and digits).
Eric Andersencb57d552001-06-28 07:25:16 +000010815 */
10816
Glenn L McGrath16e45d72004-02-04 08:24:39 +000010817static char *
Eric Andersenc470f442003-07-28 09:56:35 +000010818endofname(const char *name)
Eric Andersen90898442003-08-06 11:20:52 +000010819{
Eric Andersenc470f442003-07-28 09:56:35 +000010820 char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000010821
Eric Andersenc470f442003-07-28 09:56:35 +000010822 p = (char *) name;
10823 if (! is_name(*p))
10824 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010825 while (*++p) {
Eric Andersenc470f442003-07-28 09:56:35 +000010826 if (! is_in_name(*p))
10827 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010828 }
Eric Andersenc470f442003-07-28 09:56:35 +000010829 return p;
Eric Andersencb57d552001-06-28 07:25:16 +000010830}
10831
10832
10833/*
10834 * Called when an unexpected token is read during the parse. The argument
10835 * is the token that is expected, or -1 if more than one type of token can
10836 * occur at this point.
10837 */
10838
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010839static void synexpect(int token)
Eric Andersencb57d552001-06-28 07:25:16 +000010840{
10841 char msg[64];
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010842 int l;
Eric Andersencb57d552001-06-28 07:25:16 +000010843
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010844 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10845 if (token >= 0)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010846 sprintf(msg + l, " (expecting %s)", tokname(token));
Eric Andersencb57d552001-06-28 07:25:16 +000010847 synerror(msg);
10848 /* NOTREACHED */
10849}
10850
Eric Andersenc470f442003-07-28 09:56:35 +000010851static void
10852synerror(const char *msg)
Eric Andersen2870d962001-07-02 17:27:21 +000010853{
Eric Andersenc470f442003-07-28 09:56:35 +000010854 error("Syntax error: %s", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000010855 /* NOTREACHED */
10856}
10857
Eric Andersencb57d552001-06-28 07:25:16 +000010858
10859/*
10860 * called by editline -- any expansions to the prompt
10861 * should be added here.
10862 */
Eric Andersenc470f442003-07-28 09:56:35 +000010863
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010864#ifdef CONFIG_ASH_EXPAND_PRMT
10865static const char *
10866expandstr(const char *ps)
10867{
10868 union node n;
10869
10870 /* XXX Fix (char *) cast. */
10871 setinputstring((char *)ps);
10872 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10873 popfile();
10874
10875 n.narg.type = NARG;
10876 n.narg.next = NULL;
10877 n.narg.text = wordtext;
10878 n.narg.backquote = backquotelist;
10879
10880 expandarg(&n, NULL, 0);
10881 return stackblock();
10882}
10883#endif
10884
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010885static void setprompt(int whichprompt)
Eric Andersen2870d962001-07-02 17:27:21 +000010886{
Eric Andersenc470f442003-07-28 09:56:35 +000010887 const char *prompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010888#ifdef CONFIG_ASH_EXPAND_PRMT
10889 struct stackmark smark;
10890#endif
10891
10892 needprompt = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010893
10894 switch (whichprompt) {
Eric Andersen62483552001-07-10 06:09:16 +000010895 case 1:
10896 prompt = ps1val();
10897 break;
10898 case 2:
10899 prompt = ps2val();
10900 break;
Eric Andersenc470f442003-07-28 09:56:35 +000010901 default: /* 0 */
10902 prompt = nullstr;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010903 }
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000010904#ifdef CONFIG_ASH_EXPAND_PRMT
10905 setstackmark(&smark);
10906 stalloc(stackblocksize());
10907#endif
10908 putprompt(expandstr(prompt));
10909#ifdef CONFIG_ASH_EXPAND_PRMT
10910 popstackmark(&smark);
10911#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010912}
10913
Eric Andersencb57d552001-06-28 07:25:16 +000010914
Eric Andersenc470f442003-07-28 09:56:35 +000010915static const char *const *findkwd(const char *s)
10916{
10917 return bsearch(s, tokname_array + KWDOFFSET,
Eric Andersen90898442003-08-06 11:20:52 +000010918 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
Eric Andersenc470f442003-07-28 09:56:35 +000010919 sizeof(const char *), pstrcmp);
10920}
10921
10922/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10923
Eric Andersencb57d552001-06-28 07:25:16 +000010924/*
10925 * Code for dealing with input/output redirection.
10926 */
10927
Eric Andersenc470f442003-07-28 09:56:35 +000010928#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000010929#ifndef PIPE_BUF
Eric Andersenc470f442003-07-28 09:56:35 +000010930# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000010931#else
10932# define PIPESIZE PIPE_BUF
10933#endif
10934
Eric Andersen62483552001-07-10 06:09:16 +000010935/*
10936 * Open a file in noclobber mode.
10937 * The code was copied from bash.
10938 */
Eric Andersenc470f442003-07-28 09:56:35 +000010939static inline int
10940noclobberopen(const char *fname)
Eric Andersen62483552001-07-10 06:09:16 +000010941{
10942 int r, fd;
10943 struct stat finfo, finfo2;
10944
10945 /*
10946 * If the file exists and is a regular file, return an error
10947 * immediately.
10948 */
10949 r = stat(fname, &finfo);
10950 if (r == 0 && S_ISREG(finfo.st_mode)) {
10951 errno = EEXIST;
10952 return -1;
10953 }
10954
10955 /*
10956 * If the file was not present (r != 0), make sure we open it
10957 * exclusively so that if it is created before we open it, our open
10958 * will fail. Make sure that we do not truncate an existing file.
10959 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10960 * file was not a regular file, we leave O_EXCL off.
10961 */
10962 if (r != 0)
Eric Andersenc470f442003-07-28 09:56:35 +000010963 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10964 fd = open(fname, O_WRONLY|O_CREAT, 0666);
Eric Andersen62483552001-07-10 06:09:16 +000010965
10966 /* If the open failed, return the file descriptor right away. */
10967 if (fd < 0)
10968 return fd;
10969
10970 /*
10971 * OK, the open succeeded, but the file may have been changed from a
10972 * non-regular file to a regular file between the stat and the open.
10973 * We are assuming that the O_EXCL open handles the case where FILENAME
10974 * did not exist and is symlinked to an existing file between the stat
10975 * and open.
10976 */
10977
10978 /*
10979 * If we can open it and fstat the file descriptor, and neither check
10980 * revealed that it was a regular file, and the file has not been
10981 * replaced, return the file descriptor.
10982 */
Eric Andersenc470f442003-07-28 09:56:35 +000010983 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10984 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen62483552001-07-10 06:09:16 +000010985 return fd;
10986
10987 /* The file has been replaced. badness. */
10988 close(fd);
10989 errno = EEXIST;
10990 return -1;
10991}
Eric Andersencb57d552001-06-28 07:25:16 +000010992
10993/*
Eric Andersen62483552001-07-10 06:09:16 +000010994 * Handle here documents. Normally we fork off a process to write the
10995 * data to a pipe. If the document is short, we can stuff the data in
10996 * the pipe without forking.
Eric Andersencb57d552001-06-28 07:25:16 +000010997 */
10998
Eric Andersenc470f442003-07-28 09:56:35 +000010999static inline int
11000openhere(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011001{
11002 int pip[2];
Eric Andersenc470f442003-07-28 09:56:35 +000011003 size_t len = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011004
Eric Andersen62483552001-07-10 06:09:16 +000011005 if (pipe(pip) < 0)
11006 error("Pipe call failed");
11007 if (redir->type == NHERE) {
11008 len = strlen(redir->nhere.doc->narg.text);
11009 if (len <= PIPESIZE) {
Eric Andersen16767e22004-03-16 05:14:10 +000011010 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000011011 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000011012 }
Eric Andersencb57d552001-06-28 07:25:16 +000011013 }
Eric Andersenc470f442003-07-28 09:56:35 +000011014 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Eric Andersen62483552001-07-10 06:09:16 +000011015 close(pip[0]);
11016 signal(SIGINT, SIG_IGN);
11017 signal(SIGQUIT, SIG_IGN);
11018 signal(SIGHUP, SIG_IGN);
11019#ifdef SIGTSTP
11020 signal(SIGTSTP, SIG_IGN);
11021#endif
11022 signal(SIGPIPE, SIG_DFL);
11023 if (redir->type == NHERE)
Eric Andersen16767e22004-03-16 05:14:10 +000011024 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
Eric Andersen62483552001-07-10 06:09:16 +000011025 else
11026 expandhere(redir->nhere.doc, pip[1]);
11027 _exit(0);
11028 }
Eric Andersenc470f442003-07-28 09:56:35 +000011029out:
Eric Andersen62483552001-07-10 06:09:16 +000011030 close(pip[1]);
11031 return pip[0];
Eric Andersencb57d552001-06-28 07:25:16 +000011032}
11033
Eric Andersenc470f442003-07-28 09:56:35 +000011034static int
11035openredirect(union node *redir)
Eric Andersen62483552001-07-10 06:09:16 +000011036{
Eric Andersencb57d552001-06-28 07:25:16 +000011037 char *fname;
11038 int f;
11039
11040 switch (redir->nfile.type) {
11041 case NFROM:
11042 fname = redir->nfile.expfname;
11043 if ((f = open(fname, O_RDONLY)) < 0)
11044 goto eopen;
11045 break;
11046 case NFROMTO:
11047 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011048 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011049 goto ecreate;
11050 break;
11051 case NTO:
11052 /* Take care of noclobber mode. */
11053 if (Cflag) {
11054 fname = redir->nfile.expfname;
11055 if ((f = noclobberopen(fname)) < 0)
11056 goto ecreate;
11057 break;
11058 }
Eric Andersenc470f442003-07-28 09:56:35 +000011059 /* FALLTHROUGH */
11060 case NCLOBBER:
Eric Andersencb57d552001-06-28 07:25:16 +000011061 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011062 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011063 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011064 break;
11065 case NAPPEND:
11066 fname = redir->nfile.expfname;
Eric Andersenc470f442003-07-28 09:56:35 +000011067 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000011068 goto ecreate;
Eric Andersencb57d552001-06-28 07:25:16 +000011069 break;
11070 default:
11071#ifdef DEBUG
11072 abort();
11073#endif
11074 /* Fall through to eliminate warning. */
11075 case NTOFD:
11076 case NFROMFD:
11077 f = -1;
11078 break;
11079 case NHERE:
11080 case NXHERE:
11081 f = openhere(redir);
11082 break;
11083 }
11084
11085 return f;
Eric Andersenc470f442003-07-28 09:56:35 +000011086ecreate:
Eric Andersencb57d552001-06-28 07:25:16 +000011087 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
Eric Andersenc470f442003-07-28 09:56:35 +000011088eopen:
Eric Andersencb57d552001-06-28 07:25:16 +000011089 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11090}
11091
Eric Andersenc470f442003-07-28 09:56:35 +000011092static inline void
11093dupredirect(union node *redir, int f)
11094{
11095 int fd = redir->nfile.fd;
11096
11097 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11098 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11099 copyfd(redir->ndup.dupfd, fd);
11100 }
11101 return;
11102 }
11103
11104 if (f != fd) {
11105 copyfd(f, fd);
11106 close(f);
11107 }
11108 return;
11109}
Eric Andersencb57d552001-06-28 07:25:16 +000011110
Eric Andersen62483552001-07-10 06:09:16 +000011111/*
11112 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11113 * old file descriptors are stashed away so that the redirection can be
11114 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11115 * standard output, and the standard error if it becomes a duplicate of
Eric Andersenc470f442003-07-28 09:56:35 +000011116 * stdout, is saved in memory.
Eric Andersen62483552001-07-10 06:09:16 +000011117 */
11118
Eric Andersenc470f442003-07-28 09:56:35 +000011119static void
11120redirect(union node *redir, int flags)
Eric Andersen62483552001-07-10 06:09:16 +000011121{
11122 union node *n;
Eric Andersenc470f442003-07-28 09:56:35 +000011123 struct redirtab *sv;
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011124 int i;
Eric Andersen62483552001-07-10 06:09:16 +000011125 int fd;
11126 int newfd;
Eric Andersenc470f442003-07-28 09:56:35 +000011127 int *p;
11128 nullredirs++;
11129 if (!redir) {
11130 return;
Eric Andersen62483552001-07-10 06:09:16 +000011131 }
Eric Andersenc470f442003-07-28 09:56:35 +000011132 sv = NULL;
11133 INTOFF;
11134 if (flags & REDIR_PUSH) {
11135 struct redirtab *q;
11136 q = ckmalloc(sizeof (struct redirtab));
11137 q->next = redirlist;
11138 redirlist = q;
11139 q->nullredirs = nullredirs - 1;
11140 for (i = 0 ; i < 10 ; i++)
11141 q->renamed[i] = EMPTY;
11142 nullredirs = 0;
11143 sv = q;
11144 }
11145 n = redir;
11146 do {
Eric Andersen62483552001-07-10 06:09:16 +000011147 fd = n->nfile.fd;
Eric Andersen62483552001-07-10 06:09:16 +000011148 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
Eric Andersenc470f442003-07-28 09:56:35 +000011149 n->ndup.dupfd == fd)
11150 continue; /* redirect from/to same file descriptor */
Eric Andersen62483552001-07-10 06:09:16 +000011151
Eric Andersen62483552001-07-10 06:09:16 +000011152 newfd = openredirect(n);
Eric Andersenc470f442003-07-28 09:56:35 +000011153 if (fd == newfd)
11154 continue;
11155 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11156 i = fcntl(fd, F_DUPFD, 10);
11157
11158 if (i == -1) {
11159 i = errno;
11160 if (i != EBADF) {
11161 close(newfd);
11162 errno = i;
Eric Andersen62483552001-07-10 06:09:16 +000011163 error("%d: %m", fd);
11164 /* NOTREACHED */
11165 }
Eric Andersenc470f442003-07-28 09:56:35 +000011166 } else {
11167 *p = i;
Eric Andersen62483552001-07-10 06:09:16 +000011168 close(fd);
Eric Andersen62483552001-07-10 06:09:16 +000011169 }
Eric Andersenc470f442003-07-28 09:56:35 +000011170 } else {
Eric Andersen62483552001-07-10 06:09:16 +000011171 close(fd);
11172 }
Eric Andersenc470f442003-07-28 09:56:35 +000011173 dupredirect(n, newfd);
11174 } while ((n = n->nfile.next));
11175 INTON;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000011176 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11177 preverrout_fd = sv->renamed[2];
Eric Andersen62483552001-07-10 06:09:16 +000011178}
11179
11180
Eric Andersencb57d552001-06-28 07:25:16 +000011181/*
11182 * Undo the effects of the last redirection.
11183 */
11184
Eric Andersenc470f442003-07-28 09:56:35 +000011185void
11186popredir(int drop)
Eric Andersen2870d962001-07-02 17:27:21 +000011187{
Eric Andersenc470f442003-07-28 09:56:35 +000011188 struct redirtab *rp;
Eric Andersencb57d552001-06-28 07:25:16 +000011189 int i;
11190
Eric Andersenc470f442003-07-28 09:56:35 +000011191 if (--nullredirs >= 0)
11192 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011193 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011194 rp = redirlist;
11195 for (i = 0 ; i < 10 ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011196 if (rp->renamed[i] != EMPTY) {
Eric Andersenc470f442003-07-28 09:56:35 +000011197 if (!drop) {
11198 close(i);
11199 copyfd(rp->renamed[i], i);
Eric Andersencb57d552001-06-28 07:25:16 +000011200 }
Eric Andersenc470f442003-07-28 09:56:35 +000011201 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011202 }
11203 }
11204 redirlist = rp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000011205 nullredirs = rp->nullredirs;
11206 ckfree(rp);
Eric Andersencb57d552001-06-28 07:25:16 +000011207 INTON;
11208}
11209
11210/*
Eric Andersenc470f442003-07-28 09:56:35 +000011211 * Undo all redirections. Called on error or interrupt.
11212 */
11213
11214/*
Eric Andersencb57d552001-06-28 07:25:16 +000011215 * Discard all saved file descriptors.
11216 */
11217
Eric Andersenc470f442003-07-28 09:56:35 +000011218void
11219clearredir(int drop)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011220{
Eric Andersenc470f442003-07-28 09:56:35 +000011221 for (;;) {
11222 nullredirs = 0;
11223 if (!redirlist)
11224 break;
11225 popredir(drop);
Eric Andersencb57d552001-06-28 07:25:16 +000011226 }
Eric Andersencb57d552001-06-28 07:25:16 +000011227}
11228
11229
Eric Andersencb57d552001-06-28 07:25:16 +000011230/*
11231 * Copy a file descriptor to be >= to. Returns -1
11232 * if the source file descriptor is closed, EMPTY if there are no unused
11233 * file descriptors left.
11234 */
11235
Eric Andersenc470f442003-07-28 09:56:35 +000011236int
11237copyfd(int from, int to)
Eric Andersencb57d552001-06-28 07:25:16 +000011238{
11239 int newfd;
11240
11241 newfd = fcntl(from, F_DUPFD, to);
11242 if (newfd < 0) {
11243 if (errno == EMFILE)
11244 return EMPTY;
11245 else
Eric Andersen2870d962001-07-02 17:27:21 +000011246 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011247 }
11248 return newfd;
11249}
11250
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011251
Eric Andersenc470f442003-07-28 09:56:35 +000011252int
11253redirectsafe(union node *redir, int flags)
11254{
11255 int err;
11256 volatile int saveint;
11257 struct jmploc *volatile savehandler = handler;
11258 struct jmploc jmploc;
11259
11260 SAVEINT(saveint);
11261 if (!(err = setjmp(jmploc.loc) * 2)) {
11262 handler = &jmploc;
11263 redirect(redir, flags);
11264 }
11265 handler = savehandler;
11266 if (err && exception != EXERROR)
11267 longjmp(handler->loc, 1);
11268 RESTOREINT(saveint);
11269 return err;
11270}
11271
11272/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11273
11274#ifdef DEBUG
11275static void shtree(union node *, int, char *, FILE*);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011276static void shcmd(union node *, FILE *);
11277static void sharg(union node *, FILE *);
11278static void indent(int, char *, FILE *);
11279static void trstring(char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011280
11281
Eric Andersenc470f442003-07-28 09:56:35 +000011282void
11283showtree(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +000011284{
11285 trputs("showtree called\n");
11286 shtree(n, 1, NULL, stdout);
11287}
Eric Andersencb57d552001-06-28 07:25:16 +000011288
Eric Andersenc470f442003-07-28 09:56:35 +000011289
11290static void
11291shtree(union node *n, int ind, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011292{
11293 struct nodelist *lp;
11294 const char *s;
11295
11296 if (n == NULL)
11297 return;
11298
11299 indent(ind, pfx, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011300 switch(n->type) {
Eric Andersencb57d552001-06-28 07:25:16 +000011301 case NSEMI:
11302 s = "; ";
11303 goto binop;
11304 case NAND:
11305 s = " && ";
11306 goto binop;
11307 case NOR:
11308 s = " || ";
Eric Andersenc470f442003-07-28 09:56:35 +000011309binop:
Eric Andersencb57d552001-06-28 07:25:16 +000011310 shtree(n->nbinary.ch1, ind, NULL, fp);
Eric Andersenc470f442003-07-28 09:56:35 +000011311 /* if (ind < 0) */
11312 fputs(s, fp);
Eric Andersencb57d552001-06-28 07:25:16 +000011313 shtree(n->nbinary.ch2, ind, NULL, fp);
11314 break;
11315 case NCMD:
11316 shcmd(n, fp);
11317 if (ind >= 0)
11318 putc('\n', fp);
11319 break;
11320 case NPIPE:
Eric Andersenc470f442003-07-28 09:56:35 +000011321 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000011322 shcmd(lp->n, fp);
11323 if (lp->next)
11324 fputs(" | ", fp);
11325 }
11326 if (n->npipe.backgnd)
11327 fputs(" &", fp);
11328 if (ind >= 0)
11329 putc('\n', fp);
11330 break;
11331 default:
11332 fprintf(fp, "<node type %d>", n->type);
11333 if (ind >= 0)
11334 putc('\n', fp);
11335 break;
11336 }
11337}
11338
11339
Eric Andersenc470f442003-07-28 09:56:35 +000011340static void
11341shcmd(union node *cmd, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011342{
11343 union node *np;
11344 int first;
11345 const char *s;
11346 int dftfd;
11347
11348 first = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011349 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11350 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011351 putchar(' ');
11352 sharg(np, fp);
11353 first = 0;
11354 }
Eric Andersenc470f442003-07-28 09:56:35 +000011355 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11356 if (! first)
Eric Andersencb57d552001-06-28 07:25:16 +000011357 putchar(' ');
11358 switch (np->nfile.type) {
Eric Andersenc470f442003-07-28 09:56:35 +000011359 case NTO: s = ">"; dftfd = 1; break;
11360 case NCLOBBER: s = ">|"; dftfd = 1; break;
11361 case NAPPEND: s = ">>"; dftfd = 1; break;
11362 case NTOFD: s = ">&"; dftfd = 1; break;
11363 case NFROM: s = "<"; dftfd = 0; break;
11364 case NFROMFD: s = "<&"; dftfd = 0; break;
11365 case NFROMTO: s = "<>"; dftfd = 0; break;
11366 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011367 }
11368 if (np->nfile.fd != dftfd)
11369 fprintf(fp, "%d", np->nfile.fd);
11370 fputs(s, fp);
11371 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11372 fprintf(fp, "%d", np->ndup.dupfd);
11373 } else {
11374 sharg(np->nfile.fname, fp);
11375 }
11376 first = 0;
11377 }
11378}
11379
Glenn L McGrath50812ff2002-08-23 13:14:48 +000011380
Eric Andersenc470f442003-07-28 09:56:35 +000011381
11382static void
11383sharg(union node *arg, FILE *fp)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011384{
Eric Andersencb57d552001-06-28 07:25:16 +000011385 char *p;
11386 struct nodelist *bqlist;
11387 int subtype;
11388
11389 if (arg->type != NARG) {
Eric Andersenc470f442003-07-28 09:56:35 +000011390 out1fmt("<node type %d>\n", arg->type);
Eric Andersencb57d552001-06-28 07:25:16 +000011391 abort();
11392 }
11393 bqlist = arg->narg.backquote;
Eric Andersenc470f442003-07-28 09:56:35 +000011394 for (p = arg->narg.text ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011395 switch (*p) {
11396 case CTLESC:
11397 putc(*++p, fp);
11398 break;
11399 case CTLVAR:
11400 putc('$', fp);
11401 putc('{', fp);
11402 subtype = *++p;
11403 if (subtype == VSLENGTH)
11404 putc('#', fp);
11405
11406 while (*p != '=')
11407 putc(*p++, fp);
11408
11409 if (subtype & VSNUL)
11410 putc(':', fp);
11411
11412 switch (subtype & VSTYPE) {
11413 case VSNORMAL:
11414 putc('}', fp);
11415 break;
11416 case VSMINUS:
11417 putc('-', fp);
11418 break;
11419 case VSPLUS:
11420 putc('+', fp);
11421 break;
11422 case VSQUESTION:
11423 putc('?', fp);
11424 break;
11425 case VSASSIGN:
11426 putc('=', fp);
11427 break;
11428 case VSTRIMLEFT:
11429 putc('#', fp);
11430 break;
11431 case VSTRIMLEFTMAX:
11432 putc('#', fp);
11433 putc('#', fp);
11434 break;
11435 case VSTRIMRIGHT:
11436 putc('%', fp);
11437 break;
11438 case VSTRIMRIGHTMAX:
11439 putc('%', fp);
11440 putc('%', fp);
11441 break;
11442 case VSLENGTH:
11443 break;
11444 default:
Eric Andersenc470f442003-07-28 09:56:35 +000011445 out1fmt("<subtype %d>", subtype);
Eric Andersencb57d552001-06-28 07:25:16 +000011446 }
11447 break;
11448 case CTLENDVAR:
Eric Andersenc470f442003-07-28 09:56:35 +000011449 putc('}', fp);
11450 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011451 case CTLBACKQ:
Eric Andersenc470f442003-07-28 09:56:35 +000011452 case CTLBACKQ|CTLQUOTE:
Eric Andersencb57d552001-06-28 07:25:16 +000011453 putc('$', fp);
11454 putc('(', fp);
11455 shtree(bqlist->n, -1, NULL, fp);
11456 putc(')', fp);
11457 break;
11458 default:
11459 putc(*p, fp);
11460 break;
11461 }
11462 }
11463}
11464
11465
Eric Andersenc470f442003-07-28 09:56:35 +000011466static void
11467indent(int amount, char *pfx, FILE *fp)
Eric Andersencb57d552001-06-28 07:25:16 +000011468{
11469 int i;
11470
Eric Andersenc470f442003-07-28 09:56:35 +000011471 for (i = 0 ; i < amount ; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011472 if (pfx && i == amount - 1)
11473 fputs(pfx, fp);
11474 putc('\t', fp);
11475 }
11476}
Eric Andersencb57d552001-06-28 07:25:16 +000011477
Eric Andersenc470f442003-07-28 09:56:35 +000011478
11479
11480/*
11481 * Debugging stuff.
11482 */
11483
11484
Eric Andersencb57d552001-06-28 07:25:16 +000011485FILE *tracefile;
11486
Eric Andersencb57d552001-06-28 07:25:16 +000011487
Eric Andersenc470f442003-07-28 09:56:35 +000011488void
11489trputc(int c)
Eric Andersencb57d552001-06-28 07:25:16 +000011490{
Eric Andersenc470f442003-07-28 09:56:35 +000011491 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011492 return;
11493 putc(c, tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011494}
11495
Eric Andersenc470f442003-07-28 09:56:35 +000011496void
11497trace(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +000011498{
11499 va_list va;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011500
Eric Andersenc470f442003-07-28 09:56:35 +000011501 if (debug != 1)
11502 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011503 va_start(va, fmt);
Eric Andersenc470f442003-07-28 09:56:35 +000011504 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011505 va_end(va);
11506}
11507
Eric Andersenc470f442003-07-28 09:56:35 +000011508void
11509tracev(const char *fmt, va_list va)
Eric Andersencb57d552001-06-28 07:25:16 +000011510{
Eric Andersenc470f442003-07-28 09:56:35 +000011511 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011512 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011513 (void) vfprintf(tracefile, fmt, va);
Eric Andersencb57d552001-06-28 07:25:16 +000011514}
11515
11516
Eric Andersenc470f442003-07-28 09:56:35 +000011517void
11518trputs(const char *s)
11519{
11520 if (debug != 1)
11521 return;
11522 fputs(s, tracefile);
11523}
11524
11525
11526static void
11527trstring(char *s)
Eric Andersencb57d552001-06-28 07:25:16 +000011528{
11529 char *p;
11530 char c;
11531
Eric Andersenc470f442003-07-28 09:56:35 +000011532 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011533 return;
11534 putc('"', tracefile);
Eric Andersenc470f442003-07-28 09:56:35 +000011535 for (p = s ; *p ; p++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011536 switch (*p) {
Eric Andersenc470f442003-07-28 09:56:35 +000011537 case '\n': c = 'n'; goto backslash;
11538 case '\t': c = 't'; goto backslash;
11539 case '\r': c = 'r'; goto backslash;
11540 case '"': c = '"'; goto backslash;
11541 case '\\': c = '\\'; goto backslash;
11542 case CTLESC: c = 'e'; goto backslash;
11543 case CTLVAR: c = 'v'; goto backslash;
11544 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11545 case CTLBACKQ: c = 'q'; goto backslash;
11546 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11547backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011548 putc(c, tracefile);
11549 break;
11550 default:
11551 if (*p >= ' ' && *p <= '~')
11552 putc(*p, tracefile);
11553 else {
11554 putc('\\', tracefile);
11555 putc(*p >> 6 & 03, tracefile);
11556 putc(*p >> 3 & 07, tracefile);
11557 putc(*p & 07, tracefile);
11558 }
11559 break;
11560 }
11561 }
11562 putc('"', tracefile);
11563}
11564
11565
Eric Andersenc470f442003-07-28 09:56:35 +000011566void
11567trargs(char **ap)
Eric Andersencb57d552001-06-28 07:25:16 +000011568{
Eric Andersenc470f442003-07-28 09:56:35 +000011569 if (debug != 1)
Eric Andersencb57d552001-06-28 07:25:16 +000011570 return;
11571 while (*ap) {
11572 trstring(*ap++);
11573 if (*ap)
11574 putc(' ', tracefile);
11575 else
11576 putc('\n', tracefile);
11577 }
Eric Andersencb57d552001-06-28 07:25:16 +000011578}
11579
11580
Eric Andersenc470f442003-07-28 09:56:35 +000011581void
11582opentrace(void)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000011583{
Eric Andersencb57d552001-06-28 07:25:16 +000011584 char s[100];
11585#ifdef O_APPEND
11586 int flags;
11587#endif
11588
Eric Andersenc470f442003-07-28 09:56:35 +000011589 if (debug != 1) {
11590 if (tracefile)
11591 fflush(tracefile);
11592 /* leave open because libedit might be using it */
Eric Andersencb57d552001-06-28 07:25:16 +000011593 return;
Eric Andersencb57d552001-06-28 07:25:16 +000011594 }
Eric Andersenc470f442003-07-28 09:56:35 +000011595 scopy("./trace", s);
11596 if (tracefile) {
11597 if (!freopen(s, "a", tracefile)) {
11598 fprintf(stderr, "Can't re-open %s\n", s);
11599 debug = 0;
11600 return;
11601 }
11602 } else {
11603 if ((tracefile = fopen(s, "a")) == NULL) {
11604 fprintf(stderr, "Can't open %s\n", s);
11605 debug = 0;
11606 return;
11607 }
11608 }
Eric Andersencb57d552001-06-28 07:25:16 +000011609#ifdef O_APPEND
11610 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11611 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11612#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011613 setlinebuf(tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011614 fputs("\nTracing started.\n", tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000011615}
Eric Andersenc470f442003-07-28 09:56:35 +000011616#endif /* DEBUG */
11617
11618
11619/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11620
11621/*
11622 * Sigmode records the current value of the signal handlers for the various
11623 * modes. A value of zero means that the current handler is not known.
11624 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11625 */
11626
11627#define S_DFL 1 /* default signal handling (SIG_DFL) */
11628#define S_CATCH 2 /* signal is caught */
11629#define S_IGN 3 /* signal is ignored (SIG_IGN) */
11630#define S_HARD_IGN 4 /* signal is ignored permenantly */
11631#define S_RESET 5 /* temporary - to reset a hard ignored sig */
11632
Eric Andersencb57d552001-06-28 07:25:16 +000011633
11634
11635/*
Eric Andersencb57d552001-06-28 07:25:16 +000011636 * The trap builtin.
11637 */
11638
Eric Andersenc470f442003-07-28 09:56:35 +000011639int
11640trapcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000011641{
11642 char *action;
11643 char **ap;
11644 int signo;
11645
Eric Andersenc470f442003-07-28 09:56:35 +000011646 nextopt(nullstr);
11647 ap = argptr;
11648 if (!*ap) {
11649 for (signo = 0 ; signo < NSIG ; signo++) {
Eric Andersencb57d552001-06-28 07:25:16 +000011650 if (trap[signo] != NULL) {
Eric Andersen34506362001-08-02 05:02:46 +000011651 const char *sn;
Eric Andersencb57d552001-06-28 07:25:16 +000011652
Eric Andersenc470f442003-07-28 09:56:35 +000011653 sn = u_signal_names(0, &signo, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011654 if (sn == NULL)
Eric Andersen34506362001-08-02 05:02:46 +000011655 sn = "???";
Eric Andersenc470f442003-07-28 09:56:35 +000011656 out1fmt("trap -- %s %s\n",
11657 single_quote(trap[signo]), sn);
Eric Andersencb57d552001-06-28 07:25:16 +000011658 }
11659 }
11660 return 0;
11661 }
Eric Andersenc470f442003-07-28 09:56:35 +000011662 if (!ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000011663 action = NULL;
11664 else
11665 action = *ap++;
11666 while (*ap) {
11667 if ((signo = decode_signal(*ap, 0)) < 0)
11668 error("%s: bad trap", *ap);
11669 INTOFF;
11670 if (action) {
11671 if (action[0] == '-' && action[1] == '\0')
11672 action = NULL;
11673 else
Eric Andersenc470f442003-07-28 09:56:35 +000011674 action = savestr(action);
Eric Andersencb57d552001-06-28 07:25:16 +000011675 }
Eric Andersenc470f442003-07-28 09:56:35 +000011676 if (trap[signo])
11677 ckfree(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000011678 trap[signo] = action;
11679 if (signo != 0)
11680 setsignal(signo);
11681 INTON;
11682 ap++;
11683 }
11684 return 0;
11685}
11686
11687
Eric Andersenc470f442003-07-28 09:56:35 +000011688/*
11689 * Clear traps on a fork.
11690 */
11691
11692void
11693clear_traps(void)
11694{
11695 char **tp;
11696
11697 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11698 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11699 INTOFF;
11700 ckfree(*tp);
11701 *tp = NULL;
11702 if (tp != &trap[0])
11703 setsignal(tp - trap);
11704 INTON;
11705 }
11706 }
11707}
11708
11709
Eric Andersencb57d552001-06-28 07:25:16 +000011710/*
11711 * Set the signal handler for the specified signal. The routine figures
11712 * out what it should be set to.
11713 */
11714
Eric Andersenc470f442003-07-28 09:56:35 +000011715void
11716setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011717{
11718 int action;
Eric Andersenc470f442003-07-28 09:56:35 +000011719 char *t, tsig;
Eric Andersencb57d552001-06-28 07:25:16 +000011720 struct sigaction act;
11721
11722 if ((t = trap[signo]) == NULL)
11723 action = S_DFL;
11724 else if (*t != '\0')
11725 action = S_CATCH;
11726 else
11727 action = S_IGN;
11728 if (rootshell && action == S_DFL) {
11729 switch (signo) {
11730 case SIGINT:
11731 if (iflag || minusc || sflag == 0)
11732 action = S_CATCH;
11733 break;
11734 case SIGQUIT:
11735#ifdef DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000011736 if (debug)
11737 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011738#endif
11739 /* FALLTHROUGH */
11740 case SIGTERM:
11741 if (iflag)
11742 action = S_IGN;
11743 break;
Eric Andersenc470f442003-07-28 09:56:35 +000011744#if JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000011745 case SIGTSTP:
11746 case SIGTTOU:
11747 if (mflag)
11748 action = S_IGN;
11749 break;
11750#endif
11751 }
11752 }
11753
11754 t = &sigmode[signo - 1];
Eric Andersenc470f442003-07-28 09:56:35 +000011755 tsig = *t;
11756 if (tsig == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011757 /*
11758 * current setting unknown
11759 */
11760 if (sigaction(signo, 0, &act) == -1) {
11761 /*
11762 * Pretend it worked; maybe we should give a warning
11763 * here, but other shells don't. We don't alter
11764 * sigmode, so that we retry every time.
11765 */
11766 return;
11767 }
11768 if (act.sa_handler == SIG_IGN) {
11769 if (mflag && (signo == SIGTSTP ||
Eric Andersenc470f442003-07-28 09:56:35 +000011770 signo == SIGTTIN || signo == SIGTTOU)) {
11771 tsig = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000011772 } else
Eric Andersenc470f442003-07-28 09:56:35 +000011773 tsig = S_HARD_IGN;
Eric Andersencb57d552001-06-28 07:25:16 +000011774 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011775 tsig = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000011776 }
11777 }
Eric Andersenc470f442003-07-28 09:56:35 +000011778 if (tsig == S_HARD_IGN || tsig == action)
Eric Andersencb57d552001-06-28 07:25:16 +000011779 return;
Eric Andersenc470f442003-07-28 09:56:35 +000011780 switch (action) {
11781 case S_CATCH:
11782 act.sa_handler = onsig;
11783 break;
11784 case S_IGN:
11785 act.sa_handler = SIG_IGN;
11786 break;
11787 default:
11788 act.sa_handler = SIG_DFL;
11789 }
Eric Andersencb57d552001-06-28 07:25:16 +000011790 *t = action;
11791 act.sa_flags = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011792 sigfillset(&act.sa_mask);
Eric Andersencb57d552001-06-28 07:25:16 +000011793 sigaction(signo, &act, 0);
11794}
11795
11796/*
11797 * Ignore a signal.
11798 */
11799
Eric Andersenc470f442003-07-28 09:56:35 +000011800void
11801ignoresig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011802{
11803 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11804 signal(signo, SIG_IGN);
11805 }
11806 sigmode[signo - 1] = S_HARD_IGN;
11807}
11808
11809
Eric Andersencb57d552001-06-28 07:25:16 +000011810/*
11811 * Signal handler.
11812 */
11813
Eric Andersenc470f442003-07-28 09:56:35 +000011814void
11815onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000011816{
Eric Andersencb57d552001-06-28 07:25:16 +000011817 gotsig[signo - 1] = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011818 pendingsigs = signo;
11819
11820 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11821 if (!suppressint)
11822 onint();
11823 intpending = 1;
11824 }
Eric Andersencb57d552001-06-28 07:25:16 +000011825}
11826
11827
Eric Andersencb57d552001-06-28 07:25:16 +000011828/*
11829 * Called to execute a trap. Perhaps we should avoid entering new trap
11830 * handlers while we are executing a trap handler.
11831 */
11832
Eric Andersenc470f442003-07-28 09:56:35 +000011833void
11834dotrap(void)
Eric Andersen2870d962001-07-02 17:27:21 +000011835{
Eric Andersenc470f442003-07-28 09:56:35 +000011836 char *p;
11837 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011838 int savestatus;
11839
Eric Andersenc470f442003-07-28 09:56:35 +000011840 savestatus = exitstatus;
11841 q = gotsig;
Glenn L McGrath2f325a02004-08-06 01:49:04 +000011842 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
Eric Andersenc470f442003-07-28 09:56:35 +000011843 *p = 0;
11844 p = trap[p - q + 1];
11845 if (!p)
11846 continue;
Glenn L McGrath76620622004-01-13 10:19:37 +000011847 evalstring(p);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011848 exitstatus = savestatus;
Eric Andersencb57d552001-06-28 07:25:16 +000011849 }
Eric Andersencb57d552001-06-28 07:25:16 +000011850}
11851
Eric Andersenc470f442003-07-28 09:56:35 +000011852
Eric Andersenc470f442003-07-28 09:56:35 +000011853/*
11854 * Controls whether the shell is interactive or not.
11855 */
11856
Eric Andersenc470f442003-07-28 09:56:35 +000011857void
11858setinteractive(int on)
11859{
11860 static int is_interactive;
11861
11862 if (++on == is_interactive)
11863 return;
11864 is_interactive = on;
11865 setsignal(SIGINT);
11866 setsignal(SIGQUIT);
11867 setsignal(SIGTERM);
11868#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11869 if(is_interactive > 1) {
11870 /* Looks like they want an interactive shell */
11871 static int do_banner;
11872
11873 if(!do_banner) {
11874 out1fmt(
11875 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11876 "Enter 'help' for a list of built-in commands.\n\n");
11877 do_banner++;
11878 }
11879 }
11880#endif
11881}
11882
11883
11884#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11885/*** List the available builtins ***/
11886
11887static int helpcmd(int argc, char **argv)
11888{
11889 int col, i;
11890
11891 out1fmt("\nBuilt-in commands:\n-------------------\n");
11892 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11893 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11894 builtincmd[i].name + 1);
11895 if (col > 60) {
11896 out1fmt("\n");
11897 col = 0;
11898 }
11899 }
11900#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11901 {
11902 extern const struct BB_applet applets[];
11903 extern const size_t NUM_APPLETS;
11904
11905 for (i = 0; i < NUM_APPLETS; i++) {
11906
11907 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11908 if (col > 60) {
11909 out1fmt("\n");
11910 col = 0;
11911 }
11912 }
11913 }
11914#endif
11915 out1fmt("\n\n");
11916 return EXIT_SUCCESS;
11917}
11918#endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11919
Eric Andersencb57d552001-06-28 07:25:16 +000011920/*
11921 * Called to exit the shell.
11922 */
11923
Eric Andersenc470f442003-07-28 09:56:35 +000011924void
11925exitshell(void)
Eric Andersencb57d552001-06-28 07:25:16 +000011926{
Eric Andersenc470f442003-07-28 09:56:35 +000011927 struct jmploc loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011928 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000011929 int status;
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011930 int jmp;
Eric Andersencb57d552001-06-28 07:25:16 +000011931
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011932 jmp = setjmp(loc.loc);
Eric Andersenc470f442003-07-28 09:56:35 +000011933 status = exitstatus;
11934 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
Glenn L McGrath16e45d72004-02-04 08:24:39 +000011935 if (jmp)
Eric Andersenc470f442003-07-28 09:56:35 +000011936 goto out;
Eric Andersenc470f442003-07-28 09:56:35 +000011937 handler = &loc;
Eric Andersencb57d552001-06-28 07:25:16 +000011938 if ((p = trap[0]) != NULL && *p != '\0') {
11939 trap[0] = NULL;
Glenn L McGrath76620622004-01-13 10:19:37 +000011940 evalstring(p);
Eric Andersencb57d552001-06-28 07:25:16 +000011941 }
Eric Andersencb57d552001-06-28 07:25:16 +000011942 flushall();
Eric Andersen5dcf15e2004-07-24 12:44:13 +000011943 setjobctl(0);
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011944#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11945 if (iflag && rootshell) {
11946 const char *hp = lookupvar("HISTFILE");
11947
11948 if(hp != NULL )
11949 save_history ( hp );
11950 }
11951#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011952out:
Glenn L McGrathfdbbb042002-12-09 11:10:40 +000011953 _exit(status);
Eric Andersencb57d552001-06-28 07:25:16 +000011954 /* NOTREACHED */
11955}
11956
11957static int decode_signal(const char *string, int minsig)
11958{
11959 int signo;
Eric Andersen34506362001-08-02 05:02:46 +000011960 const char *name = u_signal_names(string, &signo, minsig);
Eric Andersencb57d552001-06-28 07:25:16 +000011961
Eric Andersen34506362001-08-02 05:02:46 +000011962 return name ? signo : -1;
Eric Andersencb57d552001-06-28 07:25:16 +000011963}
Eric Andersen34506362001-08-02 05:02:46 +000011964
Eric Andersenc470f442003-07-28 09:56:35 +000011965/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11966
11967static struct var *vartab[VTABSIZE];
11968
11969static int vpcmp(const void *, const void *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011970static struct var **findvar(struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011971
11972/*
Eric Andersenaff114c2004-04-14 17:51:38 +000011973 * Initialize the variable symbol tables and import the environment
Eric Andersencb57d552001-06-28 07:25:16 +000011974 */
11975
Eric Andersenc470f442003-07-28 09:56:35 +000011976
11977#ifdef CONFIG_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000011978/*
Eric Andersenc470f442003-07-28 09:56:35 +000011979 * Safe version of setvar, returns 1 on success 0 on failure.
Eric Andersencb57d552001-06-28 07:25:16 +000011980 */
11981
Eric Andersenc470f442003-07-28 09:56:35 +000011982int
11983setvarsafe(const char *name, const char *val, int flags)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011984{
Eric Andersenc470f442003-07-28 09:56:35 +000011985 int err;
11986 volatile int saveint;
11987 struct jmploc *volatile savehandler = handler;
11988 struct jmploc jmploc;
Eric Andersencb57d552001-06-28 07:25:16 +000011989
Eric Andersenc470f442003-07-28 09:56:35 +000011990 SAVEINT(saveint);
11991 if (setjmp(jmploc.loc))
11992 err = 1;
11993 else {
11994 handler = &jmploc;
11995 setvar(name, val, flags);
11996 err = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011997 }
Eric Andersenc470f442003-07-28 09:56:35 +000011998 handler = savehandler;
11999 RESTOREINT(saveint);
12000 return err;
Eric Andersencb57d552001-06-28 07:25:16 +000012001}
Eric Andersenc470f442003-07-28 09:56:35 +000012002#endif
Eric Andersencb57d552001-06-28 07:25:16 +000012003
12004/*
12005 * Set the value of a variable. The flags argument is ored with the
12006 * flags of the variable. If val is NULL, the variable is unset.
12007 */
12008
Eric Andersenc470f442003-07-28 09:56:35 +000012009static void
12010setvar(const char *name, const char *val, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012011{
Eric Andersenc470f442003-07-28 09:56:35 +000012012 char *p, *q;
12013 size_t namelen;
Eric Andersencb57d552001-06-28 07:25:16 +000012014 char *nameeq;
Eric Andersenc470f442003-07-28 09:56:35 +000012015 size_t vallen;
Eric Andersencb57d552001-06-28 07:25:16 +000012016
Eric Andersenc470f442003-07-28 09:56:35 +000012017 q = endofname(name);
12018 p = strchrnul(q, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012019 namelen = p - name;
Eric Andersenc470f442003-07-28 09:56:35 +000012020 if (!namelen || p != q)
Eric Andersencb57d552001-06-28 07:25:16 +000012021 error("%.*s: bad variable name", namelen, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012022 vallen = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012023 if (val == NULL) {
12024 flags |= VUNSET;
12025 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012026 vallen = strlen(val);
Eric Andersencb57d552001-06-28 07:25:16 +000012027 }
12028 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012029 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
Paul Fox8de331d2005-07-21 12:03:05 +000012030 *p++ = '\0';
12031 if (val) {
12032 p[-1] = '=';
Eric Andersenc470f442003-07-28 09:56:35 +000012033 p = mempcpy(p, val, vallen);
Eric Andersencb57d552001-06-28 07:25:16 +000012034 }
Eric Andersenc470f442003-07-28 09:56:35 +000012035 *p = '\0';
12036 setvareq(nameeq, flags | VNOSAVE);
Eric Andersencb57d552001-06-28 07:25:16 +000012037 INTON;
12038}
12039
12040
Eric Andersencb57d552001-06-28 07:25:16 +000012041/*
12042 * Same as setvar except that the variable and value are passed in
12043 * the first argument as name=value. Since the first argument will
12044 * be actually stored in the table, it should not be a string that
12045 * will go away.
Eric Andersenc470f442003-07-28 09:56:35 +000012046 * Called with interrupts off.
Eric Andersencb57d552001-06-28 07:25:16 +000012047 */
12048
Eric Andersenc470f442003-07-28 09:56:35 +000012049void
12050setvareq(char *s, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +000012051{
12052 struct var *vp, **vpp;
12053
12054 vpp = hashvar(s);
12055 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
Eric Andersenc470f442003-07-28 09:56:35 +000012056 vp = *findvar(vpp, s);
12057 if (vp) {
Eric Andersen16767e22004-03-16 05:14:10 +000012058 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12059 const char *n;
12060
Eric Andersenc470f442003-07-28 09:56:35 +000012061 if (flags & VNOSAVE)
12062 free(s);
Eric Andersen16767e22004-03-16 05:14:10 +000012063 n = vp->text;
12064 error("%.*s: is read only", strchrnul(n, '=') - n, n);
Eric Andersencb57d552001-06-28 07:25:16 +000012065 }
Eric Andersenc470f442003-07-28 09:56:35 +000012066
12067 if (flags & VNOSET)
12068 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012069
12070 if (vp->func && (flags & VNOFUNC) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012071 (*vp->func)(strchrnul(s, '=') + 1);
Eric Andersencb57d552001-06-28 07:25:16 +000012072
Eric Andersenc470f442003-07-28 09:56:35 +000012073 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12074 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012075
Eric Andersenc470f442003-07-28 09:56:35 +000012076 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12077 } else {
12078 if (flags & VNOSET)
12079 return;
12080 /* not found */
12081 vp = ckmalloc(sizeof (*vp));
12082 vp->next = *vpp;
12083 vp->func = NULL;
12084 *vpp = vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012085 }
Eric Andersenc470f442003-07-28 09:56:35 +000012086 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12087 s = savestr(s);
Eric Andersencb57d552001-06-28 07:25:16 +000012088 vp->text = s;
Eric Andersenc470f442003-07-28 09:56:35 +000012089 vp->flags = flags;
Eric Andersencb57d552001-06-28 07:25:16 +000012090}
12091
12092
Eric Andersencb57d552001-06-28 07:25:16 +000012093/*
12094 * Process a linked list of variable assignments.
12095 */
12096
Eric Andersenc470f442003-07-28 09:56:35 +000012097static void
12098listsetvar(struct strlist *list_set_var, int flags)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012099{
Eric Andersenc470f442003-07-28 09:56:35 +000012100 struct strlist *lp = list_set_var;
Eric Andersencb57d552001-06-28 07:25:16 +000012101
Eric Andersenc470f442003-07-28 09:56:35 +000012102 if (!lp)
12103 return;
Eric Andersencb57d552001-06-28 07:25:16 +000012104 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012105 do {
12106 setvareq(lp->text, flags);
12107 } while ((lp = lp->next));
Eric Andersencb57d552001-06-28 07:25:16 +000012108 INTON;
12109}
12110
12111
Eric Andersencb57d552001-06-28 07:25:16 +000012112/*
12113 * Find the value of a variable. Returns NULL if not set.
12114 */
12115
Eric Andersenc470f442003-07-28 09:56:35 +000012116static char *
12117lookupvar(const char *name)
Eric Andersenec074692001-10-31 11:05:49 +000012118{
Eric Andersencb57d552001-06-28 07:25:16 +000012119 struct var *v;
12120
Eric Andersen16767e22004-03-16 05:14:10 +000012121 if ((v = *findvar(hashvar(name), name))) {
12122#ifdef DYNAMIC_VAR
Eric Andersenef02f822004-03-11 13:34:24 +000012123 /*
12124 * Dynamic variables are implemented roughly the same way they are
12125 * in bash. Namely, they're "special" so long as they aren't unset.
12126 * As soon as they're unset, they're no longer dynamic, and dynamic
12127 * lookup will no longer happen at that point. -- PFM.
12128 */
Eric Andersen16767e22004-03-16 05:14:10 +000012129 if((v->flags & VDYNAMIC))
12130 (*v->func)(NULL);
12131#endif
12132 if(!(v->flags & VUNSET))
12133 return strchrnul(v->text, '=') + 1;
12134 }
Eric Andersenef02f822004-03-11 13:34:24 +000012135
Eric Andersencb57d552001-06-28 07:25:16 +000012136 return NULL;
12137}
12138
12139
Eric Andersencb57d552001-06-28 07:25:16 +000012140/*
12141 * Search the environment of a builtin command.
12142 */
12143
Eric Andersenc470f442003-07-28 09:56:35 +000012144static char *
12145bltinlookup(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012146{
Eric Andersenc470f442003-07-28 09:56:35 +000012147 struct strlist *sp;
Eric Andersencb57d552001-06-28 07:25:16 +000012148
Eric Andersenc470f442003-07-28 09:56:35 +000012149 for (sp = cmdenviron ; sp ; sp = sp->next) {
Eric Andersencb57d552001-06-28 07:25:16 +000012150 if (varequal(sp->text, name))
Eric Andersenc470f442003-07-28 09:56:35 +000012151 return strchrnul(sp->text, '=') + 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012152 }
12153 return lookupvar(name);
12154}
12155
12156
Eric Andersencb57d552001-06-28 07:25:16 +000012157/*
Eric Andersenc470f442003-07-28 09:56:35 +000012158 * Generate a list of variables satisfying the given conditions.
Eric Andersencb57d552001-06-28 07:25:16 +000012159 */
12160
Eric Andersenc470f442003-07-28 09:56:35 +000012161static char **
12162listvars(int on, int off, char ***end)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012163{
Eric Andersencb57d552001-06-28 07:25:16 +000012164 struct var **vpp;
12165 struct var *vp;
Eric Andersencb57d552001-06-28 07:25:16 +000012166 char **ep;
Eric Andersenc470f442003-07-28 09:56:35 +000012167 int mask;
Eric Andersencb57d552001-06-28 07:25:16 +000012168
Eric Andersenc470f442003-07-28 09:56:35 +000012169 STARTSTACKSTR(ep);
12170 vpp = vartab;
12171 mask = on | off;
12172 do {
12173 for (vp = *vpp ; vp ; vp = vp->next)
12174 if ((vp->flags & mask) == on) {
12175 if (ep == stackstrend())
12176 ep = growstackstr();
12177 *ep++ = (char *) vp->text;
12178 }
12179 } while (++vpp < vartab + VTABSIZE);
12180 if (ep == stackstrend())
12181 ep = growstackstr();
12182 if (end)
12183 *end = ep;
12184 *ep++ = NULL;
12185 return grabstackstr(ep);
Eric Andersencb57d552001-06-28 07:25:16 +000012186}
12187
12188
12189/*
Eric Andersenc470f442003-07-28 09:56:35 +000012190 * POSIX requires that 'set' (but not export or readonly) output the
12191 * variables in lexicographic order - by the locale's collating order (sigh).
12192 * Maybe we could keep them in an ordered balanced binary tree
12193 * instead of hashed lists.
12194 * For now just roll 'em through qsort for printing...
Eric Andersencb57d552001-06-28 07:25:16 +000012195 */
12196
Eric Andersenc470f442003-07-28 09:56:35 +000012197static int
12198showvars(const char *sep_prefix, int on, int off)
Eric Andersencb57d552001-06-28 07:25:16 +000012199{
Eric Andersenc470f442003-07-28 09:56:35 +000012200 const char *sep;
12201 char **ep, **epend;
12202
12203 ep = listvars(on, off, &epend);
12204 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12205
12206 sep = *sep_prefix ? spcstr : sep_prefix;
12207
12208 for (; ep < epend; ep++) {
12209 const char *p;
12210 const char *q;
12211
12212 p = strchrnul(*ep, '=');
12213 q = nullstr;
12214 if (*p)
12215 q = single_quote(++p);
12216
12217 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12218 }
12219
Eric Andersencb57d552001-06-28 07:25:16 +000012220 return 0;
12221}
12222
12223
12224
12225/*
12226 * The export and readonly commands.
12227 */
12228
Eric Andersenc470f442003-07-28 09:56:35 +000012229static int
12230exportcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012231{
12232 struct var *vp;
12233 char *name;
12234 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012235 char **aptr;
12236 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12237 int notp;
Eric Andersencb57d552001-06-28 07:25:16 +000012238
Eric Andersenc470f442003-07-28 09:56:35 +000012239 notp = nextopt("p") - 'p';
12240 if (notp && ((name = *(aptr = argptr)))) {
12241 do {
Eric Andersencb57d552001-06-28 07:25:16 +000012242 if ((p = strchr(name, '=')) != NULL) {
12243 p++;
12244 } else {
12245 if ((vp = *findvar(hashvar(name), name))) {
12246 vp->flags |= flag;
Eric Andersenc470f442003-07-28 09:56:35 +000012247 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000012248 }
12249 }
12250 setvar(name, p, flag);
Eric Andersenc470f442003-07-28 09:56:35 +000012251 } while ((name = *++aptr) != NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000012252 } else {
12253 showvars(argv[0], flag, 0);
12254 }
12255 return 0;
12256}
12257
Eric Andersen34506362001-08-02 05:02:46 +000012258
Eric Andersencb57d552001-06-28 07:25:16 +000012259/*
Eric Andersencb57d552001-06-28 07:25:16 +000012260 * Make a variable a local variable. When a variable is made local, it's
12261 * value and flags are saved in a localvar structure. The saved values
12262 * will be restored when the shell function returns. We handle the name
12263 * "-" as a special case.
12264 */
12265
Eric Andersenc470f442003-07-28 09:56:35 +000012266static inline void
12267mklocal(char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012268{
Eric Andersencb57d552001-06-28 07:25:16 +000012269 struct localvar *lvp;
12270 struct var **vpp;
12271 struct var *vp;
12272
12273 INTOFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012274 lvp = ckmalloc(sizeof (struct localvar));
Eric Andersencb57d552001-06-28 07:25:16 +000012275 if (name[0] == '-' && name[1] == '\0') {
12276 char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012277 p = ckmalloc(sizeof(optlist));
12278 lvp->text = memcpy(p, optlist, sizeof(optlist));
Eric Andersencb57d552001-06-28 07:25:16 +000012279 vp = NULL;
12280 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012281 char *eq;
12282
Eric Andersencb57d552001-06-28 07:25:16 +000012283 vpp = hashvar(name);
12284 vp = *findvar(vpp, name);
Eric Andersenc470f442003-07-28 09:56:35 +000012285 eq = strchr(name, '=');
Eric Andersencb57d552001-06-28 07:25:16 +000012286 if (vp == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012287 if (eq)
12288 setvareq(name, VSTRFIXED);
Eric Andersencb57d552001-06-28 07:25:16 +000012289 else
12290 setvar(name, NULL, VSTRFIXED);
Eric Andersenc470f442003-07-28 09:56:35 +000012291 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012292 lvp->flags = VUNSET;
12293 } else {
12294 lvp->text = vp->text;
12295 lvp->flags = vp->flags;
Eric Andersenc470f442003-07-28 09:56:35 +000012296 vp->flags |= VSTRFIXED|VTEXTFIXED;
12297 if (eq)
12298 setvareq(name, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012299 }
12300 }
12301 lvp->vp = vp;
12302 lvp->next = localvars;
12303 localvars = lvp;
12304 INTON;
12305}
12306
Eric Andersenc470f442003-07-28 09:56:35 +000012307/*
12308 * The "local" command.
12309 */
12310
12311static int
12312localcmd(int argc, char **argv)
12313{
12314 char *name;
12315
12316 argv = argptr;
12317 while ((name = *argv++) != NULL) {
12318 mklocal(name);
12319 }
12320 return 0;
12321}
12322
12323
Eric Andersencb57d552001-06-28 07:25:16 +000012324/*
12325 * Called after a function returns.
Eric Andersenc470f442003-07-28 09:56:35 +000012326 * Interrupts must be off.
Eric Andersencb57d552001-06-28 07:25:16 +000012327 */
12328
Eric Andersenc470f442003-07-28 09:56:35 +000012329static void
12330poplocalvars(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012331{
Eric Andersencb57d552001-06-28 07:25:16 +000012332 struct localvar *lvp;
12333 struct var *vp;
12334
12335 while ((lvp = localvars) != NULL) {
12336 localvars = lvp->next;
12337 vp = lvp->vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012338 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12339 if (vp == NULL) { /* $- saved */
12340 memcpy(optlist, lvp->text, sizeof(optlist));
12341 ckfree(lvp->text);
12342 optschanged();
12343 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12344 unsetvar(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012345 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000012346 if (vp->func)
12347 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12348 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12349 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012350 vp->flags = lvp->flags;
12351 vp->text = lvp->text;
12352 }
Eric Andersenc470f442003-07-28 09:56:35 +000012353 ckfree(lvp);
Eric Andersencb57d552001-06-28 07:25:16 +000012354 }
12355}
12356
12357
Eric Andersencb57d552001-06-28 07:25:16 +000012358/*
12359 * The unset builtin command. We unset the function before we unset the
12360 * variable to allow a function to be unset when there is a readonly variable
12361 * with the same name.
12362 */
12363
Eric Andersenc470f442003-07-28 09:56:35 +000012364int
12365unsetcmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012366{
12367 char **ap;
12368 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012369 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012370 int ret = 0;
12371
12372 while ((i = nextopt("vf")) != '\0') {
Eric Andersenc470f442003-07-28 09:56:35 +000012373 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012374 }
Eric Andersencb57d552001-06-28 07:25:16 +000012375
Eric Andersenc470f442003-07-28 09:56:35 +000012376 for (ap = argptr; *ap ; ap++) {
12377 if (flag != 'f') {
12378 i = unsetvar(*ap);
12379 ret |= i;
12380 if (!(i & 2))
12381 continue;
12382 }
12383 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012384 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012385 }
Eric Andersenc470f442003-07-28 09:56:35 +000012386 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012387}
12388
12389
12390/*
12391 * Unset the specified variable.
12392 */
12393
Eric Andersenc470f442003-07-28 09:56:35 +000012394int
12395unsetvar(const char *s)
Eric Andersen62483552001-07-10 06:09:16 +000012396{
Eric Andersencb57d552001-06-28 07:25:16 +000012397 struct var **vpp;
12398 struct var *vp;
Eric Andersenc470f442003-07-28 09:56:35 +000012399 int retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012400
12401 vpp = findvar(hashvar(s), s);
12402 vp = *vpp;
Eric Andersenc470f442003-07-28 09:56:35 +000012403 retval = 2;
Eric Andersencb57d552001-06-28 07:25:16 +000012404 if (vp) {
Eric Andersenc470f442003-07-28 09:56:35 +000012405 int flags = vp->flags;
12406
12407 retval = 1;
12408 if (flags & VREADONLY)
12409 goto out;
Eric Andersen16767e22004-03-16 05:14:10 +000012410#ifdef DYNAMIC_VAR
12411 vp->flags &= ~VDYNAMIC;
12412#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012413 if (flags & VUNSET)
12414 goto ok;
12415 if ((flags & VSTRFIXED) == 0) {
12416 INTOFF;
12417 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12418 ckfree(vp->text);
Eric Andersencb57d552001-06-28 07:25:16 +000012419 *vpp = vp->next;
Eric Andersenc470f442003-07-28 09:56:35 +000012420 ckfree(vp);
12421 INTON;
12422 } else {
12423 setvar(s, 0, 0);
12424 vp->flags &= ~VEXPORT;
Eric Andersencb57d552001-06-28 07:25:16 +000012425 }
Eric Andersenc470f442003-07-28 09:56:35 +000012426ok:
12427 retval = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012428 }
12429
Eric Andersenc470f442003-07-28 09:56:35 +000012430out:
12431 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000012432}
12433
12434
12435
12436/*
12437 * Find the appropriate entry in the hash table from the name.
12438 */
12439
Eric Andersenc470f442003-07-28 09:56:35 +000012440static struct var **
12441hashvar(const char *p)
Eric Andersen62483552001-07-10 06:09:16 +000012442{
Eric Andersencb57d552001-06-28 07:25:16 +000012443 unsigned int hashval;
12444
12445 hashval = ((unsigned char) *p) << 4;
12446 while (*p && *p != '=')
12447 hashval += (unsigned char) *p++;
12448 return &vartab[hashval % VTABSIZE];
12449}
12450
12451
12452
12453/*
Eric Andersenc470f442003-07-28 09:56:35 +000012454 * Compares two strings up to the first = or '\0'. The first
12455 * string must be terminated by '='; the second may be terminated by
Eric Andersencb57d552001-06-28 07:25:16 +000012456 * either '=' or '\0'.
12457 */
12458
Eric Andersenc470f442003-07-28 09:56:35 +000012459int
12460varcmp(const char *p, const char *q)
Eric Andersen62483552001-07-10 06:09:16 +000012461{
Eric Andersenc470f442003-07-28 09:56:35 +000012462 int c, d;
12463
12464 while ((c = *p) == (d = *q)) {
12465 if (!c || c == '=')
12466 goto out;
12467 p++;
12468 q++;
Eric Andersencb57d552001-06-28 07:25:16 +000012469 }
Eric Andersenc470f442003-07-28 09:56:35 +000012470 if (c == '=')
12471 c = 0;
12472 if (d == '=')
12473 d = 0;
12474out:
12475 return c - d;
Eric Andersencb57d552001-06-28 07:25:16 +000012476}
12477
Eric Andersenc470f442003-07-28 09:56:35 +000012478static int
12479vpcmp(const void *a, const void *b)
Eric Andersencb57d552001-06-28 07:25:16 +000012480{
Eric Andersenc470f442003-07-28 09:56:35 +000012481 return varcmp(*(const char **)a, *(const char **)b);
Eric Andersencb57d552001-06-28 07:25:16 +000012482}
12483
Eric Andersenc470f442003-07-28 09:56:35 +000012484static struct var **
12485findvar(struct var **vpp, const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +000012486{
12487 for (; *vpp; vpp = &(*vpp)->next) {
12488 if (varequal((*vpp)->text, name)) {
12489 break;
12490 }
12491 }
12492 return vpp;
12493}
Eric Andersenc470f442003-07-28 09:56:35 +000012494/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
Eric Andersencb57d552001-06-28 07:25:16 +000012495
Eric Andersenc470f442003-07-28 09:56:35 +000012496#include <sys/times.h>
12497
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012498static const unsigned char timescmd_str[] = {
12499 ' ', offsetof(struct tms, tms_utime),
12500 '\n', offsetof(struct tms, tms_stime),
12501 ' ', offsetof(struct tms, tms_cutime),
12502 '\n', offsetof(struct tms, tms_cstime),
12503 0
12504};
Eric Andersencb57d552001-06-28 07:25:16 +000012505
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012506static int timescmd(int ac, char **av)
12507{
12508 long int clk_tck, s, t;
12509 const unsigned char *p;
12510 struct tms buf;
12511
12512 clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersencb57d552001-06-28 07:25:16 +000012513 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012514
12515 p = timescmd_str;
12516 do {
12517 t = *(clock_t *)(((char *) &buf) + p[1]);
12518 s = t / clk_tck;
12519 out1fmt("%ldm%ld.%.3lds%c",
12520 s/60, s%60,
12521 ((t - s * clk_tck) * 1000) / clk_tck,
12522 p[0]);
12523 } while (*(p += 2));
12524
Eric Andersencb57d552001-06-28 07:25:16 +000012525 return 0;
12526}
12527
Eric Andersend35c5df2002-01-09 15:37:36 +000012528#ifdef CONFIG_ASH_MATH_SUPPORT
Eric Andersened9ecf72004-06-22 08:29:45 +000012529static arith_t
Eric Andersenc470f442003-07-28 09:56:35 +000012530dash_arith(const char *s)
Eric Andersen74bcd162001-07-30 21:41:37 +000012531{
Eric Andersened9ecf72004-06-22 08:29:45 +000012532 arith_t result;
Eric Andersenc470f442003-07-28 09:56:35 +000012533 int errcode = 0;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012534
Eric Andersenc470f442003-07-28 09:56:35 +000012535 INTOFF;
12536 result = arith(s, &errcode);
12537 if (errcode < 0) {
Eric Andersen90898442003-08-06 11:20:52 +000012538 if (errcode == -3)
12539 error("exponent less than 0");
12540 else if (errcode == -2)
Eric Andersenc470f442003-07-28 09:56:35 +000012541 error("divide by zero");
Eric Andersen90898442003-08-06 11:20:52 +000012542 else if (errcode == -5)
12543 error("expression recursion loop detected");
Eric Andersenc470f442003-07-28 09:56:35 +000012544 else
12545 synerror(s);
12546 }
12547 INTON;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000012548
Eric Andersenc470f442003-07-28 09:56:35 +000012549 return (result);
Eric Andersen74bcd162001-07-30 21:41:37 +000012550}
Eric Andersenc470f442003-07-28 09:56:35 +000012551
12552
12553/*
Eric Andersen90898442003-08-06 11:20:52 +000012554 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12555 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12556 *
12557 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012558 */
Eric Andersen90898442003-08-06 11:20:52 +000012559
Eric Andersenc470f442003-07-28 09:56:35 +000012560static int
Eric Andersen90898442003-08-06 11:20:52 +000012561letcmd(int argc, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012562{
Eric Andersenc470f442003-07-28 09:56:35 +000012563 char **ap;
Eric Andersened9ecf72004-06-22 08:29:45 +000012564 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012565
Eric Andersen90898442003-08-06 11:20:52 +000012566 ap = argv + 1;
12567 if(!*ap)
12568 error("expression expected");
12569 for (ap = argv + 1; *ap; ap++) {
12570 i = dash_arith(*ap);
12571 }
Eric Andersenc470f442003-07-28 09:56:35 +000012572
Eric Andersen90898442003-08-06 11:20:52 +000012573 return (!i);
Eric Andersenc470f442003-07-28 09:56:35 +000012574}
12575#endif /* CONFIG_ASH_MATH_SUPPORT */
12576
12577/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12578
12579/*
Eric Andersenaff114c2004-04-14 17:51:38 +000012580 * Miscellaneous builtins.
Eric Andersenc470f442003-07-28 09:56:35 +000012581 */
12582
12583#undef rflag
12584
12585#ifdef __GLIBC__
Glenn L McGrath76620622004-01-13 10:19:37 +000012586#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
Eric Andersenc470f442003-07-28 09:56:35 +000012587typedef enum __rlimit_resource rlim_t;
12588#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012589#endif
12590
12591
Eric Andersenc470f442003-07-28 09:56:35 +000012592/*
12593 * The read builtin. The -e option causes backslashes to escape the
12594 * following character.
12595 *
12596 * This uses unbuffered input, which may be avoidable in some cases.
12597 */
12598
12599static int
12600readcmd(int argc, char **argv)
12601{
12602 char **ap;
12603 int backslash;
12604 char c;
12605 int rflag;
12606 char *prompt;
12607 const char *ifs;
12608 char *p;
12609 int startword;
12610 int status;
12611 int i;
Paul Fox02eb9342005-09-07 16:56:02 +000012612#if defined(CONFIG_ASH_READ_NCHARS)
12613 int nch_flag = 0;
12614 int nchars = 0;
12615 int silent = 0;
12616 struct termios tty, old_tty;
12617#endif
12618#if defined(CONFIG_ASH_READ_TIMEOUT)
12619 fd_set set;
12620 struct timeval ts;
12621
12622 ts.tv_sec = ts.tv_usec = 0;
12623#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012624
12625 rflag = 0;
12626 prompt = NULL;
Paul Fox02eb9342005-09-07 16:56:02 +000012627#if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12628 while ((i = nextopt("p:rt:n:s")) != '\0')
12629#elif defined(CONFIG_ASH_READ_NCHARS)
12630 while ((i = nextopt("p:rn:s")) != '\0')
12631#elif defined(CONFIG_ASH_READ_TIMEOUT)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012632 while ((i = nextopt("p:rt:")) != '\0')
12633#else
12634 while ((i = nextopt("p:r")) != '\0')
12635#endif
12636 {
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012637 switch(i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012638 case 'p':
Eric Andersenc470f442003-07-28 09:56:35 +000012639 prompt = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012640 break;
12641#if defined(CONFIG_ASH_READ_NCHARS)
12642 case 'n':
12643 nchars = strtol(optionarg, &p, 10);
12644 if (*p)
12645 error("invalid count");
12646 nch_flag = (nchars > 0);
12647 break;
12648 case 's':
12649 silent = 1;
12650 break;
Ned Ludd2123b7c2005-02-09 21:07:23 +000012651#endif
Paul Fox02eb9342005-09-07 16:56:02 +000012652#if defined(CONFIG_ASH_READ_TIMEOUT)
12653 case 't':
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012654 ts.tv_sec = strtol(optionarg, &p, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012655 ts.tv_usec = 0;
12656 if (*p == '.') {
12657 char *p2;
12658 if (*++p) {
12659 int scale;
"Vladimir N. Oleynik"11d7c522005-09-26 13:24:45 +000012660 ts.tv_usec = strtol(p, &p2, 10);
Paul Fox02eb9342005-09-07 16:56:02 +000012661 if (*p2)
12662 error("invalid timeout");
12663 scale = p2 - p;
12664 /* normalize to usec */
12665 if (scale > 6)
12666 error("invalid timeout");
12667 while (scale++ < 6)
12668 ts.tv_usec *= 10;
12669 }
12670 } else if (*p) {
12671 error("invalid timeout");
12672 }
12673 if ( ! ts.tv_sec && ! ts.tv_usec)
12674 error("invalid timeout");
12675 break;
12676#endif
12677 case 'r':
12678 rflag = 1;
12679 break;
12680 default:
12681 break;
12682 }
Eric Andersenc470f442003-07-28 09:56:35 +000012683 }
12684 if (prompt && isatty(0)) {
12685 out2str(prompt);
Eric Andersenc470f442003-07-28 09:56:35 +000012686 }
12687 if (*(ap = argptr) == NULL)
12688 error("arg count");
12689 if ((ifs = bltinlookup("IFS")) == NULL)
12690 ifs = defifs;
Paul Fox02eb9342005-09-07 16:56:02 +000012691#if defined(CONFIG_ASH_READ_NCHARS)
12692 if (nch_flag || silent) {
12693 tcgetattr(0, &tty);
12694 old_tty = tty;
12695 if (nch_flag) {
12696 tty.c_lflag &= ~ICANON;
12697 tty.c_cc[VMIN] = nchars;
12698 }
12699 if (silent) {
12700 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12701
12702 }
12703 tcsetattr(0, TCSANOW, &tty);
12704 }
12705#endif
12706#if defined(CONFIG_ASH_READ_TIMEOUT)
12707 if (ts.tv_sec || ts.tv_usec) {
12708 FD_ZERO (&set);
12709 FD_SET (0, &set);
12710
12711 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12712 if (!i) {
12713#if defined(CONFIG_ASH_READ_NCHARS)
12714 if (nch_flag)
12715 tcsetattr(0, TCSANOW, &old_tty);
12716#endif
12717 return 1;
12718 }
12719 }
Ned Ludd2123b7c2005-02-09 21:07:23 +000012720#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012721 status = 0;
12722 startword = 1;
12723 backslash = 0;
12724 STARTSTACKSTR(p);
Paul Fox02eb9342005-09-07 16:56:02 +000012725#if defined(CONFIG_ASH_READ_NCHARS)
12726 while (!nch_flag || nchars--)
Ned Ludd2123b7c2005-02-09 21:07:23 +000012727#else
12728 for (;;)
12729#endif
12730 {
Eric Andersenc470f442003-07-28 09:56:35 +000012731 if (read(0, &c, 1) != 1) {
12732 status = 1;
12733 break;
12734 }
12735 if (c == '\0')
12736 continue;
12737 if (backslash) {
12738 backslash = 0;
12739 if (c != '\n')
12740 goto put;
12741 continue;
12742 }
12743 if (!rflag && c == '\\') {
12744 backslash++;
12745 continue;
12746 }
12747 if (c == '\n')
12748 break;
12749 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12750 continue;
12751 }
12752 startword = 0;
12753 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12754 STACKSTRNUL(p);
12755 setvar(*ap, stackblock(), 0);
12756 ap++;
12757 startword = 1;
12758 STARTSTACKSTR(p);
12759 } else {
12760put:
12761 STPUTC(c, p);
12762 }
12763 }
Paul Fox02eb9342005-09-07 16:56:02 +000012764#if defined(CONFIG_ASH_READ_NCHARS)
12765 if (nch_flag || silent)
12766 tcsetattr(0, TCSANOW, &old_tty);
12767#endif
12768
Eric Andersenc470f442003-07-28 09:56:35 +000012769 STACKSTRNUL(p);
12770 /* Remove trailing blanks */
12771 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12772 *p = '\0';
12773 setvar(*ap, stackblock(), 0);
12774 while (*++ap != NULL)
12775 setvar(*ap, nullstr, 0);
12776 return status;
12777}
12778
12779
12780static int umaskcmd(int argc, char **argv)
12781{
12782 static const char permuser[3] = "ugo";
12783 static const char permmode[3] = "rwx";
12784 static const short int permmask[] = {
12785 S_IRUSR, S_IWUSR, S_IXUSR,
12786 S_IRGRP, S_IWGRP, S_IXGRP,
12787 S_IROTH, S_IWOTH, S_IXOTH
12788 };
12789
12790 char *ap;
12791 mode_t mask;
12792 int i;
12793 int symbolic_mode = 0;
12794
12795 while (nextopt("S") != '\0') {
12796 symbolic_mode = 1;
12797 }
12798
12799 INTOFF;
12800 mask = umask(0);
12801 umask(mask);
12802 INTON;
12803
12804 if ((ap = *argptr) == NULL) {
12805 if (symbolic_mode) {
12806 char buf[18];
12807 char *p = buf;
12808
12809 for (i = 0; i < 3; i++) {
12810 int j;
12811
12812 *p++ = permuser[i];
12813 *p++ = '=';
12814 for (j = 0; j < 3; j++) {
12815 if ((mask & permmask[3 * i + j]) == 0) {
12816 *p++ = permmode[j];
12817 }
12818 }
12819 *p++ = ',';
12820 }
12821 *--p = 0;
12822 puts(buf);
12823 } else {
12824 out1fmt("%.4o\n", mask);
12825 }
12826 } else {
12827 if (is_digit((unsigned char) *ap)) {
12828 mask = 0;
12829 do {
12830 if (*ap >= '8' || *ap < '0')
12831 error(illnum, argv[1]);
12832 mask = (mask << 3) + (*ap - '0');
12833 } while (*++ap != '\0');
12834 umask(mask);
12835 } else {
12836 mask = ~mask & 0777;
12837 if (!bb_parse_mode(ap, &mask)) {
12838 error("Illegal mode: %s", ap);
12839 }
12840 umask(~mask & 0777);
12841 }
12842 }
12843 return 0;
12844}
12845
12846/*
12847 * ulimit builtin
12848 *
12849 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12850 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12851 * ash by J.T. Conklin.
12852 *
12853 * Public domain.
12854 */
12855
12856struct limits {
12857 const char *name;
12858 int cmd;
12859 int factor; /* multiply by to get rlim_{cur,max} values */
12860 char option;
12861};
12862
12863static const struct limits limits[] = {
12864#ifdef RLIMIT_CPU
12865 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12866#endif
12867#ifdef RLIMIT_FSIZE
12868 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12869#endif
12870#ifdef RLIMIT_DATA
12871 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12872#endif
12873#ifdef RLIMIT_STACK
12874 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12875#endif
12876#ifdef RLIMIT_CORE
12877 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12878#endif
12879#ifdef RLIMIT_RSS
12880 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12881#endif
12882#ifdef RLIMIT_MEMLOCK
12883 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12884#endif
12885#ifdef RLIMIT_NPROC
Glenn L McGrath76620622004-01-13 10:19:37 +000012886 { "process", RLIMIT_NPROC, 1, 'p' },
Eric Andersenc470f442003-07-28 09:56:35 +000012887#endif
12888#ifdef RLIMIT_NOFILE
Glenn L McGrath76620622004-01-13 10:19:37 +000012889 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
Eric Andersenc470f442003-07-28 09:56:35 +000012890#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012891#ifdef RLIMIT_AS
12892 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
Eric Andersenc470f442003-07-28 09:56:35 +000012893#endif
Glenn L McGrath76620622004-01-13 10:19:37 +000012894#ifdef RLIMIT_LOCKS
12895 { "locks", RLIMIT_LOCKS, 1, 'w' },
Eric Andersenc470f442003-07-28 09:56:35 +000012896#endif
12897 { (char *) 0, 0, 0, '\0' }
12898};
12899
Glenn L McGrath76620622004-01-13 10:19:37 +000012900enum limtype { SOFT = 0x1, HARD = 0x2 };
12901
12902static void printlim(enum limtype how, const struct rlimit *limit,
12903 const struct limits *l)
12904{
12905 rlim_t val;
12906
12907 val = limit->rlim_max;
12908 if (how & SOFT)
12909 val = limit->rlim_cur;
12910
12911 if (val == RLIM_INFINITY)
12912 out1fmt("unlimited\n");
12913 else {
12914 val /= l->factor;
12915 out1fmt("%lld\n", (long long) val);
12916 }
12917}
12918
Eric Andersenc470f442003-07-28 09:56:35 +000012919int
12920ulimitcmd(int argc, char **argv)
12921{
12922 int c;
12923 rlim_t val = 0;
Glenn L McGrath76620622004-01-13 10:19:37 +000012924 enum limtype how = SOFT | HARD;
Eric Andersenc470f442003-07-28 09:56:35 +000012925 const struct limits *l;
12926 int set, all = 0;
12927 int optc, what;
12928 struct rlimit limit;
12929
12930 what = 'f';
Glenn L McGrath16e45d72004-02-04 08:24:39 +000012931 while ((optc = nextopt("HSa"
12932#ifdef RLIMIT_CPU
12933 "t"
12934#endif
12935#ifdef RLIMIT_FSIZE
12936 "f"
12937#endif
12938#ifdef RLIMIT_DATA
12939 "d"
12940#endif
12941#ifdef RLIMIT_STACK
12942 "s"
12943#endif
12944#ifdef RLIMIT_CORE
12945 "c"
12946#endif
12947#ifdef RLIMIT_RSS
12948 "m"
12949#endif
12950#ifdef RLIMIT_MEMLOCK
12951 "l"
12952#endif
12953#ifdef RLIMIT_NPROC
12954 "p"
12955#endif
12956#ifdef RLIMIT_NOFILE
12957 "n"
12958#endif
12959#ifdef RLIMIT_AS
12960 "v"
12961#endif
12962#ifdef RLIMIT_LOCKS
12963 "w"
12964#endif
12965 )) != '\0')
Eric Andersenc470f442003-07-28 09:56:35 +000012966 switch (optc) {
12967 case 'H':
12968 how = HARD;
12969 break;
12970 case 'S':
12971 how = SOFT;
12972 break;
12973 case 'a':
12974 all = 1;
12975 break;
12976 default:
12977 what = optc;
12978 }
12979
Glenn L McGrath76620622004-01-13 10:19:37 +000012980 for (l = limits; l->option != what; l++)
Eric Andersenc470f442003-07-28 09:56:35 +000012981 ;
Eric Andersenc470f442003-07-28 09:56:35 +000012982
12983 set = *argptr ? 1 : 0;
12984 if (set) {
12985 char *p = *argptr;
12986
12987 if (all || argptr[1])
12988 error("too many arguments");
Eric Andersen81fe1232003-07-29 06:38:40 +000012989 if (strncmp(p, "unlimited\n", 9) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +000012990 val = RLIM_INFINITY;
12991 else {
12992 val = (rlim_t) 0;
12993
12994 while ((c = *p++) >= '0' && c <= '9')
12995 {
12996 val = (val * 10) + (long)(c - '0');
12997 if (val < (rlim_t) 0)
12998 break;
12999 }
13000 if (c)
13001 error("bad number");
13002 val *= l->factor;
13003 }
13004 }
13005 if (all) {
13006 for (l = limits; l->name; l++) {
13007 getrlimit(l->cmd, &limit);
Eric Andersenc470f442003-07-28 09:56:35 +000013008 out1fmt("%-20s ", l->name);
Glenn L McGrath76620622004-01-13 10:19:37 +000013009 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000013010 }
13011 return 0;
13012 }
13013
13014 getrlimit(l->cmd, &limit);
13015 if (set) {
13016 if (how & HARD)
13017 limit.rlim_max = val;
13018 if (how & SOFT)
13019 limit.rlim_cur = val;
13020 if (setrlimit(l->cmd, &limit) < 0)
13021 error("error setting limit (%m)");
13022 } else {
Glenn L McGrath76620622004-01-13 10:19:37 +000013023 printlim(how, &limit, l);
Eric Andersenc470f442003-07-28 09:56:35 +000013024 }
13025 return 0;
13026}
13027
Eric Andersen90898442003-08-06 11:20:52 +000013028
13029#ifdef CONFIG_ASH_MATH_SUPPORT
13030
13031/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
13032
13033 Permission is hereby granted, free of charge, to any person obtaining
13034 a copy of this software and associated documentation files (the
13035 "Software"), to deal in the Software without restriction, including
13036 without limitation the rights to use, copy, modify, merge, publish,
13037 distribute, sublicense, and/or sell copies of the Software, and to
13038 permit persons to whom the Software is furnished to do so, subject to
13039 the following conditions:
13040
13041 The above copyright notice and this permission notice shall be
13042 included in all copies or substantial portions of the Software.
13043
13044 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13045 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13046 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13047 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13048 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13049 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13050 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13051*/
13052
13053/* This is my infix parser/evaluator. It is optimized for size, intended
13054 * as a replacement for yacc-based parsers. However, it may well be faster
Eric Andersenaff114c2004-04-14 17:51:38 +000013055 * than a comparable parser written in yacc. The supported operators are
Eric Andersen90898442003-08-06 11:20:52 +000013056 * listed in #defines below. Parens, order of operations, and error handling
Eric Andersenaff114c2004-04-14 17:51:38 +000013057 * are supported. This code is thread safe. The exact expression format should
Eric Andersen90898442003-08-06 11:20:52 +000013058 * be that which POSIX specifies for shells. */
13059
13060/* The code uses a simple two-stack algorithm. See
13061 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
Eric Andersenaff114c2004-04-14 17:51:38 +000013062 * for a detailed explanation of the infix-to-postfix algorithm on which
Eric Andersen90898442003-08-06 11:20:52 +000013063 * this is based (this code differs in that it applies operators immediately
13064 * to the stack instead of adding them to a queue to end up with an
13065 * expression). */
13066
13067/* To use the routine, call it with an expression string and error return
13068 * pointer */
13069
13070/*
13071 * Aug 24, 2001 Manuel Novoa III
13072 *
13073 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13074 *
13075 * 1) In arith_apply():
13076 * a) Cached values of *numptr and &(numptr[-1]).
13077 * b) Removed redundant test for zero denominator.
13078 *
13079 * 2) In arith():
13080 * a) Eliminated redundant code for processing operator tokens by moving
13081 * to a table-based implementation. Also folded handling of parens
13082 * into the table.
13083 * b) Combined all 3 loops which called arith_apply to reduce generated
13084 * code size at the cost of speed.
13085 *
13086 * 3) The following expressions were treated as valid by the original code:
13087 * 1() , 0! , 1 ( *3 ) .
13088 * These bugs have been fixed by internally enclosing the expression in
13089 * parens and then checking that all binary ops and right parens are
13090 * preceded by a valid expression (NUM_TOKEN).
13091 *
Eric Andersenaff114c2004-04-14 17:51:38 +000013092 * Note: It may be desirable to replace Aaron's test for whitespace with
Eric Andersen90898442003-08-06 11:20:52 +000013093 * ctype's isspace() if it is used by another busybox applet or if additional
13094 * whitespace chars should be considered. Look below the "#include"s for a
13095 * precompiler test.
13096 */
13097
13098/*
13099 * Aug 26, 2001 Manuel Novoa III
13100 *
13101 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13102 *
13103 * Merge in Aaron's comments previously posted to the busybox list,
13104 * modified slightly to take account of my changes to the code.
13105 *
13106 */
13107
13108/*
13109 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13110 *
13111 * - allow access to variable,
13112 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13113 * - realize assign syntax (VAR=expr, +=, *= etc)
13114 * - realize exponentiation (** operator)
13115 * - realize comma separated - expr, expr
13116 * - realise ++expr --expr expr++ expr--
13117 * - realise expr ? expr : expr (but, second expr calculate always)
Eric Andersenaff114c2004-04-14 17:51:38 +000013118 * - allow hexadecimal and octal numbers
Eric Andersen90898442003-08-06 11:20:52 +000013119 * - was restored loses XOR operator
13120 * - remove one goto label, added three ;-)
13121 * - protect $((num num)) as true zero expr (Manuel`s error)
13122 * - always use special isspace(), see comment from bash ;-)
13123 */
13124
13125
13126#define arith_isspace(arithval) \
13127 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13128
13129
13130typedef unsigned char operator;
13131
13132/* An operator's token id is a bit of a bitfield. The lower 5 bits are the
Eric Andersenaff114c2004-04-14 17:51:38 +000013133 * precedence, and 3 high bits are an ID unique across operators of that
Eric Andersen90898442003-08-06 11:20:52 +000013134 * precedence. The ID portion is so that multiple operators can have the
13135 * same precedence, ensuring that the leftmost one is evaluated first.
13136 * Consider * and /. */
13137
13138#define tok_decl(prec,id) (((id)<<5)|(prec))
13139#define PREC(op) ((op) & 0x1F)
13140
13141#define TOK_LPAREN tok_decl(0,0)
13142
13143#define TOK_COMMA tok_decl(1,0)
13144
13145#define TOK_ASSIGN tok_decl(2,0)
13146#define TOK_AND_ASSIGN tok_decl(2,1)
13147#define TOK_OR_ASSIGN tok_decl(2,2)
13148#define TOK_XOR_ASSIGN tok_decl(2,3)
13149#define TOK_PLUS_ASSIGN tok_decl(2,4)
13150#define TOK_MINUS_ASSIGN tok_decl(2,5)
13151#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13152#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13153
13154#define TOK_MUL_ASSIGN tok_decl(3,0)
13155#define TOK_DIV_ASSIGN tok_decl(3,1)
13156#define TOK_REM_ASSIGN tok_decl(3,2)
13157
13158/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13159#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13160
13161/* conditional is right associativity too */
13162#define TOK_CONDITIONAL tok_decl(4,0)
13163#define TOK_CONDITIONAL_SEP tok_decl(4,1)
13164
13165#define TOK_OR tok_decl(5,0)
13166
13167#define TOK_AND tok_decl(6,0)
13168
13169#define TOK_BOR tok_decl(7,0)
13170
13171#define TOK_BXOR tok_decl(8,0)
13172
13173#define TOK_BAND tok_decl(9,0)
13174
13175#define TOK_EQ tok_decl(10,0)
13176#define TOK_NE tok_decl(10,1)
13177
13178#define TOK_LT tok_decl(11,0)
13179#define TOK_GT tok_decl(11,1)
13180#define TOK_GE tok_decl(11,2)
13181#define TOK_LE tok_decl(11,3)
13182
13183#define TOK_LSHIFT tok_decl(12,0)
13184#define TOK_RSHIFT tok_decl(12,1)
13185
13186#define TOK_ADD tok_decl(13,0)
13187#define TOK_SUB tok_decl(13,1)
13188
13189#define TOK_MUL tok_decl(14,0)
13190#define TOK_DIV tok_decl(14,1)
13191#define TOK_REM tok_decl(14,2)
13192
13193/* exponent is right associativity */
13194#define TOK_EXPONENT tok_decl(15,1)
13195
13196/* For now unary operators. */
13197#define UNARYPREC 16
13198#define TOK_BNOT tok_decl(UNARYPREC,0)
13199#define TOK_NOT tok_decl(UNARYPREC,1)
13200
13201#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13202#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13203
13204#define PREC_PRE (UNARYPREC+2)
13205
13206#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13207#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13208
13209#define PREC_POST (UNARYPREC+3)
13210
13211#define TOK_POST_INC tok_decl(PREC_POST, 0)
13212#define TOK_POST_DEC tok_decl(PREC_POST, 1)
13213
13214#define SPEC_PREC (UNARYPREC+4)
13215
13216#define TOK_NUM tok_decl(SPEC_PREC, 0)
13217#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13218
13219#define NUMPTR (*numstackptr)
13220
13221static inline int tok_have_assign(operator op)
13222{
13223 operator prec = PREC(op);
13224
13225 convert_prec_is_assing(prec);
13226 return (prec == PREC(TOK_ASSIGN) ||
13227 prec == PREC_PRE || prec == PREC_POST);
13228}
13229
13230static inline int is_right_associativity(operator prec)
13231{
13232 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13233 prec == PREC(TOK_CONDITIONAL));
13234}
13235
13236
13237typedef struct ARITCH_VAR_NUM {
Eric Andersened9ecf72004-06-22 08:29:45 +000013238 arith_t val;
13239 arith_t contidional_second_val;
Eric Andersen90898442003-08-06 11:20:52 +000013240 char contidional_second_val_initialized;
13241 char *var; /* if NULL then is regular number,
Eric Andersenaff114c2004-04-14 17:51:38 +000013242 else is variable name */
Eric Andersen90898442003-08-06 11:20:52 +000013243} v_n_t;
13244
13245
13246typedef struct CHK_VAR_RECURSIVE_LOOPED {
13247 const char *var;
13248 struct CHK_VAR_RECURSIVE_LOOPED *next;
13249} chk_var_recursive_looped_t;
13250
13251static chk_var_recursive_looped_t *prev_chk_var_recursive;
13252
13253
13254static int arith_lookup_val(v_n_t *t)
13255{
13256 if(t->var) {
13257 const char * p = lookupvar(t->var);
13258
13259 if(p) {
13260 int errcode;
13261
13262 /* recursive try as expression */
13263 chk_var_recursive_looped_t *cur;
13264 chk_var_recursive_looped_t cur_save;
13265
13266 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13267 if(strcmp(cur->var, t->var) == 0) {
13268 /* expression recursion loop detected */
13269 return -5;
13270 }
13271 }
13272 /* save current lookuped var name */
13273 cur = prev_chk_var_recursive;
13274 cur_save.var = t->var;
13275 cur_save.next = cur;
13276 prev_chk_var_recursive = &cur_save;
13277
13278 t->val = arith (p, &errcode);
13279 /* restore previous ptr after recursiving */
13280 prev_chk_var_recursive = cur;
13281 return errcode;
13282 } else {
13283 /* allow undefined var as 0 */
13284 t->val = 0;
13285 }
13286 }
13287 return 0;
13288}
13289
13290/* "applying" a token means performing it on the top elements on the integer
13291 * stack. For a unary operator it will only change the top element, but a
13292 * binary operator will pop two arguments and push a result */
13293static inline int
13294arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13295{
Eric Andersen90898442003-08-06 11:20:52 +000013296 v_n_t *numptr_m1;
Eric Andersenfac312d2004-06-22 20:09:40 +000013297 arith_t numptr_val, rez;
Eric Andersen90898442003-08-06 11:20:52 +000013298 int ret_arith_lookup_val;
13299
13300 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13301 without arguments */
13302 numptr_m1 = NUMPTR - 1;
13303
13304 /* check operand is var with noninteger value */
13305 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13306 if(ret_arith_lookup_val)
13307 return ret_arith_lookup_val;
13308
13309 rez = numptr_m1->val;
13310 if (op == TOK_UMINUS)
13311 rez *= -1;
13312 else if (op == TOK_NOT)
13313 rez = !rez;
13314 else if (op == TOK_BNOT)
13315 rez = ~rez;
13316 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13317 rez++;
13318 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13319 rez--;
13320 else if (op != TOK_UPLUS) {
13321 /* Binary operators */
13322
13323 /* check and binary operators need two arguments */
13324 if (numptr_m1 == numstack) goto err;
13325
13326 /* ... and they pop one */
13327 --NUMPTR;
13328 numptr_val = rez;
13329 if (op == TOK_CONDITIONAL) {
13330 if(! numptr_m1->contidional_second_val_initialized) {
13331 /* protect $((expr1 ? expr2)) without ": expr" */
13332 goto err;
13333 }
13334 rez = numptr_m1->contidional_second_val;
13335 } else if(numptr_m1->contidional_second_val_initialized) {
13336 /* protect $((expr1 : expr2)) without "expr ? " */
13337 goto err;
13338 }
13339 numptr_m1 = NUMPTR - 1;
13340 if(op != TOK_ASSIGN) {
13341 /* check operand is var with noninteger value for not '=' */
13342 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13343 if(ret_arith_lookup_val)
13344 return ret_arith_lookup_val;
13345 }
13346 if (op == TOK_CONDITIONAL) {
13347 numptr_m1->contidional_second_val = rez;
13348 }
13349 rez = numptr_m1->val;
13350 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13351 rez |= numptr_val;
13352 else if (op == TOK_OR)
13353 rez = numptr_val || rez;
13354 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13355 rez &= numptr_val;
13356 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13357 rez ^= numptr_val;
13358 else if (op == TOK_AND)
13359 rez = rez && numptr_val;
13360 else if (op == TOK_EQ)
13361 rez = (rez == numptr_val);
13362 else if (op == TOK_NE)
13363 rez = (rez != numptr_val);
13364 else if (op == TOK_GE)
13365 rez = (rez >= numptr_val);
13366 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13367 rez >>= numptr_val;
13368 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13369 rez <<= numptr_val;
13370 else if (op == TOK_GT)
13371 rez = (rez > numptr_val);
13372 else if (op == TOK_LT)
13373 rez = (rez < numptr_val);
13374 else if (op == TOK_LE)
13375 rez = (rez <= numptr_val);
13376 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13377 rez *= numptr_val;
13378 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13379 rez += numptr_val;
13380 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13381 rez -= numptr_val;
13382 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13383 rez = numptr_val;
13384 else if (op == TOK_CONDITIONAL_SEP) {
13385 if (numptr_m1 == numstack) {
13386 /* protect $((expr : expr)) without "expr ? " */
13387 goto err;
13388 }
13389 numptr_m1->contidional_second_val_initialized = op;
13390 numptr_m1->contidional_second_val = numptr_val;
13391 }
13392 else if (op == TOK_CONDITIONAL) {
13393 rez = rez ?
13394 numptr_val : numptr_m1->contidional_second_val;
13395 }
13396 else if(op == TOK_EXPONENT) {
13397 if(numptr_val < 0)
13398 return -3; /* exponent less than 0 */
13399 else {
Eric Andersenad63cb22004-10-08 09:43:34 +000013400 arith_t c = 1;
Eric Andersen90898442003-08-06 11:20:52 +000013401
13402 if(numptr_val)
13403 while(numptr_val--)
13404 c *= rez;
13405 rez = c;
13406 }
13407 }
13408 else if(numptr_val==0) /* zero divisor check */
13409 return -2;
13410 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13411 rez /= numptr_val;
13412 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13413 rez %= numptr_val;
13414 }
13415 if(tok_have_assign(op)) {
13416 char buf[32];
13417
13418 if(numptr_m1->var == NULL) {
13419 /* Hmm, 1=2 ? */
13420 goto err;
13421 }
13422 /* save to shell variable */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013423#ifdef CONFIG_ASH_MATH_SUPPORT_64
13424 snprintf(buf, sizeof(buf), "%lld", rez);
13425#else
13426 snprintf(buf, sizeof(buf), "%ld", rez);
13427#endif
Eric Andersen90898442003-08-06 11:20:52 +000013428 setvar(numptr_m1->var, buf, 0);
13429 /* after saving, make previous value for v++ or v-- */
13430 if(op == TOK_POST_INC)
13431 rez--;
13432 else if(op == TOK_POST_DEC)
13433 rez++;
13434 }
13435 numptr_m1->val = rez;
13436 /* protect geting var value, is number now */
13437 numptr_m1->var = NULL;
13438 return 0;
13439err: return(-1);
13440}
13441
13442/* longest must first */
13443static const char op_tokens[] = {
13444 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13445 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13446 '<','<', 0, TOK_LSHIFT,
13447 '>','>', 0, TOK_RSHIFT,
13448 '|','|', 0, TOK_OR,
13449 '&','&', 0, TOK_AND,
13450 '!','=', 0, TOK_NE,
13451 '<','=', 0, TOK_LE,
13452 '>','=', 0, TOK_GE,
13453 '=','=', 0, TOK_EQ,
13454 '|','=', 0, TOK_OR_ASSIGN,
13455 '&','=', 0, TOK_AND_ASSIGN,
13456 '*','=', 0, TOK_MUL_ASSIGN,
13457 '/','=', 0, TOK_DIV_ASSIGN,
13458 '%','=', 0, TOK_REM_ASSIGN,
13459 '+','=', 0, TOK_PLUS_ASSIGN,
13460 '-','=', 0, TOK_MINUS_ASSIGN,
13461 '-','-', 0, TOK_POST_DEC,
13462 '^','=', 0, TOK_XOR_ASSIGN,
13463 '+','+', 0, TOK_POST_INC,
13464 '*','*', 0, TOK_EXPONENT,
13465 '!', 0, TOK_NOT,
13466 '<', 0, TOK_LT,
13467 '>', 0, TOK_GT,
13468 '=', 0, TOK_ASSIGN,
13469 '|', 0, TOK_BOR,
13470 '&', 0, TOK_BAND,
13471 '*', 0, TOK_MUL,
13472 '/', 0, TOK_DIV,
13473 '%', 0, TOK_REM,
13474 '+', 0, TOK_ADD,
13475 '-', 0, TOK_SUB,
13476 '^', 0, TOK_BXOR,
13477 /* uniq */
13478 '~', 0, TOK_BNOT,
13479 ',', 0, TOK_COMMA,
13480 '?', 0, TOK_CONDITIONAL,
13481 ':', 0, TOK_CONDITIONAL_SEP,
13482 ')', 0, TOK_RPAREN,
13483 '(', 0, TOK_LPAREN,
13484 0
13485};
13486/* ptr to ")" */
13487#define endexpression &op_tokens[sizeof(op_tokens)-7]
13488
13489
Eric Andersened9ecf72004-06-22 08:29:45 +000013490static arith_t arith (const char *expr, int *perrcode)
Eric Andersen90898442003-08-06 11:20:52 +000013491{
13492 register char arithval; /* Current character under analysis */
13493 operator lasttok, op;
13494 operator prec;
13495
13496 const char *p = endexpression;
13497 int errcode;
13498
13499 size_t datasizes = strlen(expr) + 2;
13500
13501 /* Stack of integers */
13502 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
Eric Andersenaff114c2004-04-14 17:51:38 +000013503 * in any given correct or incorrect expression is left as an exercise to
Eric Andersen90898442003-08-06 11:20:52 +000013504 * the reader. */
13505 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13506 *numstackptr = numstack;
13507 /* Stack of operator tokens */
13508 operator *stack = alloca((datasizes) * sizeof(operator)),
13509 *stackptr = stack;
13510
13511 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13512 *perrcode = errcode = 0;
13513
13514 while(1) {
13515 if ((arithval = *expr) == 0) {
13516 if (p == endexpression) {
13517 /* Null expression. */
13518 return 0;
13519 }
13520
13521 /* This is only reached after all tokens have been extracted from the
13522 * input stream. If there are still tokens on the operator stack, they
13523 * are to be applied in order. At the end, there should be a final
13524 * result on the integer stack */
13525
13526 if (expr != endexpression + 1) {
13527 /* If we haven't done so already, */
13528 /* append a closing right paren */
13529 expr = endexpression;
13530 /* and let the loop process it. */
13531 continue;
13532 }
13533 /* At this point, we're done with the expression. */
13534 if (numstackptr != numstack+1) {
13535 /* ... but if there isn't, it's bad */
13536 err:
13537 return (*perrcode = -1);
13538 }
13539 if(numstack->var) {
13540 /* expression is $((var)) only, lookup now */
13541 errcode = arith_lookup_val(numstack);
13542 }
13543 ret:
13544 *perrcode = errcode;
13545 return numstack->val;
13546 } else {
13547 /* Continue processing the expression. */
13548 if (arith_isspace(arithval)) {
13549 /* Skip whitespace */
13550 goto prologue;
13551 }
13552 if((p = endofname(expr)) != expr) {
Eric Andersenad63cb22004-10-08 09:43:34 +000013553 size_t var_name_size = (p-expr) + 1; /* trailing zero */
Eric Andersen90898442003-08-06 11:20:52 +000013554
13555 numstackptr->var = alloca(var_name_size);
13556 safe_strncpy(numstackptr->var, expr, var_name_size);
13557 expr = p;
13558 num:
13559 numstackptr->contidional_second_val_initialized = 0;
13560 numstackptr++;
13561 lasttok = TOK_NUM;
13562 continue;
13563 } else if (is_digit(arithval)) {
13564 numstackptr->var = NULL;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013565#ifdef CONFIG_ASH_MATH_SUPPORT_64
Eric Andersenad63cb22004-10-08 09:43:34 +000013566 numstackptr->val = strtoll(expr, (char **) &expr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000013567#else
13568 numstackptr->val = strtol(expr, (char **) &expr, 0);
13569#endif
Eric Andersen90898442003-08-06 11:20:52 +000013570 goto num;
13571 }
13572 for(p = op_tokens; ; p++) {
13573 const char *o;
13574
13575 if(*p == 0) {
13576 /* strange operator not found */
13577 goto err;
13578 }
13579 for(o = expr; *p && *o == *p; p++)
13580 o++;
13581 if(! *p) {
13582 /* found */
13583 expr = o - 1;
13584 break;
13585 }
13586 /* skip tail uncompared token */
13587 while(*p)
13588 p++;
13589 /* skip zero delim */
13590 p++;
13591 }
13592 op = p[1];
13593
13594 /* post grammar: a++ reduce to num */
13595 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13596 lasttok = TOK_NUM;
13597
13598 /* Plus and minus are binary (not unary) _only_ if the last
13599 * token was as number, or a right paren (which pretends to be
13600 * a number, since it evaluates to one). Think about it.
13601 * It makes sense. */
13602 if (lasttok != TOK_NUM) {
13603 switch(op) {
13604 case TOK_ADD:
13605 op = TOK_UPLUS;
13606 break;
13607 case TOK_SUB:
13608 op = TOK_UMINUS;
13609 break;
13610 case TOK_POST_INC:
13611 op = TOK_PRE_INC;
13612 break;
13613 case TOK_POST_DEC:
13614 op = TOK_PRE_DEC;
13615 break;
13616 }
13617 }
13618 /* We don't want a unary operator to cause recursive descent on the
13619 * stack, because there can be many in a row and it could cause an
13620 * operator to be evaluated before its argument is pushed onto the
13621 * integer stack. */
13622 /* But for binary operators, "apply" everything on the operator
13623 * stack until we find an operator with a lesser priority than the
13624 * one we have just extracted. */
13625 /* Left paren is given the lowest priority so it will never be
13626 * "applied" in this way.
13627 * if associativity is right and priority eq, applied also skip
13628 */
13629 prec = PREC(op);
13630 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13631 /* not left paren or unary */
13632 if (lasttok != TOK_NUM) {
13633 /* binary op must be preceded by a num */
13634 goto err;
13635 }
13636 while (stackptr != stack) {
13637 if (op == TOK_RPAREN) {
13638 /* The algorithm employed here is simple: while we don't
13639 * hit an open paren nor the bottom of the stack, pop
13640 * tokens and apply them */
13641 if (stackptr[-1] == TOK_LPAREN) {
13642 --stackptr;
13643 /* Any operator directly after a */
13644 lasttok = TOK_NUM;
13645 /* close paren should consider itself binary */
13646 goto prologue;
13647 }
13648 } else {
13649 operator prev_prec = PREC(stackptr[-1]);
13650
13651 convert_prec_is_assing(prec);
13652 convert_prec_is_assing(prev_prec);
13653 if (prev_prec < prec)
13654 break;
13655 /* check right assoc */
13656 if(prev_prec == prec && is_right_associativity(prec))
13657 break;
13658 }
13659 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13660 if(errcode) goto ret;
13661 }
13662 if (op == TOK_RPAREN) {
13663 goto err;
13664 }
13665 }
13666
13667 /* Push this operator to the stack and remember it. */
13668 *stackptr++ = lasttok = op;
13669
13670 prologue:
13671 ++expr;
13672 }
13673 }
13674}
13675#endif /* CONFIG_ASH_MATH_SUPPORT */
13676
13677
Eric Andersenc470f442003-07-28 09:56:35 +000013678#ifdef DEBUG
13679const char *bb_applet_name = "debug stuff usage";
13680int main(int argc, char **argv)
13681{
13682 return ash_main(argc, argv);
13683}
13684#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013685
Eric Andersendf82f612001-06-28 07:46:40 +000013686/*-
13687 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013688 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013689 *
13690 * This code is derived from software contributed to Berkeley by
13691 * Kenneth Almquist.
13692 *
13693 * Redistribution and use in source and binary forms, with or without
13694 * modification, are permitted provided that the following conditions
13695 * are met:
13696 * 1. Redistributions of source code must retain the above copyright
13697 * notice, this list of conditions and the following disclaimer.
13698 * 2. Redistributions in binary form must reproduce the above copyright
13699 * notice, this list of conditions and the following disclaimer in the
13700 * documentation and/or other materials provided with the distribution.
13701 *
Eric Andersen2870d962001-07-02 17:27:21 +000013702 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13703 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013704 *
13705 * 4. Neither the name of the University nor the names of its contributors
13706 * may be used to endorse or promote products derived from this software
13707 * without specific prior written permission.
13708 *
13709 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13710 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13711 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13712 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13713 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13714 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13715 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13716 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13717 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13718 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13719 * SUCH DAMAGE.
13720 */