Remove vodz from credits, per his request
[oweals/busybox.git] / shell / ash.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * ash shell port for busybox
4  *
5  * Copyright (c) 1989, 1991, 1993, 1994
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Kenneth Almquist.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  *
25  * This version of ash is adapted from the source in Debian's ash 0.3.8-5 
26  * package.  
27  *
28  * Modified by Erik Andersen <andersee@debian.org> to be used in busybox.
29  *
30  * Original copyright notice is retained at the end of this file.
31  */
32
33 #undef _GNU_SOURCE
34 #undef ASH_TYPE
35 #undef ASH_GETOPTS
36 #undef ASH_MATH_SUPPORT
37 #undef FNMATCH_BROKEN
38 #undef GLOB_BROKEN
39
40 #include <assert.h>
41 #include <ctype.h>
42 #include <dirent.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <limits.h>
46 #include <paths.h>
47 #include <pwd.h>
48 #include <setjmp.h>
49 #include <signal.h>
50 #include <stdarg.h>
51 #include <stdbool.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <sysexits.h>
56 #include <unistd.h>
57 #include <sys/stat.h>
58 #include <sys/cdefs.h>
59 #include <sys/ioctl.h>
60 #include <sys/param.h>
61 #include <sys/resource.h>
62 #include <sys/time.h>
63 #include <sys/times.h>
64 #include <sys/types.h>
65 #include <sys/wait.h>
66
67
68 #if !defined(FNMATCH_BROKEN)
69 #include <fnmatch.h>
70 #endif
71 #if !defined(GLOB_BROKEN)
72 #include <glob.h>
73 #endif
74
75 #if JOBS
76 #include <termios.h>
77 #undef CEOF                     /* syntax.h redefines this */
78 #endif
79
80 #include "cmdedit.h"
81 #include "busybox.h"
82 #include "ash.h"
83
84
85 #define _DIAGASSERT(x)
86
87 #define ATABSIZE 39
88
89 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
90 #define S_CATCH 2               /* signal is caught */
91 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
92 #define S_HARD_IGN 4            /* signal is ignored permenantly */
93 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
94
95
96
97 struct alias *atab[ATABSIZE];
98
99 static void setalias __P((char *, char *));
100 static struct alias **hashalias __P((const char *));
101 static struct alias *freealias __P((struct alias *));
102 static struct alias **__lookupalias __P((const char *));
103 static char *trap[NSIG];                /* trap handler commands */
104 static char sigmode[NSIG - 1];  /* current value of signal */
105 static char gotsig[NSIG - 1];           /* indicates specified signal received */
106 static int pendingsigs;                 /* indicates some signal received */
107
108
109 static void
110 setalias(name, val)
111         char *name, *val;
112 {
113         struct alias *ap, **app;
114
115         app = __lookupalias(name);
116         ap = *app;
117         INTOFF;
118         if (ap) {
119                 if (!(ap->flag & ALIASINUSE)) {
120                         ckfree(ap->val);
121                 }
122                 ap->val = savestr(val);
123                 ap->flag &= ~ALIASDEAD;
124         } else {
125                 /* not found */
126                 ap = ckmalloc(sizeof (struct alias));
127                 ap->name = savestr(name);
128                 ap->val = savestr(val);
129                 ap->flag = 0;
130                 ap->next = 0;
131                 *app = ap;
132         }
133         INTON;
134 }
135
136 static int
137 unalias(name)
138         char *name;
139         {
140         struct alias **app;
141
142         app = __lookupalias(name);
143
144         if (*app) {
145                 INTOFF;
146                 *app = freealias(*app);
147                 INTON;
148                 return (0);
149         }
150
151         return (1);
152 }
153
154 #ifdef mkinit
155 static void rmaliases __P((void));
156
157 SHELLPROC {
158         rmaliases();
159 }
160 #endif
161
162 static void
163 rmaliases() {
164         struct alias *ap, **app;
165         int i;
166
167         INTOFF;
168         for (i = 0; i < ATABSIZE; i++) {
169                 app = &atab[i];
170                 for (ap = *app; ap; ap = *app) {
171                         *app = freealias(*app);
172                         if (ap == *app) {
173                                 app = &ap->next;
174                         }
175                 }
176         }
177         INTON;
178 }
179
180 struct alias *
181 lookupalias(name, check)
182         const char *name;
183         int check;
184 {
185         struct alias *ap = *__lookupalias(name);
186
187         if (check && ap && (ap->flag & ALIASINUSE))
188                 return (NULL);
189         return (ap);
190 }
191
192
193 /*
194  * TODO - sort output
195  */
196 static int
197 aliascmd(argc, argv)
198         int argc;
199         char **argv;
200 {
201         char *n, *v;
202         int ret = 0;
203         struct alias *ap;
204
205         if (argc == 1) {
206                 int i;
207
208                 for (i = 0; i < ATABSIZE; i++)
209                         for (ap = atab[i]; ap; ap = ap->next) {
210                                 printalias(ap);
211                         }
212                 return (0);
213         }
214         while ((n = *++argv) != NULL) {
215                 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
216                         if ((ap = *__lookupalias(n)) == NULL) {
217                                 outfmt(out2, "%s: %s not found\n", "alias", n);
218                                 ret = 1;
219                         } else
220                                 printalias(ap);
221                 }
222                 else {
223                         *v++ = '\0';
224                         setalias(n, v);
225                 }
226         }
227
228         return (ret);
229 }
230
231 static int
232 unaliascmd(argc, argv)
233         int argc;
234         char **argv;
235 {
236         int i;
237
238         while ((i = nextopt("a")) != '\0') {
239                 if (i == 'a') {
240                         rmaliases();
241                         return (0);
242                 }
243         }
244         for (i = 0; *argptr; argptr++) {
245                 if (unalias(*argptr)) {
246                         outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
247                         i = 1;
248                 }
249         }
250
251         return (i);
252 }
253
254 static struct alias **
255 hashalias(p)
256         const char *p;
257         {
258         unsigned int hashval;
259
260         hashval = *p << 4;
261         while (*p)
262                 hashval+= *p++;
263         return &atab[hashval % ATABSIZE];
264 }
265
266 static struct alias *
267 freealias(struct alias *ap) {
268         struct alias *next;
269
270         if (ap->flag & ALIASINUSE) {
271                 ap->flag |= ALIASDEAD;
272                 return ap;
273         }
274
275         next = ap->next;
276         ckfree(ap->name);
277         ckfree(ap->val);
278         ckfree(ap);
279         return next;
280 }
281
282 static void
283 printalias(const struct alias *ap) {
284         char *p;
285
286         p = single_quote(ap->val);
287         out1fmt("alias %s=%s\n", ap->name, p);
288         stunalloc(p);
289 }
290
291 static struct alias **
292 __lookupalias(const char *name) {
293         struct alias **app = hashalias(name);
294
295         for (; *app; app = &(*app)->next) {
296                 if (equal(name, (*app)->name)) {
297                         break;
298                 }
299         }
300
301         return app;
302 }
303
304 #ifdef ASH_MATH_SUPPORT
305 /* The generated file arith.c has been snipped.  If you want this
306  * stuff back in, feel free to add it to your own copy.  */
307 #endif
308
309 /*
310  * This file was generated by the mkbuiltins program.
311  */
312
313 static int bgcmd __P((int, char **));
314 static int breakcmd __P((int, char **));
315 static int cdcmd __P((int, char **));
316 static int commandcmd __P((int, char **));
317 static int dotcmd __P((int, char **));
318 static int evalcmd __P((int, char **));
319 static int execcmd __P((int, char **));
320 static int exitcmd __P((int, char **));
321 static int exportcmd __P((int, char **));
322 static int histcmd __P((int, char **));
323 static int fgcmd __P((int, char **));
324 static int hashcmd __P((int, char **));
325 static int jobscmd __P((int, char **));
326 static int killcmd __P((int, char **));
327 static int localcmd __P((int, char **));
328 static int pwdcmd __P((int, char **));
329 static int readcmd __P((int, char **));
330 static int returncmd __P((int, char **));
331 static int setcmd __P((int, char **));
332 static int setvarcmd __P((int, char **));
333 static int shiftcmd __P((int, char **));
334 static int trapcmd __P((int, char **));
335 static int umaskcmd __P((int, char **));
336 static int unaliascmd __P((int, char **));
337 static int unsetcmd __P((int, char **));
338 static int waitcmd __P((int, char **));
339 static int aliascmd __P((int, char **));
340 static int ulimitcmd __P((int, char **));
341 static int timescmd __P((int, char **));
342 #ifdef ASH_MATH_SUPPORT
343 static int expcmd __P((int, char **));
344 #endif
345 #ifdef ASH_TYPE
346 static int typecmd __P((int, char **));
347 #endif
348 #ifdef ASH_GETOPTS
349 static int getoptscmd __P((int, char **));
350 #endif
351 #ifndef BB_TRUE_FALSE
352 static int true_main __P((int, char **));
353 static int false_main __P((int, char **));
354 #endif
355
356 static struct builtincmd *DOTCMD;
357 static struct builtincmd *BLTINCMD;
358 static struct builtincmd *COMMANDCMD;
359 static struct builtincmd *EXECCMD;
360 static struct builtincmd *EVALCMD;
361
362 /* It is CRUCIAL that this listing be kept in ascii order, otherwise
363  * the binary search in find_builtin() will stop working. If you value
364  * your kneecaps, you'll be sure to *make sure* that any changes made
365  * to this array result in the listing remaining in ascii order. You
366  * have been warned.
367  */
368 static const struct builtincmd builtincmds[] = {
369         { ".", dotcmd, 1 },
370         { ":", true_main, 1 },
371         { "alias", aliascmd, 6 },
372         { "bg", bgcmd, 2 },
373         { "break", breakcmd, 1 },
374         { "builtin", bltincmd, 1 },
375         { "cd", cdcmd, 2 },
376         { "chdir", cdcmd, 0 },
377         { "command", commandcmd, 2 },
378         { "continue", breakcmd, 1 },
379         { "eval", evalcmd, 1 },
380         { "exec", execcmd, 1 },
381         { "exit", exitcmd, 1 },
382 #ifdef ASH_MATH_SUPPORT
383         { "exp", expcmd, 0 },
384 #endif
385         { "export", exportcmd, 5 },
386         { "false", false_main, 2 },
387         { "fc", histcmd, 2 },
388         { "fg", fgcmd, 2 },
389 #ifdef ASH_GETOPTS
390         { "getopts", getoptscmd, 2 },
391 #endif  
392         { "hash", hashcmd, 0 },
393         { "jobs", jobscmd, 2 },
394         { "kill", killcmd, 2 },
395 #ifdef ASH_MATH_SUPPORT
396         { "let", expcmd, 0 },
397 #endif
398         { "local", localcmd, 4 },
399         { "pwd", pwdcmd, 0 },
400         { "read", readcmd, 2 },
401         { "readonly", exportcmd, 5 },
402         { "return", returncmd, 1 },
403         { "set", setcmd, 1 },
404         { "setvar", setvarcmd, 0 },
405         { "shift", shiftcmd, 1 },
406         { "times", timescmd, 1 },
407         { "trap", trapcmd, 1 },
408         { "true", true_main, 2 },
409 #ifdef ASH_TYPE
410         { "type", typecmd, 0 },
411 #endif
412         { "ulimit", ulimitcmd, 0 },
413         { "umask", umaskcmd, 2 },
414         { "unalias", unaliascmd, 2 },
415         { "unset", unsetcmd, 1 },
416         { "wait", waitcmd, 2 },
417 };
418 #define NUMBUILTINS  (sizeof (builtincmds) / sizeof (struct builtincmd) )
419
420
421 /*      $NetBSD: cd.c,v 1.27 1999/07/09 03:05:49 christos Exp $ */
422
423 static int docd __P((char *, int));
424 static char *getcomponent __P((void));
425 static void updatepwd __P((char *));
426 static void getpwd __P((void));
427
428 static char *curdir = nullstr;          /* current working directory */
429 static char *cdcomppath;
430
431 #ifdef mkinit
432 INCLUDE "cd.h"
433 INIT {
434         setpwd(0, 0);
435 }
436 #endif
437
438 static int
439 cdcmd(argc, argv)
440         int argc;
441         char **argv;
442 {
443         const char *dest;
444         const char *path;
445         char *p;
446         struct stat statb;
447         int print = 0;
448
449         nextopt(nullstr);
450         if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
451                 error("HOME not set");
452         if (*dest == '\0')
453                 dest = ".";
454         if (dest[0] == '-' && dest[1] == '\0') {
455                 dest = bltinlookup("OLDPWD");
456                 if (!dest || !*dest) {
457                         dest = curdir;
458                 }
459                 print = 1;
460                 if (dest)
461                         print = 1;
462                 else
463                         dest = ".";
464         }
465         if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
466                 path = nullstr;
467         while ((p = padvance(&path, dest)) != NULL) {
468                 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
469                         if (!print) {
470                                 /*
471                                  * XXX - rethink
472                                  */
473                                 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
474                                         p += 2;
475                                 print = strcmp(p, dest);
476                         }
477                         if (docd(p, print) >= 0)
478                                 return 0;
479
480                 }
481         }
482         error("can't cd to %s", dest);
483         /* NOTREACHED */
484 }
485
486
487 /*
488  * Actually do the chdir.  In an interactive shell, print the
489  * directory name if "print" is nonzero.
490  */
491
492 static int
493 docd(dest, print)
494         char *dest;
495         int print;
496 {
497         char *p;
498         char *q;
499         char *component;
500         struct stat statb;
501         int first;
502         int badstat;
503
504         TRACE(("docd(\"%s\", %d) called\n", dest, print));
505
506         /*
507          *  Check each component of the path. If we find a symlink or
508          *  something we can't stat, clear curdir to force a getcwd()
509          *  next time we get the value of the current directory.
510          */
511         badstat = 0;
512         cdcomppath = sstrdup(dest);
513         STARTSTACKSTR(p);
514         if (*dest == '/') {
515                 STPUTC('/', p);
516                 cdcomppath++;
517         }
518         first = 1;
519         while ((q = getcomponent()) != NULL) {
520                 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
521                         continue;
522                 if (! first)
523                         STPUTC('/', p);
524                 first = 0;
525                 component = q;
526                 while (*q)
527                         STPUTC(*q++, p);
528                 if (equal(component, ".."))
529                         continue;
530                 STACKSTRNUL(p);
531                 if ((lstat(stackblock(), &statb) < 0)
532                     || (S_ISLNK(statb.st_mode)))  {
533                         /* print = 1; */
534                         badstat = 1;
535                         break;
536                 }
537         }
538
539         INTOFF;
540         if (chdir(dest) < 0) {
541                 INTON;
542                 return -1;
543         }
544         updatepwd(badstat ? NULL : dest);
545         INTON;
546         if (print && iflag)
547                 out1fmt(snlfmt, curdir);
548         return 0;
549 }
550
551
552 /*
553  * Get the next component of the path name pointed to by cdcomppath.
554  * This routine overwrites the string pointed to by cdcomppath.
555  */
556
557 static char *
558 getcomponent() {
559         char *p;
560         char *start;
561
562         if ((p = cdcomppath) == NULL)
563                 return NULL;
564         start = cdcomppath;
565         while (*p != '/' && *p != '\0')
566                 p++;
567         if (*p == '\0') {
568                 cdcomppath = NULL;
569         } else {
570                 *p++ = '\0';
571                 cdcomppath = p;
572         }
573         return start;
574 }
575
576
577
578 /*
579  * Update curdir (the name of the current directory) in response to a
580  * cd command.  We also call hashcd to let the routines in exec.c know
581  * that the current directory has changed.
582  */
583
584 static void
585 updatepwd(dir)
586         char *dir;
587         {
588         char *new;
589         char *p;
590         size_t len;
591
592         hashcd();                               /* update command hash table */
593
594         /*
595          * If our argument is NULL, we don't know the current directory
596          * any more because we traversed a symbolic link or something
597          * we couldn't stat().
598          */
599         if (dir == NULL || curdir == nullstr)  {
600                 setpwd(0, 1);
601                 return;
602         }
603         len = strlen(dir);
604         cdcomppath = sstrdup(dir);
605         STARTSTACKSTR(new);
606         if (*dir != '/') {
607                 p = curdir;
608                 while (*p)
609                         STPUTC(*p++, new);
610                 if (p[-1] == '/')
611                         STUNPUTC(new);
612         }
613         while ((p = getcomponent()) != NULL) {
614                 if (equal(p, "..")) {
615                         while (new > stackblock() && (STUNPUTC(new), *new) != '/');
616                 } else if (*p != '\0' && ! equal(p, ".")) {
617                         STPUTC('/', new);
618                         while (*p)
619                                 STPUTC(*p++, new);
620                 }
621         }
622         if (new == stackblock())
623                 STPUTC('/', new);
624         STACKSTRNUL(new);
625         setpwd(stackblock(), 1);
626 }
627
628
629
630 static int
631 pwdcmd(argc, argv)
632         int argc;
633         char **argv;
634 {
635         out1fmt(snlfmt, curdir);
636         return 0;
637 }
638
639
640
641
642 #define MAXPWD 256
643
644 /*
645  * Find out what the current directory is. If we already know the current
646  * directory, this routine returns immediately.
647  */
648 static void
649 getpwd()
650 {
651         char buf[MAXPWD];
652
653         /*
654          * Things are a bit complicated here; we could have just used
655          * getcwd, but traditionally getcwd is implemented using popen
656          * to /bin/pwd. This creates a problem for us, since we cannot
657          * keep track of the job if it is being ran behind our backs.
658          * So we re-implement getcwd(), and we suppress interrupts
659          * throughout the process. This is not completely safe, since
660          * the user can still break out of it by killing the pwd program.
661          * We still try to use getcwd for systems that we know have a
662          * c implementation of getcwd, that does not open a pipe to
663          * /bin/pwd.
664          */
665 #if defined(__NetBSD__) || defined(__SVR4) || defined(__GLIBC__)
666                 
667         if (getcwd(buf, sizeof(buf)) == NULL) {
668                 char *pwd = getenv("PWD");
669                 struct stat stdot, stpwd;
670
671                 if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
672                     stat(pwd, &stpwd) != -1 &&
673                     stdot.st_dev == stpwd.st_dev &&
674                     stdot.st_ino == stpwd.st_ino) {
675                         curdir = savestr(pwd);
676                         return;
677                 }
678                 error("getcwd() failed: %s", strerror(errno));
679         }
680         curdir = savestr(buf);
681 #else
682         {
683                 char *p;
684                 int i;
685                 int status;
686                 struct job *jp;
687                 int pip[2];
688
689                 if (pipe(pip) < 0)
690                         error("Pipe call failed");
691                 jp = makejob((union node *)NULL, 1);
692                 if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
693                         (void) close(pip[0]);
694                         if (pip[1] != 1) {
695                                 close(1);
696                                 dup_as_newfd(pip[1], 1);
697                                 close(pip[1]);
698                         }
699                         (void) execl("/bin/pwd", "pwd", (char *)0);
700                         error("Cannot exec /bin/pwd");
701                 }
702                 (void) close(pip[1]);
703                 pip[1] = -1;
704                 p = buf;
705                 while ((i = read(pip[0], p, buf + MAXPWD - p)) > 0
706                      || (i == -1 && errno == EINTR)) {
707                         if (i > 0)
708                                 p += i;
709                 }
710                 (void) close(pip[0]);
711                 pip[0] = -1;
712                 status = waitforjob(jp);
713                 if (status != 0)
714                         error((char *)0);
715                 if (i < 0 || p == buf || p[-1] != '\n')
716                         error("pwd command failed");
717                 p[-1] = '\0';
718         }
719         curdir = savestr(buf);
720 #endif
721 }
722
723 static void
724 setpwd(const char *val, int setold)
725 {
726         if (setold) {
727                 setvar("OLDPWD", curdir, VEXPORT);
728         }
729         INTOFF;
730         if (curdir != nullstr) {
731                 free(curdir);
732                 curdir = nullstr;
733         }
734         if (!val) {
735                 getpwd();
736         } else {
737                 curdir = savestr(val);
738         }
739         INTON;
740         setvar("PWD", curdir, VEXPORT);
741 }
742
743 /*      $NetBSD: error.c,v 1.23 2000/07/03 03:26:19 matt Exp $  */
744
745 /*
746  * Errors and exceptions.
747  */
748
749 /*
750  * Code to handle exceptions in C.
751  */
752
753 struct jmploc *handler;
754 static int exception;
755 volatile int suppressint;
756 volatile int intpending;
757
758
759 static void exverror __P((int, const char *, va_list))
760     __attribute__((__noreturn__));
761
762 /*
763  * Called to raise an exception.  Since C doesn't include exceptions, we
764  * just do a longjmp to the exception handler.  The type of exception is
765  * stored in the global variable "exception".
766  */
767
768 static void
769 exraise(e)
770         int e;
771 {
772 #ifdef DEBUG
773         if (handler == NULL)
774                 abort();
775 #endif
776         exception = e;
777         longjmp(handler->loc, 1);
778 }
779
780
781 /*
782  * Called from trap.c when a SIGINT is received.  (If the user specifies
783  * that SIGINT is to be trapped or ignored using the trap builtin, then
784  * this routine is not called.)  Suppressint is nonzero when interrupts
785  * are held using the INTOFF macro.  The call to _exit is necessary because
786  * there is a short period after a fork before the signal handlers are
787  * set to the appropriate value for the child.  (The test for iflag is
788  * just defensive programming.)
789  */
790
791 static void
792 onint() {
793         sigset_t mysigset;
794
795         if (suppressint) {
796                 intpending++;
797                 return;
798         }
799         intpending = 0;
800         sigemptyset(&mysigset);
801         sigprocmask(SIG_SETMASK, &mysigset, NULL);
802         if (rootshell && iflag)
803                 exraise(EXINT);
804         else {
805                 signal(SIGINT, SIG_DFL);
806                 raise(SIGINT);
807         }
808         /* NOTREACHED */
809 }
810
811
812 /*
813  * Exverror is called to raise the error exception.  If the first argument
814  * is not NULL then error prints an error message using printf style
815  * formatting.  It then raises the error exception.
816  */
817 static void
818 exverror(cond, msg, ap)
819         int cond;
820         const char *msg;
821         va_list ap;
822 {
823         CLEAR_PENDING_INT;
824         INTOFF;
825
826 #ifdef DEBUG
827         if (msg)
828                 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
829         else
830                 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
831 #endif
832         if (msg) {
833                 if (commandname)
834                         outfmt(&errout, "%s: ", commandname);
835                 doformat(&errout, msg, ap);
836 #if FLUSHERR
837                 outc('\n', &errout);
838 #else
839                 outcslow('\n', &errout);
840 #endif
841         }
842         flushall();
843         exraise(cond);
844         /* NOTREACHED */
845 }
846
847
848 #ifdef __STDC__
849 static void
850 error(const char *msg, ...)
851 #else
852 static void
853 error(va_alist)
854         va_dcl
855 #endif
856 {
857 #ifndef __STDC__
858         const char *msg;
859 #endif
860         va_list ap;
861 #ifdef __STDC__
862         va_start(ap, msg);
863 #else
864         va_start(ap);
865         msg = va_arg(ap, const char *);
866 #endif
867         exverror(EXERROR, msg, ap);
868         /* NOTREACHED */
869         va_end(ap);
870 }
871
872
873 #ifdef __STDC__
874 static void
875 exerror(int cond, const char *msg, ...)
876 #else
877 static void
878 exerror(va_alist)
879         va_dcl
880 #endif
881 {
882 #ifndef __STDC__
883         int cond;
884         const char *msg;
885 #endif
886         va_list ap;
887 #ifdef __STDC__
888         va_start(ap, msg);
889 #else
890         va_start(ap);
891         cond = va_arg(ap, int);
892         msg = va_arg(ap, const char *);
893 #endif
894         exverror(cond, msg, ap);
895         /* NOTREACHED */
896         va_end(ap);
897 }
898
899
900
901 /*
902  * Table of error messages.
903  */
904
905 struct errname {
906         short errcode;          /* error number */
907         short action;           /* operation which encountered the error */
908         const char *msg;        /* text describing the error */
909 };
910
911
912 #define ALL (E_OPEN|E_CREAT|E_EXEC)
913
914 static const struct errname errormsg[] = {
915         { EINTR,        ALL,    "interrupted" },
916         { EACCES,       ALL,    "permission denied" },
917         { EIO,          ALL,    "I/O error" },
918         { ENOENT,       E_OPEN, "no such file" },
919         { ENOENT,       E_CREAT,"directory nonexistent" },
920         { ENOENT,       E_EXEC, "not found" },
921         { ENOTDIR,      E_OPEN, "no such file" },
922         { ENOTDIR,      E_CREAT,"directory nonexistent" },
923         { ENOTDIR,      E_EXEC, "not found" },
924         { EISDIR,       ALL,    "is a directory" },
925         { EEXIST,       E_CREAT,"file exists" },
926 #ifdef notdef
927         { EMFILE,       ALL,    "too many open files" },
928 #endif
929         { ENFILE,       ALL,    "file table overflow" },
930         { ENOSPC,       ALL,    "file system full" },
931 #ifdef EDQUOT
932         { EDQUOT,       ALL,    "disk quota exceeded" },
933 #endif
934 #ifdef ENOSR
935         { ENOSR,        ALL,    "no streams resources" },
936 #endif
937         { ENXIO,        ALL,    "no such device or address" },
938         { EROFS,        ALL,    "read-only file system" },
939         { ETXTBSY,      ALL,    "text busy" },
940 #ifdef SYSV
941         { EAGAIN,       E_EXEC, "not enough memory" },
942 #endif
943         { ENOMEM,       ALL,    "not enough memory" },
944 #ifdef ENOLINK
945         { ENOLINK,      ALL,    "remote access failed" },
946 #endif
947 #ifdef EMULTIHOP
948         { EMULTIHOP,    ALL,    "remote access failed" },
949 #endif
950 #ifdef ECOMM
951         { ECOMM,        ALL,    "remote access failed" },
952 #endif
953 #ifdef ESTALE
954         { ESTALE,       ALL,    "remote access failed" },
955 #endif
956 #ifdef ETIMEDOUT
957         { ETIMEDOUT,    ALL,    "remote access failed" },
958 #endif
959 #ifdef ELOOP
960         { ELOOP,        ALL,    "symbolic link loop" },
961 #endif
962         { E2BIG,        E_EXEC, "argument list too long" },
963 #ifdef ELIBACC
964         { ELIBACC,      E_EXEC, "shared library missing" },
965 #endif
966         { 0,            0,      NULL },
967 };
968
969
970 /*
971  * Return a string describing an error.  The returned string may be a
972  * pointer to a static buffer that will be overwritten on the next call.
973  * Action describes the operation that got the error.
974  */
975
976 static const char *
977 errmsg(e, action)
978         int e;
979         int action;
980 {
981         struct errname const *ep;
982         static char buf[12];
983
984         for (ep = errormsg ; ep->errcode ; ep++) {
985                 if (ep->errcode == e && (ep->action & action) != 0)
986                         return ep->msg;
987         }
988         fmtstr(buf, sizeof buf, "error %d", e);
989         return buf;
990 }
991
992
993 #ifdef REALLY_SMALL
994 static void
995 __inton() {
996         if (--suppressint == 0 && intpending) {
997                 onint();
998         }
999 }
1000 #endif
1001 /*      $NetBSD: eval.c,v 1.57 2001/02/04 19:52:06 christos Exp $       */
1002
1003
1004 /* flags in argument to evaltree */
1005 #define EV_EXIT 01              /* exit after evaluating tree */
1006 #define EV_TESTED 02            /* exit status is checked; ignore -e flag */
1007 #define EV_BACKCMD 04           /* command executing within back quotes */
1008
1009 static int evalskip;                    /* set if we are skipping commands */
1010 static int skipcount;           /* number of levels to skip */
1011 static int loopnest;            /* current loop nesting level */
1012 static int funcnest;                    /* depth of function calls */
1013
1014
1015 static char *commandname;
1016 struct strlist *cmdenviron;
1017 static int exitstatus;                  /* exit status of last command */
1018 static int oexitstatus;         /* saved exit status */
1019
1020
1021 static void evalloop __P((union node *, int));
1022 static void evalfor __P((union node *, int));
1023 static void evalcase __P((union node *, int));
1024 static void evalsubshell __P((union node *, int));
1025 static void expredir __P((union node *));
1026 static void evalpipe __P((union node *));
1027 #ifdef notyet
1028 static void evalcommand __P((union node *, int, struct backcmd *));
1029 #else
1030 static void evalcommand __P((union node *, int));
1031 #endif
1032 static void prehash __P((union node *));
1033 static void eprintlist __P((struct strlist *));
1034
1035
1036 /*
1037  * Called to reset things after an exception.
1038  */
1039
1040 #ifdef mkinit
1041 INCLUDE "eval.h"
1042
1043 RESET {
1044         evalskip = 0;
1045         loopnest = 0;
1046         funcnest = 0;
1047 }
1048
1049 SHELLPROC {
1050         exitstatus = 0;
1051 }
1052 #endif
1053
1054
1055
1056 /*
1057  * The eval commmand.
1058  */
1059
1060 static int
1061 evalcmd(argc, argv)
1062         int argc;
1063         char **argv;
1064 {
1065         char *p;
1066         char *concat;
1067         char **ap;
1068
1069         if (argc > 1) {
1070                 p = argv[1];
1071                 if (argc > 2) {
1072                         STARTSTACKSTR(concat);
1073                         ap = argv + 2;
1074                         for (;;) {
1075                                 while (*p)
1076                                         STPUTC(*p++, concat);
1077                                 if ((p = *ap++) == NULL)
1078                                         break;
1079                                 STPUTC(' ', concat);
1080                         }
1081                         STPUTC('\0', concat);
1082                         p = grabstackstr(concat);
1083                 }
1084                 evalstring(p, EV_TESTED);
1085         }
1086         return exitstatus;
1087 }
1088
1089
1090 /*
1091  * Execute a command or commands contained in a string.
1092  */
1093
1094 static void
1095 evalstring(s, flag)
1096         char *s;
1097         int flag;
1098         {
1099         union node *n;
1100         struct stackmark smark;
1101
1102         setstackmark(&smark);
1103         setinputstring(s);
1104         while ((n = parsecmd(0)) != NEOF) {
1105                 evaltree(n, flag);
1106                 popstackmark(&smark);
1107         }
1108         popfile();
1109         popstackmark(&smark);
1110 }
1111
1112
1113
1114 /*
1115  * Evaluate a parse tree.  The value is left in the global variable
1116  * exitstatus.
1117  */
1118
1119 static void
1120 evaltree(n, flags)
1121         union node *n;
1122         int flags;
1123 {
1124         int checkexit = 0;
1125         if (n == NULL) {
1126                 TRACE(("evaltree(NULL) called\n"));
1127                 goto out;
1128         }
1129         TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
1130         switch (n->type) {
1131         case NSEMI:
1132                 evaltree(n->nbinary.ch1, flags & EV_TESTED);
1133                 if (evalskip)
1134                         goto out;
1135                 evaltree(n->nbinary.ch2, flags);
1136                 break;
1137         case NAND:
1138                 evaltree(n->nbinary.ch1, EV_TESTED);
1139                 if (evalskip || exitstatus != 0)
1140                         goto out;
1141                 evaltree(n->nbinary.ch2, flags);
1142                 break;
1143         case NOR:
1144                 evaltree(n->nbinary.ch1, EV_TESTED);
1145                 if (evalskip || exitstatus == 0)
1146                         goto out;
1147                 evaltree(n->nbinary.ch2, flags);
1148                 break;
1149         case NREDIR:
1150                 expredir(n->nredir.redirect);
1151                 redirect(n->nredir.redirect, REDIR_PUSH);
1152                 evaltree(n->nredir.n, flags);
1153                 popredir();
1154                 break;
1155         case NSUBSHELL:
1156                 evalsubshell(n, flags);
1157                 break;
1158         case NBACKGND:
1159                 evalsubshell(n, flags);
1160                 break;
1161         case NIF: {
1162                 evaltree(n->nif.test, EV_TESTED);
1163                 if (evalskip)
1164                         goto out;
1165                 if (exitstatus == 0)
1166                         evaltree(n->nif.ifpart, flags);
1167                 else if (n->nif.elsepart)
1168                         evaltree(n->nif.elsepart, flags);
1169                 else
1170                         exitstatus = 0;
1171                 break;
1172         }
1173         case NWHILE:
1174         case NUNTIL:
1175                 evalloop(n, flags);
1176                 break;
1177         case NFOR:
1178                 evalfor(n, flags);
1179                 break;
1180         case NCASE:
1181                 evalcase(n, flags);
1182                 break;
1183         case NDEFUN: {
1184                 struct builtincmd *bcmd;
1185                 if (
1186                         (bcmd = find_builtin(n->narg.text)) &&
1187                         bcmd->flags & BUILTIN_SPECIAL
1188                 ) {
1189                         outfmt(out2, "%s is a special built-in\n", n->narg.text);
1190                         exitstatus = 1;
1191                         break;
1192                 }
1193                 defun(n->narg.text, n->narg.next);
1194                 exitstatus = 0;
1195                 break;
1196         }
1197         case NNOT:
1198                 evaltree(n->nnot.com, EV_TESTED);
1199                 exitstatus = !exitstatus;
1200                 break;
1201
1202         case NPIPE:
1203                 evalpipe(n);
1204                 checkexit = 1;
1205                 break;
1206         case NCMD:
1207 #ifdef notyet
1208                 evalcommand(n, flags, (struct backcmd *)NULL);
1209 #else
1210                 evalcommand(n, flags);
1211 #endif
1212                 checkexit = 1;
1213                 break;
1214 #ifdef DEBUG
1215         default:
1216                 out1fmt("Node type = %d\n", n->type);
1217 #ifndef USE_GLIBC_STDIO
1218                 flushout(out1);
1219 #endif
1220                 break;
1221 #endif
1222         }
1223 out:
1224         if (pendingsigs)
1225                 dotrap();
1226         if (
1227                 flags & EV_EXIT ||
1228                 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
1229         )
1230                 exitshell(exitstatus);
1231 }
1232
1233
1234 static void
1235 evalloop(n, flags)
1236         union node *n;
1237         int flags;
1238 {
1239         int status;
1240
1241         loopnest++;
1242         status = 0;
1243         for (;;) {
1244                 evaltree(n->nbinary.ch1, EV_TESTED);
1245                 if (evalskip) {
1246 skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
1247                                 evalskip = 0;
1248                                 continue;
1249                         }
1250                         if (evalskip == SKIPBREAK && --skipcount <= 0)
1251                                 evalskip = 0;
1252                         break;
1253                 }
1254                 if (n->type == NWHILE) {
1255                         if (exitstatus != 0)
1256                                 break;
1257                 } else {
1258                         if (exitstatus == 0)
1259                                 break;
1260                 }
1261                 evaltree(n->nbinary.ch2, flags & EV_TESTED);
1262                 status = exitstatus;
1263                 if (evalskip)
1264                         goto skipping;
1265         }
1266         loopnest--;
1267         exitstatus = status;
1268 }
1269
1270
1271
1272 static void
1273 evalfor(n, flags)
1274     union node *n;
1275     int flags;
1276 {
1277         struct arglist arglist;
1278         union node *argp;
1279         struct strlist *sp;
1280         struct stackmark smark;
1281
1282         setstackmark(&smark);
1283         arglist.lastp = &arglist.list;
1284         for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
1285                 oexitstatus = exitstatus;
1286                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
1287                 if (evalskip)
1288                         goto out;
1289         }
1290         *arglist.lastp = NULL;
1291
1292         exitstatus = 0;
1293         loopnest++;
1294         for (sp = arglist.list ; sp ; sp = sp->next) {
1295                 setvar(n->nfor.var, sp->text, 0);
1296                 evaltree(n->nfor.body, flags & EV_TESTED);
1297                 if (evalskip) {
1298                         if (evalskip == SKIPCONT && --skipcount <= 0) {
1299                                 evalskip = 0;
1300                                 continue;
1301                         }
1302                         if (evalskip == SKIPBREAK && --skipcount <= 0)
1303                                 evalskip = 0;
1304                         break;
1305                 }
1306         }
1307         loopnest--;
1308 out:
1309         popstackmark(&smark);
1310 }
1311
1312
1313
1314 static void
1315 evalcase(n, flags)
1316         union node *n;
1317         int flags;
1318 {
1319         union node *cp;
1320         union node *patp;
1321         struct arglist arglist;
1322         struct stackmark smark;
1323
1324         setstackmark(&smark);
1325         arglist.lastp = &arglist.list;
1326         oexitstatus = exitstatus;
1327         expandarg(n->ncase.expr, &arglist, EXP_TILDE);
1328         for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
1329                 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
1330                         if (casematch(patp, arglist.list->text)) {
1331                                 if (evalskip == 0) {
1332                                         evaltree(cp->nclist.body, flags);
1333                                 }
1334                                 goto out;
1335                         }
1336                 }
1337         }
1338 out:
1339         popstackmark(&smark);
1340 }
1341
1342
1343
1344 /*
1345  * Kick off a subshell to evaluate a tree.
1346  */
1347
1348 static void
1349 evalsubshell(n, flags)
1350         union node *n;
1351         int flags;
1352 {
1353         struct job *jp;
1354         int backgnd = (n->type == NBACKGND);
1355
1356         expredir(n->nredir.redirect);
1357         jp = makejob(n, 1);
1358         if (forkshell(jp, n, backgnd) == 0) {
1359                 if (backgnd)
1360                         flags &=~ EV_TESTED;
1361                 redirect(n->nredir.redirect, 0);
1362                 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
1363         }
1364         if (! backgnd) {
1365                 INTOFF;
1366                 exitstatus = waitforjob(jp);
1367                 INTON;
1368         }
1369 }
1370
1371
1372
1373 /*
1374  * Compute the names of the files in a redirection list.
1375  */
1376
1377 static void
1378 expredir(n)
1379         union node *n;
1380 {
1381         union node *redir;
1382
1383         for (redir = n ; redir ; redir = redir->nfile.next) {
1384                 struct arglist fn;
1385                 fn.lastp = &fn.list;
1386                 oexitstatus = exitstatus;
1387                 switch (redir->type) {
1388                 case NFROMTO:
1389                 case NFROM:
1390                 case NTO:
1391                 case NAPPEND:
1392                 case NTOOV:
1393                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
1394                         redir->nfile.expfname = fn.list->text;
1395                         break;
1396                 case NFROMFD:
1397                 case NTOFD:
1398                         if (redir->ndup.vname) {
1399                                 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
1400                                 fixredir(redir, fn.list->text, 1);
1401                         }
1402                         break;
1403                 }
1404         }
1405 }
1406
1407
1408
1409 /*
1410  * Evaluate a pipeline.  All the processes in the pipeline are children
1411  * of the process creating the pipeline.  (This differs from some versions
1412  * of the shell, which make the last process in a pipeline the parent
1413  * of all the rest.)
1414  */
1415
1416 static void
1417 evalpipe(n)
1418         union node *n;
1419 {
1420         struct job *jp;
1421         struct nodelist *lp;
1422         int pipelen;
1423         int prevfd;
1424         int pip[2];
1425
1426         TRACE(("evalpipe(0x%lx) called\n", (long)n));
1427         pipelen = 0;
1428         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
1429                 pipelen++;
1430         INTOFF;
1431         jp = makejob(n, pipelen);
1432         prevfd = -1;
1433         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1434                 prehash(lp->n);
1435                 pip[1] = -1;
1436                 if (lp->next) {
1437                         if (pipe(pip) < 0) {
1438                                 close(prevfd);
1439                                 error("Pipe call failed");
1440                         }
1441                 }
1442                 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
1443                         INTON;
1444                         if (prevfd > 0) {
1445                                 close(0);
1446                                 dup_as_newfd(prevfd, 0);
1447                                 close(prevfd);
1448                                 if (pip[0] == 0) {
1449                                         pip[0] = -1;
1450                                 }
1451                         }
1452                         if (pip[1] >= 0) {
1453                                 if (pip[0] >= 0) {
1454                                         close(pip[0]);
1455                                 }
1456                                 if (pip[1] != 1) {
1457                                         close(1);
1458                                         dup_as_newfd(pip[1], 1);
1459                                         close(pip[1]);
1460                                 }
1461                         }
1462                         evaltree(lp->n, EV_EXIT);
1463                 }
1464                 if (prevfd >= 0)
1465                         close(prevfd);
1466                 prevfd = pip[0];
1467                 close(pip[1]);
1468         }
1469         INTON;
1470         if (n->npipe.backgnd == 0) {
1471                 INTOFF;
1472                 exitstatus = waitforjob(jp);
1473                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
1474                 INTON;
1475         }
1476 }
1477
1478
1479
1480 /*
1481  * Execute a command inside back quotes.  If it's a builtin command, we
1482  * want to save its output in a block obtained from malloc.  Otherwise
1483  * we fork off a subprocess and get the output of the command via a pipe.
1484  * Should be called with interrupts off.
1485  */
1486
1487 static void
1488 evalbackcmd(n, result)
1489         union node *n;
1490         struct backcmd *result;
1491 {
1492         int pip[2];
1493         struct job *jp;
1494         struct stackmark smark;         /* unnecessary */
1495
1496         setstackmark(&smark);
1497         result->fd = -1;
1498         result->buf = NULL;
1499         result->nleft = 0;
1500         result->jp = NULL;
1501         if (n == NULL) {
1502                 exitstatus = 0;
1503                 goto out;
1504         }
1505 #ifdef notyet
1506         /*
1507          * For now we disable executing builtins in the same
1508          * context as the shell, because we are not keeping
1509          * enough state to recover from changes that are
1510          * supposed only to affect subshells. eg. echo "`cd /`"
1511          */
1512         if (n->type == NCMD) {
1513                 exitstatus = oexitstatus;
1514                 evalcommand(n, EV_BACKCMD, result);
1515         } else
1516 #endif
1517         {
1518                 exitstatus = 0;
1519                 if (pipe(pip) < 0)
1520                         error("Pipe call failed");
1521                 jp = makejob(n, 1);
1522                 if (forkshell(jp, n, FORK_NOJOB) == 0) {
1523                         FORCEINTON;
1524                         close(pip[0]);
1525                         if (pip[1] != 1) {
1526                                 close(1);
1527                                 dup_as_newfd(pip[1], 1);
1528                                 close(pip[1]);
1529                         }
1530                         eflag = 0;
1531                         evaltree(n, EV_EXIT);
1532                 }
1533                 close(pip[1]);
1534                 result->fd = pip[0];
1535                 result->jp = jp;
1536         }
1537 out:
1538         popstackmark(&smark);
1539         TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
1540                 result->fd, result->buf, result->nleft, result->jp));
1541 }
1542
1543
1544
1545 /*
1546  * Execute a simple command.
1547  */
1548
1549 static void
1550 #ifdef notyet
1551 evalcommand(cmd, flags, backcmd)
1552         union node *cmd;
1553         int flags;
1554         struct backcmd *backcmd;
1555 #else
1556 evalcommand(cmd, flags)
1557         union node *cmd;
1558         int flags;
1559 #endif
1560 {
1561         struct stackmark smark;
1562         union node *argp;
1563         struct arglist arglist;
1564         struct arglist varlist;
1565         char **argv;
1566         int argc;
1567         char **envp;
1568         struct strlist *sp;
1569         int mode;
1570 #ifdef notyet
1571         int pip[2];
1572 #endif
1573         struct cmdentry cmdentry;
1574         struct job *jp;
1575         char *volatile savecmdname;
1576         volatile struct shparam saveparam;
1577         struct localvar *volatile savelocalvars;
1578         volatile int e;
1579         char *lastarg;
1580         const char *path;
1581         const struct builtincmd *firstbltin;
1582         struct jmploc *volatile savehandler;
1583         struct jmploc jmploc;
1584 #if __GNUC__
1585         /* Avoid longjmp clobbering */
1586         (void) &argv;
1587         (void) &argc;
1588         (void) &lastarg;
1589         (void) &flags;
1590 #endif
1591
1592         /* First expand the arguments. */
1593         TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
1594         setstackmark(&smark);
1595         arglist.lastp = &arglist.list;
1596         varlist.lastp = &varlist.list;
1597         arglist.list = 0;
1598         oexitstatus = exitstatus;
1599         exitstatus = 0;
1600         path = pathval();
1601         for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
1602                 expandarg(argp, &varlist, EXP_VARTILDE);
1603         }
1604         for (
1605                 argp = cmd->ncmd.args; argp && !arglist.list;
1606                 argp = argp->narg.next
1607         ) {
1608                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
1609         }
1610         if (argp) {
1611                 struct builtincmd *bcmd;
1612                 bool pseudovarflag;
1613                 bcmd = find_builtin(arglist.list->text);
1614                 pseudovarflag = bcmd && bcmd->flags & BUILTIN_ASSIGN;
1615                 for (; argp; argp = argp->narg.next) {
1616                         if (pseudovarflag && isassignment(argp->narg.text)) {
1617                                 expandarg(argp, &arglist, EXP_VARTILDE);
1618                                 continue;
1619                         }
1620                         expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
1621                 }
1622         }
1623         *arglist.lastp = NULL;
1624         *varlist.lastp = NULL;
1625         expredir(cmd->ncmd.redirect);
1626         argc = 0;
1627         for (sp = arglist.list ; sp ; sp = sp->next)
1628                 argc++;
1629         argv = stalloc(sizeof (char *) * (argc + 1));
1630
1631         for (sp = arglist.list ; sp ; sp = sp->next) {
1632                 TRACE(("evalcommand arg: %s\n", sp->text));
1633                 *argv++ = sp->text;
1634         }
1635         *argv = NULL;
1636         lastarg = NULL;
1637         if (iflag && funcnest == 0 && argc > 0)
1638                 lastarg = argv[-1];
1639         argv -= argc;
1640
1641         /* Print the command if xflag is set. */
1642         if (xflag) {
1643 #ifdef FLUSHERR
1644                 outc('+', &errout);
1645 #else
1646                 outcslow('+', &errout);
1647 #endif
1648                 eprintlist(varlist.list);
1649                 eprintlist(arglist.list);
1650 #ifdef FLUSHERR
1651                 outc('\n', &errout);
1652                 flushout(&errout);
1653 #else
1654                 outcslow('\n', &errout);
1655 #endif
1656         }
1657
1658         /* Now locate the command. */
1659         if (argc == 0) {
1660                 cmdentry.cmdtype = CMDBUILTIN;
1661                 firstbltin = cmdentry.u.cmd = BLTINCMD;
1662         } else {
1663                 const char *oldpath;
1664                 int findflag = DO_ERR;
1665                 int oldfindflag;
1666
1667                 /*
1668                  * Modify the command lookup path, if a PATH= assignment
1669                  * is present
1670                  */
1671                 for (sp = varlist.list ; sp ; sp = sp->next)
1672                         if (varequal(sp->text, defpathvar)) {
1673                                 path = sp->text + 5;
1674                                 findflag |= DO_BRUTE;
1675                         }
1676                 oldpath = path;
1677                 oldfindflag = findflag;
1678                 firstbltin = 0;
1679                 for(;;) {
1680                         find_command(argv[0], &cmdentry, findflag, path);
1681                         if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
1682                                 exitstatus = 127;
1683 #ifdef FLUSHERR
1684                                 flushout(&errout);
1685 #endif
1686                                 goto out;
1687                         }
1688                         /* implement bltin and command here */
1689                         if (cmdentry.cmdtype != CMDBUILTIN) {
1690                                 break;
1691                         }
1692                         if (!firstbltin) {
1693                                 firstbltin = cmdentry.u.cmd;
1694                         }
1695                         if (cmdentry.u.cmd == BLTINCMD) {
1696                                 for(;;) {
1697                                         struct builtincmd *bcmd;
1698
1699                                         argv++;
1700                                         if (--argc == 0)
1701                                                 goto found;
1702                                         if (!(bcmd = find_builtin(*argv))) {
1703                                                 outfmt(&errout, "%s: not found\n", *argv);
1704                                                 exitstatus = 127;
1705 #ifdef FLUSHERR
1706                                                 flushout(&errout);
1707 #endif
1708                                                 goto out;
1709                                         }
1710                                         cmdentry.u.cmd = bcmd;
1711                                         if (bcmd != BLTINCMD)
1712                                                 break;
1713                                 }
1714                         }
1715                         if (cmdentry.u.cmd == COMMANDCMD) {
1716                                 argv++;
1717                                 if (--argc == 0) {
1718                                         goto found;
1719                                 }
1720                                 if (*argv[0] == '-') {
1721                                         if (!equal(argv[0], "-p")) {
1722                                                 argv--;
1723                                                 argc++;
1724                                                 break;
1725                                         }
1726                                         argv++;
1727                                         if (--argc == 0) {
1728                                                 goto found;
1729                                         }
1730                                         path = defpath;
1731                                         findflag |= DO_BRUTE;
1732                                 } else {
1733                                         path = oldpath;
1734                                         findflag = oldfindflag;
1735                                 }
1736                                 findflag |= DO_NOFUN;
1737                                 continue;
1738                         }
1739 found:
1740                         break;
1741                 }
1742         }
1743
1744         /* Fork off a child process if necessary. */
1745         if (cmd->ncmd.backgnd
1746          || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
1747 #ifdef notyet
1748          || ((flags & EV_BACKCMD) != 0
1749             && (cmdentry.cmdtype != CMDBUILTIN
1750                  || cmdentry.u.bcmd == DOTCMD
1751                  || cmdentry.u.bcmd == EVALCMD))
1752 #endif
1753         ) {
1754                 jp = makejob(cmd, 1);
1755                 mode = cmd->ncmd.backgnd;
1756 #ifdef notyet
1757                 if (flags & EV_BACKCMD) {
1758                         mode = FORK_NOJOB;
1759                         if (pipe(pip) < 0)
1760                                 error("Pipe call failed");
1761                 }
1762 #endif
1763                 if (forkshell(jp, cmd, mode) != 0)
1764                         goto parent;    /* at end of routine */
1765 #ifdef notyet
1766                 if (flags & EV_BACKCMD) {
1767                         FORCEINTON;
1768                         close(pip[0]);
1769                         if (pip[1] != 1) {
1770                                 close(1);
1771                                 dup_as_newfd(pip[1], 1);
1772                                 close(pip[1]);
1773                         }
1774                 }
1775 #endif
1776                 flags |= EV_EXIT;
1777         }
1778
1779         /* This is the child process if a fork occurred. */
1780         /* Execute the command. */
1781         if (cmdentry.cmdtype == CMDFUNCTION) {
1782 #ifdef DEBUG
1783                 trputs("Shell function:  ");  trargs(argv);
1784 #endif
1785                 exitstatus = oexitstatus;
1786                 redirect(cmd->ncmd.redirect, REDIR_PUSH);
1787                 saveparam = shellparam;
1788                 shellparam.malloc = 0;
1789                 shellparam.nparam = argc - 1;
1790                 shellparam.p = argv + 1;
1791                 INTOFF;
1792                 savelocalvars = localvars;
1793                 localvars = NULL;
1794                 INTON;
1795                 if (setjmp(jmploc.loc)) {
1796                         if (exception == EXSHELLPROC) {
1797                                 freeparam((volatile struct shparam *)
1798                                     &saveparam);
1799                         } else {
1800                                 saveparam.optind = shellparam.optind;
1801                                 saveparam.optoff = shellparam.optoff;
1802                                 freeparam(&shellparam);
1803                                 shellparam = saveparam;
1804                         }
1805                         poplocalvars();
1806                         localvars = savelocalvars;
1807                         handler = savehandler;
1808                         longjmp(handler->loc, 1);
1809                 }
1810                 savehandler = handler;
1811                 handler = &jmploc;
1812                 for (sp = varlist.list ; sp ; sp = sp->next)
1813                         mklocal(sp->text);
1814                 funcnest++;
1815                 evaltree(cmdentry.u.func, flags & EV_TESTED);
1816                 funcnest--;
1817                 INTOFF;
1818                 poplocalvars();
1819                 localvars = savelocalvars;
1820                 saveparam.optind = shellparam.optind;
1821                 saveparam.optoff = shellparam.optoff;
1822                 freeparam(&shellparam);
1823                 shellparam = saveparam;
1824                 handler = savehandler;
1825                 popredir();
1826                 INTON;
1827                 if (evalskip == SKIPFUNC) {
1828                         evalskip = 0;
1829                         skipcount = 0;
1830                 }
1831                 if (flags & EV_EXIT)
1832                         exitshell(exitstatus);
1833         } else if (cmdentry.cmdtype == CMDBUILTIN) {
1834 #ifdef DEBUG
1835                 trputs("builtin command:  ");  trargs(argv);
1836 #endif
1837                 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
1838 #ifdef notyet
1839                 if (flags == EV_BACKCMD) {
1840 #ifdef USE_GLIBC_STDIO
1841                         openmemout();
1842 #else
1843                         memout.nleft = 0;
1844                         memout.nextc = memout.buf;
1845                         memout.bufsize = 64;
1846 #endif
1847                         mode |= REDIR_BACKQ;
1848                 }
1849 #endif
1850                 redirect(cmd->ncmd.redirect, mode);
1851                 savecmdname = commandname;
1852                 if (firstbltin->flags & BUILTIN_SPECIAL) {
1853                         listsetvar(varlist.list);
1854                 } else {
1855                         cmdenviron = varlist.list;
1856                 }
1857                 e = -1;
1858                 if (setjmp(jmploc.loc)) {
1859                         e = exception;
1860                         exitstatus = (e == EXINT)? SIGINT+128 : 2;
1861                         goto cmddone;
1862                 }
1863                 savehandler = handler;
1864                 handler = &jmploc;
1865                 commandname = argv[0];
1866                 argptr = argv + 1;
1867                 optptr = NULL;                  /* initialize nextopt */
1868                 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
1869                 flushall();
1870 cmddone:
1871                 exitstatus |= outerr(out1);
1872                 out1 = &output;
1873                 out2 = &errout;
1874                 freestdout();
1875                 cmdenviron = NULL;
1876                 if (e != EXSHELLPROC) {
1877                         commandname = savecmdname;
1878                         if (flags & EV_EXIT)
1879                                 exitshell(exitstatus);
1880                 }
1881                 handler = savehandler;
1882                 if (e != -1) {
1883                         if ((e != EXERROR && e != EXEXEC)
1884                            || cmdentry.u.cmd == BLTINCMD
1885                            || cmdentry.u.cmd == DOTCMD
1886                            || cmdentry.u.cmd == EVALCMD
1887                            || cmdentry.u.cmd == EXECCMD)
1888                                 exraise(e);
1889                         FORCEINTON;
1890                 }
1891                 if (cmdentry.u.cmd != EXECCMD)
1892                         popredir();
1893 #ifdef notyet
1894                 if (flags == EV_BACKCMD) {
1895                         INTOFF;
1896 #ifdef USE_GLIBC_STDIO
1897                         if (__closememout()) {
1898                                 error(
1899                                         "__closememout() failed: %s",
1900                                         strerror(errno)
1901                                 );
1902                         }
1903 #endif
1904                         backcmd->buf = memout.buf;
1905 #ifdef USE_GLIBC_STDIO
1906                         backcmd->nleft = memout.bufsize;
1907 #else
1908                         backcmd->nleft = memout.nextc - memout.buf;
1909 #endif
1910                         memout.buf = NULL;
1911                         INTON;
1912                 }
1913 #endif
1914         } else {
1915 #ifdef DEBUG
1916                 trputs("normal command:  ");  trargs(argv);
1917 #endif
1918                 redirect(cmd->ncmd.redirect, 0);
1919                 clearredir();
1920                 for (sp = varlist.list ; sp ; sp = sp->next)
1921                         setvareq(sp->text, VEXPORT|VSTACK);
1922                 envp = environment();
1923                 shellexec(argv, envp, path, cmdentry.u.index);
1924         }
1925         goto out;
1926
1927 parent: /* parent process gets here (if we forked) */
1928         if (mode == 0) {        /* argument to fork */
1929                 INTOFF;
1930                 exitstatus = waitforjob(jp);
1931                 INTON;
1932 #ifdef notyet
1933         } else if (mode == 2) {
1934                 backcmd->fd = pip[0];
1935                 close(pip[1]);
1936                 backcmd->jp = jp;
1937 #endif
1938         }
1939
1940 out:
1941         if (lastarg)
1942                 setvar("_", lastarg, 0);
1943         popstackmark(&smark);
1944 }
1945
1946
1947
1948 /*
1949  * Search for a command.  This is called before we fork so that the
1950  * location of the command will be available in the parent as well as
1951  * the child.  The check for "goodname" is an overly conservative
1952  * check that the name will not be subject to expansion.
1953  */
1954
1955 static void
1956 prehash(n)
1957         union node *n;
1958 {
1959         struct cmdentry entry;
1960
1961         if (n->type == NCMD && n->ncmd.args)
1962                 if (goodname(n->ncmd.args->narg.text))
1963                         find_command(n->ncmd.args->narg.text, &entry, 0,
1964                                      pathval());
1965 }
1966
1967
1968
1969 /*
1970  * Builtin commands.  Builtin commands whose functions are closely
1971  * tied to evaluation are implemented here.
1972  */
1973
1974 /*
1975  * No command given, or a bltin command with no arguments.  Set the
1976  * specified variables.
1977  */
1978
1979 int
1980 bltincmd(argc, argv)
1981         int argc;
1982         char **argv;
1983 {
1984         /*
1985          * Preserve exitstatus of a previous possible redirection
1986          * as POSIX mandates
1987          */
1988         return exitstatus;
1989 }
1990
1991
1992 /*
1993  * Handle break and continue commands.  Break, continue, and return are
1994  * all handled by setting the evalskip flag.  The evaluation routines
1995  * above all check this flag, and if it is set they start skipping
1996  * commands rather than executing them.  The variable skipcount is
1997  * the number of loops to break/continue, or the number of function
1998  * levels to return.  (The latter is always 1.)  It should probably
1999  * be an error to break out of more loops than exist, but it isn't
2000  * in the standard shell so we don't make it one here.
2001  */
2002
2003 static int
2004 breakcmd(argc, argv)
2005         int argc;
2006         char **argv;
2007 {
2008         int n = argc > 1 ? number(argv[1]) : 1;
2009
2010         if (n > loopnest)
2011                 n = loopnest;
2012         if (n > 0) {
2013                 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
2014                 skipcount = n;
2015         }
2016         return 0;
2017 }
2018
2019
2020 /*
2021  * The return command.
2022  */
2023
2024 static int
2025 returncmd(argc, argv)
2026         int argc;
2027         char **argv;
2028 {
2029         int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2030
2031         if (funcnest) {
2032                 evalskip = SKIPFUNC;
2033                 skipcount = 1;
2034                 return ret;
2035         }
2036         else {
2037                 /* Do what ksh does; skip the rest of the file */
2038                 evalskip = SKIPFILE;
2039                 skipcount = 1;
2040                 return ret;
2041         }
2042 }
2043
2044
2045 #ifndef BB_TRUE_FALSE
2046 static int
2047 false_main(argc, argv)
2048         int argc;
2049         char **argv;
2050 {
2051         return 1;
2052 }
2053
2054
2055 static int
2056 true_main(argc, argv)
2057         int argc;
2058         char **argv;
2059 {
2060         return 0;
2061 }
2062 #endif
2063
2064 static int
2065 execcmd(argc, argv)
2066         int argc;
2067         char **argv;
2068 {
2069         if (argc > 1) {
2070                 struct strlist *sp;
2071
2072                 iflag = 0;              /* exit on error */
2073                 mflag = 0;
2074                 optschanged();
2075                 for (sp = cmdenviron; sp ; sp = sp->next)
2076                         setvareq(sp->text, VEXPORT|VSTACK);
2077                 shellexec(argv + 1, environment(), pathval(), 0);
2078         }
2079         return 0;
2080 }
2081
2082 static void
2083 eprintlist(struct strlist *sp)
2084 {
2085         for (; sp; sp = sp->next) {
2086                 outfmt(&errout, " %s",sp->text);
2087         }
2088 }
2089 /*      $NetBSD: exec.c,v 1.32 2001/02/04 19:52:06 christos Exp $       */
2090
2091 /*
2092  * When commands are first encountered, they are entered in a hash table.
2093  * This ensures that a full path search will not have to be done for them
2094  * on each invocation.
2095  *
2096  * We should investigate converting to a linear search, even though that
2097  * would make the command name "hash" a misnomer.
2098  */
2099 #define CMDTABLESIZE 31         /* should be prime */
2100 #define ARB 1                   /* actual size determined at run time */
2101
2102
2103
2104 struct tblentry {
2105         struct tblentry *next;  /* next entry in hash chain */
2106         union param param;      /* definition of builtin function */
2107         short cmdtype;          /* index identifying command */
2108         char rehash;            /* if set, cd done since entry created */
2109         char cmdname[ARB];      /* name of command */
2110 };
2111
2112
2113 static struct tblentry *cmdtable[CMDTABLESIZE];
2114 static int builtinloc = -1;             /* index in path of %builtin, or -1 */
2115 static int exerrno = 0;                 /* Last exec error */
2116
2117
2118 static void tryexec __P((char *, char **, char **));
2119 #if !defined(BSD) && !defined(linux)
2120 static void execinterp __P((char **, char **));
2121 #endif
2122 static void printentry __P((struct tblentry *, int));
2123 static void clearcmdentry __P((int));
2124 static struct tblentry *cmdlookup __P((char *, int));
2125 static void delete_cmd_entry __P((void));
2126 #ifdef ASH_TYPE
2127 static int describe_command __P((char *, int));
2128 #endif
2129 static int path_change __P((const char *, int *));
2130
2131
2132 /*
2133  * Exec a program.  Never returns.  If you change this routine, you may
2134  * have to change the find_command routine as well.
2135  */
2136
2137 static void
2138 shellexec(argv, envp, path, idx)
2139         char **argv, **envp;
2140         const char *path;
2141         int idx;
2142 {
2143         char *cmdname;
2144         int e;
2145
2146         if (strchr(argv[0], '/') != NULL) {
2147                 tryexec(argv[0], argv, envp);
2148                 e = errno;
2149         } else {
2150                 e = ENOENT;
2151                 while ((cmdname = padvance(&path, argv[0])) != NULL) {
2152                         if (--idx < 0 && pathopt == NULL) {
2153                                 tryexec(cmdname, argv, envp);
2154                                 if (errno != ENOENT && errno != ENOTDIR)
2155                                         e = errno;
2156                         }
2157                         stunalloc(cmdname);
2158                 }
2159         }
2160
2161         /* Map to POSIX errors */
2162         switch (e) {
2163         case EACCES:
2164                 exerrno = 126;
2165                 break;
2166         case ENOENT:
2167                 exerrno = 127;
2168                 break;
2169         default:
2170                 exerrno = 2;
2171                 break;
2172         }
2173         exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
2174         /* NOTREACHED */
2175 }
2176
2177
2178 static void
2179 tryexec(cmd, argv, envp)
2180         char *cmd;
2181         char **argv;
2182         char **envp;
2183         {
2184         int e;
2185 #if !defined(BSD) && !defined(linux)
2186         char *p;
2187 #endif
2188
2189 #ifdef SYSV
2190         do {
2191                 execve(cmd, argv, envp);
2192         } while (errno == EINTR);
2193 #else
2194         execve(cmd, argv, envp);
2195 #endif
2196         e = errno;
2197         if (e == ENOEXEC) {
2198                 INTOFF;
2199                 initshellproc();
2200                 setinputfile(cmd, 0);
2201                 commandname = arg0 = savestr(argv[0]);
2202 #if !defined(BSD) && !defined(linux)
2203                 INTON;
2204                 pgetc(); pungetc();             /* fill up input buffer */
2205                 p = parsenextc;
2206                 if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
2207                         argv[0] = cmd;
2208                         execinterp(argv, envp);
2209                 }
2210                 INTOFF;
2211 #endif
2212                 setparam(argv + 1);
2213                 exraise(EXSHELLPROC);
2214         }
2215         errno = e;
2216 }
2217
2218
2219 #if !defined(BSD) && !defined(linux)
2220 /*
2221  * Execute an interpreter introduced by "#!", for systems where this
2222  * feature has not been built into the kernel.  If the interpreter is
2223  * the shell, return (effectively ignoring the "#!").  If the execution
2224  * of the interpreter fails, exit.
2225  *
2226  * This code peeks inside the input buffer in order to avoid actually
2227  * reading any input.  It would benefit from a rewrite.
2228  */
2229
2230 #define NEWARGS 5
2231
2232 static void
2233 execinterp(argv, envp)
2234         char **argv, **envp;
2235         {
2236         int n;
2237         char *inp;
2238         char *outp;
2239         char c;
2240         char *p;
2241         char **ap;
2242         char *newargs[NEWARGS];
2243         int i;
2244         char **ap2;
2245         char **new;
2246
2247         n = parsenleft - 2;
2248         inp = parsenextc + 2;
2249         ap = newargs;
2250         for (;;) {
2251                 while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
2252                         inp++;
2253                 if (n < 0)
2254                         goto bad;
2255                 if ((c = *inp++) == '\n')
2256                         break;
2257                 if (ap == &newargs[NEWARGS])
2258 bad:              error("Bad #! line");
2259                 STARTSTACKSTR(outp);
2260                 do {
2261                         STPUTC(c, outp);
2262                 } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
2263                 STPUTC('\0', outp);
2264                 n++, inp--;
2265                 *ap++ = grabstackstr(outp);
2266         }
2267         if (ap == newargs + 1) {        /* if no args, maybe no exec is needed */
2268                 p = newargs[0];
2269                 for (;;) {
2270                         if (equal(p, "sh") || equal(p, "ash")) {
2271                                 return;
2272                         }
2273                         while (*p != '/') {
2274                                 if (*p == '\0')
2275                                         goto break2;
2276                                 p++;
2277                         }
2278                         p++;
2279                 }
2280 break2:;
2281         }
2282         i = (char *)ap - (char *)newargs;               /* size in bytes */
2283         if (i == 0)
2284                 error("Bad #! line");
2285         for (ap2 = argv ; *ap2++ != NULL ; );
2286         new = ckmalloc(i + ((char *)ap2 - (char *)argv));
2287         ap = newargs, ap2 = new;
2288         while ((i -= sizeof (char **)) >= 0)
2289                 *ap2++ = *ap++;
2290         ap = argv;
2291         while (*ap2++ = *ap++);
2292         shellexec(new, envp, pathval(), 0);
2293         /* NOTREACHED */
2294 }
2295 #endif
2296
2297
2298
2299 /*
2300  * Do a path search.  The variable path (passed by reference) should be
2301  * set to the start of the path before the first call; padvance will update
2302  * this value as it proceeds.  Successive calls to padvance will return
2303  * the possible path expansions in sequence.  If an option (indicated by
2304  * a percent sign) appears in the path entry then the global variable
2305  * pathopt will be set to point to it; otherwise pathopt will be set to
2306  * NULL.
2307  */
2308
2309 static const char *pathopt;
2310
2311 static char *
2312 padvance(path, name)
2313         const char **path;
2314         const char *name;
2315         {
2316         const char *p;
2317         char *q;
2318         const char *start;
2319         int len;
2320
2321         if (*path == NULL)
2322                 return NULL;
2323         start = *path;
2324         for (p = start ; *p && *p != ':' && *p != '%' ; p++);
2325         len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
2326         while (stackblocksize() < len)
2327                 growstackblock();
2328         q = stackblock();
2329         if (p != start) {
2330                 memcpy(q, start, p - start);
2331                 q += p - start;
2332                 *q++ = '/';
2333         }
2334         strcpy(q, name);
2335         pathopt = NULL;
2336         if (*p == '%') {
2337                 pathopt = ++p;
2338                 while (*p && *p != ':')  p++;
2339         }
2340         if (*p == ':')
2341                 *path = p + 1;
2342         else
2343                 *path = NULL;
2344         return stalloc(len);
2345 }
2346
2347
2348
2349 /*** Command hashing code ***/
2350
2351
2352 static int
2353 hashcmd(argc, argv)
2354         int argc;
2355         char **argv;
2356 {
2357         struct tblentry **pp;
2358         struct tblentry *cmdp;
2359         int c;
2360         int verbose;
2361         struct cmdentry entry;
2362         char *name;
2363
2364         verbose = 0;
2365         while ((c = nextopt("rv")) != '\0') {
2366                 if (c == 'r') {
2367                         clearcmdentry(0);
2368                         return 0;
2369                 } else if (c == 'v') {
2370                         verbose++;
2371                 }
2372         }
2373         if (*argptr == NULL) {
2374                 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
2375                         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2376                                 if (cmdp->cmdtype != CMDBUILTIN) {
2377                                         printentry(cmdp, verbose);
2378                                 }
2379                         }
2380                 }
2381                 return 0;
2382         }
2383         c = 0;
2384         while ((name = *argptr) != NULL) {
2385                 if ((cmdp = cmdlookup(name, 0)) != NULL
2386                  && (cmdp->cmdtype == CMDNORMAL
2387                      || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
2388                         delete_cmd_entry();
2389                 find_command(name, &entry, DO_ERR, pathval());
2390                 if (entry.cmdtype == CMDUNKNOWN) c = 1;
2391                 else if (verbose) {
2392                         cmdp = cmdlookup(name, 0);
2393                         if (cmdp) printentry(cmdp, verbose);
2394                         flushall();
2395                 }
2396                 argptr++;
2397         }
2398         return c;
2399 }
2400
2401
2402 static void
2403 printentry(cmdp, verbose)
2404         struct tblentry *cmdp;
2405         int verbose;
2406         {
2407         int idx;
2408         const char *path;
2409         char *name;
2410
2411         if (cmdp->cmdtype == CMDNORMAL) {
2412                 idx = cmdp->param.index;
2413                 path = pathval();
2414                 do {
2415                         name = padvance(&path, cmdp->cmdname);
2416                         stunalloc(name);
2417                 } while (--idx >= 0);
2418                 out1str(name);
2419         } else if (cmdp->cmdtype == CMDBUILTIN) {
2420                 out1fmt("builtin %s", cmdp->cmdname);
2421         } else if (cmdp->cmdtype == CMDFUNCTION) {
2422                 out1fmt("function %s", cmdp->cmdname);
2423                 if (verbose) {
2424                         INTOFF;
2425                         name = commandtext(cmdp->param.func);
2426                         out1fmt(" %s", name);
2427                         ckfree(name);
2428                         INTON;
2429                 }
2430 #ifdef DEBUG
2431         } else {
2432                 error("internal error: cmdtype %d", cmdp->cmdtype);
2433 #endif
2434         }
2435         out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
2436 }
2437
2438
2439
2440 /*
2441  * Resolve a command name.  If you change this routine, you may have to
2442  * change the shellexec routine as well.
2443  */
2444
2445 static void
2446 find_command(name, entry, act, path)
2447         char *name;
2448         struct cmdentry *entry;
2449         int act;
2450         const char *path;
2451 {
2452         struct tblentry *cmdp;
2453         int idx;
2454         int prev;
2455         char *fullname;
2456         struct stat statb;
2457         int e;
2458         int bltin;
2459         int firstchange;
2460         int updatetbl;
2461         bool regular;
2462         struct builtincmd *bcmd;
2463
2464         /* If name contains a slash, don't use the hash table */
2465         if (strchr(name, '/') != NULL) {
2466                 if (act & DO_ABS) {
2467                         while (stat(name, &statb) < 0) {
2468         #ifdef SYSV
2469                                 if (errno == EINTR)
2470                                         continue;
2471         #endif
2472                                 if (errno != ENOENT && errno != ENOTDIR)
2473                                         e = errno;
2474                                 entry->cmdtype = CMDUNKNOWN;
2475                                 entry->u.index = -1;
2476                                 return;
2477                         }
2478                         entry->cmdtype = CMDNORMAL;
2479                         entry->u.index = -1;
2480                         return;
2481                 }
2482                 entry->cmdtype = CMDNORMAL;
2483                 entry->u.index = 0;
2484                 return;
2485         }
2486
2487         updatetbl = 1;
2488         if (act & DO_BRUTE) {
2489                 firstchange = path_change(path, &bltin);
2490         } else {
2491                 bltin = builtinloc;
2492                 firstchange = 9999;
2493         }
2494
2495         /* If name is in the table, and not invalidated by cd, we're done */
2496         if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
2497                 if (cmdp->cmdtype == CMDFUNCTION) {
2498                         if (act & DO_NOFUN) {
2499                                 updatetbl = 0;
2500                         } else {
2501                                 goto success;
2502                         }
2503                 } else if (act & DO_BRUTE) {
2504                         if ((cmdp->cmdtype == CMDNORMAL &&
2505                              cmdp->param.index >= firstchange) ||
2506                             (cmdp->cmdtype == CMDBUILTIN &&
2507                              ((builtinloc < 0 && bltin >= 0) ?
2508                               bltin : builtinloc) >= firstchange)) {
2509                                 /* need to recompute the entry */
2510                         } else {
2511                                 goto success;
2512                         }
2513                 } else {
2514                         goto success;
2515                 }
2516         }
2517
2518         bcmd = find_builtin(name);
2519         regular = bcmd && bcmd->flags & BUILTIN_REGULAR;
2520
2521         if (regular) {
2522                 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
2523                         goto success;
2524                 }
2525         } else if (act & DO_BRUTE) {
2526                 if (firstchange == 0) {
2527                         updatetbl = 0;
2528                 }
2529         }
2530
2531         /* If %builtin not in path, check for builtin next */
2532         if (regular || (bltin < 0 && bcmd)) {
2533 builtin:
2534                 if (!updatetbl) {
2535                         entry->cmdtype = CMDBUILTIN;
2536                         entry->u.cmd = bcmd;
2537                         return;
2538                 }
2539                 INTOFF;
2540                 cmdp = cmdlookup(name, 1);
2541                 cmdp->cmdtype = CMDBUILTIN;
2542                 cmdp->param.cmd = bcmd;
2543                 INTON;
2544                 goto success;
2545         }
2546
2547         /* We have to search path. */
2548         prev = -1;              /* where to start */
2549         if (cmdp && cmdp->rehash) {     /* doing a rehash */
2550                 if (cmdp->cmdtype == CMDBUILTIN)
2551                         prev = builtinloc;
2552                 else
2553                         prev = cmdp->param.index;
2554         }
2555
2556         e = ENOENT;
2557         idx = -1;
2558 loop:
2559         while ((fullname = padvance(&path, name)) != NULL) {
2560                 stunalloc(fullname);
2561                 idx++;
2562                 if (idx >= firstchange) {
2563                         updatetbl = 0;
2564                 }
2565                 if (pathopt) {
2566                         if (prefix("builtin", pathopt)) {
2567                                 if ((bcmd = find_builtin(name))) {
2568                                         goto builtin;
2569                                 }
2570                                 continue;
2571                         } else if (!(act & DO_NOFUN) &&
2572                                    prefix("func", pathopt)) {
2573                                 /* handled below */
2574                         } else {
2575                                 continue;       /* ignore unimplemented options */
2576                         }
2577                 }
2578                 /* if rehash, don't redo absolute path names */
2579                 if (fullname[0] == '/' && idx <= prev &&
2580                     idx < firstchange) {
2581                         if (idx < prev)
2582                                 continue;
2583                         TRACE(("searchexec \"%s\": no change\n", name));
2584                         goto success;
2585                 }
2586                 while (stat(fullname, &statb) < 0) {
2587 #ifdef SYSV
2588                         if (errno == EINTR)
2589                                 continue;
2590 #endif
2591                         if (errno != ENOENT && errno != ENOTDIR)
2592                                 e = errno;
2593                         goto loop;
2594                 }
2595                 e = EACCES;     /* if we fail, this will be the error */
2596                 if (!S_ISREG(statb.st_mode))
2597                         continue;
2598                 if (pathopt) {          /* this is a %func directory */
2599                         stalloc(strlen(fullname) + 1);
2600                         readcmdfile(fullname);
2601                         if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
2602                                 error("%s not defined in %s", name, fullname);
2603                         stunalloc(fullname);
2604                         goto success;
2605                 }
2606 #ifdef notdef
2607                 if (statb.st_uid == geteuid()) {
2608                         if ((statb.st_mode & 0100) == 0)
2609                                 goto loop;
2610                 } else if (statb.st_gid == getegid()) {
2611                         if ((statb.st_mode & 010) == 0)
2612                                 goto loop;
2613                 } else {
2614                         if ((statb.st_mode & 01) == 0)
2615                                 goto loop;
2616                 }
2617 #endif
2618                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
2619                 /* If we aren't called with DO_BRUTE and cmdp is set, it must
2620                    be a function and we're being called with DO_NOFUN */
2621                 if (!updatetbl) {
2622                         entry->cmdtype = CMDNORMAL;
2623                         entry->u.index = idx;
2624                         return;
2625                 }
2626                 INTOFF;
2627                 cmdp = cmdlookup(name, 1);
2628                 cmdp->cmdtype = CMDNORMAL;
2629                 cmdp->param.index = idx;
2630                 INTON;
2631                 goto success;
2632         }
2633
2634         /* We failed.  If there was an entry for this command, delete it */
2635         if (cmdp && updatetbl)
2636                 delete_cmd_entry();
2637         if (act & DO_ERR)
2638                 outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
2639         entry->cmdtype = CMDUNKNOWN;
2640         return;
2641
2642 success:
2643         cmdp->rehash = 0;
2644         entry->cmdtype = cmdp->cmdtype;
2645         entry->u = cmdp->param;
2646 }
2647
2648
2649
2650 /*
2651  * Search the table of builtin commands.
2652  */
2653
2654 struct builtincmd *
2655 find_builtin(name)
2656         char *name;
2657 {
2658         struct builtincmd *bp;
2659
2660         bp = bsearch( &name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
2661                 pstrcmp
2662         );
2663         return bp;
2664 }
2665
2666
2667 /*
2668  * Called when a cd is done.  Marks all commands so the next time they
2669  * are executed they will be rehashed.
2670  */
2671
2672 static void
2673 hashcd() {
2674         struct tblentry **pp;
2675         struct tblentry *cmdp;
2676
2677         for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
2678                 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2679                         if (cmdp->cmdtype == CMDNORMAL
2680                          || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
2681                                 cmdp->rehash = 1;
2682                 }
2683         }
2684 }
2685
2686
2687
2688 /*
2689  * Called before PATH is changed.  The argument is the new value of PATH;
2690  * pathval() still returns the old value at this point.  Called with
2691  * interrupts off.
2692  */
2693
2694 static void
2695 changepath(newval)
2696         const char *newval;
2697 {
2698         int firstchange;
2699         int bltin;
2700
2701         firstchange = path_change(newval, &bltin);
2702         if (builtinloc < 0 && bltin >= 0)
2703                 builtinloc = bltin;             /* zap builtins */
2704         clearcmdentry(firstchange);
2705         builtinloc = bltin;
2706 }
2707
2708
2709 /*
2710  * Clear out command entries.  The argument specifies the first entry in
2711  * PATH which has changed.
2712  */
2713
2714 static void
2715 clearcmdentry(firstchange)
2716         int firstchange;
2717 {
2718         struct tblentry **tblp;
2719         struct tblentry **pp;
2720         struct tblentry *cmdp;
2721
2722         INTOFF;
2723         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
2724                 pp = tblp;
2725                 while ((cmdp = *pp) != NULL) {
2726                         if ((cmdp->cmdtype == CMDNORMAL &&
2727                              cmdp->param.index >= firstchange)
2728                          || (cmdp->cmdtype == CMDBUILTIN &&
2729                              builtinloc >= firstchange)) {
2730                                 *pp = cmdp->next;
2731                                 ckfree(cmdp);
2732                         } else {
2733                                 pp = &cmdp->next;
2734                         }
2735                 }
2736         }
2737         INTON;
2738 }
2739
2740
2741 /*
2742  * Delete all functions.
2743  */
2744
2745 #ifdef mkinit
2746 static void deletefuncs __P((void));
2747
2748 SHELLPROC {
2749         deletefuncs();
2750 }
2751 #endif
2752
2753 static void
2754 deletefuncs() {
2755         struct tblentry **tblp;
2756         struct tblentry **pp;
2757         struct tblentry *cmdp;
2758
2759         INTOFF;
2760         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
2761                 pp = tblp;
2762                 while ((cmdp = *pp) != NULL) {
2763                         if (cmdp->cmdtype == CMDFUNCTION) {
2764                                 *pp = cmdp->next;
2765                                 freefunc(cmdp->param.func);
2766                                 ckfree(cmdp);
2767                         } else {
2768                                 pp = &cmdp->next;
2769                         }
2770                 }
2771         }
2772         INTON;
2773 }
2774
2775
2776
2777 /*
2778  * Locate a command in the command hash table.  If "add" is nonzero,
2779  * add the command to the table if it is not already present.  The
2780  * variable "lastcmdentry" is set to point to the address of the link
2781  * pointing to the entry, so that delete_cmd_entry can delete the
2782  * entry.
2783  */
2784
2785 struct tblentry **lastcmdentry;
2786
2787
2788 static struct tblentry *
2789 cmdlookup(name, add)
2790         char *name;
2791         int add;
2792 {
2793         int hashval;
2794         char *p;
2795         struct tblentry *cmdp;
2796         struct tblentry **pp;
2797
2798         p = name;
2799         hashval = *p << 4;
2800         while (*p)
2801                 hashval += *p++;
2802         hashval &= 0x7FFF;
2803         pp = &cmdtable[hashval % CMDTABLESIZE];
2804         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2805                 if (equal(cmdp->cmdname, name))
2806                         break;
2807                 pp = &cmdp->next;
2808         }
2809         if (add && cmdp == NULL) {
2810                 INTOFF;
2811                 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
2812                                         + strlen(name) + 1);
2813                 cmdp->next = NULL;
2814                 cmdp->cmdtype = CMDUNKNOWN;
2815                 cmdp->rehash = 0;
2816                 strcpy(cmdp->cmdname, name);
2817                 INTON;
2818         }
2819         lastcmdentry = pp;
2820         return cmdp;
2821 }
2822
2823 /*
2824  * Delete the command entry returned on the last lookup.
2825  */
2826
2827 static void
2828 delete_cmd_entry() {
2829         struct tblentry *cmdp;
2830
2831         INTOFF;
2832         cmdp = *lastcmdentry;
2833         *lastcmdentry = cmdp->next;
2834         ckfree(cmdp);
2835         INTON;
2836 }
2837
2838
2839
2840 #ifdef notdef
2841 static void
2842 getcmdentry(name, entry)
2843         char *name;
2844         struct cmdentry *entry;
2845         {
2846         struct tblentry *cmdp = cmdlookup(name, 0);
2847
2848         if (cmdp) {
2849                 entry->u = cmdp->param;
2850                 entry->cmdtype = cmdp->cmdtype;
2851         } else {
2852                 entry->cmdtype = CMDUNKNOWN;
2853                 entry->u.index = 0;
2854         }
2855 }
2856 #endif
2857
2858
2859 /*
2860  * Add a new command entry, replacing any existing command entry for
2861  * the same name.
2862  */
2863
2864 static void
2865 addcmdentry(name, entry)
2866         char *name;
2867         struct cmdentry *entry;
2868         {
2869         struct tblentry *cmdp;
2870
2871         INTOFF;
2872         cmdp = cmdlookup(name, 1);
2873         if (cmdp->cmdtype == CMDFUNCTION) {
2874                 freefunc(cmdp->param.func);
2875         }
2876         cmdp->cmdtype = entry->cmdtype;
2877         cmdp->param = entry->u;
2878         INTON;
2879 }
2880
2881
2882 /*
2883  * Define a shell function.
2884  */
2885
2886 static void
2887 defun(name, func)
2888         char *name;
2889         union node *func;
2890         {
2891         struct cmdentry entry;
2892
2893         entry.cmdtype = CMDFUNCTION;
2894         entry.u.func = copyfunc(func);
2895         addcmdentry(name, &entry);
2896 }
2897
2898
2899 /*
2900  * Delete a function if it exists.
2901  */
2902
2903 static void
2904 unsetfunc(name)
2905         char *name;
2906         {
2907         struct tblentry *cmdp;
2908
2909         if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
2910                 freefunc(cmdp->param.func);
2911                 delete_cmd_entry();
2912         }
2913 }
2914
2915 #ifdef ASH_TYPE
2916 /*
2917  * Locate and print what a word is...
2918  */
2919
2920 static int
2921 typecmd(argc, argv)
2922         int argc;
2923         char **argv;
2924 {
2925         int i;
2926         int err = 0;
2927
2928         for (i = 1; i < argc; i++) {
2929                 err |= describe_command(argv[i], 1);
2930         }
2931         return err;
2932 }
2933
2934 static int
2935 describe_command(command, verbose)
2936         char *command;
2937         int verbose;
2938 {
2939         struct cmdentry entry;
2940         struct tblentry *cmdp;
2941         const struct alias *ap;
2942         const char *path = pathval();
2943
2944         if (verbose) {
2945                 out1str(command);
2946         }
2947
2948         /* First look at the keywords */
2949         if (findkwd(command)) {
2950                 out1str(verbose ? " is a shell keyword" : command);
2951                 goto out;
2952         }
2953
2954         /* Then look at the aliases */
2955         if ((ap = lookupalias(command, 0)) != NULL) {
2956                 if (verbose) {
2957                         out1fmt(" is an alias for %s", ap->val);
2958                 } else {
2959                         printalias(ap);
2960                 }
2961                 goto out;
2962         }
2963
2964         /* Then check if it is a tracked alias */
2965         if ((cmdp = cmdlookup(command, 0)) != NULL) {
2966                 entry.cmdtype = cmdp->cmdtype;
2967                 entry.u = cmdp->param;
2968         } else {
2969                 /* Finally use brute force */
2970                 find_command(command, &entry, DO_ABS, path);
2971         }
2972
2973         switch (entry.cmdtype) {
2974         case CMDNORMAL: {
2975                 int j = entry.u.index;
2976                 char *p;
2977                 if (j == -1) {
2978                         p = command;
2979                 } else {
2980                         do {
2981                                 p = padvance(&path, command);
2982                                 stunalloc(p);
2983                         } while (--j >= 0);
2984                 }
2985                 if (verbose) {
2986                         out1fmt(
2987                                 " is%s %s",
2988                                 cmdp ? " a tracked alias for" : nullstr, p
2989                         );
2990                 } else {
2991                         out1str(p);
2992                 }
2993                 break;
2994         }
2995
2996         case CMDFUNCTION:
2997                 if (verbose) {
2998                         out1str(" is a shell function");
2999                 } else {
3000                         out1str(command);
3001                 }
3002                 break;
3003
3004         case CMDBUILTIN:
3005                 if (verbose) {
3006                         out1fmt(
3007                                 " is a %sshell builtin",
3008                                 entry.u.cmd->flags & BUILTIN_SPECIAL ?
3009                                         "special " : nullstr
3010                         );
3011                 } else {
3012                         out1str(command);
3013                 }
3014                 break;
3015
3016         default:
3017                 if (verbose) {
3018                         out1str(": not found\n");
3019                 }
3020                 return 127;
3021         }
3022
3023 out:
3024         out1c('\n');
3025         return 0;
3026 }
3027 #endif  
3028
3029 static int
3030 commandcmd(argc, argv)
3031         int argc;
3032         char **argv;
3033 {
3034         int c;
3035         int default_path = 0;
3036         int verify_only = 0;
3037         int verbose_verify_only = 0;
3038
3039         while ((c = nextopt("pvV")) != '\0')
3040                 switch (c) {
3041                 case 'p':
3042                         default_path = 1;
3043                         break;
3044                 case 'v':
3045                         verify_only = 1;
3046                         break;
3047                 case 'V':
3048                         verbose_verify_only = 1;
3049                         break;
3050                 default:
3051                         outfmt(out2,
3052 "command: nextopt returned character code 0%o\n", c);
3053                         return EX_SOFTWARE;
3054                 }
3055
3056         if (default_path + verify_only + verbose_verify_only > 1 ||
3057             !*argptr) {
3058                         outfmt(out2,
3059 "command [-p] command [arg ...]\n");
3060                         outfmt(out2,
3061 "command {-v|-V} command\n");
3062                         return EX_USAGE;
3063         }
3064
3065 #ifdef ASH_TYPE
3066         if (verify_only || verbose_verify_only) {
3067                 return describe_command(*argptr, verbose_verify_only);
3068         }
3069 #endif  
3070
3071         return 0;
3072 }
3073
3074 static int
3075 path_change(newval, bltin)
3076         const char *newval;
3077         int *bltin;
3078 {
3079         const char *old, *new;
3080         int idx;
3081         int firstchange;
3082
3083         old = pathval();
3084         new = newval;
3085         firstchange = 9999;     /* assume no change */
3086         idx = 0;
3087         *bltin = -1;
3088         for (;;) {
3089                 if (*old != *new) {
3090                         firstchange = idx;
3091                         if ((*old == '\0' && *new == ':')
3092                          || (*old == ':' && *new == '\0'))
3093                                 firstchange++;
3094                         old = new;      /* ignore subsequent differences */
3095                 }
3096                 if (*new == '\0')
3097                         break;
3098                 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
3099                         *bltin = idx;
3100                 if (*new == ':') {
3101                         idx++;
3102                 }
3103                 new++, old++;
3104         }
3105         if (builtinloc >= 0 && *bltin < 0)
3106                 firstchange = 0;
3107         return firstchange;
3108 }
3109 /*      $NetBSD: expand.c,v 1.50 2001/02/04 19:52:06 christos Exp $     */
3110
3111 /*
3112  * Routines to expand arguments to commands.  We have to deal with
3113  * backquotes, shell variables, and file metacharacters.
3114  */
3115 /*
3116  * _rmescape() flags
3117  */
3118 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
3119 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
3120
3121 /*
3122  * Structure specifying which parts of the string should be searched
3123  * for IFS characters.
3124  */
3125
3126 struct ifsregion {
3127         struct ifsregion *next; /* next region in list */
3128         int begoff;             /* offset of start of region */
3129         int endoff;             /* offset of end of region */
3130         int nulonly;            /* search for nul bytes only */
3131 };
3132
3133
3134 static char *expdest;                   /* output of current string */
3135 struct nodelist *argbackq;      /* list of back quote expressions */
3136 struct ifsregion ifsfirst;      /* first struct in list of ifs regions */
3137 struct ifsregion *ifslastp;     /* last struct in list */
3138 struct arglist exparg;          /* holds expanded arg list */
3139
3140 static void argstr __P((char *, int));
3141 static char *exptilde __P((char *, int));
3142 static void expbackq __P((union node *, int, int));
3143 static int subevalvar __P((char *, char *, int, int, int, int, int));
3144 static char *evalvar __P((char *, int));
3145 static int varisset __P((char *, int));
3146 static void strtodest __P((const char *, const char *, int));
3147 static void varvalue __P((char *, int, int));
3148 static void recordregion __P((int, int, int));
3149 static void removerecordregions __P((int)); 
3150 static void ifsbreakup __P((char *, struct arglist *));
3151 static void ifsfree __P((void));
3152 static void expandmeta __P((struct strlist *, int));
3153 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
3154 #define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
3155 #if !defined(GLOB_BROKEN)
3156 static void addglob __P((const glob_t *));
3157 #endif
3158 #endif
3159 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
3160 static void expmeta __P((char *, char *));
3161 #endif
3162 static void addfname __P((char *));
3163 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
3164 static struct strlist *expsort __P((struct strlist *));
3165 static struct strlist *msort __P((struct strlist *, int));
3166 #endif
3167 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
3168 static int patmatch __P((char *, char *, int));
3169 static int patmatch2 __P((char *, char *, int));
3170 #else
3171 static int pmatch __P((char *, char *, int));
3172 #define patmatch2 patmatch
3173 #endif
3174 static char *cvtnum __P((int, char *));
3175
3176 extern int oexitstatus;
3177
3178 /*
3179  * Expand shell variables and backquotes inside a here document.
3180  */
3181
3182 static void
3183 expandhere(arg, fd)
3184         union node *arg;        /* the document */
3185         int fd;                 /* where to write the expanded version */
3186         {
3187         herefd = fd;
3188         expandarg(arg, (struct arglist *)NULL, 0);
3189         xwrite(fd, stackblock(), expdest - stackblock());
3190 }
3191
3192
3193 /*
3194  * Perform variable substitution and command substitution on an argument,
3195  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
3196  * perform splitting and file name expansion.  When arglist is NULL, perform
3197  * here document expansion.
3198  */
3199
3200 static void
3201 expandarg(arg, arglist, flag)
3202         union node *arg;
3203         struct arglist *arglist;
3204         int flag;
3205 {
3206         struct strlist *sp;
3207         char *p;
3208
3209         argbackq = arg->narg.backquote;
3210         STARTSTACKSTR(expdest);
3211         ifsfirst.next = NULL;
3212         ifslastp = NULL;
3213         argstr(arg->narg.text, flag);
3214         if (arglist == NULL) {
3215                 return;                 /* here document expanded */
3216         }
3217         STPUTC('\0', expdest);
3218         p = grabstackstr(expdest);
3219         exparg.lastp = &exparg.list;
3220         /*
3221          * TODO - EXP_REDIR
3222          */
3223         if (flag & EXP_FULL) {
3224                 ifsbreakup(p, &exparg);
3225                 *exparg.lastp = NULL;
3226                 exparg.lastp = &exparg.list;
3227                 expandmeta(exparg.list, flag);
3228         } else {
3229                 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
3230                         rmescapes(p);
3231                 sp = (struct strlist *)stalloc(sizeof (struct strlist));
3232                 sp->text = p;
3233                 *exparg.lastp = sp;
3234                 exparg.lastp = &sp->next;
3235         }
3236         ifsfree();
3237         *exparg.lastp = NULL;
3238         if (exparg.list) {
3239                 *arglist->lastp = exparg.list;
3240                 arglist->lastp = exparg.lastp;
3241         }
3242 }
3243
3244
3245
3246 /*
3247  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
3248  * characters to allow for further processing.  Otherwise treat
3249  * $@ like $* since no splitting will be performed.
3250  */
3251
3252 static void
3253 argstr(p, flag)
3254         char *p;
3255         int flag;
3256 {
3257         char c;
3258         int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
3259         int firsteq = 1;
3260
3261         if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
3262                 p = exptilde(p, flag);
3263         for (;;) {
3264                 switch (c = *p++) {
3265                 case '\0':
3266                 case CTLENDVAR: /* ??? */
3267                         goto breakloop;
3268                 case CTLQUOTEMARK:
3269                         /* "$@" syntax adherence hack */
3270                         if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
3271                                 break;
3272                         if ((flag & EXP_FULL) != 0)
3273                                 STPUTC(c, expdest);
3274                         break;
3275                 case CTLESC:
3276                         if (quotes)
3277                                 STPUTC(c, expdest);
3278                         c = *p++;
3279                         STPUTC(c, expdest);
3280                         break;
3281                 case CTLVAR:
3282                         p = evalvar(p, flag);
3283                         break;
3284                 case CTLBACKQ:
3285                 case CTLBACKQ|CTLQUOTE:
3286                         expbackq(argbackq->n, c & CTLQUOTE, flag);
3287                         argbackq = argbackq->next;
3288                         break;
3289 #ifdef ASH_MATH_SUPPORT
3290                 case CTLENDARI:
3291                         expari(flag);
3292                         break;
3293 #endif  
3294                 case ':':
3295                 case '=':
3296                         /*
3297                          * sort of a hack - expand tildes in variable
3298                          * assignments (after the first '=' and after ':'s).
3299                          */
3300                         STPUTC(c, expdest);
3301                         if (flag & EXP_VARTILDE && *p == '~') {
3302                                 if (c == '=') {
3303                                         if (firsteq)
3304                                                 firsteq = 0;
3305                                         else
3306                                                 break;
3307                                 }
3308                                 p = exptilde(p, flag);
3309                         }
3310                         break;
3311                 default:
3312                         STPUTC(c, expdest);
3313                 }
3314         }
3315 breakloop:;
3316         return;
3317 }
3318
3319 static char *
3320 exptilde(p, flag)
3321         char *p;
3322         int flag;
3323 {
3324         char c, *startp = p;
3325         struct passwd *pw;
3326         const char *home;
3327         int quotes = flag & (EXP_FULL | EXP_CASE);
3328
3329         while ((c = *p) != '\0') {
3330                 switch(c) {
3331                 case CTLESC:
3332                         return (startp);
3333                 case CTLQUOTEMARK:
3334                         return (startp);
3335                 case ':':
3336                         if (flag & EXP_VARTILDE)
3337                                 goto done;
3338                         break;
3339                 case '/':
3340                         goto done;
3341                 }
3342                 p++;
3343         }
3344 done:
3345         *p = '\0';
3346         if (*(startp+1) == '\0') {
3347                 if ((home = lookupvar("HOME")) == NULL)
3348                         goto lose;
3349         } else {
3350                 if ((pw = getpwnam(startp+1)) == NULL)
3351                         goto lose;
3352                 home = pw->pw_dir;
3353         }
3354         if (*home == '\0')
3355                 goto lose;
3356         *p = c;
3357         strtodest(home, SQSYNTAX, quotes);
3358         return (p);
3359 lose:
3360         *p = c;
3361         return (startp);
3362 }
3363
3364
3365 static void 
3366 removerecordregions(endoff)
3367         int endoff;
3368 {
3369         if (ifslastp == NULL)
3370                 return;
3371
3372         if (ifsfirst.endoff > endoff) {
3373                 while (ifsfirst.next != NULL) {
3374                         struct ifsregion *ifsp;
3375                         INTOFF;
3376                         ifsp = ifsfirst.next->next;
3377                         ckfree(ifsfirst.next);
3378                         ifsfirst.next = ifsp;
3379                         INTON;
3380                 }
3381                 if (ifsfirst.begoff > endoff)
3382                         ifslastp = NULL;
3383                 else {
3384                         ifslastp = &ifsfirst;
3385                         ifsfirst.endoff = endoff;
3386                 }
3387                 return;
3388         }
3389         
3390         ifslastp = &ifsfirst;
3391         while (ifslastp->next && ifslastp->next->begoff < endoff)
3392                 ifslastp=ifslastp->next;
3393         while (ifslastp->next != NULL) {
3394                 struct ifsregion *ifsp;
3395                 INTOFF;
3396                 ifsp = ifslastp->next->next;
3397                 ckfree(ifslastp->next);
3398                 ifslastp->next = ifsp;
3399                 INTON;
3400         }
3401         if (ifslastp->endoff > endoff)
3402                 ifslastp->endoff = endoff;
3403 }
3404
3405
3406 #ifdef ASH_MATH_SUPPORT
3407 /*
3408  * Expand arithmetic expression.  Backup to start of expression,
3409  * evaluate, place result in (backed up) result, adjust string position.
3410  */
3411 static void
3412 expari(flag)
3413         int flag;
3414 {
3415         char *p, *start;
3416         int result;
3417         int begoff;
3418         int quotes = flag & (EXP_FULL | EXP_CASE);
3419         int quoted;
3420
3421         /*      ifsfree(); */
3422
3423         /*
3424          * This routine is slightly over-complicated for
3425          * efficiency.  First we make sure there is
3426          * enough space for the result, which may be bigger
3427          * than the expression if we add exponentation.  Next we
3428          * scan backwards looking for the start of arithmetic.  If the
3429          * next previous character is a CTLESC character, then we
3430          * have to rescan starting from the beginning since CTLESC
3431          * characters have to be processed left to right.
3432          */
3433         CHECKSTRSPACE(10, expdest);
3434         USTPUTC('\0', expdest);
3435         start = stackblock();
3436         p = expdest - 1;
3437         while (*p != CTLARI && p >= start)
3438                 --p;
3439         if (*p != CTLARI)
3440                 error("missing CTLARI (shouldn't happen)");
3441         if (p > start && *(p-1) == CTLESC)
3442                 for (p = start; *p != CTLARI; p++)
3443                         if (*p == CTLESC)
3444                                 p++;
3445
3446         if (p[1] == '"')
3447                 quoted=1;
3448         else
3449                 quoted=0;
3450         begoff = p - start;
3451         removerecordregions(begoff);
3452         if (quotes)
3453                 rmescapes(p+2);
3454         result = arith(p+2);
3455         fmtstr(p, 12, "%d", result);
3456
3457         while (*p++)
3458                 ;
3459
3460         if (quoted == 0)
3461                 recordregion(begoff, p - 1 - start, 0);
3462         result = expdest - p + 1;
3463         STADJUST(-result, expdest);
3464 }
3465 #endif  
3466
3467
3468 /*
3469  * Expand stuff in backwards quotes.
3470  */
3471
3472 static void
3473 expbackq(cmd, quoted, flag)
3474         union node *cmd;
3475         int quoted;
3476         int flag;
3477 {
3478         volatile struct backcmd in;
3479         int i;
3480         char buf[128];
3481         char *p;
3482         char *dest = expdest;
3483         volatile struct ifsregion saveifs;
3484         struct ifsregion *volatile savelastp;
3485         struct nodelist *volatile saveargbackq;
3486         char lastc;
3487         int startloc = dest - stackblock();
3488         char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
3489         volatile int saveherefd;
3490         int quotes = flag & (EXP_FULL | EXP_CASE);
3491         struct jmploc jmploc;
3492         struct jmploc *volatile savehandler;
3493         int ex;
3494
3495 #if __GNUC__
3496         /* Avoid longjmp clobbering */
3497         (void) &dest;
3498         (void) &syntax;
3499 #endif
3500
3501         in.fd = -1;
3502         in.buf = 0;
3503         in.jp = 0;
3504
3505         INTOFF;
3506         saveifs = ifsfirst;
3507         savelastp = ifslastp;
3508         saveargbackq = argbackq;
3509         saveherefd = herefd;
3510         herefd = -1;
3511         if ((ex = setjmp(jmploc.loc))) {
3512                 goto err1;
3513         }
3514         savehandler = handler;
3515         handler = &jmploc;
3516         INTON;
3517         p = grabstackstr(dest);
3518         evalbackcmd(cmd, (struct backcmd *) &in);
3519         ungrabstackstr(p, dest);
3520 err1:
3521         INTOFF;
3522         ifsfirst = saveifs;
3523         ifslastp = savelastp;
3524         argbackq = saveargbackq;
3525         herefd = saveherefd;
3526         if (ex) {
3527                 goto err2;
3528         }
3529
3530         p = in.buf;
3531         lastc = '\0';
3532         for (;;) {
3533                 if (--in.nleft < 0) {
3534                         if (in.fd < 0)
3535                                 break;
3536                         while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
3537                         TRACE(("expbackq: read returns %d\n", i));
3538                         if (i <= 0)
3539                                 break;
3540                         p = buf;
3541                         in.nleft = i - 1;
3542                 }
3543                 lastc = *p++;
3544                 if (lastc != '\0') {
3545                         if (quotes && syntax[(int)lastc] == CCTL)
3546                                 STPUTC(CTLESC, dest);
3547                         STPUTC(lastc, dest);
3548                 }
3549         }
3550
3551         /* Eat all trailing newlines */
3552         for (; dest > stackblock() && dest[-1] == '\n';)
3553                 STUNPUTC(dest);
3554
3555 err2:
3556         if (in.fd >= 0)
3557                 close(in.fd);
3558         if (in.buf)
3559                 ckfree(in.buf);
3560         if (in.jp)
3561                 exitstatus = waitforjob(in.jp);
3562         handler = savehandler;
3563         if (ex) {
3564                 longjmp(handler->loc, 1);
3565         }
3566         if (quoted == 0)
3567                 recordregion(startloc, dest - stackblock(), 0);
3568         TRACE(("evalbackq: size=%d: \"%.*s\"\n",
3569                 (dest - stackblock()) - startloc,
3570                 (dest - stackblock()) - startloc,
3571                 stackblock() + startloc));
3572         expdest = dest;
3573         INTON;
3574 }
3575
3576
3577
3578 static int
3579 subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
3580         char *p;
3581         char *str;
3582         int strloc;
3583         int subtype;
3584         int startloc;
3585         int varflags;
3586         int quotes;
3587 {
3588         char *startp;
3589         char *loc = NULL;
3590         char *q;
3591         int c = 0;
3592         int saveherefd = herefd;
3593         struct nodelist *saveargbackq = argbackq;
3594         int amount;
3595
3596         herefd = -1;
3597         argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
3598         STACKSTRNUL(expdest);
3599         herefd = saveherefd;
3600         argbackq = saveargbackq;
3601         startp = stackblock() + startloc;
3602         if (str == NULL)
3603             str = stackblock() + strloc;
3604
3605         switch (subtype) {
3606         case VSASSIGN:
3607                 setvar(str, startp, 0);
3608                 amount = startp - expdest;
3609                 STADJUST(amount, expdest);
3610                 varflags &= ~VSNUL;
3611                 if (c != 0)
3612                         *loc = c;
3613                 return 1;
3614
3615         case VSQUESTION:
3616                 if (*p != CTLENDVAR) {
3617                         outfmt(&errout, snlfmt, startp);
3618                         error((char *)NULL);
3619                 }
3620                 error("%.*s: parameter %snot set", p - str - 1,
3621                       str, (varflags & VSNUL) ? "null or "
3622                                               : nullstr);
3623                 /* NOTREACHED */
3624
3625         case VSTRIMLEFT:
3626                 for (loc = startp; loc < str; loc++) {
3627                         c = *loc;
3628                         *loc = '\0';
3629                         if (patmatch2(str, startp, quotes))
3630                                 goto recordleft;
3631                         *loc = c;
3632                         if (quotes && *loc == CTLESC)
3633                                 loc++;
3634                 }
3635                 return 0;
3636
3637         case VSTRIMLEFTMAX:
3638                 for (loc = str - 1; loc >= startp;) {
3639                         c = *loc;
3640                         *loc = '\0';
3641                         if (patmatch2(str, startp, quotes))
3642                                 goto recordleft;
3643                         *loc = c;
3644                         loc--;
3645                         if (quotes && loc > startp && *(loc - 1) == CTLESC) {
3646                                 for (q = startp; q < loc; q++)
3647                                         if (*q == CTLESC)
3648                                                 q++;
3649                                 if (q > loc)
3650                                         loc--;
3651                         }
3652                 }
3653                 return 0;
3654
3655         case VSTRIMRIGHT:
3656                 for (loc = str - 1; loc >= startp;) {
3657                         if (patmatch2(str, loc, quotes))
3658                                 goto recordright;
3659                         loc--;
3660                         if (quotes && loc > startp && *(loc - 1) == CTLESC) { 
3661                                 for (q = startp; q < loc; q++)
3662                                         if (*q == CTLESC)
3663                                                 q++;
3664                                 if (q > loc)
3665                                         loc--;
3666                         }
3667                 }
3668                 return 0;
3669
3670         case VSTRIMRIGHTMAX:
3671                 for (loc = startp; loc < str - 1; loc++) {
3672                         if (patmatch2(str, loc, quotes))
3673                                 goto recordright;
3674                         if (quotes && *loc == CTLESC)
3675                                 loc++;
3676                 }
3677                 return 0;
3678
3679 #ifdef DEBUG
3680         default:
3681                 abort();
3682 #endif
3683         }
3684
3685 recordleft:
3686         *loc = c;
3687         amount = ((str - 1) - (loc - startp)) - expdest;
3688         STADJUST(amount, expdest);
3689         while (loc != str - 1)
3690                 *startp++ = *loc++;
3691         return 1;
3692
3693 recordright:
3694         amount = loc - expdest;
3695         STADJUST(amount, expdest);
3696         STPUTC('\0', expdest);
3697         STADJUST(-1, expdest);
3698         return 1;
3699 }
3700
3701
3702 /*
3703  * Expand a variable, and return a pointer to the next character in the
3704  * input string.
3705  */
3706
3707 static char *
3708 evalvar(p, flag)
3709         char *p;
3710         int flag;
3711 {
3712         int subtype;
3713         int varflags;
3714         char *var;
3715         char *val;
3716         int patloc;
3717         int c;
3718         int set;
3719         int special;
3720         int startloc;
3721         int varlen;
3722         int easy;
3723         int quotes = flag & (EXP_FULL | EXP_CASE);
3724
3725         varflags = *p++;
3726         subtype = varflags & VSTYPE;
3727         var = p;
3728         special = 0;
3729         if (! is_name(*p))
3730                 special = 1;
3731         p = strchr(p, '=') + 1;
3732 again: /* jump here after setting a variable with ${var=text} */
3733         if (special) {
3734                 set = varisset(var, varflags & VSNUL);
3735                 val = NULL;
3736         } else {
3737                 val = lookupvar(var);
3738                 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
3739                         val = NULL;
3740                         set = 0;
3741                 } else
3742                         set = 1;
3743         }
3744         varlen = 0;
3745         startloc = expdest - stackblock();
3746         if (set && subtype != VSPLUS) {
3747                 /* insert the value of the variable */
3748                 if (special) {
3749                         varvalue(var, varflags & VSQUOTE, flag);
3750                         if (subtype == VSLENGTH) {
3751                                 varlen = expdest - stackblock() - startloc;
3752                                 STADJUST(-varlen, expdest);
3753                         }
3754                 } else {
3755                         if (subtype == VSLENGTH) {
3756                                 varlen = strlen(val);
3757                         } else {
3758                                 strtodest(
3759                                         val,
3760                                         varflags & VSQUOTE ?
3761                                                 DQSYNTAX : BASESYNTAX,
3762                                         quotes
3763                                 );
3764                         }
3765                 }
3766         }
3767
3768         if (subtype == VSPLUS)
3769                 set = ! set;
3770
3771         easy = ((varflags & VSQUOTE) == 0 ||
3772                 (*var == '@' && shellparam.nparam != 1));
3773
3774
3775         switch (subtype) {
3776         case VSLENGTH:
3777                 expdest = cvtnum(varlen, expdest);
3778                 goto record;
3779
3780         case VSNORMAL:
3781                 if (!easy)
3782                         break;
3783 record:
3784                 recordregion(startloc, expdest - stackblock(),
3785                              varflags & VSQUOTE);
3786                 break;
3787
3788         case VSPLUS:
3789         case VSMINUS:
3790                 if (!set) {
3791                         argstr(p, flag);
3792                         break;
3793                 }
3794                 if (easy)
3795                         goto record;
3796                 break;
3797
3798         case VSTRIMLEFT:
3799         case VSTRIMLEFTMAX:
3800         case VSTRIMRIGHT:
3801         case VSTRIMRIGHTMAX:
3802                 if (!set)
3803                         break;
3804                 /*
3805                  * Terminate the string and start recording the pattern
3806                  * right after it
3807                  */
3808                 STPUTC('\0', expdest);
3809                 patloc = expdest - stackblock();
3810                 if (subevalvar(p, NULL, patloc, subtype,
3811                                startloc, varflags, quotes) == 0) {
3812                         int amount = (expdest - stackblock() - patloc) + 1;
3813                         STADJUST(-amount, expdest);
3814                 }
3815                 /* Remove any recorded regions beyond start of variable */
3816                 removerecordregions(startloc);
3817                 goto record;
3818
3819         case VSASSIGN:
3820         case VSQUESTION:
3821                 if (!set) {
3822                         if (subevalvar(p, var, 0, subtype, startloc,
3823                                        varflags, quotes)) {
3824                                 varflags &= ~VSNUL;
3825                                 /* 
3826                                  * Remove any recorded regions beyond 
3827                                  * start of variable 
3828                                  */
3829                                 removerecordregions(startloc);
3830                                 goto again;
3831                         }
3832                         break;
3833                 }
3834                 if (easy)
3835                         goto record;
3836                 break;
3837
3838 #ifdef DEBUG
3839         default:
3840                 abort();
3841 #endif
3842         }
3843
3844         if (subtype != VSNORMAL) {      /* skip to end of alternative */
3845                 int nesting = 1;
3846                 for (;;) {
3847                         if ((c = *p++) == CTLESC)
3848                                 p++;
3849                         else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
3850                                 if (set)
3851                                         argbackq = argbackq->next;
3852                         } else if (c == CTLVAR) {
3853                                 if ((*p++ & VSTYPE) != VSNORMAL)
3854                                         nesting++;
3855                         } else if (c == CTLENDVAR) {
3856                                 if (--nesting == 0)
3857                                         break;
3858                         }
3859                 }
3860         }
3861         return p;
3862 }
3863
3864
3865
3866 /*
3867  * Test whether a specialized variable is set.
3868  */
3869
3870 static int
3871 varisset(name, nulok)
3872         char *name;
3873         int nulok;
3874 {
3875         if (*name == '!')
3876                 return backgndpid != -1;
3877         else if (*name == '@' || *name == '*') {
3878                 if (*shellparam.p == NULL)
3879                         return 0;
3880
3881                 if (nulok) {
3882                         char **av;
3883
3884                         for (av = shellparam.p; *av; av++)
3885                                 if (**av != '\0')
3886                                         return 1;
3887                         return 0;
3888                 }
3889         } else if (is_digit(*name)) {
3890                 char *ap;
3891                 int num = atoi(name);
3892
3893                 if (num > shellparam.nparam)
3894                         return 0;
3895
3896                 if (num == 0)
3897                         ap = arg0;
3898                 else
3899                         ap = shellparam.p[num - 1];
3900
3901                 if (nulok && (ap == NULL || *ap == '\0'))
3902                         return 0;
3903         }
3904         return 1;
3905 }
3906
3907
3908
3909 /*
3910  * Put a string on the stack.
3911  */
3912
3913 static void
3914 strtodest(p, syntax, quotes)
3915         const char *p;
3916         const char *syntax;
3917         int quotes;
3918 {
3919         while (*p) {
3920                 if (quotes && syntax[(int) *p] == CCTL)
3921                         STPUTC(CTLESC, expdest);
3922                 STPUTC(*p++, expdest);
3923         }
3924 }
3925
3926
3927
3928 /*
3929  * Add the value of a specialized variable to the stack string.
3930  */
3931
3932 static void
3933 varvalue(name, quoted, flags)
3934         char *name;
3935         int quoted;
3936         int flags;
3937 {
3938         int num;
3939         char *p;
3940         int i;
3941         int sep;
3942         int sepq = 0;
3943         char **ap;
3944         char const *syntax;
3945         int allow_split = flags & EXP_FULL;
3946         int quotes = flags & (EXP_FULL | EXP_CASE);
3947
3948         syntax = quoted ? DQSYNTAX : BASESYNTAX;
3949         switch (*name) {
3950         case '$':
3951                 num = rootpid;
3952                 goto numvar;
3953         case '?':
3954                 num = oexitstatus;
3955                 goto numvar;
3956         case '#':
3957                 num = shellparam.nparam;
3958                 goto numvar;
3959         case '!':
3960                 num = backgndpid;
3961 numvar:
3962                 expdest = cvtnum(num, expdest);
3963                 break;
3964         case '-':
3965                 for (i = 0 ; i < NOPTS ; i++) {
3966                         if (optlist[i].val)
3967                                 STPUTC(optlist[i].letter, expdest);
3968                 }
3969                 break;
3970         case '@':
3971                 if (allow_split && quoted) {
3972                         sep = 1 << CHAR_BIT;
3973                         goto param;
3974                 }
3975                 /* fall through */
3976         case '*':
3977                 sep = ifsset() ? ifsval()[0] : ' ';
3978                 if (quotes) {
3979                         sepq = syntax[(int) sep] == CCTL;
3980                 }
3981 param:
3982                 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
3983                         strtodest(p, syntax, quotes);
3984                         if (*ap && sep) {
3985                                 if (sepq)
3986                                         STPUTC(CTLESC, expdest);
3987                                 STPUTC(sep, expdest);
3988                         }
3989                 }
3990                 break;
3991         case '0':
3992                 strtodest(arg0, syntax, quotes);
3993                 break;
3994         default:
3995                 num = atoi(name);
3996                 if (num > 0 && num <= shellparam.nparam) {
3997                         strtodest(shellparam.p[num - 1], syntax, quotes);
3998                 }
3999                 break;
4000         }
4001 }
4002
4003
4004
4005 /*
4006  * Record the fact that we have to scan this region of the
4007  * string for IFS characters.
4008  */
4009
4010 static void
4011 recordregion(start, end, nulonly)
4012         int start;
4013         int end;
4014         int nulonly;
4015 {
4016         struct ifsregion *ifsp;
4017
4018         if (ifslastp == NULL) {
4019                 ifsp = &ifsfirst;
4020         } else {
4021                 INTOFF;
4022                 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
4023                 ifsp->next = NULL;
4024                 ifslastp->next = ifsp;
4025                 INTON;
4026         }
4027         ifslastp = ifsp;
4028         ifslastp->begoff = start;
4029         ifslastp->endoff = end;
4030         ifslastp->nulonly = nulonly;
4031 }
4032
4033
4034
4035 /*
4036  * Break the argument string into pieces based upon IFS and add the
4037  * strings to the argument list.  The regions of the string to be
4038  * searched for IFS characters have been stored by recordregion.
4039  */
4040 static void
4041 ifsbreakup(string, arglist)
4042         char *string;
4043         struct arglist *arglist;
4044         {
4045         struct ifsregion *ifsp;
4046         struct strlist *sp;
4047         char *start;
4048         char *p;
4049         char *q;
4050         const char *ifs, *realifs;
4051         int ifsspc;
4052         int nulonly;
4053
4054
4055         start = string;
4056         ifsspc = 0;
4057         nulonly = 0;
4058         realifs = ifsset() ? ifsval() : defifs;
4059         if (ifslastp != NULL) {
4060                 ifsp = &ifsfirst;
4061                 do {
4062                         p = string + ifsp->begoff;
4063                         nulonly = ifsp->nulonly;
4064                         ifs = nulonly ? nullstr : realifs;
4065                         ifsspc = 0;
4066                         while (p < string + ifsp->endoff) {
4067                                 q = p;
4068                                 if (*p == CTLESC)
4069                                         p++;
4070                                 if (strchr(ifs, *p)) {
4071                                         if (!nulonly)
4072                                                 ifsspc = (strchr(defifs, *p) != NULL);
4073                                         /* Ignore IFS whitespace at start */
4074                                         if (q == start && ifsspc) {
4075                                                 p++;
4076                                                 start = p;
4077                                                 continue;
4078                                         }
4079                                         *q = '\0';
4080                                         sp = (struct strlist *)stalloc(sizeof *sp);
4081                                         sp->text = start;
4082                                         *arglist->lastp = sp;
4083                                         arglist->lastp = &sp->next;
4084                                         p++;
4085                                         if (!nulonly) {
4086                                                 for (;;) {
4087                                                         if (p >= string + ifsp->endoff) {
4088                                                                 break;
4089                                                         }
4090                                                         q = p;
4091                                                         if (*p == CTLESC)
4092                                                                 p++;
4093                                                         if (strchr(ifs, *p) == NULL ) {
4094                                                                 p = q;
4095                                                                 break;
4096                                                         } else if (strchr(defifs, *p) == NULL) {
4097                                                                 if (ifsspc) {
4098                                                                         p++;
4099                                                                         ifsspc = 0;
4100                                                                 } else {
4101                                                                         p = q;
4102                                                                         break;
4103                                                                 }
4104                                                         } else
4105                                                                 p++;
4106                                                 }
4107                                         }
4108                                         start = p;
4109                                 } else
4110                                         p++;
4111                         }
4112                 } while ((ifsp = ifsp->next) != NULL);
4113                 if (!(*start || (!ifsspc && start > string && nulonly))) {
4114                         return;
4115                 }
4116         }
4117
4118         sp = (struct strlist *)stalloc(sizeof *sp);
4119         sp->text = start;
4120         *arglist->lastp = sp;
4121         arglist->lastp = &sp->next;
4122 }
4123
4124 static void
4125 ifsfree()
4126 {
4127         while (ifsfirst.next != NULL) {
4128                 struct ifsregion *ifsp;
4129                 INTOFF;
4130                 ifsp = ifsfirst.next->next;
4131                 ckfree(ifsfirst.next);
4132                 ifsfirst.next = ifsp;
4133                 INTON;
4134         }
4135         ifslastp = NULL;
4136         ifsfirst.next = NULL;
4137 }
4138
4139
4140
4141 /*
4142  * Expand shell metacharacters.  At this point, the only control characters
4143  * should be escapes.  The results are stored in the list exparg.
4144  */
4145
4146 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
4147 static void
4148 expandmeta(str, flag)
4149         struct strlist *str;
4150         int flag;
4151 {
4152         const char *p;
4153         glob_t pglob;
4154         /* TODO - EXP_REDIR */
4155
4156         while (str) {
4157                 if (fflag)
4158                         goto nometa;
4159                 p = preglob(str->text);
4160                 INTOFF;
4161                 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
4162                 case 0:
4163                         if (!(pglob.gl_flags & GLOB_MAGCHAR))
4164                                 goto nometa2;
4165                         addglob(&pglob);
4166                         globfree(&pglob);
4167                         INTON;
4168                         break;
4169                 case GLOB_NOMATCH:
4170 nometa2:
4171                         globfree(&pglob);
4172                         INTON;
4173 nometa:
4174                         *exparg.lastp = str;
4175                         rmescapes(str->text);
4176                         exparg.lastp = &str->next;
4177                         break;
4178                 default:        /* GLOB_NOSPACE */
4179                         error("Out of space");
4180                 }
4181                 str = str->next;
4182         }
4183 }
4184
4185
4186 /*
4187  * Add the result of glob(3) to the list.
4188  */
4189
4190 static void
4191 addglob(pglob)
4192         const glob_t *pglob;
4193 {
4194         char **p = pglob->gl_pathv;
4195
4196         do {
4197                 addfname(*p);
4198         } while (*++p);
4199 }
4200
4201
4202 #else   /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
4203 static char *expdir;
4204
4205
4206 static void
4207 expandmeta(str, flag)
4208         struct strlist *str;
4209         int flag;
4210 {
4211         char *p;
4212         struct strlist **savelastp;
4213         struct strlist *sp;
4214         char c;
4215         /* TODO - EXP_REDIR */
4216
4217         while (str) {
4218                 if (fflag)
4219                         goto nometa;
4220                 p = str->text;
4221                 for (;;) {                      /* fast check for meta chars */
4222                         if ((c = *p++) == '\0')
4223                                 goto nometa;
4224                         if (c == '*' || c == '?' || c == '[' || c == '!')
4225                                 break;
4226                 }
4227                 savelastp = exparg.lastp;
4228                 INTOFF;
4229                 if (expdir == NULL) {
4230                         int i = strlen(str->text);
4231                         expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
4232                 }
4233
4234                 expmeta(expdir, str->text);
4235                 ckfree(expdir);
4236                 expdir = NULL;
4237                 INTON;
4238                 if (exparg.lastp == savelastp) {
4239                         /*
4240                          * no matches
4241                          */
4242 nometa:
4243                         *exparg.lastp = str;
4244                         rmescapes(str->text);
4245                         exparg.lastp = &str->next;
4246                 } else {
4247                         *exparg.lastp = NULL;
4248                         *savelastp = sp = expsort(*savelastp);
4249                         while (sp->next != NULL)
4250                                 sp = sp->next;
4251                         exparg.lastp = &sp->next;
4252                 }
4253                 str = str->next;
4254         }
4255 }
4256
4257
4258 /*
4259  * Do metacharacter (i.e. *, ?, [...]) expansion.
4260  */
4261
4262 static void
4263 expmeta(enddir, name)
4264         char *enddir;
4265         char *name;
4266         {
4267         char *p;
4268         const char *cp;
4269         char *q;
4270         char *start;
4271         char *endname;
4272         int metaflag;
4273         struct stat statb;
4274         DIR *dirp;
4275         struct dirent *dp;
4276         int atend;
4277         int matchdot;
4278
4279         metaflag = 0;
4280         start = name;
4281         for (p = name ; ; p++) {
4282                 if (*p == '*' || *p == '?')
4283                         metaflag = 1;
4284                 else if (*p == '[') {
4285                         q = p + 1;
4286                         if (*q == '!')
4287                                 q++;
4288                         for (;;) {
4289                                 while (*q == CTLQUOTEMARK)
4290                                         q++;
4291                                 if (*q == CTLESC)
4292                                         q++;
4293                                 if (*q == '/' || *q == '\0')
4294                                         break;
4295                                 if (*++q == ']') {
4296                                         metaflag = 1;
4297                                         break;
4298                                 }
4299                         }
4300                 } else if (*p == '!' && p[1] == '!'     && (p == name || p[-1] == '/')) {
4301                         metaflag = 1;
4302                 } else if (*p == '\0')
4303                         break;
4304                 else if (*p == CTLQUOTEMARK)
4305                         continue;
4306                 else if (*p == CTLESC)
4307                         p++;
4308                 if (*p == '/') {
4309                         if (metaflag)
4310                                 break;
4311                         start = p + 1;
4312                 }
4313         }
4314         if (metaflag == 0) {    /* we've reached the end of the file name */
4315                 if (enddir != expdir)
4316                         metaflag++;
4317                 for (p = name ; ; p++) {
4318                         if (*p == CTLQUOTEMARK)
4319                                 continue;
4320                         if (*p == CTLESC)
4321                                 p++;
4322                         *enddir++ = *p;
4323                         if (*p == '\0')
4324                                 break;
4325                 }
4326                 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
4327                         addfname(expdir);
4328                 return;
4329         }
4330         endname = p;
4331         if (start != name) {
4332                 p = name;
4333                 while (p < start) {
4334                         while (*p == CTLQUOTEMARK)
4335                                 p++;
4336                         if (*p == CTLESC)
4337                                 p++;
4338                         *enddir++ = *p++;
4339                 }
4340         }
4341         if (enddir == expdir) {
4342                 cp = ".";
4343         } else if (enddir == expdir + 1 && *expdir == '/') {
4344                 cp = "/";
4345         } else {
4346                 cp = expdir;
4347                 enddir[-1] = '\0';
4348         }
4349         if ((dirp = opendir(cp)) == NULL)
4350                 return;
4351         if (enddir != expdir)
4352                 enddir[-1] = '/';
4353         if (*endname == 0) {
4354                 atend = 1;
4355         } else {
4356                 atend = 0;
4357                 *endname++ = '\0';
4358         }
4359         matchdot = 0;
4360         p = start;
4361         while (*p == CTLQUOTEMARK)
4362                 p++;
4363         if (*p == CTLESC)
4364                 p++;
4365         if (*p == '.')
4366                 matchdot++;
4367         while (! int_pending() && (dp = readdir(dirp)) != NULL) {
4368                 if (dp->d_name[0] == '.' && ! matchdot)
4369                         continue;
4370                 if (patmatch(start, dp->d_name, 0)) {
4371                         if (atend) {
4372                                 scopy(dp->d_name, enddir);
4373                                 addfname(expdir);
4374                         } else {
4375                                 for (p = enddir, cp = dp->d_name;
4376                                      (*p++ = *cp++) != '\0';)
4377                                         continue;
4378                                 p[-1] = '/';
4379                                 expmeta(p, endname);
4380                         }
4381                 }
4382         }
4383         closedir(dirp);
4384         if (! atend)
4385                 endname[-1] = '/';
4386 }
4387 #endif  /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
4388
4389
4390 /*
4391  * Add a file name to the list.
4392  */
4393
4394 static void
4395 addfname(name)
4396         char *name;
4397         {
4398         char *p;
4399         struct strlist *sp;
4400
4401         p = sstrdup(name);
4402         sp = (struct strlist *)stalloc(sizeof *sp);
4403         sp->text = p;
4404         *exparg.lastp = sp;
4405         exparg.lastp = &sp->next;
4406 }
4407
4408
4409 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4410 /*
4411  * Sort the results of file name expansion.  It calculates the number of
4412  * strings to sort and then calls msort (short for merge sort) to do the
4413  * work.
4414  */
4415
4416 static struct strlist *
4417 expsort(str)
4418         struct strlist *str;
4419         {
4420         int len;
4421         struct strlist *sp;
4422
4423         len = 0;
4424         for (sp = str ; sp ; sp = sp->next)
4425                 len++;
4426         return msort(str, len);
4427 }
4428
4429
4430 static struct strlist *
4431 msort(list, len)
4432         struct strlist *list;
4433         int len;
4434 {
4435         struct strlist *p, *q = NULL;
4436         struct strlist **lpp;
4437         int half;
4438         int n;
4439
4440         if (len <= 1)
4441                 return list;
4442         half = len >> 1;
4443         p = list;
4444         for (n = half ; --n >= 0 ; ) {
4445                 q = p;
4446                 p = p->next;
4447         }
4448         q->next = NULL;                 /* terminate first half of list */
4449         q = msort(list, half);          /* sort first half of list */
4450         p = msort(p, len - half);               /* sort second half */
4451         lpp = &list;
4452         for (;;) {
4453                 if (strcmp(p->text, q->text) < 0) {
4454                         *lpp = p;
4455                         lpp = &p->next;
4456                         if ((p = *lpp) == NULL) {
4457                                 *lpp = q;
4458                                 break;
4459                         }
4460                 } else {
4461                         *lpp = q;
4462                         lpp = &q->next;
4463                         if ((q = *lpp) == NULL) {
4464                                 *lpp = p;
4465                                 break;
4466                         }
4467                 }
4468         }
4469         return list;
4470 }
4471 #endif
4472
4473
4474
4475 /*
4476  * Returns true if the pattern matches the string.
4477  */
4478
4479 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4480 static int
4481 patmatch(pattern, string, squoted)
4482         char *pattern;
4483         char *string;
4484         int squoted;    /* string might have quote chars */
4485         {
4486         const char *p;
4487         char *q;
4488
4489         p = preglob(pattern);
4490         q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
4491
4492         return !fnmatch(p, q, 0);
4493 }
4494
4495
4496 static int
4497 patmatch2(pattern, string, squoted)
4498         char *pattern;
4499         char *string;
4500         int squoted;    /* string might have quote chars */
4501         {
4502         char *p;
4503         int res;
4504
4505         sstrnleft--;
4506         p = grabstackstr(expdest);
4507         res = patmatch(pattern, string, squoted);
4508         ungrabstackstr(p, expdest);
4509         return res;
4510 }
4511 #else
4512 static int
4513 patmatch(pattern, string, squoted)
4514         char *pattern;
4515         char *string;
4516         int squoted;    /* string might have quote chars */
4517         {
4518 #ifdef notdef
4519         if (pattern[0] == '!' && pattern[1] == '!')
4520                 return 1 - pmatch(pattern + 2, string);
4521         else
4522 #endif
4523                 return pmatch(pattern, string, squoted);
4524 }
4525
4526
4527 static int
4528 pmatch(pattern, string, squoted)
4529         char *pattern;
4530         char *string;
4531         int squoted;
4532         {
4533         char *p, *q;
4534         char c;
4535
4536         p = pattern;
4537         q = string;
4538         for (;;) {
4539                 switch (c = *p++) {
4540                 case '\0':
4541                         goto breakloop;
4542                 case CTLESC:
4543                         if (squoted && *q == CTLESC)
4544                                 q++;
4545                         if (*q++ != *p++)
4546                                 return 0;
4547                         break;
4548                 case CTLQUOTEMARK:
4549                         continue;
4550                 case '?':
4551                         if (squoted && *q == CTLESC)
4552                                 q++;
4553                         if (*q++ == '\0')
4554                                 return 0;
4555                         break;
4556                 case '*':
4557                         c = *p;
4558                         while (c == CTLQUOTEMARK || c == '*')
4559                                 c = *++p;
4560                         if (c != CTLESC &&  c != CTLQUOTEMARK &&
4561                             c != '?' && c != '*' && c != '[') {
4562                                 while (*q != c) {
4563                                         if (squoted && *q == CTLESC &&
4564                                             q[1] == c)
4565                                                 break;
4566                                         if (*q == '\0')
4567                                                 return 0;
4568                                         if (squoted && *q == CTLESC)
4569                                                 q++;
4570                                         q++;
4571                                 }
4572                         }
4573                         do {
4574                                 if (pmatch(p, q, squoted))
4575                                         return 1;
4576                                 if (squoted && *q == CTLESC)
4577                                         q++;
4578                         } while (*q++ != '\0');
4579                         return 0;
4580                 case '[': {
4581                         char *endp;
4582                         int invert, found;
4583                         char chr;
4584
4585                         endp = p;
4586                         if (*endp == '!')
4587                                 endp++;
4588                         for (;;) {
4589                                 while (*endp == CTLQUOTEMARK)
4590                                         endp++;
4591                                 if (*endp == '\0')
4592                                         goto dft;               /* no matching ] */
4593                                 if (*endp == CTLESC)
4594                                         endp++;
4595                                 if (*++endp == ']')
4596                                         break;
4597                         }
4598                         invert = 0;
4599                         if (*p == '!') {
4600                                 invert++;
4601                                 p++;
4602                         }
4603                         found = 0;
4604                         chr = *q++;
4605                         if (squoted && chr == CTLESC)
4606                                 chr = *q++;
4607                         if (chr == '\0')
4608                                 return 0;
4609                         c = *p++;
4610                         do {
4611                                 if (c == CTLQUOTEMARK)
4612                                         continue;
4613                                 if (c == CTLESC)
4614                                         c = *p++;
4615                                 if (*p == '-' && p[1] != ']') {
4616                                         p++;
4617                                         while (*p == CTLQUOTEMARK)
4618                                                 p++;
4619                                         if (*p == CTLESC)
4620                                                 p++;
4621                                         if (chr >= c && chr <= *p)
4622                                                 found = 1;
4623                                         p++;
4624                                 } else {
4625                                         if (chr == c)
4626                                                 found = 1;
4627                                 }
4628                         } while ((c = *p++) != ']');
4629                         if (found == invert)
4630                                 return 0;
4631                         break;
4632                 }
4633 dft:            default:
4634                         if (squoted && *q == CTLESC)
4635                                 q++;
4636                         if (*q++ != c)
4637                                 return 0;
4638                         break;
4639                 }
4640         }
4641 breakloop:
4642         if (*q != '\0')
4643                 return 0;
4644         return 1;
4645 }
4646 #endif
4647
4648
4649
4650 /*
4651  * Remove any CTLESC characters from a string.
4652  */
4653
4654 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4655 static char *
4656 _rmescapes(str, flag)
4657         char *str;
4658         int flag;
4659 {
4660         char *p, *q, *r;
4661         static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
4662
4663         p = strpbrk(str, qchars);
4664         if (!p) {
4665                 return str;
4666         }
4667         q = p;
4668         r = str;
4669         if (flag & RMESCAPE_ALLOC) {
4670                 size_t len = p - str;
4671                 q = r = stalloc(strlen(p) + len + 1);
4672                 if (len > 0) {
4673 #ifdef _GNU_SOURCE
4674                         q = mempcpy(q, str, len);
4675 #else
4676                         memcpy(q, str, len);
4677                         q += len;
4678 #endif
4679                 }
4680         }
4681         while (*p) {
4682                 if (*p == CTLQUOTEMARK) {
4683                         p++;
4684                         continue;
4685                 }
4686                 if (*p == CTLESC) {
4687                         p++;
4688                         if (flag & RMESCAPE_GLOB && *p != '/') {
4689                                 *q++ = '\\';
4690                         }
4691                 }
4692                 *q++ = *p++;
4693         }
4694         *q = '\0';
4695         return r;
4696 }
4697 #else
4698 static void
4699 rmescapes(str)
4700         char *str;
4701 {
4702         char *p, *q;
4703
4704         p = str;
4705         while (*p != CTLESC && *p != CTLQUOTEMARK) {
4706                 if (*p++ == '\0')
4707                         return;
4708         }
4709         q = p;
4710         while (*p) {
4711                 if (*p == CTLQUOTEMARK) {
4712                         p++;
4713                         continue;
4714                 }
4715                 if (*p == CTLESC)
4716                         p++;
4717                 *q++ = *p++;
4718         }
4719         *q = '\0';
4720 }
4721 #endif
4722
4723
4724
4725 /*
4726  * See if a pattern matches in a case statement.
4727  */
4728
4729 static int
4730 casematch(pattern, val)
4731         union node *pattern;
4732         char *val;
4733         {
4734         struct stackmark smark;
4735         int result;
4736         char *p;
4737
4738         setstackmark(&smark);
4739         argbackq = pattern->narg.backquote;
4740         STARTSTACKSTR(expdest);
4741         ifslastp = NULL;
4742         argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
4743         STPUTC('\0', expdest);
4744         p = grabstackstr(expdest);
4745         result = patmatch(p, val, 0);
4746         popstackmark(&smark);
4747         return result;
4748 }
4749
4750 /*
4751  * Our own itoa().
4752  */
4753
4754 static char *
4755 cvtnum(num, buf)
4756         int num;
4757         char *buf;
4758         {
4759         int len;
4760
4761         CHECKSTRSPACE(32, buf);
4762         len = sprintf(buf, "%d", num);
4763         STADJUST(len, buf);
4764         return buf;
4765 }
4766 /*      $NetBSD: histedit.c,v 1.25 2001/02/04 19:52:06 christos Exp $   */
4767
4768 /*
4769  * Editline and history functions (and glue).
4770  */
4771 static int histcmd(argc, argv)
4772         int argc;
4773         char **argv;
4774 {
4775         error("not compiled with history support");
4776         /* NOTREACHED */
4777 }
4778
4779
4780 /*
4781  * This file was generated by the mkinit program.
4782  */
4783
4784 extern void rmaliases __P((void));
4785
4786 extern int loopnest;            /* current loop nesting level */
4787
4788 extern void deletefuncs __P((void));
4789
4790 struct strpush {
4791         struct strpush *prev;   /* preceding string on stack */
4792         char *prevstring;
4793         int prevnleft;
4794         struct alias *ap;       /* if push was associated with an alias */
4795         char *string;           /* remember the string since it may change */
4796 };
4797
4798 struct parsefile {
4799         struct parsefile *prev; /* preceding file on stack */
4800         int linno;              /* current line */
4801         int fd;                 /* file descriptor (or -1 if string) */
4802         int nleft;              /* number of chars left in this line */
4803         int lleft;              /* number of chars left in this buffer */
4804         char *nextc;            /* next char in buffer */
4805         char *buf;              /* input buffer */
4806         struct strpush *strpush; /* for pushing strings at this level */
4807         struct strpush basestrpush; /* so pushing one is fast */
4808 };
4809
4810 extern int parselleft;          /* copy of parsefile->lleft */
4811 extern struct parsefile basepf; /* top level input file */
4812 extern char basebuf[BUFSIZ];    /* buffer for top level input file */
4813
4814 extern short backgndpid;        /* pid of last background process */
4815 extern int jobctl;
4816
4817 extern int tokpushback;         /* last token pushed back */
4818 extern int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
4819
4820 struct redirtab {
4821         struct redirtab *next;
4822         short renamed[10];
4823 };
4824
4825 extern struct redirtab *redirlist;
4826
4827 extern char sigmode[NSIG - 1];  /* current value of signal */
4828
4829 extern char **environ;
4830
4831
4832
4833 /*
4834  * Initialization code.
4835  */
4836
4837 static void
4838 init() {
4839
4840       /* from cd.c: */
4841       {
4842               setpwd(0, 0);
4843       }
4844
4845       /* from input.c: */
4846       {
4847               basepf.nextc = basepf.buf = basebuf;
4848       }
4849
4850       /* from output.c: */
4851       {
4852 #ifdef USE_GLIBC_STDIO
4853               initstreams();
4854 #endif
4855       }
4856
4857       /* from var.c: */
4858       {
4859               char **envp;
4860               char ppid[32];
4861
4862               initvar();
4863               for (envp = environ ; *envp ; envp++) {
4864                       if (strchr(*envp, '=')) {
4865                               setvareq(*envp, VEXPORT|VTEXTFIXED);
4866                       }
4867               }
4868
4869               fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
4870               setvar("PPID", ppid, 0);
4871       }
4872 }
4873
4874
4875
4876 /*
4877  * This routine is called when an error or an interrupt occurs in an
4878  * interactive shell and control is returned to the main command loop.
4879  */
4880
4881 static void
4882 reset() {
4883
4884       /* from eval.c: */
4885       {
4886               evalskip = 0;
4887               loopnest = 0;
4888               funcnest = 0;
4889       }
4890
4891       /* from input.c: */
4892       {
4893               if (exception != EXSHELLPROC)
4894                       parselleft = parsenleft = 0;      /* clear input buffer */
4895               popallfiles();
4896       }
4897
4898       /* from parser.c: */
4899       {
4900               tokpushback = 0;
4901               checkkwd = 0;
4902               checkalias = 0;
4903       }
4904
4905       /* from redir.c: */
4906       {
4907               while (redirlist)
4908                       popredir();
4909       }
4910
4911       /* from output.c: */
4912       {
4913               out1 = &output;
4914               out2 = &errout;
4915 #ifdef USE_GLIBC_STDIO
4916               if (memout.stream != NULL)
4917                       __closememout();
4918 #endif
4919               if (memout.buf != NULL) {
4920                       ckfree(memout.buf);
4921                       memout.buf = NULL;
4922               }
4923       }
4924 }
4925
4926
4927
4928 /*
4929  * This routine is called to initialize the shell to run a shell procedure.
4930  */
4931
4932 static void
4933 initshellproc() {
4934
4935       /* from alias.c: */
4936       {
4937               rmaliases();
4938       }
4939
4940       /* from eval.c: */
4941       {
4942               exitstatus = 0;
4943       }
4944
4945       /* from exec.c: */
4946       {
4947               deletefuncs();
4948       }
4949
4950       /* from jobs.c: */
4951       {
4952               backgndpid = -1;
4953 #if JOBS
4954               jobctl = 0;
4955 #endif
4956       }
4957
4958       /* from options.c: */
4959       {
4960               int i;
4961
4962               for (i = 0; i < NOPTS; i++)
4963                       optlist[i].val = 0;
4964               optschanged();
4965
4966       }
4967
4968       /* from redir.c: */
4969       {
4970               clearredir();
4971       }
4972
4973       /* from trap.c: */
4974       {
4975               char *sm;
4976
4977               clear_traps();
4978               for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
4979                       if (*sm == S_IGN)
4980                               *sm = S_HARD_IGN;
4981               }
4982       }
4983
4984       /* from var.c: */
4985       {
4986               shprocvar();
4987       }
4988 }
4989 /*      $NetBSD: input.c,v 1.35 2001/02/04 19:52:06 christos Exp $      */
4990
4991 /*
4992  * This file implements the input routines used by the parser.
4993  */
4994
4995 #ifdef BB_FEATURE_COMMAND_EDITING
4996 unsigned int shell_context;
4997 static const char * cmdedit_prompt;
4998 static inline void putprompt(const char *s) {
4999     cmdedit_prompt = s;
5000 }
5001 #else
5002 static inline void putprompt(const char *s) {
5003     out2str(s);
5004 }
5005 #endif
5006
5007 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
5008
5009 static int plinno = 1;                  /* input line number */
5010 static int parsenleft;                  /* copy of parsefile->nleft */
5011 static int parselleft;          /* copy of parsefile->lleft */
5012 static char *parsenextc;                /* copy of parsefile->nextc */
5013 struct parsefile basepf;        /* top level input file */
5014 static char basebuf[BUFSIZ];    /* buffer for top level input file */
5015 struct parsefile *parsefile = &basepf;  /* current input file */
5016 static int whichprompt;         /* 1 == PS1, 2 == PS2 */
5017
5018 static void pushfile __P((void));
5019 static int preadfd __P((void));
5020
5021 #ifdef mkinit
5022 INCLUDE <stdio.h>
5023 INCLUDE "input.h"
5024 INCLUDE "error.h"
5025
5026 INIT {
5027         basepf.nextc = basepf.buf = basebuf;
5028 }
5029
5030 RESET {
5031         if (exception != EXSHELLPROC)
5032                 parselleft = parsenleft = 0;    /* clear input buffer */
5033         popallfiles();
5034 }
5035 #endif
5036
5037
5038 /*
5039  * Read a line from the script.
5040  */
5041
5042 static char *
5043 pfgets(line, len)
5044         char *line;
5045         int len;
5046 {
5047         char *p = line;
5048         int nleft = len;
5049         int c;
5050
5051         while (--nleft > 0) {
5052                 c = pgetc2();
5053                 if (c == PEOF) {
5054                         if (p == line)
5055                                 return NULL;
5056                         break;
5057                 }
5058                 *p++ = c;
5059                 if (c == '\n')
5060                         break;
5061         }
5062         *p = '\0';
5063         return line;
5064 }
5065
5066
5067 /*
5068  * Read a character from the script, returning PEOF on end of file.
5069  * Nul characters in the input are silently discarded.
5070  */
5071
5072 static int
5073 pgetc()
5074 {
5075         return pgetc_macro();
5076 }
5077
5078
5079 /*
5080  * Same as pgetc(), but ignores PEOA.
5081  */
5082
5083 static int
5084 pgetc2()
5085 {
5086         int c;
5087         do {
5088                 c = pgetc_macro();
5089         } while (c == PEOA);
5090         return c;
5091 }
5092
5093
5094 static int
5095 preadfd()
5096 {
5097     int nr;
5098     char *buf =  parsefile->buf;
5099     parsenextc = buf;
5100
5101 retry:
5102 #ifdef BB_FEATURE_COMMAND_EDITING
5103         {
5104             if (parsefile->fd)
5105                 nr = read(parsefile->fd, buf, BUFSIZ - 1);
5106             else { 
5107                 do {
5108                     cmdedit_read_input((char*)cmdedit_prompt, buf);
5109                     nr = strlen(buf);
5110                 } while (nr <=0 || shell_context);
5111                 cmdedit_terminate();
5112             }
5113         }
5114 #else
5115         nr = read(parsefile->fd, buf, BUFSIZ - 1);
5116 #endif
5117
5118         if (nr < 0) {
5119                 if (errno == EINTR)
5120                         goto retry;
5121                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5122                         int flags = fcntl(0, F_GETFL, 0);
5123                         if (flags >= 0 && flags & O_NONBLOCK) {
5124                                 flags &=~ O_NONBLOCK;
5125                                 if (fcntl(0, F_SETFL, flags) >= 0) {
5126                                         out2str("sh: turning off NDELAY mode\n");
5127                                         goto retry;
5128                                 }
5129                         }
5130                 }
5131         }
5132         return nr;
5133 }
5134
5135 /*
5136  * Refill the input buffer and return the next input character:
5137  *
5138  * 1) If a string was pushed back on the input, pop it;
5139  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5140  *    from a string so we can't refill the buffer, return EOF.
5141  * 3) If the is more stuff in this buffer, use it else call read to fill it.
5142  * 4) Process input up to the next newline, deleting nul characters.
5143  */
5144
5145 static int
5146 preadbuffer()
5147 {
5148         char *p, *q;
5149         int more;
5150         char savec;
5151
5152         while (parsefile->strpush) {
5153                 if (
5154                         parsenleft == -1 && parsefile->strpush->ap &&
5155                         parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
5156                 ) {
5157                         return PEOA;
5158                 }
5159                 popstring();
5160                 if (--parsenleft >= 0)
5161                         return (*parsenextc++);
5162         }
5163         if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5164                 return PEOF;
5165         flushout(&output);
5166 #ifdef FLUSHERR
5167         flushout(&errout);
5168 #endif
5169
5170 again:
5171         if (parselleft <= 0) {
5172                 if ((parselleft = preadfd()) <= 0) {
5173                         parselleft = parsenleft = EOF_NLEFT;
5174                         return PEOF;
5175                 }
5176         }
5177
5178         q = p = parsenextc;
5179
5180         /* delete nul characters */
5181         for (more = 1; more;) {
5182                 switch (*p) {
5183                 case '\0':
5184                         p++;    /* Skip nul */
5185                         goto check;
5186
5187
5188                 case '\n':
5189                         parsenleft = q - parsenextc;
5190                         more = 0; /* Stop processing here */
5191                         break;
5192                 }
5193
5194                 *q++ = *p++;
5195 check:
5196                 if (--parselleft <= 0 && more) {
5197                         parsenleft = q - parsenextc - 1;
5198                         if (parsenleft < 0)
5199                                 goto again;
5200                         more = 0;
5201                 }
5202         }
5203
5204         savec = *q;
5205         *q = '\0';
5206
5207         if (vflag) {
5208                 out2str(parsenextc);
5209 #ifdef FLUSHERR
5210                 flushout(out2);
5211 #endif
5212         }
5213
5214         *q = savec;
5215
5216         return *parsenextc++;
5217 }
5218
5219 /*
5220  * Undo the last call to pgetc.  Only one character may be pushed back.
5221  * PEOF may be pushed back.
5222  */
5223
5224 static void
5225 pungetc() {
5226         parsenleft++;
5227         parsenextc--;
5228 }
5229
5230 /*
5231  * Push a string back onto the input at this current parsefile level.
5232  * We handle aliases this way.
5233  */
5234 static void
5235 pushstring(s, len, ap)
5236         char *s;
5237         int len;
5238         void *ap;
5239         {
5240         struct strpush *sp;
5241
5242         INTOFF;
5243 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
5244         if (parsefile->strpush) {
5245                 sp = ckmalloc(sizeof (struct strpush));
5246                 sp->prev = parsefile->strpush;
5247                 parsefile->strpush = sp;
5248         } else
5249                 sp = parsefile->strpush = &(parsefile->basestrpush);
5250         sp->prevstring = parsenextc;
5251         sp->prevnleft = parsenleft;
5252         sp->ap = (struct alias *)ap;
5253         if (ap) {
5254                 ((struct alias *)ap)->flag |= ALIASINUSE;
5255                 sp->string = s;
5256         }
5257         parsenextc = s;
5258         parsenleft = len;
5259         INTON;
5260 }
5261
5262 static void
5263 popstring()
5264 {
5265         struct strpush *sp = parsefile->strpush;
5266
5267         INTOFF;
5268         if (sp->ap) {
5269                 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5270                         if (!checkalias) {
5271                                 checkalias = 1;
5272                         }
5273                 }
5274                 if (sp->string != sp->ap->val) {
5275                         ckfree(sp->string);
5276                 }
5277                 sp->ap->flag &= ~ALIASINUSE;
5278                 if (sp->ap->flag & ALIASDEAD) {
5279                         unalias(sp->ap->name);
5280                 }
5281         }
5282         parsenextc = sp->prevstring;
5283         parsenleft = sp->prevnleft;
5284 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5285         parsefile->strpush = sp->prev;
5286         if (sp != &(parsefile->basestrpush))
5287                 ckfree(sp);
5288         INTON;
5289 }
5290
5291 /*
5292  * Set the input to take input from a file.  If push is set, push the
5293  * old input onto the stack first.
5294  */
5295
5296 static void
5297 setinputfile(fname, push)
5298         const char *fname;
5299         int push;
5300 {
5301         int fd;
5302         int myfileno2;
5303
5304         INTOFF;
5305         if ((fd = open(fname, O_RDONLY)) < 0)
5306                 error("Can't open %s", fname);
5307         if (fd < 10) {
5308                 myfileno2 = dup_as_newfd(fd, 10);
5309                 close(fd);
5310                 if (myfileno2 < 0)
5311                         error("Out of file descriptors");
5312                 fd = myfileno2;
5313         }
5314         setinputfd(fd, push);
5315         INTON;
5316 }
5317
5318
5319 /*
5320  * Like setinputfile, but takes an open file descriptor.  Call this with
5321  * interrupts off.
5322  */
5323
5324 static void
5325 setinputfd(fd, push)
5326         int fd, push;
5327 {
5328         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
5329         if (push) {
5330                 pushfile();
5331                 parsefile->buf = 0;
5332         } else {
5333                 closescript();
5334                 while (parsefile->strpush)
5335                         popstring();
5336         }
5337         parsefile->fd = fd;
5338         if (parsefile->buf == NULL)
5339                 parsefile->buf = ckmalloc(BUFSIZ);
5340         parselleft = parsenleft = 0;
5341         plinno = 1;
5342 }
5343
5344
5345 /*
5346  * Like setinputfile, but takes input from a string.
5347  */
5348
5349 static void
5350 setinputstring(string)
5351         char *string;
5352         {
5353         INTOFF;
5354         pushfile();
5355         parsenextc = string;
5356         parsenleft = strlen(string);
5357         parsefile->buf = NULL;
5358         plinno = 1;
5359         INTON;
5360 }
5361
5362
5363
5364 /*
5365  * To handle the "." command, a stack of input files is used.  Pushfile
5366  * adds a new entry to the stack and popfile restores the previous level.
5367  */
5368
5369 static void
5370 pushfile() {
5371         struct parsefile *pf;
5372
5373         parsefile->nleft = parsenleft;
5374         parsefile->lleft = parselleft;
5375         parsefile->nextc = parsenextc;
5376         parsefile->linno = plinno;
5377         pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
5378         pf->prev = parsefile;
5379         pf->fd = -1;
5380         pf->strpush = NULL;
5381         pf->basestrpush.prev = NULL;
5382         parsefile = pf;
5383 }
5384
5385
5386 static void
5387 popfile() {
5388         struct parsefile *pf = parsefile;
5389
5390         INTOFF;
5391         if (pf->fd >= 0)
5392                 close(pf->fd);
5393         if (pf->buf)
5394                 ckfree(pf->buf);
5395         while (pf->strpush)
5396                 popstring();
5397         parsefile = pf->prev;
5398         ckfree(pf);
5399         parsenleft = parsefile->nleft;
5400         parselleft = parsefile->lleft;
5401         parsenextc = parsefile->nextc;
5402         plinno = parsefile->linno;
5403         INTON;
5404 }
5405
5406
5407 /*
5408  * Return to top level.
5409  */
5410
5411 static void
5412 popallfiles() {
5413         while (parsefile != &basepf)
5414                 popfile();
5415 }
5416
5417
5418
5419 /*
5420  * Close the file(s) that the shell is reading commands from.  Called
5421  * after a fork is done.
5422  */
5423
5424 static void
5425 closescript() {
5426         popallfiles();
5427         if (parsefile->fd > 0) {
5428                 close(parsefile->fd);
5429                 parsefile->fd = 0;
5430         }
5431 }
5432 /*      $NetBSD: jobs.c,v 1.36 2000/05/22 10:18:47 elric Exp $  */
5433
5434
5435 struct job *jobtab;             /* array of jobs */
5436 static int njobs;                       /* size of array */
5437 short backgndpid = -1;  /* pid of last background process */
5438 #if JOBS
5439 static int initialpgrp;         /* pgrp of shell on invocation */
5440 short curjob;                   /* current job */
5441 #endif
5442 static int intreceived;
5443
5444 static void restartjob __P((struct job *));
5445 static void freejob __P((struct job *));
5446 static struct job *getjob __P((char *));
5447 static int dowait __P((int, struct job *));
5448 #ifdef SYSV
5449 static int onsigchild __P((void));
5450 #endif
5451 static int waitproc __P((int, int *));
5452 static void cmdtxt __P((union node *));
5453 static void cmdputs __P((const char *));
5454 static void waitonint(int);
5455
5456
5457 #if JOBS
5458 /*
5459  * Turn job control on and off.
5460  *
5461  * Note:  This code assumes that the third arg to ioctl is a character
5462  * pointer, which is true on Berkeley systems but not System V.  Since
5463  * System V doesn't have job control yet, this isn't a problem now.
5464  */
5465
5466 static int jobctl;
5467
5468 static void setjobctl(int enable)
5469 {
5470 #ifdef OLD_TTY_DRIVER
5471         int ldisc;
5472 #endif
5473
5474         if (enable == jobctl || rootshell == 0)
5475                 return;
5476         if (enable) {
5477                 do { /* while we are in the background */
5478 #ifdef OLD_TTY_DRIVER
5479                         if (ioctl(fileno2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
5480 #else
5481                         initialpgrp = tcgetpgrp(fileno2);
5482                         if (initialpgrp < 0) {
5483 #endif
5484                                 out2str("sh: can't access tty; job cenabletrol turned off\n");
5485                                 mflag = 0;
5486                                 return;
5487                         }
5488                         if (initialpgrp == -1)
5489                                 initialpgrp = getpgrp();
5490                         else if (initialpgrp != getpgrp()) {
5491                                 killpg(initialpgrp, SIGTTIN);
5492                                 continue;
5493                         }
5494                 } while (0);
5495 #ifdef OLD_TTY_DRIVER
5496                 if (ioctl(fileno2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
5497                         out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
5498                         mflag = 0;
5499                         return;
5500                 }
5501 #endif
5502                 setsignal(SIGTSTP);
5503                 setsignal(SIGTTOU);
5504                 setsignal(SIGTTIN);
5505                 setpgid(0, rootpid);
5506 #ifdef OLD_TTY_DRIVER
5507                 ioctl(fileno2, TIOCSPGRP, (char *)&rootpid);
5508 #else
5509                 tcsetpgrp(fileno2, rootpid);
5510 #endif
5511         } else { /* turning job cenabletrol off */
5512                 setpgid(0, initialpgrp);
5513 #ifdef OLD_TTY_DRIVER
5514                 ioctl(fileno2, TIOCSPGRP, (char *)&initialpgrp);
5515 #else
5516                 tcsetpgrp(fileno2, initialpgrp);
5517 #endif
5518                 setsignal(SIGTSTP);
5519                 setsignal(SIGTTOU);
5520                 setsignal(SIGTTIN);
5521         }
5522         jobctl = enable;
5523 }
5524 #endif
5525
5526
5527 #ifdef mkinit
5528 INCLUDE <stdlib.h>
5529
5530 SHELLPROC {
5531         backgndpid = -1;
5532 #if JOBS
5533         jobctl = 0;
5534 #endif
5535 }
5536
5537 #endif
5538
5539
5540 /* This file was automatically created by ./mksignames.
5541    Do not edit.  Edit support/mksignames.c instead. */
5542
5543 /* A translation list so we can be polite to our users. */
5544 static char *signal_names[NSIG + 2] = {
5545     "EXIT",
5546     "SIGHUP",
5547     "SIGINT",
5548     "SIGQUIT",
5549     "SIGILL",
5550     "SIGTRAP",
5551     "SIGABRT",
5552     "SIGBUS",
5553     "SIGFPE",
5554     "SIGKILL",
5555     "SIGUSR1",
5556     "SIGSEGV",
5557     "SIGUSR2",
5558     "SIGPIPE",
5559     "SIGALRM",
5560     "SIGTERM",
5561     "SIGJUNK(16)",
5562     "SIGCHLD",
5563     "SIGCONT",
5564     "SIGSTOP",
5565     "SIGTSTP",
5566     "SIGTTIN",
5567     "SIGTTOU",
5568     "SIGURG",
5569     "SIGXCPU",
5570     "SIGXFSZ",
5571     "SIGVTALRM",
5572     "SIGPROF",
5573     "SIGWINCH",
5574     "SIGIO",
5575     "SIGPWR",
5576     "SIGSYS",
5577     "SIGRTMIN",
5578     "SIGRTMIN+1",
5579     "SIGRTMIN+2",
5580     "SIGRTMIN+3",
5581     "SIGRTMIN+4",
5582     "SIGRTMIN+5",
5583     "SIGRTMIN+6",
5584     "SIGRTMIN+7",
5585     "SIGRTMIN+8",
5586     "SIGRTMIN+9",
5587     "SIGRTMIN+10",
5588     "SIGRTMIN+11",
5589     "SIGRTMIN+12",
5590     "SIGRTMIN+13",
5591     "SIGRTMIN+14",
5592     "SIGRTMIN+15",
5593     "SIGRTMAX-15",
5594     "SIGRTMAX-14",
5595     "SIGRTMAX-13",
5596     "SIGRTMAX-12",
5597     "SIGRTMAX-11",
5598     "SIGRTMAX-10",
5599     "SIGRTMAX-9",
5600     "SIGRTMAX-8",
5601     "SIGRTMAX-7",
5602     "SIGRTMAX-6",
5603     "SIGRTMAX-5",
5604     "SIGRTMAX-4",
5605     "SIGRTMAX-3",
5606     "SIGRTMAX-2",
5607     "SIGRTMAX-1",
5608     "SIGRTMAX",
5609     "DEBUG",
5610     (char *)0x0,
5611 };
5612
5613
5614
5615 #if JOBS
5616 static int
5617 killcmd(argc, argv)
5618         int argc;
5619         char **argv;
5620 {
5621         int signo = -1;
5622         int list = 0;
5623         int i;
5624         pid_t pid;
5625         struct job *jp;
5626
5627         if (argc <= 1) {
5628 usage:
5629                 error(
5630 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
5631 "kill -l [exitstatus]"
5632                 );
5633         }
5634
5635         if (*argv[1] == '-') {
5636                 signo = decode_signal(argv[1] + 1, 1);
5637                 if (signo < 0) {
5638                         int c;
5639
5640                         while ((c = nextopt("ls:")) != '\0')
5641                                 switch (c) {
5642                                 case 'l':
5643                                         list = 1;
5644                                         break;
5645                                 case 's':
5646                                         signo = decode_signal(optionarg, 1);
5647                                         if (signo < 0) {
5648                                                 error(
5649                                                         "invalid signal number or name: %s",
5650                                                         optionarg
5651                                                 );
5652                                         }
5653                                         break;
5654 #ifdef DEBUG
5655                                 default:
5656                                         error(
5657         "nextopt returned character code 0%o", c);
5658 #endif
5659                         }
5660                 } else
5661                         argptr++;
5662         }
5663
5664         if (!list && signo < 0)
5665                 signo = SIGTERM;
5666
5667         if ((signo < 0 || !*argptr) ^ list) {
5668                 goto usage;
5669         }
5670
5671         if (list) {
5672                 if (!*argptr) {
5673                         out1str("0\n");
5674                         for (i = 1; i < NSIG; i++) {
5675                                 out1fmt(snlfmt, signal_names[i] + 3);
5676                         }
5677                         return 0;
5678                 }
5679                 signo = atoi(*argptr);
5680                 if (signo > 128)
5681                         signo -= 128;
5682                 if (0 < signo && signo < NSIG)
5683                                 out1fmt(snlfmt, signal_names[signo] + 3);
5684                 else
5685                         error("invalid signal number or exit status: %s",
5686                               *argptr);
5687                 return 0;
5688         }
5689
5690         do {
5691                 if (**argptr == '%') {
5692                         jp = getjob(*argptr);
5693                         if (jp->jobctl == 0)
5694                                 error("job %s not created under job control",
5695                                       *argptr);
5696                         pid = -jp->ps[0].pid;
5697                 } else
5698                         pid = atoi(*argptr);
5699                 if (kill(pid, signo) != 0)
5700                         error("%s: %s", *argptr, strerror(errno));
5701         } while (*++argptr);
5702
5703         return 0;
5704 }
5705
5706 static int
5707 fgcmd(argc, argv)
5708         int argc;
5709         char **argv;
5710 {
5711         struct job *jp;
5712         int pgrp;
5713         int status;
5714
5715         jp = getjob(argv[1]);
5716         if (jp->jobctl == 0)
5717                 error("job not created under job control");
5718         pgrp = jp->ps[0].pid;
5719 #ifdef OLD_TTY_DRIVER
5720         ioctl(fileno2, TIOCSPGRP, (char *)&pgrp);
5721 #else
5722         tcsetpgrp(fileno2, pgrp);
5723 #endif
5724         restartjob(jp);
5725         INTOFF;
5726         status = waitforjob(jp);
5727         INTON;
5728         return status;
5729 }
5730
5731
5732 static int
5733 bgcmd(argc, argv)
5734         int argc;
5735         char **argv;
5736 {
5737         struct job *jp;
5738
5739         do {
5740                 jp = getjob(*++argv);
5741                 if (jp->jobctl == 0)
5742                         error("job not created under job control");
5743                 restartjob(jp);
5744         } while (--argc > 1);
5745         return 0;
5746 }
5747
5748
5749 static void
5750 restartjob(jp)
5751         struct job *jp;
5752 {
5753         struct procstat *ps;
5754         int i;
5755
5756         if (jp->state == JOBDONE)
5757                 return;
5758         INTOFF;
5759         killpg(jp->ps[0].pid, SIGCONT);
5760         for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
5761                 if (WIFSTOPPED(ps->status)) {
5762                         ps->status = -1;
5763                         jp->state = 0;
5764                 }
5765         }
5766         INTON;
5767 }
5768 #endif
5769
5770
5771 static int
5772 jobscmd(argc, argv)
5773         int argc;
5774         char **argv;
5775 {
5776         showjobs(0);
5777         return 0;
5778 }
5779
5780
5781 /*
5782  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
5783  * statuses have changed since the last call to showjobs.
5784  *
5785  * If the shell is interrupted in the process of creating a job, the
5786  * result may be a job structure containing zero processes.  Such structures
5787  * will be freed here.
5788  */
5789
5790 static void
5791 showjobs(change)
5792         int change;
5793 {
5794         int jobno;
5795         int procno;
5796         int i;
5797         struct job *jp;
5798         struct procstat *ps;
5799         int col;
5800         char s[64];
5801
5802         TRACE(("showjobs(%d) called\n", change));
5803         while (dowait(0, (struct job *)NULL) > 0);
5804         for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
5805                 if (! jp->used)
5806                         continue;
5807                 if (jp->nprocs == 0) {
5808                         freejob(jp);
5809                         continue;
5810                 }
5811                 if (change && ! jp->changed)
5812                         continue;
5813                 procno = jp->nprocs;
5814                 for (ps = jp->ps ; ; ps++) {    /* for each process */
5815                         if (ps == jp->ps)
5816                                 fmtstr(s, 64, "[%d] %ld ", jobno, 
5817                                     (long)ps->pid);
5818                         else
5819                                 fmtstr(s, 64, "    %ld ", 
5820                                     (long)ps->pid);
5821                         out1str(s);
5822                         col = strlen(s);
5823                         s[0] = '\0';
5824                         if (ps->status == -1) {
5825                                 /* don't print anything */
5826                         } else if (WIFEXITED(ps->status)) {
5827                                 fmtstr(s, 64, "Exit %d", 
5828                                        WEXITSTATUS(ps->status));
5829                         } else {
5830 #if JOBS
5831                                 if (WIFSTOPPED(ps->status)) 
5832                                         i = WSTOPSIG(ps->status);
5833                                 else /* WIFSIGNALED(ps->status) */
5834 #endif
5835                                         i = WTERMSIG(ps->status);
5836                                 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
5837                                         scopy(sys_siglist[i & 0x7F], s);
5838                                 else
5839                                         fmtstr(s, 64, "Signal %d", i & 0x7F);
5840                                 if (WCOREDUMP(ps->status))
5841                                         strcat(s, " (core dumped)");
5842                         }
5843                         out1str(s);
5844                         col += strlen(s);
5845                         out1fmt(
5846                                 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
5847                                 ps->cmd
5848                         );
5849                         if (--procno <= 0)
5850                                 break;
5851                 }
5852                 jp->changed = 0;
5853                 if (jp->state == JOBDONE) {
5854                         freejob(jp);
5855                 }
5856         }
5857 }
5858
5859
5860 /*
5861  * Mark a job structure as unused.
5862  */
5863
5864 static void
5865 freejob(jp)
5866         struct job *jp;
5867         {
5868         struct procstat *ps;
5869         int i;
5870
5871         INTOFF;
5872         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
5873                 if (ps->cmd != nullstr)
5874                         ckfree(ps->cmd);
5875         }
5876         if (jp->ps != &jp->ps0)
5877                 ckfree(jp->ps);
5878         jp->used = 0;
5879 #if JOBS
5880         if (curjob == jp - jobtab + 1)
5881                 curjob = 0;
5882 #endif
5883         INTON;
5884 }
5885
5886
5887
5888 static int
5889 waitcmd(argc, argv)
5890         int argc;
5891         char **argv;
5892 {
5893         struct job *job;
5894         int status, retval;
5895         struct job *jp;
5896
5897         if (--argc > 0) {
5898 start:
5899                 job = getjob(*++argv);
5900         } else {
5901                 job = NULL;
5902         }
5903         for (;;) {      /* loop until process terminated or stopped */
5904                 if (job != NULL) {
5905                         if (job->state) {
5906                                 status = job->ps[job->nprocs - 1].status;
5907                                 if (! iflag)
5908                                         freejob(job);
5909                                 if (--argc) {
5910                                         goto start;
5911                                 }
5912                                 if (WIFEXITED(status))
5913                                         retval = WEXITSTATUS(status);
5914 #if JOBS
5915                                 else if (WIFSTOPPED(status))
5916                                         retval = WSTOPSIG(status) + 128;
5917 #endif
5918                                 else {
5919                                         /* XXX: limits number of signals */
5920                                         retval = WTERMSIG(status) + 128;
5921                                 }
5922                                 return retval;
5923                         }
5924                 } else {
5925                         for (jp = jobtab ; ; jp++) {
5926                                 if (jp >= jobtab + njobs) {     /* no running procs */
5927                                         return 0;
5928                                 }
5929                                 if (jp->used && jp->state == 0)
5930                                         break;
5931                         }
5932                 }
5933                 if (dowait(2, 0) < 0 && errno == EINTR) {
5934                         return 129;
5935                 }
5936         }
5937 }
5938
5939
5940
5941 /*
5942  * Convert a job name to a job structure.
5943  */
5944
5945 static struct job *
5946 getjob(name)
5947         char *name;
5948         {
5949         int jobno;
5950         struct job *jp;
5951         int pid;
5952         int i;
5953
5954         if (name == NULL) {
5955 #if JOBS
5956 currentjob:
5957                 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
5958                         error("No current job");
5959                 return &jobtab[jobno - 1];
5960 #else
5961                 error("No current job");
5962 #endif
5963         } else if (name[0] == '%') {
5964                 if (is_digit(name[1])) {
5965                         jobno = number(name + 1);
5966                         if (jobno > 0 && jobno <= njobs
5967                          && jobtab[jobno - 1].used != 0)
5968                                 return &jobtab[jobno - 1];
5969 #if JOBS
5970                 } else if (name[1] == '%' && name[2] == '\0') {
5971                         goto currentjob;
5972 #endif
5973                 } else {
5974                         struct job *found = NULL;
5975                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
5976                                 if (jp->used && jp->nprocs > 0
5977                                  && prefix(name + 1, jp->ps[0].cmd)) {
5978                                         if (found)
5979                                                 error("%s: ambiguous", name);
5980                                         found = jp;
5981                                 }
5982                         }
5983                         if (found)
5984                                 return found;
5985                 }
5986         } else if (is_number(name)) {
5987                 pid = number(name);
5988                 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
5989                         if (jp->used && jp->nprocs > 0
5990                          && jp->ps[jp->nprocs - 1].pid == pid)
5991                                 return jp;
5992                 }
5993         }
5994         error("No such job: %s", name);
5995         /* NOTREACHED */
5996 }
5997
5998
5999
6000 /*
6001  * Return a new job structure,
6002  */
6003
6004 struct job *
6005 makejob(node, nprocs)
6006         union node *node;
6007         int nprocs;
6008 {
6009         int i;
6010         struct job *jp;
6011
6012         for (i = njobs, jp = jobtab ; ; jp++) {
6013                 if (--i < 0) {
6014                         INTOFF;
6015                         if (njobs == 0) {
6016                                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6017                         } else {
6018                                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6019                                 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6020                                 /* Relocate `ps' pointers */
6021                                 for (i = 0; i < njobs; i++)
6022                                         if (jp[i].ps == &jobtab[i].ps0)
6023                                                 jp[i].ps = &jp[i].ps0;
6024                                 ckfree(jobtab);
6025                                 jobtab = jp;
6026                         }
6027                         jp = jobtab + njobs;
6028                         for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6029                         INTON;
6030                         break;
6031                 }
6032                 if (jp->used == 0)
6033                         break;
6034         }
6035         INTOFF;
6036         jp->state = 0;
6037         jp->used = 1;
6038         jp->changed = 0;
6039         jp->nprocs = 0;
6040 #if JOBS
6041         jp->jobctl = jobctl;
6042 #endif
6043         if (nprocs > 1) {
6044                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6045         } else {
6046                 jp->ps = &jp->ps0;
6047         }
6048         INTON;
6049         TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6050             jp - jobtab + 1));
6051         return jp;
6052 }
6053
6054
6055 /*
6056  * Fork of a subshell.  If we are doing job control, give the subshell its
6057  * own process group.  Jp is a job structure that the job is to be added to.
6058  * N is the command that will be evaluated by the child.  Both jp and n may
6059  * be NULL.  The mode parameter can be one of the following:
6060  *      FORK_FG - Fork off a foreground process.
6061  *      FORK_BG - Fork off a background process.
6062  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
6063  *                   process group even if job control is on.
6064  *
6065  * When job control is turned off, background processes have their standard
6066  * input redirected to /dev/null (except for the second and later processes
6067  * in a pipeline).
6068  */
6069
6070 static int
6071 forkshell(jp, n, mode)
6072         union node *n;
6073         struct job *jp;
6074         int mode;
6075 {
6076         int pid;
6077         int pgrp;
6078         const char *devnull = _PATH_DEVNULL;
6079         const char *nullerr = "Can't open %s";
6080
6081         TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6082             mode));
6083         INTOFF;
6084         pid = fork();
6085         if (pid == -1) {
6086                 TRACE(("Fork failed, errno=%d\n", errno));
6087                 INTON;
6088                 error("Cannot fork");
6089         }
6090         if (pid == 0) {
6091                 struct job *p;
6092                 int wasroot;
6093                 int i;
6094
6095                 TRACE(("Child shell %d\n", getpid()));
6096                 wasroot = rootshell;
6097                 rootshell = 0;
6098                 closescript();
6099                 INTON;
6100                 clear_traps();
6101 #if JOBS
6102                 jobctl = 0;             /* do job control only in root shell */
6103                 if (wasroot && mode != FORK_NOJOB && mflag) {
6104                         if (jp == NULL || jp->nprocs == 0)
6105                                 pgrp = getpid();
6106                         else
6107                                 pgrp = jp->ps[0].pid;
6108                         setpgid(0, pgrp);
6109                         if (mode == FORK_FG) {
6110                                 /*** this causes superfluous TIOCSPGRPS ***/
6111 #ifdef OLD_TTY_DRIVER
6112                                 if (ioctl(fileno2, TIOCSPGRP, (char *)&pgrp) < 0)
6113                                         error("TIOCSPGRP failed, errno=%d", errno);
6114 #else
6115                                 if (tcsetpgrp(fileno2, pgrp) < 0)
6116                                         error("tcsetpgrp failed, errno=%d", errno);
6117 #endif
6118                         }
6119                         setsignal(SIGTSTP);
6120                         setsignal(SIGTTOU);
6121                 } else if (mode == FORK_BG) {
6122                         ignoresig(SIGINT);
6123                         ignoresig(SIGQUIT);
6124                         if ((jp == NULL || jp->nprocs == 0) &&
6125                             ! fd0_redirected_p ()) {
6126                                 close(0);
6127                                 if (open(devnull, O_RDONLY) != 0)
6128                                         error(nullerr, devnull);
6129                         }
6130                 }
6131 #else
6132                 if (mode == FORK_BG) {
6133                         ignoresig(SIGINT);
6134                         ignoresig(SIGQUIT);
6135                         if ((jp == NULL || jp->nprocs == 0) &&
6136                             ! fd0_redirected_p ()) {
6137                                 close(0);
6138                                 if (open(devnull, O_RDONLY) != 0)
6139                                         error(nullerr, devnull);
6140                         }
6141                 }
6142 #endif
6143                 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6144                         if (p->used)
6145                                 freejob(p);
6146                 if (wasroot && iflag) {
6147                         setsignal(SIGINT);
6148                         setsignal(SIGQUIT);
6149                         setsignal(SIGTERM);
6150                 }
6151                 return pid;
6152         }
6153         if (rootshell && mode != FORK_NOJOB && mflag) {
6154                 if (jp == NULL || jp->nprocs == 0)
6155                         pgrp = pid;
6156                 else
6157                         pgrp = jp->ps[0].pid;
6158                 setpgid(pid, pgrp);
6159         }
6160         if (mode == FORK_BG)
6161                 backgndpid = pid;               /* set $! */
6162         if (jp) {
6163                 struct procstat *ps = &jp->ps[jp->nprocs++];
6164                 ps->pid = pid;
6165                 ps->status = -1;
6166                 ps->cmd = nullstr;
6167                 if (iflag && rootshell && n)
6168                         ps->cmd = commandtext(n);
6169         }
6170         INTON;
6171         TRACE(("In parent shell:  child = %d\n", pid));
6172         return pid;
6173 }
6174
6175
6176
6177 /*
6178  * Wait for job to finish.
6179  *
6180  * Under job control we have the problem that while a child process is
6181  * running interrupts generated by the user are sent to the child but not
6182  * to the shell.  This means that an infinite loop started by an inter-
6183  * active user may be hard to kill.  With job control turned off, an
6184  * interactive user may place an interactive program inside a loop.  If
6185  * the interactive program catches interrupts, the user doesn't want
6186  * these interrupts to also abort the loop.  The approach we take here
6187  * is to have the shell ignore interrupt signals while waiting for a
6188  * forground process to terminate, and then send itself an interrupt
6189  * signal if the child process was terminated by an interrupt signal.
6190  * Unfortunately, some programs want to do a bit of cleanup and then
6191  * exit on interrupt; unless these processes terminate themselves by
6192  * sending a signal to themselves (instead of calling exit) they will
6193  * confuse this approach.
6194  */
6195
6196 static int
6197 waitforjob(jp)
6198         struct job *jp;
6199         {
6200 #if JOBS
6201         int mypgrp = getpgrp();
6202 #endif
6203         int status;
6204         int st;
6205         struct sigaction act, oact;
6206
6207         INTOFF;
6208         intreceived = 0;
6209 #if JOBS
6210         if (!jobctl) {
6211 #else
6212         if (!iflag) {
6213 #endif
6214                 sigaction(SIGINT, 0, &act);
6215                 act.sa_handler = waitonint;
6216                 sigaction(SIGINT, &act, &oact);
6217         }
6218         TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6219         while (jp->state == 0) {
6220                 dowait(1, jp);
6221         }
6222 #if JOBS
6223         if (!jobctl) {
6224 #else
6225         if (!iflag) {
6226 #endif
6227                 sigaction(SIGINT, &oact, 0);
6228                 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
6229         }
6230 #if JOBS
6231         if (jp->jobctl) {
6232 #ifdef OLD_TTY_DRIVER
6233                 if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0)
6234                         error("TIOCSPGRP failed, errno=%d\n", errno);
6235 #else
6236                 if (tcsetpgrp(fileno2, mypgrp) < 0)
6237                         error("tcsetpgrp failed, errno=%d\n", errno);
6238 #endif
6239         }
6240         if (jp->state == JOBSTOPPED)
6241                 curjob = jp - jobtab + 1;
6242 #endif
6243         status = jp->ps[jp->nprocs - 1].status;
6244         /* convert to 8 bits */
6245         if (WIFEXITED(status))
6246                 st = WEXITSTATUS(status);
6247 #if JOBS
6248         else if (WIFSTOPPED(status))
6249                 st = WSTOPSIG(status) + 128;
6250 #endif
6251         else
6252                 st = WTERMSIG(status) + 128;
6253 #if JOBS
6254         if (jp->jobctl) {
6255                 /*
6256                  * This is truly gross.
6257                  * If we're doing job control, then we did a TIOCSPGRP which
6258                  * caused us (the shell) to no longer be in the controlling
6259                  * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
6260                  * intuit from the subprocess exit status whether a SIGINT
6261                  * occured, and if so interrupt ourselves.  Yuck.  - mycroft
6262                  */
6263                 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6264                         raise(SIGINT);
6265         }
6266 #endif
6267         if (! JOBS || jp->state == JOBDONE)
6268                 freejob(jp);
6269         INTON;
6270         return st;
6271 }
6272
6273
6274
6275 /*
6276  * Wait for a process to terminate.
6277  */
6278
6279 static int
6280 dowait(block, job)
6281         int block;
6282         struct job *job;
6283 {
6284         int pid;
6285         int status;
6286         struct procstat *sp;
6287         struct job *jp;
6288         struct job *thisjob;
6289         int done;
6290         int stopped;
6291         int core;
6292         int sig;
6293
6294         TRACE(("dowait(%d) called\n", block));
6295         do {
6296                 pid = waitproc(block, &status);
6297                 TRACE(("wait returns %d, status=%d\n", pid, status));
6298         } while (!(block & 2) && pid == -1 && errno == EINTR);
6299         if (pid <= 0)
6300                 return pid;
6301         INTOFF;
6302         thisjob = NULL;
6303         for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
6304                 if (jp->used) {
6305                         done = 1;
6306                         stopped = 1;
6307                         for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
6308                                 if (sp->pid == -1)
6309                                         continue;
6310                                 if (sp->pid == pid) {
6311                                         TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
6312                                         sp->status = status;
6313                                         thisjob = jp;
6314                                 }
6315                                 if (sp->status == -1)
6316                                         stopped = 0;
6317                                 else if (WIFSTOPPED(sp->status))
6318                                         done = 0;
6319                         }
6320                         if (stopped) {          /* stopped or done */
6321                                 int state = done? JOBDONE : JOBSTOPPED;
6322                                 if (jp->state != state) {
6323                                         TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
6324                                         jp->state = state;
6325 #if JOBS
6326                                         if (done && curjob == jp - jobtab + 1)
6327                                                 curjob = 0;             /* no current job */
6328 #endif
6329                                 }
6330                         }
6331                 }
6332         }
6333         INTON;
6334         if (! rootshell || ! iflag || (job && thisjob == job)) {
6335                 core = WCOREDUMP(status);
6336 #if JOBS
6337                 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
6338                 else
6339 #endif
6340                 if (WIFEXITED(status)) sig = 0;
6341                 else sig = WTERMSIG(status);
6342
6343                 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6344                         if (thisjob != job)
6345                                 outfmt(out2, "%d: ", pid);
6346 #if JOBS
6347                         if (sig == SIGTSTP && rootshell && iflag)
6348                                 outfmt(out2, "%%%ld ",
6349                                     (long)(job - jobtab + 1));
6350 #endif
6351                         if (sig < NSIG && sys_siglist[sig])
6352                                 out2str(sys_siglist[sig]);
6353                         else
6354                                 outfmt(out2, "Signal %d", sig);
6355                         if (core)
6356                                 out2str(" - core dumped");
6357                         out2c('\n');
6358 #ifdef FLUSHERR
6359                         flushout(&errout);
6360 #endif
6361                 } else {
6362                         TRACE(("Not printing status: status=%d, sig=%d\n", 
6363                                status, sig));
6364                 }
6365         } else {
6366                 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
6367                 if (thisjob)
6368                         thisjob->changed = 1;
6369         }
6370         return pid;
6371 }
6372
6373
6374
6375 /*
6376  * Do a wait system call.  If job control is compiled in, we accept
6377  * stopped processes.  If block is zero, we return a value of zero
6378  * rather than blocking.
6379  *
6380  * System V doesn't have a non-blocking wait system call.  It does
6381  * have a SIGCLD signal that is sent to a process when one of it's
6382  * children dies.  The obvious way to use SIGCLD would be to install
6383  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6384  * was received, and have waitproc bump another counter when it got
6385  * the status of a process.  Waitproc would then know that a wait
6386  * system call would not block if the two counters were different.
6387  * This approach doesn't work because if a process has children that
6388  * have not been waited for, System V will send it a SIGCLD when it
6389  * installs a signal handler for SIGCLD.  What this means is that when
6390  * a child exits, the shell will be sent SIGCLD signals continuously
6391  * until is runs out of stack space, unless it does a wait call before
6392  * restoring the signal handler.  The code below takes advantage of
6393  * this (mis)feature by installing a signal handler for SIGCLD and
6394  * then checking to see whether it was called.  If there are any
6395  * children to be waited for, it will be.
6396  *
6397  * If neither SYSV nor BSD is defined, we don't implement nonblocking
6398  * waits at all.  In this case, the user will not be informed when
6399  * a background process until the next time she runs a real program
6400  * (as opposed to running a builtin command or just typing return),
6401  * and the jobs command may give out of date information.
6402  */
6403
6404 #ifdef SYSV
6405 static int gotsigchild;
6406
6407 static int onsigchild() {
6408         gotsigchild = 1;
6409 }
6410 #endif
6411
6412
6413 static int
6414 waitproc(block, status)
6415         int block;
6416         int *status;
6417 {
6418 #ifdef BSD
6419         int flags;
6420
6421         flags = 0;
6422 #if JOBS
6423         if (jobctl)
6424                 flags |= WUNTRACED;
6425 #endif
6426         if (block == 0)
6427                 flags |= WNOHANG;
6428         return wait3(status, flags, (struct rusage *)NULL);
6429 #else
6430 #ifdef SYSV
6431         int (*save)();
6432
6433         if (block == 0) {
6434                 gotsigchild = 0;
6435                 save = signal(SIGCLD, onsigchild);
6436                 signal(SIGCLD, save);
6437                 if (gotsigchild == 0)
6438                         return 0;
6439         }
6440         return wait(status);
6441 #else
6442         if (block == 0)
6443                 return 0;
6444         return wait(status);
6445 #endif
6446 #endif
6447 }
6448
6449 /*
6450  * return 1 if there are stopped jobs, otherwise 0
6451  */
6452 static int job_warning = 0;
6453 static int
6454 stoppedjobs()
6455 {
6456         int jobno;
6457         struct job *jp;
6458
6459         if (job_warning)
6460                 return (0);
6461         for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6462                 if (jp->used == 0)
6463                         continue;
6464                 if (jp->state == JOBSTOPPED) {
6465                         out2str("You have stopped jobs.\n");
6466                         job_warning = 2;
6467                         return (1);
6468                 }
6469         }
6470
6471         return (0);
6472 }
6473
6474 /*
6475  * Return a string identifying a command (to be printed by the
6476  * jobs command.
6477  */
6478
6479 static char *cmdnextc;
6480 static int cmdnleft;
6481 #define MAXCMDTEXT      200
6482
6483 static char *
6484 commandtext(n)
6485         union node *n;
6486         {
6487         char *name;
6488
6489         cmdnextc = name = ckmalloc(MAXCMDTEXT);
6490         cmdnleft = MAXCMDTEXT - 4;
6491         cmdtxt(n);
6492         *cmdnextc = '\0';
6493         return name;
6494 }
6495
6496
6497 static void
6498 cmdtxt(n)
6499         union node *n;
6500         {
6501         union node *np;
6502         struct nodelist *lp;
6503         const char *p;
6504         int i;
6505         char s[2];
6506
6507         if (n == NULL)
6508                 return;
6509         switch (n->type) {
6510         case NSEMI:
6511                 cmdtxt(n->nbinary.ch1);
6512                 cmdputs("; ");
6513                 cmdtxt(n->nbinary.ch2);
6514                 break;
6515         case NAND:
6516                 cmdtxt(n->nbinary.ch1);
6517                 cmdputs(" && ");
6518                 cmdtxt(n->nbinary.ch2);
6519                 break;
6520         case NOR:
6521                 cmdtxt(n->nbinary.ch1);
6522                 cmdputs(" || ");
6523                 cmdtxt(n->nbinary.ch2);
6524                 break;
6525         case NPIPE:
6526                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
6527                         cmdtxt(lp->n);
6528                         if (lp->next)
6529                                 cmdputs(" | ");
6530                 }
6531                 break;
6532         case NSUBSHELL:
6533                 cmdputs("(");
6534                 cmdtxt(n->nredir.n);
6535                 cmdputs(")");
6536                 break;
6537         case NREDIR:
6538         case NBACKGND:
6539                 cmdtxt(n->nredir.n);
6540                 break;
6541         case NIF:
6542                 cmdputs("if ");
6543                 cmdtxt(n->nif.test);
6544                 cmdputs("; then ");
6545                 cmdtxt(n->nif.ifpart);
6546                 cmdputs("...");
6547                 break;
6548         case NWHILE:
6549                 cmdputs("while ");
6550                 goto until;
6551         case NUNTIL:
6552                 cmdputs("until ");
6553 until:
6554                 cmdtxt(n->nbinary.ch1);
6555                 cmdputs("; do ");
6556                 cmdtxt(n->nbinary.ch2);
6557                 cmdputs("; done");
6558                 break;
6559         case NFOR:
6560                 cmdputs("for ");
6561                 cmdputs(n->nfor.var);
6562                 cmdputs(" in ...");
6563                 break;
6564         case NCASE:
6565                 cmdputs("case ");
6566                 cmdputs(n->ncase.expr->narg.text);
6567                 cmdputs(" in ...");
6568                 break;
6569         case NDEFUN:
6570                 cmdputs(n->narg.text);
6571                 cmdputs("() ...");
6572                 break;
6573         case NCMD:
6574                 for (np = n->ncmd.args ; np ; np = np->narg.next) {
6575                         cmdtxt(np);
6576                         if (np->narg.next)
6577                                 cmdputs(spcstr);
6578                 }
6579                 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
6580                         cmdputs(spcstr);
6581                         cmdtxt(np);
6582                 }
6583                 break;
6584         case NARG:
6585                 cmdputs(n->narg.text);
6586                 break;
6587         case NTO:
6588                 p = ">";  i = 1;  goto redir;
6589         case NAPPEND:
6590                 p = ">>";  i = 1;  goto redir;
6591         case NTOFD:
6592                 p = ">&";  i = 1;  goto redir;
6593         case NTOOV:
6594                 p = ">|";  i = 1;  goto redir;
6595         case NFROM:
6596                 p = "<";  i = 0;  goto redir;
6597         case NFROMFD:
6598                 p = "<&";  i = 0;  goto redir;
6599         case NFROMTO:
6600                 p = "<>";  i = 0;  goto redir;
6601 redir:
6602                 if (n->nfile.fd != i) {
6603                         s[0] = n->nfile.fd + '0';
6604                         s[1] = '\0';
6605                         cmdputs(s);
6606                 }
6607                 cmdputs(p);
6608                 if (n->type == NTOFD || n->type == NFROMFD) {
6609                         s[0] = n->ndup.dupfd + '0';
6610                         s[1] = '\0';
6611                         cmdputs(s);
6612                 } else {
6613                         cmdtxt(n->nfile.fname);
6614                 }
6615                 break;
6616         case NHERE:
6617         case NXHERE:
6618                 cmdputs("<<...");
6619                 break;
6620         default:
6621                 cmdputs("???");
6622                 break;
6623         }
6624 }
6625
6626
6627
6628 static void
6629 cmdputs(s)
6630         const char *s;
6631         {
6632         const char *p;
6633         char *q;
6634         char c;
6635         int subtype = 0;
6636
6637         if (cmdnleft <= 0)
6638                 return;
6639         p = s;
6640         q = cmdnextc;
6641         while ((c = *p++) != '\0') {
6642                 if (c == CTLESC)
6643                         *q++ = *p++;
6644                 else if (c == CTLVAR) {
6645                         *q++ = '$';
6646                         if (--cmdnleft > 0)
6647                                 *q++ = '{';
6648                         subtype = *p++;
6649                 } else if (c == '=' && subtype != 0) {
6650                         *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6651                         subtype = 0;
6652                 } else if (c == CTLENDVAR) {
6653                         *q++ = '}';
6654                 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
6655                         cmdnleft++;             /* ignore it */
6656                 else
6657                         *q++ = c;
6658                 if (--cmdnleft <= 0) {
6659                         *q++ = '.';
6660                         *q++ = '.';
6661                         *q++ = '.';
6662                         break;
6663                 }
6664         }
6665         cmdnextc = q;
6666 }
6667
6668 static void waitonint(int sig) {
6669         intreceived = 1;
6670         return;
6671 }
6672 /*      $NetBSD: mail.c,v 1.14 2000/07/03 03:26:19 matt Exp $   */
6673
6674 /*
6675  * Routines to check for mail.  (Perhaps make part of main.c?)
6676  */
6677
6678
6679 #define MAXMBOXES 10
6680
6681
6682 static int nmboxes;                     /* number of mailboxes */
6683 static time_t mailtime[MAXMBOXES];      /* times of mailboxes */
6684
6685
6686
6687 /*
6688  * Print appropriate message(s) if mail has arrived.  If the argument is
6689  * nozero, then the value of MAIL has changed, so we just update the
6690  * values.
6691  */
6692
6693 static void
6694 chkmail(silent)
6695         int silent;
6696 {
6697         int i;
6698         const char *mpath;
6699         char *p;
6700         char *q;
6701         struct stackmark smark;
6702         struct stat statb;
6703
6704         if (silent)
6705                 nmboxes = 10;
6706         if (nmboxes == 0)
6707                 return;
6708         setstackmark(&smark);
6709         mpath = mpathset()? mpathval() : mailval();
6710         for (i = 0 ; i < nmboxes ; i++) {
6711                 p = padvance(&mpath, nullstr);
6712                 if (p == NULL)
6713                         break;
6714                 if (*p == '\0')
6715                         continue;
6716                 for (q = p ; *q ; q++);
6717 #ifdef DEBUG
6718                 if (q[-1] != '/')
6719                         abort();
6720 #endif
6721                 q[-1] = '\0';                   /* delete trailing '/' */
6722 #ifdef notdef /* this is what the System V shell claims to do (it lies) */
6723                 if (stat(p, &statb) < 0)
6724                         statb.st_mtime = 0;
6725                 if (statb.st_mtime > mailtime[i] && ! silent) {
6726                         outfmt(
6727                                 &errout, snlfmt,
6728                                 pathopt? pathopt : "you have mail"
6729                         );
6730                 }
6731                 mailtime[i] = statb.st_mtime;
6732 #else /* this is what it should do */
6733                 if (stat(p, &statb) < 0)
6734                         statb.st_size = 0;
6735                 if (statb.st_size > mailtime[i] && ! silent) {
6736                         outfmt(
6737                                 &errout, snlfmt,
6738                                 pathopt? pathopt : "you have mail"
6739                         );
6740                 }
6741                 mailtime[i] = statb.st_size;
6742 #endif
6743         }
6744         nmboxes = i;
6745         popstackmark(&smark);
6746 }
6747 /*      $NetBSD: main.c,v 1.40 2001/02/04 19:52:06 christos Exp $       */
6748
6749
6750 #define PROFILE 0
6751
6752 static int rootpid;
6753 static int rootshell;
6754 #if PROFILE
6755 short profile_buf[16384];
6756 extern int etext();
6757 #endif
6758
6759 static void read_profile __P((const char *));
6760 static char *find_dot_file __P((char *));
6761 int shell_main __P((int, char **));
6762
6763 extern int oexitstatus;
6764 /*
6765  * Main routine.  We initialize things, parse the arguments, execute
6766  * profiles if we're a login shell, and then call cmdloop to execute
6767  * commands.  The setjmp call sets up the location to jump to when an
6768  * exception occurs.  When an exception occurs the variable "state"
6769  * is used to figure out how far we had gotten.
6770  */
6771
6772 int
6773 shell_main(argc, argv)
6774         int argc;
6775         char **argv;
6776 {
6777         struct jmploc jmploc;
6778         struct stackmark smark;
6779         volatile int state;
6780         char *shinit;
6781
6782         DOTCMD = find_builtin(".");
6783         BLTINCMD = find_builtin("builtin");
6784         COMMANDCMD = find_builtin("command");
6785         EXECCMD = find_builtin("exec");
6786         EVALCMD = find_builtin("eval");
6787
6788 #if PROFILE
6789         monitor(4, etext, profile_buf, sizeof profile_buf, 50);
6790 #endif
6791 #if defined(linux) || defined(__GNU__)
6792         signal(SIGCHLD, SIG_DFL);
6793 #endif
6794         state = 0;
6795         if (setjmp(jmploc.loc)) {
6796                 INTOFF;
6797                 /*
6798                  * When a shell procedure is executed, we raise the
6799                  * exception EXSHELLPROC to clean up before executing
6800                  * the shell procedure.
6801                  */
6802                 switch (exception) {
6803                 case EXSHELLPROC:
6804                         rootpid = getpid();
6805                         rootshell = 1;
6806                         minusc = NULL;
6807                         state = 3;
6808                         break;
6809
6810                 case EXEXEC:
6811                         exitstatus = exerrno;
6812                         break;
6813
6814                 case EXERROR:
6815                         exitstatus = 2;
6816                         break;
6817
6818                 default:
6819                         break;
6820                 }
6821
6822                 if (exception != EXSHELLPROC) {
6823                     if (state == 0 || iflag == 0 || ! rootshell)
6824                             exitshell(exitstatus);
6825                 }
6826                 reset();
6827                 if (exception == EXINT
6828 #if ATTY
6829                  && (! attyset() || equal(termval(), "emacs"))
6830 #endif
6831                  ) {
6832                         out2c('\n');
6833 #ifdef FLUSHERR
6834                         flushout(out2);
6835 #endif
6836                 }
6837                 popstackmark(&smark);
6838                 FORCEINTON;                             /* enable interrupts */
6839                 if (state == 1)
6840                         goto state1;
6841                 else if (state == 2)
6842                         goto state2;
6843                 else if (state == 3)
6844                         goto state3;
6845                 else
6846                         goto state4;
6847         }
6848         handler = &jmploc;
6849 #ifdef DEBUG
6850         opentrace();
6851         trputs("Shell args:  ");  trargs(argv);
6852 #endif
6853         rootpid = getpid();
6854         rootshell = 1;
6855         init();
6856         setstackmark(&smark);
6857         procargs(argc, argv);
6858         if (argv[0] && argv[0][0] == '-') {
6859                 state = 1;
6860                 read_profile("/etc/profile");
6861 state1:
6862                 state = 2;
6863                 read_profile(".profile");
6864         }
6865 state2:
6866         state = 3;
6867 #ifndef linux
6868         if (getuid() == geteuid() && getgid() == getegid()) {
6869 #endif
6870                 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
6871                         state = 3;
6872                         read_profile(shinit);
6873                 }
6874 #ifndef linux
6875         }
6876 #endif
6877 state3:
6878         state = 4;
6879         if (sflag == 0 || minusc) {
6880                 static int sigs[] =  {
6881                     SIGINT, SIGQUIT, SIGHUP, 
6882 #ifdef SIGTSTP
6883                     SIGTSTP,
6884 #endif
6885                     SIGPIPE
6886                 };
6887 #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
6888                 int i;
6889
6890                 for (i = 0; i < SIGSSIZE; i++)
6891                     setsignal(sigs[i]);
6892         }
6893
6894         if (minusc)
6895                 evalstring(minusc, 0);
6896
6897         if (sflag || minusc == NULL) {
6898 state4: /* XXX ??? - why isn't this before the "if" statement */
6899                 cmdloop(1);
6900         }
6901 #if PROFILE
6902         monitor(0);
6903 #endif
6904         exitshell(exitstatus);
6905         /* NOTREACHED */
6906 }
6907
6908
6909 /*
6910  * Read and execute commands.  "Top" is nonzero for the top level command
6911  * loop; it turns on prompting if the shell is interactive.
6912  */
6913
6914 static void
6915 cmdloop(top)
6916         int top;
6917 {
6918         union node *n;
6919         struct stackmark smark;
6920         int inter;
6921         int numeof = 0;
6922
6923         TRACE(("cmdloop(%d) called\n", top));
6924         setstackmark(&smark);
6925         for (;;) {
6926                 if (pendingsigs)
6927                         dotrap();
6928                 inter = 0;
6929                 if (iflag && top) {
6930                         inter++;
6931                         showjobs(1);
6932                         chkmail(0);
6933                         flushout(&output);
6934                 }
6935                 n = parsecmd(inter);
6936                 /* showtree(n); DEBUG */
6937                 if (n == NEOF) {
6938                         if (!top || numeof >= 50)
6939                                 break;
6940                         if (!stoppedjobs()) {
6941                                 if (!Iflag)
6942                                         break;
6943                                 out2str("\nUse \"exit\" to leave shell.\n");
6944                         }
6945                         numeof++;
6946                 } else if (n != NULL && nflag == 0) {
6947                         job_warning = (job_warning == 2) ? 1 : 0;
6948                         numeof = 0;
6949                         evaltree(n, 0);
6950                 }
6951                 popstackmark(&smark);
6952                 setstackmark(&smark);
6953                 if (evalskip == SKIPFILE) {
6954                         evalskip = 0;
6955                         break;
6956                 }
6957         }
6958         popstackmark(&smark);
6959 }
6960
6961
6962
6963 /*
6964  * Read /etc/profile or .profile.  Return on error.
6965  */
6966
6967 static void
6968 read_profile(name)
6969         const char *name;
6970 {
6971         int fd;
6972         int xflag_set = 0;
6973         int vflag_set = 0;
6974
6975         INTOFF;
6976         if ((fd = open(name, O_RDONLY)) >= 0)
6977                 setinputfd(fd, 1);
6978         INTON;
6979         if (fd < 0)
6980                 return;
6981         /* -q turns off -x and -v just when executing init files */
6982         if (qflag)  {
6983             if (xflag)
6984                     xflag = 0, xflag_set = 1;
6985             if (vflag)
6986                     vflag = 0, vflag_set = 1;
6987         }
6988         cmdloop(0);
6989         if (qflag)  {
6990             if (xflag_set)
6991                     xflag = 1;
6992             if (vflag_set)
6993                     vflag = 1;
6994         }
6995         popfile();
6996 }
6997
6998
6999
7000 /*
7001  * Read a file containing shell functions.
7002  */
7003
7004 static void
7005 readcmdfile(name)
7006         char *name;
7007 {
7008         int fd;
7009
7010         INTOFF;
7011         if ((fd = open(name, O_RDONLY)) >= 0)
7012                 setinputfd(fd, 1);
7013         else
7014                 error("Can't open %s", name);
7015         INTON;
7016         cmdloop(0);
7017         popfile();
7018 }
7019
7020
7021
7022 /*
7023  * Take commands from a file.  To be compatable we should do a path
7024  * search for the file, which is necessary to find sub-commands.
7025  */
7026
7027
7028 static char *
7029 find_dot_file(mybasename)
7030         char *mybasename;
7031 {
7032         char *fullname;
7033         const char *path = pathval();
7034         struct stat statb;
7035
7036         /* don't try this for absolute or relative paths */
7037         if (strchr(mybasename, '/'))
7038                 return mybasename;
7039
7040         while ((fullname = padvance(&path, mybasename)) != NULL) {
7041                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7042                         /*
7043                          * Don't bother freeing here, since it will
7044                          * be freed by the caller.
7045                          */
7046                         return fullname;
7047                 }
7048                 stunalloc(fullname);
7049         }
7050
7051         /* not found in the PATH */
7052         error("%s: not found", mybasename);
7053         /* NOTREACHED */
7054 }
7055
7056 static int
7057 dotcmd(argc, argv)
7058         int argc;
7059         char **argv;
7060 {
7061         struct strlist *sp;
7062         exitstatus = 0;
7063
7064         for (sp = cmdenviron; sp ; sp = sp->next)
7065                 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7066
7067         if (argc >= 2) {                /* That's what SVR2 does */
7068                 char *fullname;
7069                 struct stackmark smark;
7070
7071                 setstackmark(&smark);
7072                 fullname = find_dot_file(argv[1]);
7073                 setinputfile(fullname, 1);
7074                 commandname = fullname;
7075                 cmdloop(0);
7076                 popfile();
7077                 popstackmark(&smark);
7078         }
7079         return exitstatus;
7080 }
7081
7082
7083 static int
7084 exitcmd(argc, argv)
7085         int argc;
7086         char **argv;
7087 {
7088         if (stoppedjobs())
7089                 return 0;
7090         if (argc > 1)
7091                 exitstatus = number(argv[1]);
7092         else
7093                 exitstatus = oexitstatus;
7094         exitshell(exitstatus);
7095         /* NOTREACHED */
7096 }
7097 /*      $NetBSD: memalloc.c,v 1.23 2000/11/01 19:56:01 christos Exp $   */
7098
7099 /*
7100  * Parse trees for commands are allocated in lifo order, so we use a stack
7101  * to make this more efficient, and also to avoid all sorts of exception
7102  * handling code to handle interrupts in the middle of a parse.
7103  *
7104  * The size 504 was chosen because the Ultrix malloc handles that size
7105  * well.
7106  */
7107
7108 #define MINSIZE 504             /* minimum size of a block */
7109
7110
7111 struct stack_block {
7112         struct stack_block *prev;
7113         char space[MINSIZE];
7114 };
7115
7116 struct stack_block stackbase;
7117 struct stack_block *stackp = &stackbase;
7118 struct stackmark *markp;
7119 static char *stacknxt = stackbase.space;
7120 static int stacknleft = MINSIZE;
7121 static int sstrnleft;
7122 static int herefd = -1;
7123
7124
7125
7126 pointer
7127 stalloc(nbytes)
7128         int nbytes;
7129 {
7130         char *p;
7131
7132         nbytes = ALIGN(nbytes);
7133         if (nbytes > stacknleft) {
7134                 int blocksize;
7135                 struct stack_block *sp;
7136
7137                 blocksize = nbytes;
7138                 if (blocksize < MINSIZE)
7139                         blocksize = MINSIZE;
7140                 INTOFF;
7141                 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
7142                 sp->prev = stackp;
7143                 stacknxt = sp->space;
7144                 stacknleft = blocksize;
7145                 stackp = sp;
7146                 INTON;
7147         }
7148         p = stacknxt;
7149         stacknxt += nbytes;
7150         stacknleft -= nbytes;
7151         return p;
7152 }
7153
7154
7155 static void
7156 stunalloc(p)
7157         pointer p;
7158         {
7159 #ifdef DEBUG
7160         if (p == NULL) {                /*DEBUG */
7161                 write(2, "stunalloc\n", 10);
7162                 abort();
7163         }
7164 #endif
7165         if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7166                 p = stackp->space;
7167         }
7168         stacknleft += stacknxt - (char *)p;
7169         stacknxt = p;
7170 }
7171
7172
7173
7174 static void
7175 setstackmark(mark)
7176         struct stackmark *mark;
7177         {
7178         mark->stackp = stackp;
7179         mark->stacknxt = stacknxt;
7180         mark->stacknleft = stacknleft;
7181         mark->marknext = markp;
7182         markp = mark;
7183 }
7184
7185
7186 static void
7187 popstackmark(mark)
7188         struct stackmark *mark;
7189         {
7190         struct stack_block *sp;
7191
7192         INTOFF;
7193         markp = mark->marknext;
7194         while (stackp != mark->stackp) {
7195                 sp = stackp;
7196                 stackp = sp->prev;
7197                 ckfree(sp);
7198         }
7199         stacknxt = mark->stacknxt;
7200         stacknleft = mark->stacknleft;
7201         INTON;
7202 }
7203
7204
7205 /*
7206  * When the parser reads in a string, it wants to stick the string on the
7207  * stack and only adjust the stack pointer when it knows how big the
7208  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
7209  * of space on top of the stack and stackblocklen returns the length of
7210  * this block.  Growstackblock will grow this space by at least one byte,
7211  * possibly moving it (like realloc).  Grabstackblock actually allocates the
7212  * part of the block that has been used.
7213  */
7214
7215 static void
7216 growstackblock() {
7217         char *p;
7218         int newlen = ALIGN(stacknleft * 2 + 100);
7219         char *oldspace = stacknxt;
7220         int oldlen = stacknleft;
7221         struct stack_block *sp;
7222         struct stack_block *oldstackp;
7223
7224         if (stacknxt == stackp->space && stackp != &stackbase) {
7225                 INTOFF;
7226                 oldstackp = stackp;
7227                 sp = stackp;
7228                 stackp = sp->prev;
7229                 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
7230                 sp->prev = stackp;
7231                 stackp = sp;
7232                 stacknxt = sp->space;
7233                 stacknleft = newlen;
7234                 {
7235                   /* Stack marks pointing to the start of the old block
7236                    * must be relocated to point to the new block 
7237                    */
7238                   struct stackmark *xmark;
7239                   xmark = markp;
7240                   while (xmark != NULL && xmark->stackp == oldstackp) {
7241                     xmark->stackp = stackp;
7242                     xmark->stacknxt = stacknxt;
7243                     xmark->stacknleft = stacknleft;
7244                     xmark = xmark->marknext;
7245                   }
7246                 }
7247                 INTON;
7248         } else {
7249                 p = stalloc(newlen);
7250                 memcpy(p, oldspace, oldlen);
7251                 stacknxt = p;                   /* free the space */
7252                 stacknleft += newlen;           /* we just allocated */
7253         }
7254 }
7255
7256
7257
7258 static void
7259 grabstackblock(len)
7260         int len;
7261 {
7262         len = ALIGN(len);
7263         stacknxt += len;
7264         stacknleft -= len;
7265 }
7266
7267
7268
7269 /*
7270  * The following routines are somewhat easier to use that the above.
7271  * The user declares a variable of type STACKSTR, which may be declared
7272  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
7273  * the user uses the macro STPUTC to add characters to the string.  In
7274  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7275  * grown as necessary.  When the user is done, she can just leave the
7276  * string there and refer to it using stackblock().  Or she can allocate
7277  * the space for it using grabstackstr().  If it is necessary to allow
7278  * someone else to use the stack temporarily and then continue to grow
7279  * the string, the user should use grabstack to allocate the space, and
7280  * then call ungrabstr(p) to return to the previous mode of operation.
7281  *
7282  * USTPUTC is like STPUTC except that it doesn't check for overflow.
7283  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7284  * is space for at least one character.
7285  */
7286
7287
7288 static char *
7289 growstackstr() {
7290         int len = stackblocksize();
7291         if (herefd >= 0 && len >= 1024) {
7292                 xwrite(herefd, stackblock(), len);
7293                 sstrnleft = len - 1;
7294                 return stackblock();
7295         }
7296         growstackblock();
7297         sstrnleft = stackblocksize() - len - 1;
7298         return stackblock() + len;
7299 }
7300
7301
7302 /*
7303  * Called from CHECKSTRSPACE.
7304  */
7305
7306 static char *
7307 makestrspace(size_t newlen) {
7308         int len = stackblocksize() - sstrnleft;
7309         do {
7310                 growstackblock();
7311                 sstrnleft = stackblocksize() - len;
7312         } while (sstrnleft < newlen);
7313         return stackblock() + len;
7314 }
7315
7316
7317
7318 static void
7319 ungrabstackstr(s, p)
7320         char *s;
7321         char *p;
7322         {
7323         stacknleft += stacknxt - s;
7324         stacknxt = s;
7325         sstrnleft = stacknleft - (p - s);
7326 }
7327 /*      $NetBSD: miscbltin.c,v 1.30 2001/02/04 19:52:06 christos Exp $  */
7328
7329 /*
7330  * Miscelaneous builtins.
7331  */
7332
7333
7334 #undef rflag
7335
7336 #ifdef __GLIBC__
7337 mode_t getmode(const void *, mode_t);
7338 static void *setmode(const char *);
7339
7340 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
7341 typedef enum __rlimit_resource rlim_t;
7342 #endif
7343 #endif
7344
7345
7346
7347 /*
7348  * The read builtin.  The -e option causes backslashes to escape the
7349  * following character.
7350  *
7351  * This uses unbuffered input, which may be avoidable in some cases.
7352  */
7353
7354 static int
7355 readcmd(argc, argv)
7356         int argc;
7357         char **argv;
7358 {
7359         char **ap;
7360         int backslash;
7361         char c;
7362         int rflag;
7363         char *prompt;
7364         const char *ifs;
7365         char *p;
7366         int startword;
7367         int status;
7368         int i;
7369
7370         rflag = 0;
7371         prompt = NULL;
7372         while ((i = nextopt("p:r")) != '\0') {
7373                 if (i == 'p')
7374                         prompt = optionarg;
7375                 else
7376                         rflag = 1;
7377         }
7378         if (prompt && isatty(0)) {
7379                 putprompt(prompt);
7380                 flushall();
7381         }
7382         if (*(ap = argptr) == NULL)
7383                 error("arg count");
7384         if ((ifs = bltinlookup("IFS")) == NULL)
7385                 ifs = defifs;
7386         status = 0;
7387         startword = 1;
7388         backslash = 0;
7389         STARTSTACKSTR(p);
7390         for (;;) {
7391                 if (read(0, &c, 1) != 1) {
7392                         status = 1;
7393                         break;
7394                 }
7395                 if (c == '\0')
7396                         continue;
7397                 if (backslash) {
7398                         backslash = 0;
7399                         if (c != '\n')
7400                                 STPUTC(c, p);
7401                         continue;
7402                 }
7403                 if (!rflag && c == '\\') {
7404                         backslash++;
7405                         continue;
7406                 }
7407                 if (c == '\n')
7408                         break;
7409                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
7410                         continue;
7411                 }
7412                 startword = 0;
7413                 if (backslash && c == '\\') {
7414                         if (read(0, &c, 1) != 1) {
7415                                 status = 1;
7416                                 break;
7417                         }
7418                         STPUTC(c, p);
7419                 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
7420                         STACKSTRNUL(p);
7421                         setvar(*ap, stackblock(), 0);
7422                         ap++;
7423                         startword = 1;
7424                         STARTSTACKSTR(p);
7425                 } else {
7426                         STPUTC(c, p);
7427                 }
7428         }
7429         STACKSTRNUL(p);
7430         /* Remove trailing blanks */
7431         while (stackblock() <= --p && strchr(ifs, *p) != NULL)
7432                 *p = '\0';
7433         setvar(*ap, stackblock(), 0);
7434         while (*++ap != NULL)
7435                 setvar(*ap, nullstr, 0);
7436         return status;
7437 }
7438
7439
7440
7441 static int
7442 umaskcmd(argc, argv)
7443         int argc;
7444         char **argv;
7445 {
7446         char *ap;
7447         int mask;
7448         int i;
7449         int symbolic_mode = 0;
7450
7451         while ((i = nextopt("S")) != '\0') {
7452                 symbolic_mode = 1;
7453         }
7454
7455         INTOFF;
7456         mask = umask(0);
7457         umask(mask);
7458         INTON;
7459
7460         if ((ap = *argptr) == NULL) {
7461                 if (symbolic_mode) {
7462                         char u[4], g[4], o[4];
7463
7464                         i = 0;
7465                         if ((mask & S_IRUSR) == 0)
7466                                 u[i++] = 'r';
7467                         if ((mask & S_IWUSR) == 0)
7468                                 u[i++] = 'w';
7469                         if ((mask & S_IXUSR) == 0)
7470                                 u[i++] = 'x';
7471                         u[i] = '\0';
7472
7473                         i = 0;
7474                         if ((mask & S_IRGRP) == 0)
7475                                 g[i++] = 'r';
7476                         if ((mask & S_IWGRP) == 0)
7477                                 g[i++] = 'w';
7478                         if ((mask & S_IXGRP) == 0)
7479                                 g[i++] = 'x';
7480                         g[i] = '\0';
7481
7482                         i = 0;
7483                         if ((mask & S_IROTH) == 0)
7484                                 o[i++] = 'r';
7485                         if ((mask & S_IWOTH) == 0)
7486                                 o[i++] = 'w';
7487                         if ((mask & S_IXOTH) == 0)
7488                                 o[i++] = 'x';
7489                         o[i] = '\0';
7490
7491                         out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
7492                 } else {
7493                         out1fmt("%.4o\n", mask);
7494                 }
7495         } else {
7496                 if (isdigit((unsigned char)*ap)) {
7497                         mask = 0;
7498                         do {
7499                                 if (*ap >= '8' || *ap < '0')
7500                                         error("Illegal number: %s", argv[1]);
7501                                 mask = (mask << 3) + (*ap - '0');
7502                         } while (*++ap != '\0');
7503                         umask(mask);
7504                 } else {
7505                         void *set;
7506
7507                         INTOFF;
7508                         if ((set = setmode(ap)) != 0) {
7509                                 mask = getmode(set, ~mask & 0777);
7510                                 ckfree(set);
7511                         }
7512                         INTON;
7513                         if (!set)
7514                                 error("Illegal mode: %s", ap);
7515
7516                         umask(~mask & 0777);
7517                 }
7518         }
7519         return 0;
7520 }
7521
7522 /*
7523  * ulimit builtin
7524  *
7525  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
7526  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
7527  * ash by J.T. Conklin.
7528  *
7529  * Public domain.
7530  */
7531
7532 struct limits {
7533         const char *name;
7534         int     cmd;
7535         int     factor; /* multiply by to get rlim_{cur,max} values */
7536         char    option;
7537 };
7538
7539 static const struct limits limits[] = {
7540 #ifdef RLIMIT_CPU
7541         { "time(seconds)",              RLIMIT_CPU,        1, 't' },
7542 #endif
7543 #ifdef RLIMIT_FSIZE
7544         { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
7545 #endif
7546 #ifdef RLIMIT_DATA
7547         { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
7548 #endif
7549 #ifdef RLIMIT_STACK
7550         { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
7551 #endif
7552 #ifdef  RLIMIT_CORE
7553         { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
7554 #endif
7555 #ifdef RLIMIT_RSS
7556         { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
7557 #endif
7558 #ifdef RLIMIT_MEMLOCK
7559         { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
7560 #endif
7561 #ifdef RLIMIT_NPROC
7562         { "process(processes)",         RLIMIT_NPROC,      1, 'p' },
7563 #endif
7564 #ifdef RLIMIT_NOFILE
7565         { "nofiles(descriptors)",       RLIMIT_NOFILE,     1, 'n' },
7566 #endif
7567 #ifdef RLIMIT_VMEM
7568         { "vmemory(kbytes)",            RLIMIT_VMEM,    1024, 'v' },
7569 #endif
7570 #ifdef RLIMIT_SWAP
7571         { "swap(kbytes)",               RLIMIT_SWAP,    1024, 'w' },
7572 #endif
7573         { (char *) 0,                   0,                 0,  '\0' }
7574 };
7575
7576 static int
7577 ulimitcmd(argc, argv)
7578         int argc;
7579         char **argv;
7580 {
7581         int     c;
7582         rlim_t val = 0;
7583         enum { SOFT = 0x1, HARD = 0x2 }
7584                         how = SOFT | HARD;
7585         const struct limits     *l;
7586         int             set, all = 0;
7587         int             optc, what;
7588         struct rlimit   limit;
7589
7590         what = 'f';
7591         while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
7592                 switch (optc) {
7593                 case 'H':
7594                         how = HARD;
7595                         break;
7596                 case 'S':
7597                         how = SOFT;
7598                         break;
7599                 case 'a':
7600                         all = 1;
7601                         break;
7602                 default:
7603                         what = optc;
7604                 }
7605
7606         for (l = limits; l->name && l->option != what; l++)
7607                 ;
7608         if (!l->name)
7609                 error("internal error (%c)", what);
7610
7611         set = *argptr ? 1 : 0;
7612         if (set) {
7613                 char *p = *argptr;
7614
7615                 if (all || argptr[1])
7616                         error("too many arguments");
7617                 if (strcmp(p, "unlimited") == 0)
7618                         val = RLIM_INFINITY;
7619                 else {
7620                         val = (rlim_t) 0;
7621
7622                         while ((c = *p++) >= '0' && c <= '9')
7623                         {
7624                                 val = (val * 10) + (long)(c - '0');
7625                                 if (val < (rlim_t) 0)
7626                                         break;
7627                         }
7628                         if (c)
7629                                 error("bad number");
7630                         val *= l->factor;
7631                 }
7632         }
7633         if (all) {
7634                 for (l = limits; l->name; l++) {
7635                         getrlimit(l->cmd, &limit);
7636                         if (how & SOFT)
7637                                 val = limit.rlim_cur;
7638                         else if (how & HARD)
7639                                 val = limit.rlim_max;
7640
7641                         out1fmt("%-20s ", l->name);
7642                         if (val == RLIM_INFINITY)
7643                                 out1fmt("unlimited\n");
7644                         else
7645                         {
7646                                 val /= l->factor;
7647 #ifdef BSD4_4
7648                                 out1fmt("%lld\n", (long long) val);
7649 #else
7650                                 out1fmt("%ld\n", (long) val);
7651 #endif
7652                         }
7653                 }
7654                 return 0;
7655         }
7656
7657         getrlimit(l->cmd, &limit);
7658         if (set) {
7659                 if (how & HARD)
7660                         limit.rlim_max = val;
7661                 if (how & SOFT)
7662                         limit.rlim_cur = val;
7663                 if (setrlimit(l->cmd, &limit) < 0)
7664                         error("error setting limit (%s)", strerror(errno));
7665         } else {
7666                 if (how & SOFT)
7667                         val = limit.rlim_cur;
7668                 else if (how & HARD)
7669                         val = limit.rlim_max;
7670
7671                 if (val == RLIM_INFINITY)
7672                         out1fmt("unlimited\n");
7673                 else
7674                 {
7675                         val /= l->factor;
7676 #ifdef BSD4_4
7677                         out1fmt("%lld\n", (long long) val);
7678 #else
7679                         out1fmt("%ld\n", (long) val);
7680 #endif
7681                 }
7682         }
7683         return 0;
7684 }
7685 /*      $NetBSD: mystring.c,v 1.14 1999/07/09 03:05:50 christos Exp $   */
7686
7687 /*
7688  * String functions.
7689  *
7690  *      equal(s1, s2)           Return true if strings are equal.
7691  *      scopy(from, to)         Copy a string.
7692  *      scopyn(from, to, n)     Like scopy, but checks for overflow.
7693  *      number(s)               Convert a string of digits to an integer.
7694  *      is_number(s)            Return true if s is a string of digits.
7695  */
7696
7697 static char nullstr[1];         /* zero length string */
7698 static const char spcstr[] = " ";
7699 static const char snlfmt[] = "%s\n";
7700
7701 /*
7702  * equal - #defined in mystring.h
7703  */
7704
7705 /*
7706  * scopy - #defined in mystring.h
7707  */
7708
7709
7710 #if 0
7711 /*
7712  * scopyn - copy a string from "from" to "to", truncating the string
7713  *              if necessary.  "To" is always nul terminated, even if
7714  *              truncation is performed.  "Size" is the size of "to".
7715  */
7716
7717 static void
7718 scopyn(from, to, size)
7719         char const *from;
7720         char *to;
7721         int size;
7722         {
7723
7724         while (--size > 0) {
7725                 if ((*to++ = *from++) == '\0')
7726                         return;
7727         }
7728         *to = '\0';
7729 }
7730 #endif
7731
7732
7733 /*
7734  * prefix -- see if pfx is a prefix of string.
7735  */
7736
7737 static int
7738 prefix(pfx, string)
7739         char const *pfx;
7740         char const *string;
7741         {
7742         while (*pfx) {
7743                 if (*pfx++ != *string++)
7744                         return 0;
7745         }
7746         return 1;
7747 }
7748
7749
7750 /*
7751  * Convert a string of digits to an integer, printing an error message on
7752  * failure.
7753  */
7754
7755 static int
7756 number(s)
7757         const char *s;
7758         {
7759
7760         if (! is_number(s))
7761                 error("Illegal number: %s", s);
7762         return atoi(s);
7763 }
7764
7765
7766
7767 /*
7768  * Check for a valid number.  This should be elsewhere.
7769  */
7770
7771 static int
7772 is_number(p)
7773         const char *p;
7774         {
7775         do {
7776                 if (! is_digit(*p))
7777                         return 0;
7778         } while (*++p != '\0');
7779         return 1;
7780 }
7781
7782
7783 /*
7784  * Produce a possibly single quoted string suitable as input to the shell.
7785  * The return string is allocated on the stack.
7786  */
7787
7788 static char *
7789 single_quote(const char *s) {
7790         char *p;
7791
7792         STARTSTACKSTR(p);
7793
7794         do {
7795                 char *q = p;
7796                 size_t len1, len1p, len2, len2p;
7797
7798                 len1 = strcspn(s, "'");
7799                 len2 = strspn(s + len1, "'");
7800
7801                 len1p = len1 ? len1 + 2 : len1;
7802                 switch (len2) {
7803                 case 0:
7804                         len2p = 0;
7805                         break;
7806                 case 1:
7807                         len2p = 2;
7808                         break;
7809                 default:
7810                         len2p = len2 + 2;
7811                 }
7812
7813                 CHECKSTRSPACE(len1p + len2p + 1, p);
7814
7815                 if (len1) {
7816                         *p = '\'';
7817 #ifdef _GNU_SOURCE
7818                         q = mempcpy(p + 1, s, len1);
7819 #else
7820                         q = p + 1 + len1;
7821                         memcpy(p + 1, s, len1);
7822 #endif
7823                         *q++ = '\'';
7824                         s += len1;
7825                 }
7826
7827                 switch (len2) {
7828                 case 0:
7829                         break;
7830                 case 1:
7831                         *q++ = '\\';
7832                         *q = '\'';
7833                         s++;
7834                         break;
7835                 default:
7836                         *q = '"';
7837 #ifdef _GNU_SOURCE
7838                         *(char *) mempcpy(q + 1, s, len2) = '"';
7839 #else
7840                         q += 1 + len2;
7841                         memcpy(q + 1, s, len2);
7842                         *q = '"';
7843 #endif
7844                         s += len2;
7845                 }
7846
7847                 STADJUST(len1p + len2p, p);
7848         } while (*s);
7849
7850         USTPUTC(0, p);
7851
7852         return grabstackstr(p);
7853 }
7854
7855 /*
7856  * Like strdup but works with the ash stack.
7857  */
7858
7859 static char *
7860 sstrdup(const char *p)
7861 {
7862         size_t len = strlen(p) + 1;
7863         return memcpy(stalloc(len), p, len);
7864 }
7865
7866 /*
7867  * Wrapper around strcmp for qsort/bsearch/...
7868  */
7869 static int
7870 pstrcmp(const void *a, const void *b)
7871 {
7872         return strcmp(*(const char *const *) a, *(const char *const *) b);
7873 }
7874
7875 /*
7876  * Find a string is in a sorted array.
7877  */
7878 static const char *const *
7879 findstring(const char *s, const char *const *array, size_t nmemb)
7880 {
7881         return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp);
7882 }
7883 /*
7884  * This file was generated by the mknodes program.
7885  */
7886
7887 /*      $NetBSD: nodes.c.pat,v 1.8 1997/04/11 23:03:09 christos Exp $   */
7888
7889 /*
7890  * Routine for dealing with parsed shell commands.
7891  */
7892
7893
7894 static int     funcblocksize;           /* size of structures in function */
7895 static int     funcstringsize;          /* size of strings in node */
7896 pointer funcblock;              /* block to allocate function from */
7897 static char   *funcstring;              /* block to allocate strings from */
7898
7899 static const short nodesize[26] = {
7900       ALIGN(sizeof (struct nbinary)),
7901       ALIGN(sizeof (struct ncmd)),
7902       ALIGN(sizeof (struct npipe)),
7903       ALIGN(sizeof (struct nredir)),
7904       ALIGN(sizeof (struct nredir)),
7905       ALIGN(sizeof (struct nredir)),
7906       ALIGN(sizeof (struct nbinary)),
7907       ALIGN(sizeof (struct nbinary)),
7908       ALIGN(sizeof (struct nif)),
7909       ALIGN(sizeof (struct nbinary)),
7910       ALIGN(sizeof (struct nbinary)),
7911       ALIGN(sizeof (struct nfor)),
7912       ALIGN(sizeof (struct ncase)),
7913       ALIGN(sizeof (struct nclist)),
7914       ALIGN(sizeof (struct narg)),
7915       ALIGN(sizeof (struct narg)),
7916       ALIGN(sizeof (struct nfile)),
7917       ALIGN(sizeof (struct nfile)),
7918       ALIGN(sizeof (struct nfile)),
7919       ALIGN(sizeof (struct nfile)),
7920       ALIGN(sizeof (struct nfile)),
7921       ALIGN(sizeof (struct ndup)),
7922       ALIGN(sizeof (struct ndup)),
7923       ALIGN(sizeof (struct nhere)),
7924       ALIGN(sizeof (struct nhere)),
7925       ALIGN(sizeof (struct nnot)),
7926 };
7927
7928
7929 static void calcsize __P((union node *));
7930 static void sizenodelist __P((struct nodelist *));
7931 static union node *copynode __P((union node *));
7932 static struct nodelist *copynodelist __P((struct nodelist *));
7933 static char *nodesavestr __P((char *));
7934
7935
7936
7937 /*
7938  * Make a copy of a parse tree.
7939  */
7940
7941 union node *
7942 copyfunc(n)
7943         union node *n;
7944 {
7945         if (n == NULL)
7946                 return NULL;
7947         funcblocksize = 0;
7948         funcstringsize = 0;
7949         calcsize(n);
7950         funcblock = ckmalloc(funcblocksize + funcstringsize);
7951         funcstring = (char *) funcblock + funcblocksize;
7952         return copynode(n);
7953 }
7954
7955
7956
7957 static void
7958 calcsize(n)
7959         union node *n;
7960 {
7961       if (n == NULL)
7962             return;
7963       funcblocksize += nodesize[n->type];
7964       switch (n->type) {
7965       case NSEMI:
7966       case NAND:
7967       case NOR:
7968       case NWHILE:
7969       case NUNTIL:
7970             calcsize(n->nbinary.ch2);
7971             calcsize(n->nbinary.ch1);
7972             break;
7973       case NCMD:
7974             calcsize(n->ncmd.redirect);
7975             calcsize(n->ncmd.args);
7976             calcsize(n->ncmd.assign);
7977             break;
7978       case NPIPE:
7979             sizenodelist(n->npipe.cmdlist);
7980             break;
7981       case NREDIR:
7982       case NBACKGND:
7983       case NSUBSHELL:
7984             calcsize(n->nredir.redirect);
7985             calcsize(n->nredir.n);
7986             break;
7987       case NIF:
7988             calcsize(n->nif.elsepart);
7989             calcsize(n->nif.ifpart);
7990             calcsize(n->nif.test);
7991             break;
7992       case NFOR:
7993             funcstringsize += strlen(n->nfor.var) + 1;
7994             calcsize(n->nfor.body);
7995             calcsize(n->nfor.args);
7996             break;
7997       case NCASE:
7998             calcsize(n->ncase.cases);
7999             calcsize(n->ncase.expr);
8000             break;
8001       case NCLIST:
8002             calcsize(n->nclist.body);
8003             calcsize(n->nclist.pattern);
8004             calcsize(n->nclist.next);
8005             break;
8006       case NDEFUN:
8007       case NARG:
8008             sizenodelist(n->narg.backquote);
8009             funcstringsize += strlen(n->narg.text) + 1;
8010             calcsize(n->narg.next);
8011             break;
8012       case NTO:
8013       case NFROM:
8014       case NFROMTO:
8015       case NAPPEND:
8016       case NTOOV:
8017             calcsize(n->nfile.fname);
8018             calcsize(n->nfile.next);
8019             break;
8020       case NTOFD:
8021       case NFROMFD:
8022             calcsize(n->ndup.vname);
8023             calcsize(n->ndup.next);
8024             break;
8025       case NHERE:
8026       case NXHERE:
8027             calcsize(n->nhere.doc);
8028             calcsize(n->nhere.next);
8029             break;
8030       case NNOT:
8031             calcsize(n->nnot.com);
8032             break;
8033       };
8034 }
8035
8036
8037
8038 static void
8039 sizenodelist(lp)
8040         struct nodelist *lp;
8041 {
8042         while (lp) {
8043                 funcblocksize += ALIGN(sizeof(struct nodelist));
8044                 calcsize(lp->n);
8045                 lp = lp->next;
8046         }
8047 }
8048
8049
8050
8051 static union node *
8052 copynode(n)
8053         union node *n;
8054 {
8055         union node *new;
8056
8057       if (n == NULL)
8058             return NULL;
8059       new = funcblock;
8060       funcblock = (char *) funcblock + nodesize[n->type];
8061       switch (n->type) {
8062       case NSEMI:
8063       case NAND:
8064       case NOR:
8065       case NWHILE:
8066       case NUNTIL:
8067             new->nbinary.ch2 = copynode(n->nbinary.ch2);
8068             new->nbinary.ch1 = copynode(n->nbinary.ch1);
8069             break;
8070       case NCMD:
8071             new->ncmd.redirect = copynode(n->ncmd.redirect);
8072             new->ncmd.args = copynode(n->ncmd.args);
8073             new->ncmd.assign = copynode(n->ncmd.assign);
8074             new->ncmd.backgnd = n->ncmd.backgnd;
8075             break;
8076       case NPIPE:
8077             new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8078             new->npipe.backgnd = n->npipe.backgnd;
8079             break;
8080       case NREDIR:
8081       case NBACKGND:
8082       case NSUBSHELL:
8083             new->nredir.redirect = copynode(n->nredir.redirect);
8084             new->nredir.n = copynode(n->nredir.n);
8085             break;
8086       case NIF:
8087             new->nif.elsepart = copynode(n->nif.elsepart);
8088             new->nif.ifpart = copynode(n->nif.ifpart);
8089             new->nif.test = copynode(n->nif.test);
8090             break;
8091       case NFOR:
8092             new->nfor.var = nodesavestr(n->nfor.var);
8093             new->nfor.body = copynode(n->nfor.body);
8094             new->nfor.args = copynode(n->nfor.args);
8095             break;
8096       case NCASE:
8097             new->ncase.cases = copynode(n->ncase.cases);
8098             new->ncase.expr = copynode(n->ncase.expr);
8099             break;
8100       case NCLIST:
8101             new->nclist.body = copynode(n->nclist.body);
8102             new->nclist.pattern = copynode(n->nclist.pattern);
8103             new->nclist.next = copynode(n->nclist.next);
8104             break;
8105       case NDEFUN:
8106       case NARG:
8107             new->narg.backquote = copynodelist(n->narg.backquote);
8108             new->narg.text = nodesavestr(n->narg.text);
8109             new->narg.next = copynode(n->narg.next);
8110             break;
8111       case NTO:
8112       case NFROM:
8113       case NFROMTO:
8114       case NAPPEND:
8115       case NTOOV:
8116             new->nfile.fname = copynode(n->nfile.fname);
8117             new->nfile.fd = n->nfile.fd;
8118             new->nfile.next = copynode(n->nfile.next);
8119             break;
8120       case NTOFD:
8121       case NFROMFD:
8122             new->ndup.vname = copynode(n->ndup.vname);
8123             new->ndup.dupfd = n->ndup.dupfd;
8124             new->ndup.fd = n->ndup.fd;
8125             new->ndup.next = copynode(n->ndup.next);
8126             break;
8127       case NHERE:
8128       case NXHERE:
8129             new->nhere.doc = copynode(n->nhere.doc);
8130             new->nhere.fd = n->nhere.fd;
8131             new->nhere.next = copynode(n->nhere.next);
8132             break;
8133       case NNOT:
8134             new->nnot.com = copynode(n->nnot.com);
8135             break;
8136       };
8137       new->type = n->type;
8138         return new;
8139 }
8140
8141
8142 static struct nodelist *
8143 copynodelist(lp)
8144         struct nodelist *lp;
8145 {
8146         struct nodelist *start;
8147         struct nodelist **lpp;
8148
8149         lpp = &start;
8150         while (lp) {
8151                 *lpp = funcblock;
8152                 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8153                 (*lpp)->n = copynode(lp->n);
8154                 lp = lp->next;
8155                 lpp = &(*lpp)->next;
8156         }
8157         *lpp = NULL;
8158         return start;
8159 }
8160
8161
8162
8163 static char *
8164 nodesavestr(s)
8165         char   *s;
8166 {
8167 #ifdef _GNU_SOURCE
8168         char   *rtn = funcstring;
8169
8170         funcstring = stpcpy(funcstring, s) + 1;
8171         return rtn;
8172 #else
8173         register char *p = s;
8174         register char *q = funcstring;
8175         char   *rtn = funcstring;
8176
8177         while ((*q++ = *p++) != '\0')
8178                 continue;
8179         funcstring = q;
8180         return rtn;
8181 #endif
8182 }
8183
8184
8185
8186 /*
8187  * Free a parse tree.
8188  */
8189
8190 static void
8191 freefunc(n)
8192         union node *n;
8193 {
8194         if (n)
8195                 ckfree(n);
8196 }
8197 /*      $NetBSD: options.c,v 1.31 2001/02/26 13:06:43 wiz Exp $ */
8198
8199
8200 struct optent optlist[NOPTS] = {
8201         { "errexit",    'e',    0 },
8202         { "noglob",     'f',    0 },
8203         { "ignoreeof",  'I',    0 },
8204         { "interactive",'i',    0 },
8205         { "monitor",    'm',    0 },
8206         { "noexec",     'n',    0 },
8207         { "stdin",      's',    0 },
8208         { "xtrace",     'x',    0 },
8209         { "verbose",    'v',    0 },
8210         { "vi",         'V',    0 },
8211         { "emacs",      'E',    0 },
8212         { "noclobber",  'C',    0 },
8213         { "allexport",  'a',    0 },
8214         { "notify",     'b',    0 },
8215         { "nounset",    'u',    0 },
8216         { "quietprofile", 'q',  0 },
8217 };
8218 static char *arg0;                      /* value of $0 */
8219 struct shparam shellparam;      /* current positional parameters */
8220 static char **argptr;                   /* argument list for builtin commands */
8221 static char *optionarg;         /* set by nextopt (like getopt) */
8222 static char *optptr;                    /* used by nextopt */
8223
8224 static char *minusc;                    /* argument to -c option */
8225
8226
8227 static void options __P((int));
8228 static void minus_o __P((char *, int));
8229 static void setoption __P((int, int));
8230 #ifdef ASH_GETOPTS
8231 static int getopts __P((char *, char *, char **, int *, int *));
8232 #endif
8233
8234
8235 /*
8236  * Process the shell command line arguments.
8237  */
8238
8239 static void
8240 procargs(argc, argv)
8241         int argc;
8242         char **argv;
8243 {
8244         int i;
8245
8246         argptr = argv;
8247         if (argc > 0)
8248                 argptr++;
8249         for (i = 0; i < NOPTS; i++)
8250                 optlist[i].val = 2;
8251         options(1);
8252         if (*argptr == NULL && minusc == NULL)
8253                 sflag = 1;
8254         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8255                 iflag = 1;
8256         if (mflag == 2)
8257                 mflag = iflag;
8258         for (i = 0; i < NOPTS; i++)
8259                 if (optlist[i].val == 2)
8260                         optlist[i].val = 0;
8261         arg0 = argv[0];
8262         if (sflag == 0 && minusc == NULL) {
8263                 commandname = argv[0];
8264                 arg0 = *argptr++;
8265                 setinputfile(arg0, 0);
8266                 commandname = arg0;
8267         }
8268         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8269         if (argptr && minusc && *argptr)
8270                 arg0 = *argptr++;
8271
8272         shellparam.p = argptr;
8273         shellparam.optind = 1;
8274         shellparam.optoff = -1;
8275         /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8276         while (*argptr) {
8277                 shellparam.nparam++;
8278                 argptr++;
8279         }
8280         optschanged();
8281 }
8282
8283
8284 static void
8285 optschanged()
8286 {
8287         setinteractive(iflag);
8288         setjobctl(mflag);
8289 }
8290
8291 /*
8292  * Process shell options.  The global variable argptr contains a pointer
8293  * to the argument list; we advance it past the options.
8294  */
8295
8296 static void
8297 options(cmdline)
8298         int cmdline;
8299 {
8300         char *p;
8301         int val;
8302         int c;
8303
8304         if (cmdline)
8305                 minusc = NULL;
8306         while ((p = *argptr) != NULL) {
8307                 argptr++;
8308                 if ((c = *p++) == '-') {
8309                         val = 1;
8310                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8311                                 if (!cmdline) {
8312                                         /* "-" means turn off -x and -v */
8313                                         if (p[0] == '\0')
8314                                                 xflag = vflag = 0;
8315                                         /* "--" means reset params */
8316                                         else if (*argptr == NULL)
8317                                                 setparam(argptr);
8318                                 }
8319                                 break;    /* "-" or  "--" terminates options */
8320                         }
8321                 } else if (c == '+') {
8322                         val = 0;
8323                 } else {
8324                         argptr--;
8325                         break;
8326                 }
8327                 while ((c = *p++) != '\0') {
8328                         if (c == 'c' && cmdline) {
8329                                 char *q;
8330 #ifdef NOHACK   /* removing this code allows sh -ce 'foo' for compat */
8331                                 if (*p == '\0')
8332 #endif
8333                                         q = *argptr++;
8334                                 if (q == NULL || minusc != NULL)
8335                                         error("Bad -c option");
8336                                 minusc = q;
8337 #ifdef NOHACK
8338                                 break;
8339 #endif
8340                         } else if (c == 'o') {
8341                                 minus_o(*argptr, val);
8342                                 if (*argptr)
8343                                         argptr++;
8344                         } else {
8345                                 setoption(c, val);
8346                         }
8347                 }
8348         }
8349 }
8350
8351 static void
8352 minus_o(name, val)
8353         char *name;
8354         int val;
8355 {
8356         int i;
8357
8358         if (name == NULL) {
8359                 out1str("Current option settings\n");
8360                 for (i = 0; i < NOPTS; i++)
8361                         out1fmt("%-16s%s\n", optlist[i].name,
8362                                 optlist[i].val ? "on" : "off");
8363         } else {
8364                 for (i = 0; i < NOPTS; i++)
8365                         if (equal(name, optlist[i].name)) {
8366                                 setoption(optlist[i].letter, val);
8367                                 return;
8368                         }
8369                 error("Illegal option -o %s", name);
8370         }
8371 }
8372
8373
8374 static void
8375 setoption(flag, val)
8376         char flag;
8377         int val;
8378         {
8379         int i;
8380
8381         for (i = 0; i < NOPTS; i++)
8382                 if (optlist[i].letter == flag) {
8383                         optlist[i].val = val;
8384                         if (val) {
8385                                 /* #%$ hack for ksh semantics */
8386                                 if (flag == 'V')
8387                                         Eflag = 0;
8388                                 else if (flag == 'E')
8389                                         Vflag = 0;
8390                         }
8391                         return;
8392                 }
8393         error("Illegal option -%c", flag);
8394         /* NOTREACHED */
8395 }
8396
8397
8398
8399 #ifdef mkinit
8400 SHELLPROC {
8401         int i;
8402
8403         for (i = 0; i < NOPTS; i++)
8404                 optlist[i].val = 0;
8405         optschanged();
8406
8407 }
8408 #endif
8409
8410
8411 /*
8412  * Set the shell parameters.
8413  */
8414
8415 static void
8416 setparam(argv)
8417         char **argv;
8418         {
8419         char **newparam;
8420         char **ap;
8421         int nparam;
8422
8423         for (nparam = 0 ; argv[nparam] ; nparam++);
8424         ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8425         while (*argv) {
8426                 *ap++ = savestr(*argv++);
8427         }
8428         *ap = NULL;
8429         freeparam(&shellparam);
8430         shellparam.malloc = 1;
8431         shellparam.nparam = nparam;
8432         shellparam.p = newparam;
8433         shellparam.optind = 1;
8434         shellparam.optoff = -1;
8435 }
8436
8437
8438 /*
8439  * Free the list of positional parameters.
8440  */
8441
8442 static void
8443 freeparam(param)
8444         volatile struct shparam *param;
8445         {
8446         char **ap;
8447
8448         if (param->malloc) {
8449                 for (ap = param->p ; *ap ; ap++)
8450                         ckfree(*ap);
8451                 ckfree(param->p);
8452         }
8453 }
8454
8455
8456
8457 /*
8458  * The shift builtin command.
8459  */
8460
8461 static int
8462 shiftcmd(argc, argv)
8463         int argc;
8464         char **argv;
8465 {
8466         int n;
8467         char **ap1, **ap2;
8468
8469         n = 1;
8470         if (argc > 1)
8471                 n = number(argv[1]);
8472         if (n > shellparam.nparam)
8473                 error("can't shift that many");
8474         INTOFF;
8475         shellparam.nparam -= n;
8476         for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8477                 if (shellparam.malloc)
8478                         ckfree(*ap1);
8479         }
8480         ap2 = shellparam.p;
8481         while ((*ap2++ = *ap1++) != NULL);
8482         shellparam.optind = 1;
8483         shellparam.optoff = -1;
8484         INTON;
8485         return 0;
8486 }
8487
8488
8489
8490 /*
8491  * The set command builtin.
8492  */
8493
8494 static int
8495 setcmd(argc, argv)
8496         int argc;
8497         char **argv;
8498 {
8499         if (argc == 1)
8500                 return showvarscmd(argc, argv);
8501         INTOFF;
8502         options(0);
8503         optschanged();
8504         if (*argptr != NULL) {
8505                 setparam(argptr);
8506         }
8507         INTON;
8508         return 0;
8509 }
8510
8511
8512 static void
8513 getoptsreset(value)
8514         const char *value;
8515 {
8516         shellparam.optind = number(value);
8517         shellparam.optoff = -1;
8518 }
8519
8520 #ifdef ASH_GETOPTS
8521 /*
8522  * The getopts builtin.  Shellparam.optnext points to the next argument
8523  * to be processed.  Shellparam.optptr points to the next character to
8524  * be processed in the current argument.  If shellparam.optnext is NULL,
8525  * then it's the first time getopts has been called.
8526  */
8527
8528 static int
8529 getoptscmd(argc, argv)
8530         int argc;
8531         char **argv;
8532 {
8533         char **optbase;
8534
8535         if (argc < 3)
8536                 error("Usage: getopts optstring var [arg]");
8537         else if (argc == 3) {
8538                 optbase = shellparam.p;
8539                 if (shellparam.optind > shellparam.nparam + 1) {
8540                         shellparam.optind = 1;
8541                         shellparam.optoff = -1;
8542                 }
8543         }
8544         else {
8545                 optbase = &argv[3];
8546                 if (shellparam.optind > argc - 2) {
8547                         shellparam.optind = 1;
8548                         shellparam.optoff = -1;
8549                 }
8550         }
8551
8552         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
8553                        &shellparam.optoff);
8554 }
8555
8556 /*
8557  * Safe version of setvar, returns 1 on success 0 on failure.
8558  */
8559
8560 static int
8561 setvarsafe(name, val, flags)
8562         const char *name, *val;
8563         int flags;
8564 {
8565         struct jmploc jmploc;
8566         struct jmploc *volatile savehandler = handler;
8567         int err = 0;
8568 #ifdef __GNUC__
8569         (void) &err;
8570 #endif
8571
8572         if (setjmp(jmploc.loc))
8573                 err = 1;
8574         else {
8575                 handler = &jmploc;
8576                 setvar(name, val, flags);
8577         }
8578         handler = savehandler;
8579         return err;
8580 }
8581
8582 static int
8583 getopts(optstr, optvar, optfirst, myoptind, optoff)
8584         char *optstr;
8585         char *optvar;
8586         char **optfirst;
8587         int *myoptind;
8588         int *optoff;
8589 {
8590         char *p, *q;
8591         char c = '?';
8592         int done = 0;
8593         int err = 0;
8594         char s[10];
8595         char **optnext = optfirst + *myoptind - 1;
8596
8597         if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
8598             strlen(*(optnext - 1)) < *optoff)
8599                 p = NULL;
8600         else
8601                 p = *(optnext - 1) + *optoff;
8602         if (p == NULL || *p == '\0') {
8603                 /* Current word is done, advance */
8604                 if (optnext == NULL)
8605                         return 1;
8606                 p = *optnext;
8607                 if (p == NULL || *p != '-' || *++p == '\0') {
8608 atend:
8609                         *myoptind = optnext - optfirst + 1;
8610                         p = NULL;
8611                         done = 1;
8612                         goto out;
8613                 }
8614                 optnext++;
8615                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
8616                         goto atend;
8617         }
8618
8619         c = *p++;
8620         for (q = optstr; *q != c; ) {
8621                 if (*q == '\0') {
8622                         if (optstr[0] == ':') {
8623                                 s[0] = c;
8624                                 s[1] = '\0';
8625                                 err |= setvarsafe("OPTARG", s, 0);
8626                         }
8627                         else {
8628                                 outfmt(&errout, "Illegal option -%c\n", c);
8629                                 (void) unsetvar("OPTARG");
8630                         }
8631                         c = '?';
8632                         goto bad;
8633                 }
8634                 if (*++q == ':')
8635                         q++;
8636         }
8637
8638         if (*++q == ':') {
8639                 if (*p == '\0' && (p = *optnext) == NULL) {
8640                         if (optstr[0] == ':') {
8641                                 s[0] = c;
8642                                 s[1] = '\0';
8643                                 err |= setvarsafe("OPTARG", s, 0);
8644                                 c = ':';
8645                         }
8646                         else {
8647                                 outfmt(&errout, "No arg for -%c option\n", c);
8648                                 (void) unsetvar("OPTARG");
8649                                 c = '?';
8650                         }
8651                         goto bad;
8652                 }
8653
8654                 if (p == *optnext)
8655                         optnext++;
8656                 setvarsafe("OPTARG", p, 0);
8657                 p = NULL;
8658         }
8659         else
8660                 setvarsafe("OPTARG", "", 0);
8661         *myoptind = optnext - optfirst + 1;
8662         goto out;
8663
8664 bad:
8665         *myoptind = 1;
8666         p = NULL;
8667 out:
8668         *optoff = p ? p - *(optnext - 1) : -1;
8669         fmtstr(s, sizeof(s), "%d", *myoptind);
8670         err |= setvarsafe("OPTIND", s, VNOFUNC);
8671         s[0] = c;
8672         s[1] = '\0';
8673         err |= setvarsafe(optvar, s, 0);
8674         if (err) {
8675                 *myoptind = 1;
8676                 *optoff = -1;
8677                 flushall();
8678                 exraise(EXERROR);
8679         }
8680         return done;
8681 }
8682 #endif  
8683
8684 /*
8685  * XXX - should get rid of.  have all builtins use getopt(3).  the
8686  * library getopt must have the BSD extension static variable "optreset"
8687  * otherwise it can't be used within the shell safely.
8688  *
8689  * Standard option processing (a la getopt) for builtin routines.  The
8690  * only argument that is passed to nextopt is the option string; the
8691  * other arguments are unnecessary.  It return the character, or '\0' on
8692  * end of input.
8693  */
8694
8695 static int
8696 nextopt(optstring)
8697         const char *optstring;
8698         {
8699         char *p;
8700         const char *q;
8701         char c;
8702
8703         if ((p = optptr) == NULL || *p == '\0') {
8704                 p = *argptr;
8705                 if (p == NULL || *p != '-' || *++p == '\0')
8706                         return '\0';
8707                 argptr++;
8708                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
8709                         return '\0';
8710         }
8711         c = *p++;
8712         for (q = optstring ; *q != c ; ) {
8713                 if (*q == '\0')
8714                         error("Illegal option -%c", c);
8715                 if (*++q == ':')
8716                         q++;
8717         }
8718         if (*++q == ':') {
8719                 if (*p == '\0' && (p = *argptr++) == NULL)
8720                         error("No arg for -%c option", c);
8721                 optionarg = p;
8722                 p = NULL;
8723         }
8724         optptr = p;
8725         return c;
8726 }
8727
8728
8729 /*      $NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $        */
8730
8731 /*
8732  * Shell output routines.  We use our own output routines because:
8733  *      When a builtin command is interrupted we have to discard
8734  *              any pending output.
8735  *      When a builtin command appears in back quotes, we want to
8736  *              save the output of the command in a region obtained
8737  *              via malloc, rather than doing a fork and reading the
8738  *              output of the command via a pipe.
8739  *      Our output routines may be smaller than the stdio routines.
8740  */
8741
8742
8743 #define OUTBUFSIZ BUFSIZ
8744 #define MEM_OUT -3              /* output to dynamically allocated memory */
8745
8746
8747 #ifdef USE_GLIBC_STDIO
8748 struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
8749 struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
8750 struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
8751 #else
8752 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
8753 struct output errout = {NULL, 0, NULL, 0, 2, 0};
8754 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
8755 #endif
8756 struct output *out1 = &output;
8757 struct output *out2 = &errout;
8758
8759
8760 #ifndef USE_GLIBC_STDIO
8761 static void __outstr __P((const char *, size_t, struct output*));
8762 #endif
8763
8764
8765 #ifdef mkinit
8766
8767 INCLUDE "output.h"
8768 INCLUDE "memalloc.h"
8769
8770 INIT {
8771 #ifdef USE_GLIBC_STDIO
8772         initstreams();
8773 #endif
8774 }
8775
8776 RESET {
8777         out1 = &output;
8778         out2 = &errout;
8779 #ifdef USE_GLIBC_STDIO
8780         if (memout.stream != NULL)
8781                 __closememout();
8782 #endif
8783         if (memout.buf != NULL) {
8784                 ckfree(memout.buf);
8785                 memout.buf = NULL;
8786         }
8787 }
8788
8789 #endif
8790
8791
8792 #ifndef USE_GLIBC_STDIO
8793 static void
8794 __outstr(const char *p, size_t len, struct output *dest) {
8795         if (!dest->bufsize) {
8796                 dest->nleft = 0;
8797         } else if (dest->buf == NULL) {
8798                 if (len > dest->bufsize && dest->fd == MEM_OUT) {
8799                         dest->bufsize = len;
8800                 }
8801                 INTOFF;
8802                 dest->buf = ckmalloc(dest->bufsize);
8803                 dest->nextc = dest->buf;
8804                 dest->nleft = dest->bufsize;
8805                 INTON;
8806         } else if (dest->fd == MEM_OUT) {
8807                 int offset;
8808
8809                 offset = dest->bufsize;
8810                 INTOFF;
8811                 if (dest->bufsize >= len) {
8812                         dest->bufsize <<= 1;
8813                 } else {
8814                         dest->bufsize += len;
8815                 }
8816                 dest->buf = ckrealloc(dest->buf, dest->bufsize);
8817                 dest->nleft = dest->bufsize - offset;
8818                 dest->nextc = dest->buf + offset;
8819                 INTON;
8820         } else {
8821                 flushout(dest);
8822         }
8823
8824         if (len < dest->nleft) {
8825                 dest->nleft -= len;
8826                 memcpy(dest->nextc, p, len);
8827                 dest->nextc += len;
8828                 return;
8829         }
8830
8831         if (xwrite(dest->fd, p, len) < len)
8832                 dest->flags |= OUTPUT_ERR;
8833 }
8834 #endif
8835
8836
8837 static void
8838 outstr(p, file)
8839         const char *p;
8840         struct output *file;
8841         {
8842 #ifdef USE_GLIBC_STDIO
8843         INTOFF;
8844         fputs(p, file->stream);
8845         INTON;
8846 #else
8847         size_t len;
8848
8849         if (!*p) {
8850                 return;
8851         }
8852         len = strlen(p);
8853         if ((file->nleft -= len) > 0) {
8854                 memcpy(file->nextc, p, len);
8855                 file->nextc += len;
8856                 return;
8857         }
8858         __outstr(p, len, file);
8859 #endif
8860 }
8861
8862
8863 #ifndef USE_GLIBC_STDIO
8864
8865
8866 static void
8867 outcslow(c, dest)
8868         char c;
8869         struct output *dest;
8870         {
8871         __outstr(&c, 1, dest);
8872 }
8873 #endif
8874
8875
8876 static void
8877 flushall() {
8878         flushout(&output);
8879 #ifdef FLUSHERR
8880         flushout(&errout);
8881 #endif
8882 }
8883
8884
8885 static void
8886 flushout(dest)
8887         struct output *dest;
8888         {
8889 #ifdef USE_GLIBC_STDIO
8890         INTOFF;
8891         fflush(dest->stream);
8892         INTON;
8893 #else
8894         size_t len;
8895
8896         len = dest->nextc - dest->buf;
8897         if (dest->buf == NULL || !len || dest->fd < 0)
8898                 return;
8899         dest->nextc = dest->buf;
8900         dest->nleft = dest->bufsize;
8901         if (xwrite(dest->fd, dest->buf, len) < len)
8902                 dest->flags |= OUTPUT_ERR;
8903 #endif
8904 }
8905
8906
8907 static void
8908 freestdout() {
8909         if (output.buf) {
8910                 INTOFF;
8911                 ckfree(output.buf);
8912                 output.buf = NULL;
8913                 output.nleft = 0;
8914                 INTON;
8915         }
8916         output.flags = 0;
8917 }
8918
8919
8920 static void
8921 #ifdef __STDC__
8922 outfmt(struct output *file, const char *fmt, ...)
8923 #else
8924 static void
8925 outfmt(va_alist)
8926         va_dcl
8927 #endif
8928 {
8929         va_list ap;
8930 #ifndef __STDC__
8931         struct output *file;
8932         const char *fmt;
8933
8934         va_start(ap);
8935         file = va_arg(ap, struct output *);
8936         fmt = va_arg(ap, const char *);
8937 #else
8938         va_start(ap, fmt);
8939 #endif
8940         doformat(file, fmt, ap);
8941         va_end(ap);
8942 }
8943
8944
8945 static void
8946 #ifdef __STDC__
8947 out1fmt(const char *fmt, ...)
8948 #else
8949 out1fmt(va_alist)
8950         va_dcl
8951 #endif
8952 {
8953         va_list ap;
8954 #ifndef __STDC__
8955         const char *fmt;
8956
8957         va_start(ap);
8958         fmt = va_arg(ap, const char *);
8959 #else
8960         va_start(ap, fmt);
8961 #endif
8962         doformat(out1, fmt, ap);
8963         va_end(ap);
8964 }
8965
8966 static void
8967 #ifdef __STDC__
8968 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
8969 #else
8970 fmtstr(va_alist)
8971         va_dcl
8972 #endif
8973 {
8974         va_list ap;
8975 #ifndef __STDC__
8976         char *outbuf;
8977         size_t length;
8978         const char *fmt;
8979
8980         va_start(ap);
8981         outbuf = va_arg(ap, char *);
8982         length = va_arg(ap, size_t);
8983         fmt = va_arg(ap, const char *);
8984 #else
8985         va_start(ap, fmt);
8986 #endif
8987         INTOFF;
8988         vsnprintf(outbuf, length, fmt, ap);
8989         INTON;
8990 }
8991
8992 #ifndef USE_GLIBC_STDIO
8993 /*
8994  * Formatted output.  This routine handles a subset of the printf formats:
8995  * - Formats supported: d, u, o, p, X, s, and c.
8996  * - The x format is also accepted but is treated like X.
8997  * - The l, ll and q modifiers are accepted.
8998  * - The - and # flags are accepted; # only works with the o format.
8999  * - Width and precision may be specified with any format except c.
9000  * - An * may be given for the width or precision.
9001  * - The obsolete practice of preceding the width with a zero to get
9002  *   zero padding is not supported; use the precision field.
9003  * - A % may be printed by writing %% in the format string.
9004  */
9005
9006 #define TEMPSIZE 24
9007
9008 #ifdef BSD4_4
9009 #define HAVE_VASPRINTF 1
9010 #endif
9011
9012 #if     !HAVE_VASPRINTF
9013 static const char digit[] = "0123456789ABCDEF";
9014 #endif
9015
9016
9017 static void
9018 doformat(dest, f, ap)
9019         struct output *dest;
9020         const char *f;          /* format string */
9021         va_list ap;
9022 {
9023 #if     HAVE_VASPRINTF
9024         char *s, *t;
9025         int len;
9026
9027         INTOFF;
9028         len = vasprintf(&t, f, ap);
9029         if (len < 0) {
9030                 return;
9031         }
9032         s = stalloc(++len);
9033         memcpy(s, t, len);
9034         free(t);
9035         INTON;
9036         outstr(s, dest);
9037         stunalloc(s);
9038 #else   /* !HAVE_VASPRINTF */
9039         char c;
9040         char temp[TEMPSIZE];
9041         int flushleft;
9042         int sharp;
9043         int width;
9044         int prec;
9045         int islong;
9046         int isquad;
9047         char *p;
9048         int sign;
9049 #ifdef BSD4_4
9050         quad_t l;
9051         u_quad_t num;
9052 #else
9053         long l;
9054         u_long num;
9055 #endif
9056         unsigned base;
9057         int len;
9058         int size;
9059         int pad;
9060
9061         while ((c = *f++) != '\0') {
9062                 if (c != '%') {
9063                         outc(c, dest);
9064                         continue;
9065                 }
9066                 flushleft = 0;
9067                 sharp = 0;
9068                 width = 0;
9069                 prec = -1;
9070                 islong = 0;
9071                 isquad = 0;
9072                 for (;;) {
9073                         if (*f == '-')
9074                                 flushleft++;
9075                         else if (*f == '#')
9076                                 sharp++;
9077                         else
9078                                 break;
9079                         f++;
9080                 }
9081                 if (*f == '*') {
9082                         width = va_arg(ap, int);
9083                         f++;
9084                 } else {
9085                         while (is_digit(*f)) {
9086                                 width = 10 * width + digit_val(*f++);
9087                         }
9088                 }
9089                 if (*f == '.') {
9090                         if (*++f == '*') {
9091                                 prec = va_arg(ap, int);
9092                                 f++;
9093                         } else {
9094                                 prec = 0;
9095                                 while (is_digit(*f)) {
9096                                         prec = 10 * prec + digit_val(*f++);
9097                                 }
9098                         }
9099                 }
9100                 if (*f == 'l') {
9101                         f++;
9102                         if (*f == 'l') {
9103                                 isquad++;
9104                                 f++;
9105                         } else
9106                                 islong++;
9107                 } else if (*f == 'q') {
9108                         isquad++;
9109                         f++;
9110                 }
9111                 switch (*f) {
9112                 case 'd':
9113 #ifdef BSD4_4
9114                         if (isquad)
9115                                 l = va_arg(ap, quad_t);
9116                         else
9117 #endif
9118                         if (islong)
9119                                 l = va_arg(ap, long);
9120                         else
9121                                 l = va_arg(ap, int);
9122                         sign = 0;
9123                         num = l;
9124                         if (l < 0) {
9125                                 num = -l;
9126                                 sign = 1;
9127                         }
9128                         base = 10;
9129                         goto number;
9130                 case 'u':
9131                         base = 10;
9132                         goto uns_number;
9133                 case 'o':
9134                         base = 8;
9135                         goto uns_number;
9136                 case 'p':
9137                         outc('0', dest);
9138                         outc('x', dest);
9139                         /*FALLTHROUGH*/
9140                 case 'x':
9141                         /* we don't implement 'x'; treat like 'X' */
9142                 case 'X':
9143                         base = 16;
9144 uns_number:       /* an unsigned number */
9145                         sign = 0;
9146 #ifdef BSD4_4
9147                         if (isquad)
9148                                 num = va_arg(ap, u_quad_t);
9149                         else
9150 #endif
9151                         if (islong)
9152                                 num = va_arg(ap, unsigned long);
9153                         else
9154                                 num = va_arg(ap, unsigned int);
9155 number:           /* process a number */
9156                         p = temp + TEMPSIZE - 1;
9157                         *p = '\0';
9158                         while (num) {
9159                                 *--p = digit[num % base];
9160                                 num /= base;
9161                         }
9162                         len = (temp + TEMPSIZE - 1) - p;
9163                         if (prec < 0)
9164                                 prec = 1;
9165                         if (sharp && *f == 'o' && prec <= len)
9166                                 prec = len + 1;
9167                         pad = 0;
9168                         if (width) {
9169                                 size = len;
9170                                 if (size < prec)
9171                                         size = prec;
9172                                 size += sign;
9173                                 pad = width - size;
9174                                 if (flushleft == 0) {
9175                                         while (--pad >= 0)
9176                                                 outc(' ', dest);
9177                                 }
9178                         }
9179                         if (sign)
9180                                 outc('-', dest);
9181                         prec -= len;
9182                         while (--prec >= 0)
9183                                 outc('0', dest);
9184                         while (*p)
9185                                 outc(*p++, dest);
9186                         while (--pad >= 0)
9187                                 outc(' ', dest);
9188                         break;
9189                 case 's':
9190                         p = va_arg(ap, char *);
9191                         pad = 0;
9192                         if (width) {
9193                                 len = strlen(p);
9194                                 if (prec >= 0 && len > prec)
9195                                         len = prec;
9196                                 pad = width - len;
9197                                 if (flushleft == 0) {
9198                                         while (--pad >= 0)
9199                                                 outc(' ', dest);
9200                                 }
9201                         }
9202                         prec++;
9203                         while (--prec != 0 && *p)
9204                                 outc(*p++, dest);
9205                         while (--pad >= 0)
9206                                 outc(' ', dest);
9207                         break;
9208                 case 'c':
9209                         c = va_arg(ap, int);
9210                         outc(c, dest);
9211                         break;
9212                 default:
9213                         outc(*f, dest);
9214                         break;
9215                 }
9216                 f++;
9217         }
9218 #endif  /* !HAVE_VASPRINTF */
9219 }
9220 #endif
9221
9222
9223
9224 /*
9225  * Version of write which resumes after a signal is caught.
9226  */
9227
9228 static int
9229 xwrite(fd, buf, nbytes)
9230         int fd;
9231         const char *buf;
9232         int nbytes;
9233         {
9234         int ntry;
9235         int i;
9236         int n;
9237
9238         n = nbytes;
9239         ntry = 0;
9240         for (;;) {
9241                 i = write(fd, buf, n);
9242                 if (i > 0) {
9243                         if ((n -= i) <= 0)
9244                                 return nbytes;
9245                         buf += i;
9246                         ntry = 0;
9247                 } else if (i == 0) {
9248                         if (++ntry > 10)
9249                                 return nbytes - n;
9250                 } else if (errno != EINTR) {
9251                         return -1;
9252                 }
9253         }
9254 }
9255
9256
9257 #ifdef notdef
9258 /*
9259  * Version of ioctl that retries after a signal is caught.
9260  * XXX unused function
9261  */
9262
9263 static int
9264 xioctl(fd, request, arg)
9265         int fd;
9266         unsigned long request;
9267         char * arg;
9268 {
9269         int i;
9270
9271         while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
9272         return i;
9273 }
9274 #endif
9275
9276
9277 #ifdef USE_GLIBC_STDIO
9278 static void initstreams() {
9279         output.stream = stdout;
9280         errout.stream = stderr;
9281 }
9282
9283
9284 static void
9285 openmemout() {
9286         INTOFF;
9287         memout.stream = open_memstream(&memout.buf, &memout.bufsize);
9288         INTON;
9289 }
9290
9291
9292 static int
9293 __closememout() {
9294         int error;
9295         error = fclose(memout.stream);
9296         memout.stream = NULL;
9297         return error;
9298 }
9299 #endif
9300 /*      $NetBSD: parser.c,v 1.46 2001/02/04 19:52:06 christos Exp $     */
9301
9302 /*
9303  * Shell command parser.
9304  */
9305
9306 #define EOFMARKLEN 79
9307
9308
9309
9310 struct heredoc {
9311         struct heredoc *next;   /* next here document in list */
9312         union node *here;               /* redirection node */
9313         char *eofmark;          /* string indicating end of input */
9314         int striptabs;          /* if set, strip leading tabs */
9315 };
9316
9317
9318
9319 struct heredoc *heredoclist;    /* list of here documents to read */
9320 static int parsebackquote;              /* nonzero if we are inside backquotes */
9321 static int doprompt;                    /* if set, prompt the user */
9322 static int needprompt;                  /* true if interactive and at start of line */
9323 static int lasttoken;                   /* last token read */
9324 static int tokpushback;         /* last token pushed back */
9325 static char *wordtext;                  /* text of last word returned by readtoken */
9326 static int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
9327 /* 1 == check for aliases, 2 == also check for assignments */
9328 static int checkalias;
9329 struct nodelist *backquotelist;
9330 union node *redirnode;
9331 struct heredoc *heredoc;
9332 static int quoteflag;                   /* set if (part of) last token was quoted */
9333 static int startlinno;                  /* line # where last token started */
9334
9335
9336 static union node *list __P((int));
9337 static union node *andor __P((void));
9338 static union node *pipeline __P((void));
9339 static union node *command __P((void));
9340 static union node *simplecmd __P((void));
9341 static union node *makename __P((void));
9342 static void parsefname __P((void));
9343 static void parseheredoc __P((void));
9344 static int peektoken __P((void));
9345 static int readtoken __P((void));
9346 static int xxreadtoken __P((void));
9347 static int readtoken1 __P((int, char const *, char *, int));
9348 static int noexpand __P((char *));
9349 static void synexpect __P((int)) __attribute__((noreturn));
9350 static void synerror __P((const char *)) __attribute__((noreturn));
9351 static void setprompt __P((int));
9352
9353
9354 /*
9355  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
9356  * valid parse tree indicating a blank line.)
9357  */
9358
9359 union node *
9360 parsecmd(int interact)
9361 {
9362         int t;
9363
9364         tokpushback = 0;
9365         doprompt = interact;
9366         if (doprompt)
9367                 setprompt(1);
9368         else
9369                 setprompt(0);
9370         needprompt = 0;
9371         t = readtoken();
9372         if (t == TEOF)
9373                 return NEOF;
9374         if (t == TNL)
9375                 return NULL;
9376         tokpushback++;
9377         return list(1);
9378 }
9379
9380
9381 static union node *
9382 list(nlflag)
9383         int nlflag;
9384 {
9385         union node *n1, *n2, *n3;
9386         int tok;
9387
9388         checkkwd = 2;
9389         if (nlflag == 0 && tokendlist[peektoken()])
9390                 return NULL;
9391         n1 = NULL;
9392         for (;;) {
9393                 n2 = andor();
9394                 tok = readtoken();
9395                 if (tok == TBACKGND) {
9396                         if (n2->type == NCMD || n2->type == NPIPE) {
9397                                 n2->ncmd.backgnd = 1;
9398                         } else if (n2->type == NREDIR) {
9399                                 n2->type = NBACKGND;
9400                         } else {
9401                                 n3 = (union node *)stalloc(sizeof (struct nredir));
9402                                 n3->type = NBACKGND;
9403                                 n3->nredir.n = n2;
9404                                 n3->nredir.redirect = NULL;
9405                                 n2 = n3;
9406                         }
9407                 }
9408                 if (n1 == NULL) {
9409                         n1 = n2;
9410                 }
9411                 else {
9412                         n3 = (union node *)stalloc(sizeof (struct nbinary));
9413                         n3->type = NSEMI;
9414                         n3->nbinary.ch1 = n1;
9415                         n3->nbinary.ch2 = n2;
9416                         n1 = n3;
9417                 }
9418                 switch (tok) {
9419                 case TBACKGND:
9420                 case TSEMI:
9421                         tok = readtoken();
9422                         /* fall through */
9423                 case TNL:
9424                         if (tok == TNL) {
9425                                 parseheredoc();
9426                                 if (nlflag)
9427                                         return n1;
9428                         } else {
9429                                 tokpushback++;
9430                         }
9431                         checkkwd = 2;
9432                         if (tokendlist[peektoken()])
9433                                 return n1;
9434                         break;
9435                 case TEOF:
9436                         if (heredoclist)
9437                                 parseheredoc();
9438                         else
9439                                 pungetc();              /* push back EOF on input */
9440                         return n1;
9441                 default:
9442                         if (nlflag)
9443                                 synexpect(-1);
9444                         tokpushback++;
9445                         return n1;
9446                 }
9447         }
9448 }
9449
9450
9451
9452 static union node *
9453 andor() {
9454         union node *n1, *n2, *n3;
9455         int t;
9456
9457         checkkwd = 1;
9458         n1 = pipeline();
9459         for (;;) {
9460                 if ((t = readtoken()) == TAND) {
9461                         t = NAND;
9462                 } else if (t == TOR) {
9463                         t = NOR;
9464                 } else {
9465                         tokpushback++;
9466                         return n1;
9467                 }
9468                 checkkwd = 2;
9469                 n2 = pipeline();
9470                 n3 = (union node *)stalloc(sizeof (struct nbinary));
9471                 n3->type = t;
9472                 n3->nbinary.ch1 = n1;
9473                 n3->nbinary.ch2 = n2;
9474                 n1 = n3;
9475         }
9476 }
9477
9478
9479
9480 static union node *
9481 pipeline() {
9482         union node *n1, *n2, *pipenode;
9483         struct nodelist *lp, *prev;
9484         int negate;
9485
9486         negate = 0;
9487         TRACE(("pipeline: entered\n"));
9488         if (readtoken() == TNOT) {
9489                 negate = !negate;
9490                 checkkwd = 1;
9491         } else
9492                 tokpushback++;
9493         n1 = command();
9494         if (readtoken() == TPIPE) {
9495                 pipenode = (union node *)stalloc(sizeof (struct npipe));
9496                 pipenode->type = NPIPE;
9497                 pipenode->npipe.backgnd = 0;
9498                 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9499                 pipenode->npipe.cmdlist = lp;
9500                 lp->n = n1;
9501                 do {
9502                         prev = lp;
9503                         lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9504                         checkkwd = 2;
9505                         lp->n = command();
9506                         prev->next = lp;
9507                 } while (readtoken() == TPIPE);
9508                 lp->next = NULL;
9509                 n1 = pipenode;
9510         }
9511         tokpushback++;
9512         if (negate) {
9513                 n2 = (union node *)stalloc(sizeof (struct nnot));
9514                 n2->type = NNOT;
9515                 n2->nnot.com = n1;
9516                 return n2;
9517         } else
9518                 return n1;
9519 }
9520
9521
9522
9523 static union node *
9524 command() {
9525         union node *n1, *n2;
9526         union node *ap, **app;
9527         union node *cp, **cpp;
9528         union node *redir, **rpp;
9529         int t;
9530
9531         redir = NULL;
9532         n1 = NULL;
9533         rpp = &redir;
9534
9535         switch (readtoken()) {
9536         case TIF:
9537                 n1 = (union node *)stalloc(sizeof (struct nif));
9538                 n1->type = NIF;
9539                 n1->nif.test = list(0);
9540                 if (readtoken() != TTHEN)
9541                         synexpect(TTHEN);
9542                 n1->nif.ifpart = list(0);
9543                 n2 = n1;
9544                 while (readtoken() == TELIF) {
9545                         n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9546                         n2 = n2->nif.elsepart;
9547                         n2->type = NIF;
9548                         n2->nif.test = list(0);
9549                         if (readtoken() != TTHEN)
9550                                 synexpect(TTHEN);
9551                         n2->nif.ifpart = list(0);
9552                 }
9553                 if (lasttoken == TELSE)
9554                         n2->nif.elsepart = list(0);
9555                 else {
9556                         n2->nif.elsepart = NULL;
9557                         tokpushback++;
9558                 }
9559                 if (readtoken() != TFI)
9560                         synexpect(TFI);
9561                 checkkwd = 1;
9562                 break;
9563         case TWHILE:
9564         case TUNTIL: {
9565                 int got;
9566                 n1 = (union node *)stalloc(sizeof (struct nbinary));
9567                 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9568                 n1->nbinary.ch1 = list(0);
9569                 if ((got=readtoken()) != TDO) {
9570 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9571                         synexpect(TDO);
9572                 }
9573                 n1->nbinary.ch2 = list(0);
9574                 if (readtoken() != TDONE)
9575                         synexpect(TDONE);
9576                 checkkwd = 1;
9577                 break;
9578         }
9579         case TFOR:
9580                 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9581                         synerror("Bad for loop variable");
9582                 n1 = (union node *)stalloc(sizeof (struct nfor));
9583                 n1->type = NFOR;
9584                 n1->nfor.var = wordtext;
9585                 checkkwd = 1;
9586                 if (readtoken() == TIN) {
9587                         app = &ap;
9588                         while (readtoken() == TWORD) {
9589                                 n2 = (union node *)stalloc(sizeof (struct narg));
9590                                 n2->type = NARG;
9591                                 n2->narg.text = wordtext;
9592                                 n2->narg.backquote = backquotelist;
9593                                 *app = n2;
9594                                 app = &n2->narg.next;
9595                         }
9596                         *app = NULL;
9597                         n1->nfor.args = ap;
9598                         if (lasttoken != TNL && lasttoken != TSEMI)
9599                                 synexpect(-1);
9600                 } else {
9601                         static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9602                                                                    '@', '=', '\0'};
9603                         n2 = (union node *)stalloc(sizeof (struct narg));
9604                         n2->type = NARG;
9605                         n2->narg.text = argvars;
9606                         n2->narg.backquote = NULL;
9607                         n2->narg.next = NULL;
9608                         n1->nfor.args = n2;
9609                         /*
9610                          * Newline or semicolon here is optional (but note
9611                          * that the original Bourne shell only allowed NL).
9612                          */
9613                         if (lasttoken != TNL && lasttoken != TSEMI)
9614                                 tokpushback++;
9615                 }
9616                 checkkwd = 2;
9617                 if (readtoken() != TDO)
9618                         synexpect(TDO);
9619                 n1->nfor.body = list(0);
9620                 if (readtoken() != TDONE)
9621                         synexpect(TDONE);
9622                 checkkwd = 1;
9623                 break;
9624         case TCASE:
9625                 n1 = (union node *)stalloc(sizeof (struct ncase));
9626                 n1->type = NCASE;
9627                 if (readtoken() != TWORD)
9628                         synexpect(TWORD);
9629                 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9630                 n2->type = NARG;
9631                 n2->narg.text = wordtext;
9632                 n2->narg.backquote = backquotelist;
9633                 n2->narg.next = NULL;
9634                 do {
9635                         checkkwd = 1;
9636                 } while (readtoken() == TNL);
9637                 if (lasttoken != TIN)
9638                         synerror("expecting \"in\"");
9639                 cpp = &n1->ncase.cases;
9640                 checkkwd = 2, readtoken();
9641                 do {
9642                         if (lasttoken == TLP)
9643                                 readtoken();
9644                         *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9645                         cp->type = NCLIST;
9646                         app = &cp->nclist.pattern;
9647                         for (;;) {
9648                                 *app = ap = (union node *)stalloc(sizeof (struct narg));
9649                                 ap->type = NARG;
9650                                 ap->narg.text = wordtext;
9651                                 ap->narg.backquote = backquotelist;
9652                                 if (checkkwd = 2, readtoken() != TPIPE)
9653                                         break;
9654                                 app = &ap->narg.next;
9655                                 readtoken();
9656                         }
9657                         ap->narg.next = NULL;
9658                         if (lasttoken != TRP)
9659                                 synexpect(TRP);
9660                         cp->nclist.body = list(0);
9661
9662                         checkkwd = 2;
9663                         if ((t = readtoken()) != TESAC) {
9664                                 if (t != TENDCASE)
9665                                         synexpect(TENDCASE);
9666                                 else
9667                                         checkkwd = 2, readtoken();
9668                         }
9669                         cpp = &cp->nclist.next;
9670                 } while(lasttoken != TESAC);
9671                 *cpp = NULL;
9672                 checkkwd = 1;
9673                 break;
9674         case TLP:
9675                 n1 = (union node *)stalloc(sizeof (struct nredir));
9676                 n1->type = NSUBSHELL;
9677                 n1->nredir.n = list(0);
9678                 n1->nredir.redirect = NULL;
9679                 if (readtoken() != TRP)
9680                         synexpect(TRP);
9681                 checkkwd = 1;
9682                 break;
9683         case TBEGIN:
9684                 n1 = list(0);
9685                 if (readtoken() != TEND)
9686                         synexpect(TEND);
9687                 checkkwd = 1;
9688                 break;
9689         /* Handle an empty command like other simple commands.  */
9690         case TSEMI:
9691         case TAND:
9692         case TOR:
9693         case TNL:
9694         case TEOF:
9695         case TRP:
9696         case TBACKGND:
9697                 /*
9698                  * An empty command before a ; doesn't make much sense, and
9699                  * should certainly be disallowed in the case of `if ;'.
9700                  */
9701                 if (!redir)
9702                         synexpect(-1);
9703         case TWORD:
9704         case TREDIR:
9705                 tokpushback++;
9706                 n1 = simplecmd();
9707                 return n1;
9708         default:
9709                 synexpect(-1);
9710                 /* NOTREACHED */
9711         }
9712
9713         /* Now check for redirection which may follow command */
9714         while (readtoken() == TREDIR) {
9715                 *rpp = n2 = redirnode;
9716                 rpp = &n2->nfile.next;
9717                 parsefname();
9718         }
9719         tokpushback++;
9720         *rpp = NULL;
9721         if (redir) {
9722                 if (n1->type != NSUBSHELL) {
9723                         n2 = (union node *)stalloc(sizeof (struct nredir));
9724                         n2->type = NREDIR;
9725                         n2->nredir.n = n1;
9726                         n1 = n2;
9727                 }
9728                 n1->nredir.redirect = redir;
9729         }
9730
9731         return n1;
9732 }
9733
9734
9735 static union node *
9736 simplecmd() {
9737         union node *args, **app;
9738         union node *n = NULL;
9739         union node *vars, **vpp;
9740         union node **rpp, *redir;
9741
9742         args = NULL;
9743         app = &args;
9744         vars = NULL;
9745         vpp = &vars;
9746         redir = NULL;
9747         rpp = &redir;
9748
9749         checkalias = 2;
9750         for (;;) {
9751                 switch (readtoken()) {
9752                 case TWORD:
9753                 case TASSIGN:
9754                         n = (union node *)stalloc(sizeof (struct narg));
9755                         n->type = NARG;
9756                         n->narg.text = wordtext;
9757                         n->narg.backquote = backquotelist;
9758                         if (lasttoken == TWORD) {
9759                                 *app = n;
9760                                 app = &n->narg.next;
9761                         } else {
9762                                 *vpp = n;
9763                                 vpp = &n->narg.next;
9764                         }
9765                         break;
9766                 case TREDIR:
9767                         *rpp = n = redirnode;
9768                         rpp = &n->nfile.next;
9769                         parsefname();   /* read name of redirection file */
9770                         break;
9771                 case TLP:
9772                         if (
9773                                 args && app == &args->narg.next &&
9774                                 !vars && !redir
9775                         ) {
9776                                 /* We have a function */
9777                                 if (readtoken() != TRP)
9778                                         synexpect(TRP);
9779 #ifdef notdef
9780                                 if (! goodname(n->narg.text))
9781                                         synerror("Bad function name");
9782 #endif
9783                                 n->type = NDEFUN;
9784                                 checkkwd = 2;
9785                                 n->narg.next = command();
9786                                 return n;
9787                         }
9788                         /* fall through */
9789                 default:
9790                         tokpushback++;
9791                         goto out;
9792                 }
9793         }
9794 out:
9795         *app = NULL;
9796         *vpp = NULL;
9797         *rpp = NULL;
9798         n = (union node *)stalloc(sizeof (struct ncmd));
9799         n->type = NCMD;
9800         n->ncmd.backgnd = 0;
9801         n->ncmd.args = args;
9802         n->ncmd.assign = vars;
9803         n->ncmd.redirect = redir;
9804         return n;
9805 }
9806
9807 static union node *
9808 makename() {
9809         union node *n;
9810
9811         n = (union node *)stalloc(sizeof (struct narg));
9812         n->type = NARG;
9813         n->narg.next = NULL;
9814         n->narg.text = wordtext;
9815         n->narg.backquote = backquotelist;
9816         return n;
9817 }
9818
9819 static void fixredir(union node *n, const char *text, int err)
9820         {
9821         TRACE(("Fix redir %s %d\n", text, err));
9822         if (!err)
9823                 n->ndup.vname = NULL;
9824
9825         if (is_digit(text[0]) && text[1] == '\0')
9826                 n->ndup.dupfd = digit_val(text[0]);
9827         else if (text[0] == '-' && text[1] == '\0')
9828                 n->ndup.dupfd = -1;
9829         else {
9830
9831                 if (err)
9832                         synerror("Bad fd number");
9833                 else
9834                         n->ndup.vname = makename();
9835         }
9836 }
9837
9838
9839 static void
9840 parsefname() {
9841         union node *n = redirnode;
9842
9843         if (readtoken() != TWORD)
9844                 synexpect(-1);
9845         if (n->type == NHERE) {
9846                 struct heredoc *here = heredoc;
9847                 struct heredoc *p;
9848                 int i;
9849
9850                 if (quoteflag == 0)
9851                         n->type = NXHERE;
9852                 TRACE(("Here document %d\n", n->type));
9853                 if (here->striptabs) {
9854                         while (*wordtext == '\t')
9855                                 wordtext++;
9856                 }
9857                 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9858                         synerror("Illegal eof marker for << redirection");
9859                 rmescapes(wordtext);
9860                 here->eofmark = wordtext;
9861                 here->next = NULL;
9862                 if (heredoclist == NULL)
9863                         heredoclist = here;
9864                 else {
9865                         for (p = heredoclist ; p->next ; p = p->next);
9866                         p->next = here;
9867                 }
9868         } else if (n->type == NTOFD || n->type == NFROMFD) {
9869                 fixredir(n, wordtext, 0);
9870         } else {
9871                 n->nfile.fname = makename();
9872         }
9873 }
9874
9875
9876 /*
9877  * Input any here documents.
9878  */
9879
9880 static void
9881 parseheredoc() {
9882         struct heredoc *here;
9883         union node *n;
9884
9885         while (heredoclist) {
9886                 here = heredoclist;
9887                 heredoclist = here->next;
9888                 if (needprompt) {
9889                         setprompt(2);
9890                         needprompt = 0;
9891                 }
9892                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9893                                 here->eofmark, here->striptabs);
9894                 n = (union node *)stalloc(sizeof (struct narg));
9895                 n->narg.type = NARG;
9896                 n->narg.next = NULL;
9897                 n->narg.text = wordtext;
9898                 n->narg.backquote = backquotelist;
9899                 here->here->nhere.doc = n;
9900         }
9901 }
9902
9903 static int
9904 peektoken() {
9905         int t;
9906
9907         t = readtoken();
9908         tokpushback++;
9909         return (t);
9910 }
9911
9912 static int
9913 readtoken() {
9914         int t;
9915         int savecheckkwd = checkkwd;
9916         int savecheckalias = checkalias;
9917         struct alias *ap;
9918 #ifdef DEBUG
9919         int alreadyseen = tokpushback;
9920 #endif
9921
9922 top:
9923         t = xxreadtoken();
9924         checkalias = savecheckalias;
9925
9926         if (checkkwd) {
9927                 /*
9928                  * eat newlines
9929                  */
9930                 if (checkkwd == 2) {
9931                         checkkwd = 0;
9932                         while (t == TNL) {
9933                                 parseheredoc();
9934                                 t = xxreadtoken();
9935                         }
9936                 }
9937                 checkkwd = 0;
9938                 /*
9939                  * check for keywords
9940                  */
9941                 if (t == TWORD && !quoteflag)
9942                 {
9943                         const char *const *pp;
9944
9945                         if ((pp = findkwd(wordtext))) {
9946                                 lasttoken = t = pp - parsekwd + KWDOFFSET;
9947                                 TRACE(("keyword %s recognized\n", tokname[t]));
9948                                 goto out;
9949                         }
9950                 }
9951         }
9952
9953         if (t != TWORD) {
9954                 if (t != TREDIR) {
9955                         checkalias = 0;
9956                 }
9957         } else if (checkalias == 2 && isassignment(wordtext)) {
9958                 lasttoken = t = TASSIGN;
9959         } else if (checkalias) {
9960                 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
9961                         if (*ap->val) {
9962                                 pushstring(ap->val, strlen(ap->val), ap);
9963                         }
9964                         checkkwd = savecheckkwd;
9965                         goto top;
9966                 }
9967                 checkalias = 0;
9968         }
9969 out:
9970 #ifdef DEBUG
9971         if (!alreadyseen)
9972             TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9973         else
9974             TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9975 #endif
9976         return (t);
9977 }
9978
9979
9980 /*
9981  * Read the next input token.
9982  * If the token is a word, we set backquotelist to the list of cmds in
9983  *      backquotes.  We set quoteflag to true if any part of the word was
9984  *      quoted.
9985  * If the token is TREDIR, then we set redirnode to a structure containing
9986  *      the redirection.
9987  * In all cases, the variable startlinno is set to the number of the line
9988  *      on which the token starts.
9989  *
9990  * [Change comment:  here documents and internal procedures]
9991  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
9992  *  word parsing code into a separate routine.  In this case, readtoken
9993  *  doesn't need to have any internal procedures, but parseword does.
9994  *  We could also make parseoperator in essence the main routine, and
9995  *  have parseword (readtoken1?) handle both words and redirection.]
9996  */
9997
9998 #define RETURN(token)   return lasttoken = token
9999
10000 static int
10001 xxreadtoken() {
10002         int c;
10003
10004         if (tokpushback) {
10005                 tokpushback = 0;
10006                 return lasttoken;
10007         }
10008         if (needprompt) {
10009                 setprompt(2);
10010                 needprompt = 0;
10011         }
10012         startlinno = plinno;
10013         for (;;) {      /* until token or start of word found */
10014                 c = pgetc_macro();
10015                 switch (c) {
10016                 case ' ': case '\t':
10017                 case PEOA:
10018                         continue;
10019                 case '#':
10020                         while ((c = pgetc()) != '\n' && c != PEOF);
10021                         pungetc();
10022                         continue;
10023                 case '\\':
10024                         if (pgetc() == '\n') {
10025                                 startlinno = ++plinno;
10026                                 if (doprompt)
10027                                         setprompt(2);
10028                                 else
10029                                         setprompt(0);
10030                                 continue;
10031                         }
10032                         pungetc();
10033                         goto breakloop;
10034                 case '\n':
10035                         plinno++;
10036                         needprompt = doprompt;
10037                         RETURN(TNL);
10038                 case PEOF:
10039                         RETURN(TEOF);
10040                 case '&':
10041                         if (pgetc() == '&')
10042                                 RETURN(TAND);
10043                         pungetc();
10044                         RETURN(TBACKGND);
10045                 case '|':
10046                         if (pgetc() == '|')
10047                                 RETURN(TOR);
10048                         pungetc();
10049                         RETURN(TPIPE);
10050                 case ';':
10051                         if (pgetc() == ';')
10052                                 RETURN(TENDCASE);
10053                         pungetc();
10054                         RETURN(TSEMI);
10055                 case '(':
10056                         RETURN(TLP);
10057                 case ')':
10058                         RETURN(TRP);
10059                 default:
10060                         goto breakloop;
10061                 }
10062         }
10063 breakloop:
10064         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10065 #undef RETURN
10066 }
10067
10068
10069
10070 /*
10071  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10072  * is not NULL, read a here document.  In the latter case, eofmark is the
10073  * word which marks the end of the document and striptabs is true if
10074  * leading tabs should be stripped from the document.  The argument firstc
10075  * is the first character of the input token or document.
10076  *
10077  * Because C does not have internal subroutines, I have simulated them
10078  * using goto's to implement the subroutine linkage.  The following macros
10079  * will run code that appears at the end of readtoken1.
10080  */
10081
10082 #define CHECKEND()      {goto checkend; checkend_return:;}
10083 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10084 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10085 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10086 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10087 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10088
10089 static int
10090 readtoken1(firstc, syntax, eofmark, striptabs)
10091         int firstc;
10092         char const *syntax;
10093         char *eofmark;
10094         int striptabs;
10095         {
10096         int c = firstc;
10097         char *out;
10098         int len;
10099         char line[EOFMARKLEN + 1];
10100         struct nodelist *bqlist;
10101         int quotef;
10102         int dblquote;
10103         int varnest;    /* levels of variables expansion */
10104         int arinest;    /* levels of arithmetic expansion */
10105         int parenlevel; /* levels of parens in arithmetic */
10106         int dqvarnest;  /* levels of variables expansion within double quotes */
10107         int oldstyle;
10108         char const *prevsyntax; /* syntax before arithmetic */
10109 #if __GNUC__
10110         /* Avoid longjmp clobbering */
10111         (void) &out;
10112         (void) &quotef;
10113         (void) &dblquote;
10114         (void) &varnest;
10115         (void) &arinest;
10116         (void) &parenlevel;
10117         (void) &dqvarnest;
10118         (void) &oldstyle;
10119         (void) &prevsyntax;
10120         (void) &syntax;
10121 #endif
10122
10123         startlinno = plinno;
10124         dblquote = 0;
10125         if (syntax == DQSYNTAX)
10126                 dblquote = 1;
10127         quotef = 0;
10128         bqlist = NULL;
10129         varnest = 0;
10130         arinest = 0;
10131         parenlevel = 0;
10132         dqvarnest = 0;
10133
10134         STARTSTACKSTR(out);
10135         loop: { /* for each line, until end of word */
10136 #if ATTY
10137                 if (c == '\034' && doprompt
10138                  && attyset() && ! equal(termval(), "emacs")) {
10139                         attyline();
10140                         if (syntax == BASESYNTAX)
10141                                 return readtoken();
10142                         c = pgetc();
10143                         goto loop;
10144                 }
10145 #endif
10146                 CHECKEND();     /* set c to PEOF if at end of here document */
10147                 for (;;) {      /* until end of line or end of word */
10148                         CHECKSTRSPACE(3, out);  /* permit 3 calls to USTPUTC */
10149                         switch(syntax[c]) {
10150                         case CNL:       /* '\n' */
10151                                 if (syntax == BASESYNTAX)
10152                                         goto endword;   /* exit outer loop */
10153                                 USTPUTC(c, out);
10154                                 plinno++;
10155                                 if (doprompt)
10156                                         setprompt(2);
10157                                 else
10158                                         setprompt(0);
10159                                 c = pgetc();
10160                                 goto loop;              /* continue outer loop */
10161                         case CWORD:
10162                                 USTPUTC(c, out);
10163                                 break;
10164                         case CCTL:
10165                                 if ((eofmark == NULL || dblquote) &&
10166                                     dqvarnest == 0)
10167                                         USTPUTC(CTLESC, out);
10168                                 USTPUTC(c, out);
10169                                 break;
10170                         case CBACK:     /* backslash */
10171                                 c = pgetc2();
10172                                 if (c == PEOF) {
10173                                         USTPUTC('\\', out);
10174                                         pungetc();
10175                                 } else if (c == '\n') {
10176                                         if (doprompt)
10177                                                 setprompt(2);
10178                                         else
10179                                                 setprompt(0);
10180                                 } else {
10181                                         if (dblquote && c != '\\' && c != '`' && c != '$'
10182                                                          && (c != '"' || eofmark != NULL))
10183                                                 USTPUTC('\\', out);
10184                                         if (SQSYNTAX[c] == CCTL)
10185                                                 USTPUTC(CTLESC, out);
10186                                         else if (eofmark == NULL)
10187                                                 USTPUTC(CTLQUOTEMARK, out);
10188                                         USTPUTC(c, out);
10189                                         quotef++;
10190                                 }
10191                                 break;
10192                         case CSQUOTE:
10193                                 if (eofmark == NULL)
10194                                         USTPUTC(CTLQUOTEMARK, out);
10195                                 syntax = SQSYNTAX;
10196                                 break;
10197                         case CDQUOTE:
10198                                 if (eofmark == NULL)
10199                                         USTPUTC(CTLQUOTEMARK, out);
10200                                 syntax = DQSYNTAX;
10201                                 dblquote = 1;
10202                                 break;
10203                         case CENDQUOTE:
10204                                 if (eofmark != NULL && arinest == 0 &&
10205                                     varnest == 0) {
10206                                         USTPUTC(c, out);
10207                                 } else {
10208                                         if (arinest) {
10209                                                 syntax = ARISYNTAX;
10210                                                 dblquote = 0;
10211                                         } else if (eofmark == NULL &&
10212                                                    dqvarnest == 0) {
10213                                                 syntax = BASESYNTAX;
10214                                                 dblquote = 0;
10215                                         }
10216                                         quotef++;
10217                                 }
10218                                 break;
10219                         case CVAR:      /* '$' */
10220                                 PARSESUB();             /* parse substitution */
10221                                 break;
10222                         case CENDVAR:   /* '}' */
10223                                 if (varnest > 0) {
10224                                         varnest--;
10225                                         if (dqvarnest > 0) {
10226                                                 dqvarnest--;
10227                                         }
10228                                         USTPUTC(CTLENDVAR, out);
10229                                 } else {
10230                                         USTPUTC(c, out);
10231                                 }
10232                                 break;
10233 #ifdef ASH_MATH_SUPPORT
10234                         case CLP:       /* '(' in arithmetic */
10235                                 parenlevel++;
10236                                 USTPUTC(c, out);
10237                                 break;
10238                         case CRP:       /* ')' in arithmetic */
10239                                 if (parenlevel > 0) {
10240                                         USTPUTC(c, out);
10241                                         --parenlevel;
10242                                 } else {
10243                                         if (pgetc() == ')') {
10244                                                 if (--arinest == 0) {
10245                                                         USTPUTC(CTLENDARI, out);
10246                                                         syntax = prevsyntax;
10247                                                         if (syntax == DQSYNTAX)
10248                                                                 dblquote = 1;
10249                                                         else
10250                                                                 dblquote = 0;
10251                                                 } else
10252                                                         USTPUTC(')', out);
10253                                         } else {
10254                                                 /*
10255                                                  * unbalanced parens
10256                                                  *  (don't 2nd guess - no error)
10257                                                  */
10258                                                 pungetc();
10259                                                 USTPUTC(')', out);
10260                                         }
10261                                 }
10262                                 break;
10263 #endif
10264                         case CBQUOTE:   /* '`' */
10265                                 PARSEBACKQOLD();
10266                                 break;
10267                         case CEOF:
10268                                 goto endword;           /* exit outer loop */
10269                         case CIGN:
10270                                 break;
10271                         default:
10272                                 if (varnest == 0)
10273                                         goto endword;   /* exit outer loop */
10274                                 if (c != PEOA) {
10275                                         USTPUTC(c, out);
10276                                 }
10277                         }
10278                         c = pgetc_macro();
10279                 }
10280         }
10281 endword:
10282         if (syntax == ARISYNTAX)
10283                 synerror("Missing '))'");
10284         if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10285                 synerror("Unterminated quoted string");
10286         if (varnest != 0) {
10287                 startlinno = plinno;
10288                 synerror("Missing '}'");
10289         }
10290         USTPUTC('\0', out);
10291         len = out - stackblock();
10292         out = stackblock();
10293         if (eofmark == NULL) {
10294                 if ((c == '>' || c == '<')
10295                  && quotef == 0
10296                  && len <= 2
10297                  && (*out == '\0' || is_digit(*out))) {
10298                         PARSEREDIR();
10299                         return lasttoken = TREDIR;
10300                 } else {
10301                         pungetc();
10302                 }
10303         }
10304         quoteflag = quotef;
10305         backquotelist = bqlist;
10306         grabstackblock(len);
10307         wordtext = out;
10308         return lasttoken = TWORD;
10309 /* end of readtoken routine */
10310
10311
10312
10313 /*
10314  * Check to see whether we are at the end of the here document.  When this
10315  * is called, c is set to the first character of the next input line.  If
10316  * we are at the end of the here document, this routine sets the c to PEOF.
10317  */
10318
10319 checkend: {
10320         if (eofmark) {
10321                 if (c == PEOA) {
10322                         c = pgetc2();
10323                 }
10324                 if (striptabs) {
10325                         while (c == '\t') {
10326                                 c = pgetc2();
10327                         }
10328                 }
10329                 if (c == *eofmark) {
10330                         if (pfgets(line, sizeof line) != NULL) {
10331                                 char *p, *q;
10332
10333                                 p = line;
10334                                 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10335                                 if (*p == '\n' && *q == '\0') {
10336                                         c = PEOF;
10337                                         plinno++;
10338                                         needprompt = doprompt;
10339                                 } else {
10340                                         pushstring(line, strlen(line), NULL);
10341                                 }
10342                         }
10343                 }
10344         }
10345         goto checkend_return;
10346 }
10347
10348
10349 /*
10350  * Parse a redirection operator.  The variable "out" points to a string
10351  * specifying the fd to be redirected.  The variable "c" contains the
10352  * first character of the redirection operator.
10353  */
10354
10355 parseredir: {
10356         char fd = *out;
10357         union node *np;
10358
10359         np = (union node *)stalloc(sizeof (struct nfile));
10360         if (c == '>') {
10361                 np->nfile.fd = 1;
10362                 c = pgetc();
10363                 if (c == '>')
10364                         np->type = NAPPEND;
10365                 else if (c == '&')
10366                         np->type = NTOFD;
10367                 else if (c == '|')
10368                         np->type = NTOOV;
10369                 else {
10370                         np->type = NTO;
10371                         pungetc();
10372                 }
10373         } else {        /* c == '<' */
10374                 np->nfile.fd = 0;
10375                 switch (c = pgetc()) {
10376                 case '<':
10377                         if (sizeof (struct nfile) != sizeof (struct nhere)) {
10378                                 np = (union node *)stalloc(sizeof (struct nhere));
10379                                 np->nfile.fd = 0;
10380                         }
10381                         np->type = NHERE;
10382                         heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10383                         heredoc->here = np;
10384                         if ((c = pgetc()) == '-') {
10385                                 heredoc->striptabs = 1;
10386                         } else {
10387                                 heredoc->striptabs = 0;
10388                                 pungetc();
10389                         }
10390                         break;
10391
10392                 case '&':
10393                         np->type = NFROMFD;
10394                         break;
10395
10396                 case '>':
10397                         np->type = NFROMTO;
10398                         break;
10399
10400                 default:
10401                         np->type = NFROM;
10402                         pungetc();
10403                         break;
10404                 }
10405         }
10406         if (fd != '\0')
10407                 np->nfile.fd = digit_val(fd);
10408         redirnode = np;
10409         goto parseredir_return;
10410 }
10411
10412
10413 /*
10414  * Parse a substitution.  At this point, we have read the dollar sign
10415  * and nothing else.
10416  */
10417
10418 parsesub: {
10419         int subtype;
10420         int typeloc;
10421         int flags;
10422         char *p;
10423         static const char types[] = "}-+?=";
10424
10425         c = pgetc();
10426         if (
10427                 c <= PEOA  ||
10428                 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10429         ) {
10430                 USTPUTC('$', out);
10431                 pungetc();
10432         } else if (c == '(') {  /* $(command) or $((arith)) */
10433                 if (pgetc() == '(') {
10434                         PARSEARITH();
10435                 } else {
10436                         pungetc();
10437                         PARSEBACKQNEW();
10438                 }
10439         } else {
10440                 USTPUTC(CTLVAR, out);
10441                 typeloc = out - stackblock();
10442                 USTPUTC(VSNORMAL, out);
10443                 subtype = VSNORMAL;
10444                 if (c == '{') {
10445                         c = pgetc();
10446                         if (c == '#') {
10447                                 if ((c = pgetc()) == '}')
10448                                         c = '#';
10449                                 else
10450                                         subtype = VSLENGTH;
10451                         }
10452                         else
10453                                 subtype = 0;
10454                 }
10455                 if (c > PEOA && is_name(c)) {
10456                         do {
10457                                 STPUTC(c, out);
10458                                 c = pgetc();
10459                         } while (c > PEOA && is_in_name(c));
10460                 } else if (is_digit(c)) {
10461                         do {
10462                                 USTPUTC(c, out);
10463                                 c = pgetc();
10464                         } while (is_digit(c));
10465                 }
10466                 else if (is_special(c)) {
10467                         USTPUTC(c, out);
10468                         c = pgetc();
10469                 }
10470                 else
10471 badsub:                 synerror("Bad substitution");
10472
10473                 STPUTC('=', out);
10474                 flags = 0;
10475                 if (subtype == 0) {
10476                         switch (c) {
10477                         case ':':
10478                                 flags = VSNUL;
10479                                 c = pgetc();
10480                                 /*FALLTHROUGH*/
10481                         default:
10482                                 p = strchr(types, c);
10483                                 if (p == NULL)
10484                                         goto badsub;
10485                                 subtype = p - types + VSNORMAL;
10486                                 break;
10487                         case '%':
10488                         case '#':
10489                                 {
10490                                         int cc = c;
10491                                         subtype = c == '#' ? VSTRIMLEFT :
10492                                                              VSTRIMRIGHT;
10493                                         c = pgetc();
10494                                         if (c == cc)
10495                                                 subtype++;
10496                                         else
10497                                                 pungetc();
10498                                         break;
10499                                 }
10500                         }
10501                 } else {
10502                         pungetc();
10503                 }
10504                 if (dblquote || arinest)
10505                         flags |= VSQUOTE;
10506                 *(stackblock() + typeloc) = subtype | flags;
10507                 if (subtype != VSNORMAL) {
10508                         varnest++;
10509                         if (dblquote) {
10510                                 dqvarnest++;
10511                         }
10512                 }
10513         }
10514         goto parsesub_return;
10515 }
10516
10517
10518 /*
10519  * Called to parse command substitutions.  Newstyle is set if the command
10520  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10521  * list of commands (passed by reference), and savelen is the number of
10522  * characters on the top of the stack which must be preserved.
10523  */
10524
10525 parsebackq: {
10526         struct nodelist **nlpp;
10527         int savepbq;
10528         union node *n;
10529         char *volatile str;
10530         struct jmploc jmploc;
10531         struct jmploc *volatile savehandler;
10532         int savelen;
10533         int saveprompt;
10534 #ifdef __GNUC__
10535         (void) &saveprompt;
10536 #endif
10537
10538         savepbq = parsebackquote;
10539         if (setjmp(jmploc.loc)) {
10540                 if (str)
10541                         ckfree(str);
10542                 parsebackquote = 0;
10543                 handler = savehandler;
10544                 longjmp(handler->loc, 1);
10545         }
10546         INTOFF;
10547         str = NULL;
10548         savelen = out - stackblock();
10549         if (savelen > 0) {
10550                 str = ckmalloc(savelen);
10551                 memcpy(str, stackblock(), savelen);
10552         }
10553         savehandler = handler;
10554         handler = &jmploc;
10555         INTON;
10556         if (oldstyle) {
10557                 /* We must read until the closing backquote, giving special
10558                    treatment to some slashes, and then push the string and
10559                    reread it as input, interpreting it normally.  */
10560                 char *pout;
10561                 int pc;
10562                 int psavelen;
10563                 char *pstr;
10564
10565
10566                 STARTSTACKSTR(pout);
10567                 for (;;) {
10568                         if (needprompt) {
10569                                 setprompt(2);
10570                                 needprompt = 0;
10571                         }
10572                         switch (pc = pgetc()) {
10573                         case '`':
10574                                 goto done;
10575
10576                         case '\\':
10577                                 if ((pc = pgetc()) == '\n') {
10578                                         plinno++;
10579                                         if (doprompt)
10580                                                 setprompt(2);
10581                                         else
10582                                                 setprompt(0);
10583                                         /*
10584                                          * If eating a newline, avoid putting
10585                                          * the newline into the new character
10586                                          * stream (via the STPUTC after the
10587                                          * switch).
10588                                          */
10589                                         continue;
10590                                 }
10591                                 if (pc != '\\' && pc != '`' && pc != '$'
10592                                     && (!dblquote || pc != '"'))
10593                                         STPUTC('\\', pout);
10594                                 if (pc > PEOA) {
10595                                         break;
10596                                 }
10597                                 /* fall through */
10598
10599                         case PEOF:
10600                         case PEOA:
10601                                 startlinno = plinno;
10602                                 synerror("EOF in backquote substitution");
10603
10604                         case '\n':
10605                                 plinno++;
10606                                 needprompt = doprompt;
10607                                 break;
10608
10609                         default:
10610                                 break;
10611                         }
10612                         STPUTC(pc, pout);
10613                 }
10614 done:
10615                 STPUTC('\0', pout);
10616                 psavelen = pout - stackblock();
10617                 if (psavelen > 0) {
10618                         pstr = grabstackstr(pout);
10619                         setinputstring(pstr);
10620                 }
10621         }
10622         nlpp = &bqlist;
10623         while (*nlpp)
10624                 nlpp = &(*nlpp)->next;
10625         *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10626         (*nlpp)->next = NULL;
10627         parsebackquote = oldstyle;
10628
10629         if (oldstyle) {
10630                 saveprompt = doprompt;
10631                 doprompt = 0;
10632         }
10633
10634         n = list(0);
10635
10636         if (oldstyle)
10637                 doprompt = saveprompt;
10638         else {
10639                 if (readtoken() != TRP)
10640                         synexpect(TRP);
10641         }
10642
10643         (*nlpp)->n = n;
10644         if (oldstyle) {
10645                 /*
10646                  * Start reading from old file again, ignoring any pushed back
10647                  * tokens left from the backquote parsing
10648                  */
10649                 popfile();
10650                 tokpushback = 0;
10651         }
10652         while (stackblocksize() <= savelen)
10653                 growstackblock();
10654         STARTSTACKSTR(out);
10655         if (str) {
10656                 memcpy(out, str, savelen);
10657                 STADJUST(savelen, out);
10658                 INTOFF;
10659                 ckfree(str);
10660                 str = NULL;
10661                 INTON;
10662         }
10663         parsebackquote = savepbq;
10664         handler = savehandler;
10665         if (arinest || dblquote)
10666                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10667         else
10668                 USTPUTC(CTLBACKQ, out);
10669         if (oldstyle)
10670                 goto parsebackq_oldreturn;
10671         else
10672                 goto parsebackq_newreturn;
10673 }
10674
10675 /*
10676  * Parse an arithmetic expansion (indicate start of one and set state)
10677  */
10678 parsearith: {
10679
10680         if (++arinest == 1) {
10681                 prevsyntax = syntax;
10682                 syntax = ARISYNTAX;
10683                 USTPUTC(CTLARI, out);
10684                 if (dblquote)
10685                         USTPUTC('"',out);
10686                 else
10687                         USTPUTC(' ',out);
10688         } else {
10689                 /*
10690                  * we collapse embedded arithmetic expansion to
10691                  * parenthesis, which should be equivalent
10692                  */
10693                 USTPUTC('(', out);
10694         }
10695         goto parsearith_return;
10696 }
10697
10698 } /* end of readtoken */
10699
10700
10701
10702 #ifdef mkinit
10703 INCLUDE "parser.h"
10704 RESET {
10705         tokpushback = 0;
10706         checkkwd = 0;
10707         checkalias = 0;
10708 }
10709 #endif
10710
10711 /*
10712  * Returns true if the text contains nothing to expand (no dollar signs
10713  * or backquotes).
10714  */
10715
10716 static int
10717 noexpand(text)
10718         char *text;
10719         {
10720         char *p;
10721         char c;
10722
10723         p = text;
10724         while ((c = *p++) != '\0') {
10725                 if (c == CTLQUOTEMARK)
10726                         continue;
10727                 if (c == CTLESC)
10728                         p++;
10729                 else if (BASESYNTAX[(int)c] == CCTL)
10730                         return 0;
10731         }
10732         return 1;
10733 }
10734
10735
10736 /*
10737  * Return true if the argument is a legal variable name (a letter or
10738  * underscore followed by zero or more letters, underscores, and digits).
10739  */
10740
10741 static int
10742 goodname(char *name)
10743         {
10744         char *p;
10745
10746         p = name;
10747         if (! is_name(*p))
10748                 return 0;
10749         while (*++p) {
10750                 if (! is_in_name(*p))
10751                         return 0;
10752         }
10753         return 1;
10754 }
10755
10756
10757 /*
10758  * Called when an unexpected token is read during the parse.  The argument
10759  * is the token that is expected, or -1 if more than one type of token can
10760  * occur at this point.
10761  */
10762
10763 static void
10764 synexpect(token)
10765         int token;
10766 {
10767         char msg[64];
10768
10769         if (token >= 0) {
10770                 fmtstr(msg, 64, "%s unexpected (expecting %s)",
10771                         tokname[lasttoken], tokname[token]);
10772         } else {
10773                 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
10774         }
10775         synerror(msg);
10776         /* NOTREACHED */
10777 }
10778
10779
10780 static void
10781 synerror(msg)
10782         const char *msg;
10783         {
10784         if (commandname)
10785                 outfmt(&errout, "%s: %d: ", commandname, startlinno);
10786         outfmt(&errout, "Syntax error: %s\n", msg);
10787         error((char *)NULL);
10788         /* NOTREACHED */
10789 }
10790
10791 static void
10792 setprompt(int which)
10793 {
10794     whichprompt = which;
10795     putprompt(getprompt(NULL));
10796 }
10797
10798 /*
10799  * called by editline -- any expansions to the prompt
10800  *    should be added here.
10801  */
10802 static const char *
10803 getprompt(void *unused)
10804         {
10805         switch (whichprompt) {
10806         case 0:
10807                 return "";
10808         case 1:
10809                 return ps1val();
10810         case 2:
10811                 return ps2val();
10812         default:
10813                 return "<internal prompt error>";
10814         }
10815 }
10816
10817 static int
10818 isassignment(const char *word) {
10819         if (!is_name(*word)) {
10820                 return 0;
10821         }
10822         do {
10823                 word++;
10824         } while (is_in_name(*word));
10825         return *word == '=';
10826 }
10827
10828 static const char *const *
10829 findkwd(const char *s) {
10830         return findstring(
10831                 s, parsekwd, sizeof(parsekwd) / sizeof(const char *)
10832         );
10833 }
10834 /*      $NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric Exp $ */
10835
10836 /*
10837  * Code for dealing with input/output redirection.
10838  */
10839
10840 #define EMPTY -2                /* marks an unused slot in redirtab */
10841 #ifndef PIPE_BUF
10842 # define PIPESIZE 4096          /* amount of buffering in a pipe */
10843 #else
10844 # define PIPESIZE PIPE_BUF
10845 #endif
10846
10847
10848 struct redirtab *redirlist;
10849
10850 /*
10851  * We keep track of whether or not fd0 has been redirected.  This is for
10852  * background commands, where we want to redirect fd0 to /dev/null only
10853  * if it hasn't already been redirected.
10854 */
10855 static int fd0_redirected = 0;
10856
10857 /*
10858  * We also keep track of where fileno2 goes.
10859  */
10860 static int fileno2 = 2;
10861
10862 static int openredirect __P((union node *));
10863 static void dupredirect __P((union node *, int, char[10 ]));
10864 static int openhere __P((union node *));
10865 static int noclobberopen __P((const char *));
10866
10867
10868 /*
10869  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
10870  * old file descriptors are stashed away so that the redirection can be
10871  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
10872  * standard output, and the standard error if it becomes a duplicate of
10873  * stdout, is saved in memory.
10874  */
10875
10876 static void
10877 redirect(redir, flags)
10878         union node *redir;
10879         int flags;
10880         {
10881         union node *n;
10882         struct redirtab *sv = NULL;
10883         int i;
10884         int fd;
10885         int newfd;
10886         int try;
10887         char memory[10];        /* file descriptors to write to memory */
10888
10889         for (i = 10 ; --i >= 0 ; )
10890                 memory[i] = 0;
10891         memory[1] = flags & REDIR_BACKQ;
10892         if (flags & REDIR_PUSH) {
10893                 sv = ckmalloc(sizeof (struct redirtab));
10894                 for (i = 0 ; i < 10 ; i++)
10895                         sv->renamed[i] = EMPTY;
10896                 sv->next = redirlist;
10897                 redirlist = sv;
10898         }
10899         for (n = redir ; n ; n = n->nfile.next) {
10900                 fd = n->nfile.fd;
10901                 try = 0;
10902                 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
10903                     n->ndup.dupfd == fd)
10904                         continue; /* redirect from/to same file descriptor */
10905
10906                 INTOFF;
10907                 newfd = openredirect(n);
10908                 if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
10909                     (fd == fileno2)) {
10910                         if (newfd == fd) {
10911                                 try++;
10912                         } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
10913                                 switch (errno) {
10914                                 case EBADF:
10915                                         if (!try) {
10916                                                 dupredirect(n, newfd, memory);
10917                                                 try++;
10918                                                 break;
10919                                         }
10920                                         /* FALLTHROUGH*/
10921                                 default:
10922                                         if (newfd >= 0) {
10923                                                 close(newfd);
10924                                         }
10925                                         INTON;
10926                                         error("%d: %s", fd, strerror(errno));
10927                                         /* NOTREACHED */
10928                                 }
10929                         }
10930                         if (!try) {
10931                                 close(fd);
10932                                 if (flags & REDIR_PUSH) {
10933                                         sv->renamed[fd] = i;
10934                                 }
10935                                 if (fd == fileno2) {
10936                                         fileno2 = i;
10937                                 }
10938                         }
10939                 } else if (fd != newfd) {
10940                         close(fd);
10941                 }
10942                 if (fd == 0)
10943                         fd0_redirected++;
10944                 if (!try)
10945                         dupredirect(n, newfd, memory);
10946                 INTON;
10947         }
10948         if (memory[1])
10949                 out1 = &memout;
10950         if (memory[2])
10951                 out2 = &memout;
10952 }
10953
10954
10955 static int
10956 openredirect(redir)
10957         union node *redir;
10958         {
10959         char *fname;
10960         int f;
10961
10962         switch (redir->nfile.type) {
10963         case NFROM:
10964                 fname = redir->nfile.expfname;
10965                 if ((f = open(fname, O_RDONLY)) < 0)
10966                         goto eopen;
10967                 break;
10968         case NFROMTO:
10969                 fname = redir->nfile.expfname;
10970                 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10971                         goto ecreate;
10972                 break;
10973         case NTO:
10974                 /* Take care of noclobber mode. */
10975                 if (Cflag) {
10976                         fname = redir->nfile.expfname;
10977                         if ((f = noclobberopen(fname)) < 0)
10978                                 goto ecreate;
10979                         break;
10980                 }
10981         case NTOOV:
10982                 fname = redir->nfile.expfname;
10983 #ifdef O_CREAT
10984                 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10985                         goto ecreate;
10986 #else
10987                 if ((f = creat(fname, 0666)) < 0)
10988                         goto ecreate;
10989 #endif
10990                 break;
10991         case NAPPEND:
10992                 fname = redir->nfile.expfname;
10993 #ifdef O_APPEND
10994                 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10995                         goto ecreate;
10996 #else
10997                 if ((f = open(fname, O_WRONLY)) < 0
10998                  && (f = creat(fname, 0666)) < 0)
10999                         goto ecreate;
11000                 lseek(f, (off_t)0, 2);
11001 #endif
11002                 break;
11003         default:
11004 #ifdef DEBUG
11005                 abort();
11006 #endif
11007                 /* Fall through to eliminate warning. */
11008         case NTOFD:
11009         case NFROMFD:
11010                 f = -1;
11011                 break;
11012         case NHERE:
11013         case NXHERE:
11014                 f = openhere(redir);
11015                 break;
11016         }
11017
11018         return f;
11019 ecreate:
11020         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11021 eopen:
11022         error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11023 }
11024
11025
11026 static void
11027 dupredirect(redir, f, memory)
11028         union node *redir;
11029         int f;
11030         char memory[10];
11031         {
11032         int fd = redir->nfile.fd;
11033
11034         memory[fd] = 0;
11035         if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11036                 if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
11037                         if (memory[redir->ndup.dupfd])
11038                                 memory[fd] = 1;
11039                         else
11040                                 dup_as_newfd(redir->ndup.dupfd, fd);
11041                 }
11042                 return;
11043         }
11044
11045         if (f != fd) {
11046                 dup_as_newfd(f, fd);
11047                 close(f);
11048         }
11049         return;
11050 }
11051
11052
11053 /*
11054  * Handle here documents.  Normally we fork off a process to write the
11055  * data to a pipe.  If the document is short, we can stuff the data in
11056  * the pipe without forking.
11057  */
11058
11059 static int
11060 openhere(redir)
11061         union node *redir;
11062         {
11063         int pip[2];
11064         int len = 0;
11065
11066         if (pipe(pip) < 0)
11067                 error("Pipe call failed");
11068         if (redir->type == NHERE) {
11069                 len = strlen(redir->nhere.doc->narg.text);
11070                 if (len <= PIPESIZE) {
11071                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
11072                         goto out;
11073                 }
11074         }
11075         if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11076                 close(pip[0]);
11077                 signal(SIGINT, SIG_IGN);
11078                 signal(SIGQUIT, SIG_IGN);
11079                 signal(SIGHUP, SIG_IGN);
11080 #ifdef SIGTSTP
11081                 signal(SIGTSTP, SIG_IGN);
11082 #endif
11083                 signal(SIGPIPE, SIG_DFL);
11084                 if (redir->type == NHERE)
11085                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
11086                 else
11087                         expandhere(redir->nhere.doc, pip[1]);
11088                 _exit(0);
11089         }
11090 out:
11091         close(pip[1]);
11092         return pip[0];
11093 }
11094
11095
11096
11097 /*
11098  * Undo the effects of the last redirection.
11099  */
11100
11101 static void
11102 popredir() {
11103         struct redirtab *rp = redirlist;
11104         int i;
11105
11106         INTOFF;
11107         for (i = 0 ; i < 10 ; i++) {
11108                 if (rp->renamed[i] != EMPTY) {
11109                         if (i == 0)
11110                                 fd0_redirected--;
11111                         close(i);
11112                         if (rp->renamed[i] >= 0) {
11113                                 dup_as_newfd(rp->renamed[i], i);
11114                                 close(rp->renamed[i]);
11115                         }
11116                         if (rp->renamed[i] == fileno2) {
11117                                 fileno2 = i;
11118                         }
11119                 }
11120         }
11121         redirlist = rp->next;
11122         ckfree(rp);
11123         INTON;
11124 }
11125
11126 /*
11127  * Undo all redirections.  Called on error or interrupt.
11128  */
11129
11130 #ifdef mkinit
11131
11132 INCLUDE "redir.h"
11133
11134 RESET {
11135         while (redirlist)
11136                 popredir();
11137 }
11138
11139 SHELLPROC {
11140         clearredir();
11141 }
11142
11143 #endif
11144
11145 /* Return true if fd 0 has already been redirected at least once.  */
11146 static int
11147 fd0_redirected_p () {
11148         return fd0_redirected != 0;
11149 }
11150
11151 /*
11152  * Discard all saved file descriptors.
11153  */
11154
11155 static void
11156 clearredir() {
11157         struct redirtab *rp;
11158         int i;
11159
11160         for (rp = redirlist ; rp ; rp = rp->next) {
11161                 for (i = 0 ; i < 10 ; i++) {
11162                         if (rp->renamed[i] >= 0) {
11163                                 close(rp->renamed[i]);
11164                                 if (rp->renamed[i] == fileno2) {
11165                                         fileno2 = -1;
11166                                 }
11167                         }
11168                         rp->renamed[i] = EMPTY;
11169                 }
11170         }
11171         if (fileno2 != 2 && fileno2 >= 0) {
11172                 close(fileno2);
11173                 fileno2 = -1;
11174         }
11175 }
11176
11177
11178
11179 /*
11180  * Copy a file descriptor to be >= to.  Returns -1
11181  * if the source file descriptor is closed, EMPTY if there are no unused
11182  * file descriptors left.
11183  */
11184
11185 static int
11186 dup_as_newfd(from, to)
11187         int from;
11188         int to;
11189 {
11190         int newfd;
11191
11192         newfd = fcntl(from, F_DUPFD, to);
11193         if (newfd < 0) {
11194                 if (errno == EMFILE)
11195                         return EMPTY;
11196                 else
11197                         error("%d: %s", from, strerror(errno));
11198         }
11199         return newfd;
11200 }
11201
11202 /*
11203  * Open a file in noclobber mode.
11204  * The code was copied from bash.
11205  */
11206 static int
11207 noclobberopen(fname)
11208         const char *fname;
11209 {
11210         int r, fd;
11211         struct stat finfo, finfo2;
11212
11213         /*
11214          * If the file exists and is a regular file, return an error
11215          * immediately.
11216          */
11217         r = stat(fname, &finfo);
11218         if (r == 0 && S_ISREG(finfo.st_mode)) {
11219                 errno = EEXIST;
11220                 return -1;
11221         }
11222
11223         /*
11224          * If the file was not present (r != 0), make sure we open it
11225          * exclusively so that if it is created before we open it, our open
11226          * will fail.  Make sure that we do not truncate an existing file.
11227          * Note that we don't turn on O_EXCL unless the stat failed -- if the
11228          * file was not a regular file, we leave O_EXCL off.
11229          */
11230         if (r != 0)
11231                 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11232         fd = open(fname, O_WRONLY|O_CREAT, 0666);
11233
11234         /* If the open failed, return the file descriptor right away. */
11235         if (fd < 0)
11236                 return fd;
11237
11238         /*
11239          * OK, the open succeeded, but the file may have been changed from a
11240          * non-regular file to a regular file between the stat and the open.
11241          * We are assuming that the O_EXCL open handles the case where FILENAME
11242          * did not exist and is symlinked to an existing file between the stat
11243          * and open.
11244          */
11245
11246         /*
11247          * If we can open it and fstat the file descriptor, and neither check
11248          * revealed that it was a regular file, and the file has not been
11249          * replaced, return the file descriptor.
11250          */
11251          if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11252              finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11253                 return fd;
11254
11255         /* The file has been replaced.  badness. */
11256         close(fd);
11257         errno = EEXIST;
11258         return -1;
11259 }
11260 /*      $NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $       */
11261
11262 #ifdef __weak_alias
11263 __weak_alias(getmode,_getmode)
11264 __weak_alias(setmode,_setmode)
11265 #endif
11266
11267 #ifdef __GLIBC__
11268 #define S_ISTXT __S_ISVTX
11269 #endif
11270
11271 #define SET_LEN 6               /* initial # of bitcmd struct to malloc */
11272 #define SET_LEN_INCR 4          /* # of bitcmd structs to add as needed */
11273
11274 typedef struct bitcmd {
11275         char    cmd;
11276         char    cmd2;
11277         mode_t  bits;
11278 } BITCMD;
11279
11280 #define CMD2_CLR        0x01
11281 #define CMD2_SET        0x02
11282 #define CMD2_GBITS      0x04
11283 #define CMD2_OBITS      0x08
11284 #define CMD2_UBITS      0x10
11285
11286 static BITCMD   *addcmd __P((BITCMD *, int, int, int, u_int));
11287 static void      compress_mode __P((BITCMD *));
11288 #ifdef SETMODE_DEBUG
11289 static void      dumpmode __P((BITCMD *));
11290 #endif
11291
11292 /*
11293  * Given the old mode and an array of bitcmd structures, apply the operations
11294  * described in the bitcmd structures to the old mode, and return the new mode.
11295  * Note that there is no '=' command; a strict assignment is just a '-' (clear
11296  * bits) followed by a '+' (set bits).
11297  */
11298 mode_t
11299 getmode(bbox, omode)
11300         const void *bbox;
11301         mode_t omode;
11302 {
11303         const BITCMD *set;
11304         mode_t clrval, newmode, value;
11305
11306         _DIAGASSERT(bbox != NULL);
11307
11308         set = (const BITCMD *)bbox;
11309         newmode = omode;
11310         for (value = 0;; set++)
11311                 switch(set->cmd) {
11312                 /*
11313                  * When copying the user, group or other bits around, we "know"
11314                  * where the bits are in the mode so that we can do shifts to
11315                  * copy them around.  If we don't use shifts, it gets real
11316                  * grundgy with lots of single bit checks and bit sets.
11317                  */
11318                 case 'u':
11319                         value = (newmode & S_IRWXU) >> 6;
11320                         goto common;
11321
11322                 case 'g':
11323                         value = (newmode & S_IRWXG) >> 3;
11324                         goto common;
11325
11326                 case 'o':
11327                         value = newmode & S_IRWXO;
11328 common:                 if (set->cmd2 & CMD2_CLR) {
11329                                 clrval =
11330                                     (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
11331                                 if (set->cmd2 & CMD2_UBITS)
11332                                         newmode &= ~((clrval<<6) & set->bits);
11333                                 if (set->cmd2 & CMD2_GBITS)
11334                                         newmode &= ~((clrval<<3) & set->bits);
11335                                 if (set->cmd2 & CMD2_OBITS)
11336                                         newmode &= ~(clrval & set->bits);
11337                         }
11338                         if (set->cmd2 & CMD2_SET) {
11339                                 if (set->cmd2 & CMD2_UBITS)
11340                                         newmode |= (value<<6) & set->bits;
11341                                 if (set->cmd2 & CMD2_GBITS)
11342                                         newmode |= (value<<3) & set->bits;
11343                                 if (set->cmd2 & CMD2_OBITS)
11344                                         newmode |= value & set->bits;
11345                         }
11346                         break;
11347
11348                 case '+':
11349                         newmode |= set->bits;
11350                         break;
11351
11352                 case '-':
11353                         newmode &= ~set->bits;
11354                         break;
11355
11356                 case 'X':
11357                         if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11358                                 newmode |= set->bits;
11359                         break;
11360
11361                 case '\0':
11362                 default:
11363 #ifdef SETMODE_DEBUG
11364                         (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11365 #endif
11366                         return (newmode);
11367                 }
11368 }
11369
11370 #define ADDCMD(a, b, c, d) do {                                         \
11371         if (set >= endset) {                                            \
11372                 BITCMD *newset;                                         \
11373                 setlen += SET_LEN_INCR;                                 \
11374                 newset = realloc(saveset, sizeof(BITCMD) * setlen);     \
11375                 if (newset == NULL) {                                   \
11376                         free(saveset);                                  \
11377                         return (NULL);                                  \
11378                 }                                                       \
11379                 set = newset + (set - saveset);                         \
11380                 saveset = newset;                                       \
11381                 endset = newset + (setlen - 2);                         \
11382         }                                                               \
11383         set = addcmd(set, (a), (b), (c), (d));                          \
11384 } while (/*CONSTCOND*/0)
11385
11386 #define STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
11387
11388 static void *
11389 setmode(p)
11390         const char *p;
11391 {
11392         int perm, who;
11393         char op, *ep;
11394         BITCMD *set, *saveset, *endset;
11395         sigset_t mysigset, sigoset;
11396         mode_t mask;
11397         int equalopdone = 0;    /* pacify gcc */
11398         int permXbits, setlen;
11399
11400         if (!*p)
11401                 return (NULL);
11402
11403         /*
11404          * Get a copy of the mask for the permissions that are mask relative.
11405          * Flip the bits, we want what's not set.  Since it's possible that
11406          * the caller is opening files inside a signal handler, protect them
11407          * as best we can.
11408          */
11409         sigfillset(&mysigset);
11410         (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11411         (void)umask(mask = umask(0));
11412         mask = ~mask;
11413         (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11414
11415         setlen = SET_LEN + 2;
11416         
11417         if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11418                 return (NULL);
11419         saveset = set;
11420         endset = set + (setlen - 2);
11421
11422         /*
11423          * If an absolute number, get it and return; disallow non-octal digits
11424          * or illegal bits.
11425          */
11426         if (isdigit((unsigned char)*p)) {
11427                 perm = (mode_t)strtol(p, &ep, 8);
11428                 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11429                         free(saveset);
11430                         return (NULL);
11431                 }
11432                 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11433                 set->cmd = 0;
11434                 return (saveset);
11435         }
11436
11437         /*
11438          * Build list of structures to set/clear/copy bits as described by
11439          * each clause of the symbolic mode.
11440          */
11441         for (;;) {
11442                 /* First, find out which bits might be modified. */
11443                 for (who = 0;; ++p) {
11444                         switch (*p) {
11445                         case 'a':
11446                                 who |= STANDARD_BITS;
11447                                 break;
11448                         case 'u':
11449                                 who |= S_ISUID|S_IRWXU;
11450                                 break;
11451                         case 'g':
11452                                 who |= S_ISGID|S_IRWXG;
11453                                 break;
11454                         case 'o':
11455                                 who |= S_IRWXO;
11456                                 break;
11457                         default:
11458                                 goto getop;
11459                         }
11460                 }
11461
11462 getop:          if ((op = *p++) != '+' && op != '-' && op != '=') {
11463                         free(saveset);
11464                         return (NULL);
11465                 }
11466                 if (op == '=')
11467                         equalopdone = 0;
11468
11469                 who &= ~S_ISTXT;
11470                 for (perm = 0, permXbits = 0;; ++p) {
11471                         switch (*p) {
11472                         case 'r':
11473                                 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11474                                 break;
11475                         case 's':
11476                                 /*
11477                                  * If specific bits where requested and 
11478                                  * only "other" bits ignore set-id. 
11479                                  */
11480                                 if (who == 0 || (who & ~S_IRWXO))
11481                                         perm |= S_ISUID|S_ISGID;
11482                                 break;
11483                         case 't':
11484                                 /*
11485                                  * If specific bits where requested and 
11486                                  * only "other" bits ignore set-id. 
11487                                  */
11488                                 if (who == 0 || (who & ~S_IRWXO)) {
11489                                         who |= S_ISTXT;
11490                                         perm |= S_ISTXT;
11491                                 }
11492                                 break;
11493                         case 'w':
11494                                 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11495                                 break;
11496                         case 'X':
11497                                 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11498                                 break;
11499                         case 'x':
11500                                 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11501                                 break;
11502                         case 'u':
11503                         case 'g':
11504                         case 'o':
11505                                 /*
11506                                  * When ever we hit 'u', 'g', or 'o', we have
11507                                  * to flush out any partial mode that we have,
11508                                  * and then do the copying of the mode bits.
11509                                  */
11510                                 if (perm) {
11511                                         ADDCMD(op, who, perm, mask);
11512                                         perm = 0;
11513                                 }
11514                                 if (op == '=')
11515                                         equalopdone = 1;
11516                                 if (op == '+' && permXbits) {
11517                                         ADDCMD('X', who, permXbits, mask);
11518                                         permXbits = 0;
11519                                 }
11520                                 ADDCMD(*p, who, op, mask);
11521                                 break;
11522
11523                         default:
11524                                 /*
11525                                  * Add any permissions that we haven't already
11526                                  * done.
11527                                  */
11528                                 if (perm || (op == '=' && !equalopdone)) {
11529                                         if (op == '=')
11530                                                 equalopdone = 1;
11531                                         ADDCMD(op, who, perm, mask);
11532                                         perm = 0;
11533                                 }
11534                                 if (permXbits) {
11535                                         ADDCMD('X', who, permXbits, mask);
11536                                         permXbits = 0;
11537                                 }
11538                                 goto apply;
11539                         }
11540                 }
11541
11542 apply:          if (!*p)
11543                         break;
11544                 if (*p != ',')
11545                         goto getop;
11546                 ++p;
11547         }
11548         set->cmd = 0;
11549 #ifdef SETMODE_DEBUG
11550         (void)printf("Before compress_mode()\n");
11551         dumpmode(saveset);
11552 #endif
11553         compress_mode(saveset);
11554 #ifdef SETMODE_DEBUG
11555         (void)printf("After compress_mode()\n");
11556         dumpmode(saveset);
11557 #endif
11558         return (saveset);
11559 }
11560
11561 static BITCMD *
11562 addcmd(set, op, who, oparg, mask)
11563         BITCMD *set;
11564         int oparg, who;
11565         int op;
11566         u_int mask;
11567 {
11568
11569         _DIAGASSERT(set != NULL);
11570
11571         switch (op) {
11572         case '=':
11573                 set->cmd = '-';
11574                 set->bits = who ? who : STANDARD_BITS;
11575                 set++;
11576
11577                 op = '+';
11578                 /* FALLTHROUGH */
11579         case '+':
11580         case '-':
11581         case 'X':
11582                 set->cmd = op;
11583                 set->bits = (who ? who : mask) & oparg;
11584                 break;
11585
11586         case 'u':
11587         case 'g':
11588         case 'o':
11589                 set->cmd = op;
11590                 if (who) {
11591                         set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11592                                     ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11593                                     ((who & S_IROTH) ? CMD2_OBITS : 0);
11594                         set->bits = (mode_t)~0;
11595                 } else {
11596                         set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11597                         set->bits = mask;
11598                 }
11599         
11600                 if (oparg == '+')
11601                         set->cmd2 |= CMD2_SET;
11602                 else if (oparg == '-')
11603                         set->cmd2 |= CMD2_CLR;
11604                 else if (oparg == '=')
11605                         set->cmd2 |= CMD2_SET|CMD2_CLR;
11606                 break;
11607         }
11608         return (set + 1);
11609 }
11610
11611 #ifdef SETMODE_DEBUG
11612 static void
11613 dumpmode(set)
11614         BITCMD *set;
11615 {
11616
11617         _DIAGASSERT(set != NULL);
11618
11619         for (; set->cmd; ++set)
11620                 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11621                     set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11622                     set->cmd2 & CMD2_CLR ? " CLR" : "",
11623                     set->cmd2 & CMD2_SET ? " SET" : "",
11624                     set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11625                     set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11626                     set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11627 }
11628 #endif
11629
11630 /*
11631  * Given an array of bitcmd structures, compress by compacting consecutive
11632  * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
11633  * 'g' and 'o' commands continue to be separate.  They could probably be 
11634  * compacted, but it's not worth the effort.
11635  */
11636 static void
11637 compress_mode(set)
11638         BITCMD *set;
11639 {
11640         BITCMD *nset;
11641         int setbits, clrbits, Xbits, op;
11642
11643         _DIAGASSERT(set != NULL);
11644
11645         for (nset = set;;) {
11646                 /* Copy over any 'u', 'g' and 'o' commands. */
11647                 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11648                         *set++ = *nset++;
11649                         if (!op)
11650                                 return;
11651                 }
11652
11653                 for (setbits = clrbits = Xbits = 0;; nset++) {
11654                         if ((op = nset->cmd) == '-') {
11655                                 clrbits |= nset->bits;
11656                                 setbits &= ~nset->bits;
11657                                 Xbits &= ~nset->bits;
11658                         } else if (op == '+') {
11659                                 setbits |= nset->bits;
11660                                 clrbits &= ~nset->bits;
11661                                 Xbits &= ~nset->bits;
11662                         } else if (op == 'X')
11663                                 Xbits |= nset->bits & ~setbits;
11664                         else
11665                                 break;
11666                 }
11667                 if (clrbits) {
11668                         set->cmd = '-';
11669                         set->cmd2 = 0;
11670                         set->bits = clrbits;
11671                         set++;
11672                 }
11673                 if (setbits) {
11674                         set->cmd = '+';
11675                         set->cmd2 = 0;
11676                         set->bits = setbits;
11677                         set++;
11678                 }
11679                 if (Xbits) {
11680                         set->cmd = 'X';
11681                         set->cmd2 = 0;
11682                         set->bits = Xbits;
11683                         set++;
11684                 }
11685         }
11686 }
11687 /*      $NetBSD: show.c,v 1.18 1999/10/08 21:10:44 pk Exp $     */
11688
11689
11690 #ifdef DEBUG
11691 static void shtree __P((union node *, int, char *, FILE*));
11692 static void shcmd __P((union node *, FILE *));
11693 static void sharg __P((union node *, FILE *));
11694 static void indent __P((int, char *, FILE *));
11695 static void trstring __P((char *));
11696
11697
11698 static void
11699 showtree(n)
11700         union node *n;
11701 {
11702         trputs("showtree called\n");
11703         shtree(n, 1, NULL, stdout);
11704 }
11705
11706
11707 static void
11708 shtree(n, ind, pfx, fp)
11709         union node *n;
11710         int ind;
11711         char *pfx;
11712         FILE *fp;
11713 {
11714         struct nodelist *lp;
11715         const char *s;
11716
11717         if (n == NULL)
11718                 return;
11719
11720         indent(ind, pfx, fp);
11721         switch(n->type) {
11722         case NSEMI:
11723                 s = "; ";
11724                 goto binop;
11725         case NAND:
11726                 s = " && ";
11727                 goto binop;
11728         case NOR:
11729                 s = " || ";
11730 binop:
11731                 shtree(n->nbinary.ch1, ind, NULL, fp);
11732            /*    if (ind < 0) */
11733                         fputs(s, fp);
11734                 shtree(n->nbinary.ch2, ind, NULL, fp);
11735                 break;
11736         case NCMD:
11737                 shcmd(n, fp);
11738                 if (ind >= 0)
11739                         putc('\n', fp);
11740                 break;
11741         case NPIPE:
11742                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11743                         shcmd(lp->n, fp);
11744                         if (lp->next)
11745                                 fputs(" | ", fp);
11746                 }
11747                 if (n->npipe.backgnd)
11748                         fputs(" &", fp);
11749                 if (ind >= 0)
11750                         putc('\n', fp);
11751                 break;
11752         default:
11753                 fprintf(fp, "<node type %d>", n->type);
11754                 if (ind >= 0)
11755                         putc('\n', fp);
11756                 break;
11757         }
11758 }
11759
11760
11761
11762 static void
11763 shcmd(cmd, fp)
11764         union node *cmd;
11765         FILE *fp;
11766 {
11767         union node *np;
11768         int first;
11769         const char *s;
11770         int dftfd;
11771
11772         first = 1;
11773         for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11774                 if (! first)
11775                         putchar(' ');
11776                 sharg(np, fp);
11777                 first = 0;
11778         }
11779         for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11780                 if (! first)
11781                         putchar(' ');
11782                 switch (np->nfile.type) {
11783                         case NTO:       s = ">";  dftfd = 1; break;
11784                         case NAPPEND:   s = ">>"; dftfd = 1; break;
11785                         case NTOFD:     s = ">&"; dftfd = 1; break;
11786                         case NTOOV:     s = ">|"; dftfd = 1; break;
11787                         case NFROM:     s = "<";  dftfd = 0; break;
11788                         case NFROMFD:   s = "<&"; dftfd = 0; break;
11789                         case NFROMTO:   s = "<>"; dftfd = 0; break;
11790                         default:        s = "*error*"; dftfd = 0; break;
11791                 }
11792                 if (np->nfile.fd != dftfd)
11793                         fprintf(fp, "%d", np->nfile.fd);
11794                 fputs(s, fp);
11795                 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11796                         fprintf(fp, "%d", np->ndup.dupfd);
11797                 } else {
11798                         sharg(np->nfile.fname, fp);
11799                 }
11800                 first = 0;
11801         }
11802 }
11803
11804
11805
11806 static void
11807 sharg(arg, fp)
11808         union node *arg;
11809         FILE *fp;
11810         {
11811         char *p;
11812         struct nodelist *bqlist;
11813         int subtype;
11814
11815         if (arg->type != NARG) {
11816                 printf("<node type %d>\n", arg->type);
11817                 fflush(stdout);
11818                 abort();
11819         }
11820         bqlist = arg->narg.backquote;
11821         for (p = arg->narg.text ; *p ; p++) {
11822                 switch (*p) {
11823                 case CTLESC:
11824                         putc(*++p, fp);
11825                         break;
11826                 case CTLVAR:
11827                         putc('$', fp);
11828                         putc('{', fp);
11829                         subtype = *++p;
11830                         if (subtype == VSLENGTH)
11831                                 putc('#', fp);
11832
11833                         while (*p != '=')
11834                                 putc(*p++, fp);
11835
11836                         if (subtype & VSNUL)
11837                                 putc(':', fp);
11838
11839                         switch (subtype & VSTYPE) {
11840                         case VSNORMAL:
11841                                 putc('}', fp);
11842                                 break;
11843                         case VSMINUS:
11844                                 putc('-', fp);
11845                                 break;
11846                         case VSPLUS:
11847                                 putc('+', fp);
11848                                 break;
11849                         case VSQUESTION:
11850                                 putc('?', fp);
11851                                 break;
11852                         case VSASSIGN:
11853                                 putc('=', fp);
11854                                 break;
11855                         case VSTRIMLEFT:
11856                                 putc('#', fp);
11857                                 break;
11858                         case VSTRIMLEFTMAX:
11859                                 putc('#', fp);
11860                                 putc('#', fp);
11861                                 break;
11862                         case VSTRIMRIGHT:
11863                                 putc('%', fp);
11864                                 break;
11865                         case VSTRIMRIGHTMAX:
11866                                 putc('%', fp);
11867                                 putc('%', fp);
11868                                 break;
11869                         case VSLENGTH:
11870                                 break;
11871                         default:
11872                                 printf("<subtype %d>", subtype);
11873                         }
11874                         break;
11875                 case CTLENDVAR:
11876                      putc('}', fp);
11877                      break;
11878                 case CTLBACKQ:
11879                 case CTLBACKQ|CTLQUOTE:
11880                         putc('$', fp);
11881                         putc('(', fp);
11882                         shtree(bqlist->n, -1, NULL, fp);
11883                         putc(')', fp);
11884                         break;
11885                 default:
11886                         putc(*p, fp);
11887                         break;
11888                 }
11889         }
11890 }
11891
11892
11893 static void
11894 indent(amount, pfx, fp)
11895         int amount;
11896         char *pfx;
11897         FILE *fp;
11898 {
11899         int i;
11900
11901         for (i = 0 ; i < amount ; i++) {
11902                 if (pfx && i == amount - 1)
11903                         fputs(pfx, fp);
11904                 putc('\t', fp);
11905         }
11906 }
11907 #endif
11908
11909
11910
11911 /*
11912  * Debugging stuff.
11913  */
11914
11915
11916 #ifdef DEBUG
11917 FILE *tracefile;
11918
11919 #if DEBUG == 2
11920 static int debug = 1;
11921 #else
11922 static int debug = 0;
11923 #endif
11924
11925
11926 static void
11927 trputc(c)
11928         int c;
11929 {
11930         if (tracefile == NULL)
11931                 return;
11932         putc(c, tracefile);
11933         if (c == '\n')
11934                 fflush(tracefile);
11935 }
11936
11937 static void
11938 trace(const char *fmt, ...)
11939 {
11940         va_list va;
11941 #ifdef __STDC__
11942         va_start(va, fmt);
11943 #else
11944         char *fmt;
11945         va_start(va);
11946         fmt = va_arg(va, char *);
11947 #endif
11948         if (tracefile != NULL) {
11949                 (void) vfprintf(tracefile, fmt, va);
11950                 if (strchr(fmt, '\n'))
11951                         (void) fflush(tracefile);
11952         }
11953         va_end(va);
11954 }
11955
11956
11957 static void
11958 trputs(s)
11959         const char *s;
11960 {
11961         if (tracefile == NULL)
11962                 return;
11963         fputs(s, tracefile);
11964         if (strchr(s, '\n'))
11965                 fflush(tracefile);
11966 }
11967
11968
11969 static void
11970 trstring(s)
11971         char *s;
11972 {
11973         char *p;
11974         char c;
11975
11976         if (tracefile == NULL)
11977                 return;
11978         putc('"', tracefile);
11979         for (p = s ; *p ; p++) {
11980                 switch (*p) {
11981                 case '\n':  c = 'n';  goto backslash;
11982                 case '\t':  c = 't';  goto backslash;
11983                 case '\r':  c = 'r';  goto backslash;
11984                 case '"':  c = '"';  goto backslash;
11985                 case '\\':  c = '\\';  goto backslash;
11986                 case CTLESC:  c = 'e';  goto backslash;
11987                 case CTLVAR:  c = 'v';  goto backslash;
11988                 case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
11989                 case CTLBACKQ:  c = 'q';  goto backslash;
11990                 case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
11991 backslash:        putc('\\', tracefile);
11992                         putc(c, tracefile);
11993                         break;
11994                 default:
11995                         if (*p >= ' ' && *p <= '~')
11996                                 putc(*p, tracefile);
11997                         else {
11998                                 putc('\\', tracefile);
11999                                 putc(*p >> 6 & 03, tracefile);
12000                                 putc(*p >> 3 & 07, tracefile);
12001                                 putc(*p & 07, tracefile);
12002                         }
12003                         break;
12004                 }
12005         }
12006         putc('"', tracefile);
12007 }
12008
12009
12010 static void
12011 trargs(ap)
12012         char **ap;
12013 {
12014         if (tracefile == NULL)
12015                 return;
12016         while (*ap) {
12017                 trstring(*ap++);
12018                 if (*ap)
12019                         putc(' ', tracefile);
12020                 else
12021                         putc('\n', tracefile);
12022         }
12023         fflush(tracefile);
12024 }
12025
12026
12027 static void
12028 opentrace() {
12029         char s[100];
12030 #ifdef O_APPEND
12031         int flags;
12032 #endif
12033
12034         if (!debug)
12035                 return;
12036 #ifdef not_this_way
12037         {
12038                 char *p;
12039                 if ((p = getenv("HOME")) == NULL) {
12040                         if (geteuid() == 0)
12041                                 p = "/";
12042                         else
12043                                 p = "/tmp";
12044                 }
12045                 scopy(p, s);
12046                 strcat(s, "/trace");
12047         }
12048 #else
12049         scopy("./trace", s);
12050 #endif /* not_this_way */
12051         if ((tracefile = fopen(s, "a")) == NULL) {
12052                 fprintf(stderr, "Can't open %s\n", s);
12053                 return;
12054         }
12055 #ifdef O_APPEND
12056         if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12057                 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12058 #endif
12059         fputs("\nTracing started.\n", tracefile);
12060         fflush(tracefile);
12061 }
12062 #endif /* DEBUG */
12063
12064
12065 /*
12066  * This file was generated by the mksyntax program.
12067  */
12068
12069 /* syntax table used when not in quotes */
12070 static const char basesyntax[257] = {
12071       CEOF,    CSPCL,   CWORD,   CCTL,
12072       CCTL,    CCTL,    CCTL,    CCTL,
12073       CCTL,    CCTL,    CCTL,    CWORD,
12074       CWORD,   CWORD,   CWORD,   CWORD,
12075       CWORD,   CWORD,   CWORD,   CWORD,
12076       CWORD,   CWORD,   CWORD,   CWORD,
12077       CWORD,   CWORD,   CWORD,   CWORD,
12078       CWORD,   CWORD,   CWORD,   CWORD,
12079       CWORD,   CWORD,   CWORD,   CWORD,
12080       CWORD,   CWORD,   CWORD,   CWORD,
12081       CWORD,   CWORD,   CWORD,   CWORD,
12082       CWORD,   CWORD,   CWORD,   CWORD,
12083       CWORD,   CWORD,   CWORD,   CWORD,
12084       CWORD,   CWORD,   CWORD,   CWORD,
12085       CWORD,   CWORD,   CWORD,   CWORD,
12086       CWORD,   CWORD,   CWORD,   CWORD,
12087       CWORD,   CWORD,   CWORD,   CWORD,
12088       CWORD,   CWORD,   CWORD,   CWORD,
12089       CWORD,   CWORD,   CWORD,   CWORD,
12090       CWORD,   CWORD,   CWORD,   CWORD,
12091       CWORD,   CWORD,   CWORD,   CWORD,
12092       CWORD,   CWORD,   CWORD,   CWORD,
12093       CWORD,   CWORD,   CWORD,   CWORD,
12094       CWORD,   CWORD,   CWORD,   CWORD,
12095       CWORD,   CWORD,   CWORD,   CWORD,
12096       CWORD,   CWORD,   CWORD,   CWORD,
12097       CWORD,   CWORD,   CWORD,   CWORD,
12098       CWORD,   CWORD,   CWORD,   CWORD,
12099       CWORD,   CWORD,   CWORD,   CWORD,
12100       CWORD,   CWORD,   CWORD,   CWORD,
12101       CWORD,   CWORD,   CWORD,   CWORD,
12102       CWORD,   CWORD,   CWORD,   CWORD,
12103       CWORD,   CWORD,   CWORD,   CWORD,
12104       CWORD,   CWORD,   CWORD,   CWORD,
12105       CWORD,   CWORD,   CWORD,   CSPCL,
12106       CNL,     CWORD,   CWORD,   CWORD,
12107       CWORD,   CWORD,   CWORD,   CWORD,
12108       CWORD,   CWORD,   CWORD,   CWORD,
12109       CWORD,   CWORD,   CWORD,   CWORD,
12110       CWORD,   CWORD,   CWORD,   CWORD,
12111       CWORD,   CWORD,   CSPCL,   CWORD,
12112       CDQUOTE, CWORD,   CVAR,    CWORD,
12113       CSPCL,   CSQUOTE, CSPCL,   CSPCL,
12114       CWORD,   CWORD,   CWORD,   CWORD,
12115       CWORD,   CWORD,   CWORD,   CWORD,
12116       CWORD,   CWORD,   CWORD,   CWORD,
12117       CWORD,   CWORD,   CWORD,   CWORD,
12118       CWORD,   CSPCL,   CSPCL,   CWORD,
12119       CSPCL,   CWORD,   CWORD,   CWORD,
12120       CWORD,   CWORD,   CWORD,   CWORD,
12121       CWORD,   CWORD,   CWORD,   CWORD,
12122       CWORD,   CWORD,   CWORD,   CWORD,
12123       CWORD,   CWORD,   CWORD,   CWORD,
12124       CWORD,   CWORD,   CWORD,   CWORD,
12125       CWORD,   CWORD,   CWORD,   CWORD,
12126       CWORD,   CWORD,   CBACK,   CWORD,
12127       CWORD,   CWORD,   CBQUOTE, CWORD,
12128       CWORD,   CWORD,   CWORD,   CWORD,
12129       CWORD,   CWORD,   CWORD,   CWORD,
12130       CWORD,   CWORD,   CWORD,   CWORD,
12131       CWORD,   CWORD,   CWORD,   CWORD,
12132       CWORD,   CWORD,   CWORD,   CWORD,
12133       CWORD,   CWORD,   CWORD,   CWORD,
12134       CWORD,   CWORD,   CSPCL,   CENDVAR,
12135       CWORD
12136 };
12137
12138 /* syntax table used when in double quotes */
12139 static const char dqsyntax[257] = {
12140       CEOF,    CIGN,    CWORD,   CCTL,
12141       CCTL,    CCTL,    CCTL,    CCTL,
12142       CCTL,    CCTL,    CCTL,    CWORD,
12143       CWORD,   CWORD,   CWORD,   CWORD,
12144       CWORD,   CWORD,   CWORD,   CWORD,
12145       CWORD,   CWORD,   CWORD,   CWORD,
12146       CWORD,   CWORD,   CWORD,   CWORD,
12147       CWORD,   CWORD,   CWORD,   CWORD,
12148       CWORD,   CWORD,   CWORD,   CWORD,
12149       CWORD,   CWORD,   CWORD,   CWORD,
12150       CWORD,   CWORD,   CWORD,   CWORD,
12151       CWORD,   CWORD,   CWORD,   CWORD,
12152       CWORD,   CWORD,   CWORD,   CWORD,
12153       CWORD,   CWORD,   CWORD,   CWORD,
12154       CWORD,   CWORD,   CWORD,   CWORD,
12155       CWORD,   CWORD,   CWORD,   CWORD,
12156       CWORD,   CWORD,   CWORD,   CWORD,
12157       CWORD,   CWORD,   CWORD,   CWORD,
12158       CWORD,   CWORD,   CWORD,   CWORD,
12159       CWORD,   CWORD,   CWORD,   CWORD,
12160       CWORD,   CWORD,   CWORD,   CWORD,
12161       CWORD,   CWORD,   CWORD,   CWORD,
12162       CWORD,   CWORD,   CWORD,   CWORD,
12163       CWORD,   CWORD,   CWORD,   CWORD,
12164       CWORD,   CWORD,   CWORD,   CWORD,
12165       CWORD,   CWORD,   CWORD,   CWORD,
12166       CWORD,   CWORD,   CWORD,   CWORD,
12167       CWORD,   CWORD,   CWORD,   CWORD,
12168       CWORD,   CWORD,   CWORD,   CWORD,
12169       CWORD,   CWORD,   CWORD,   CWORD,
12170       CWORD,   CWORD,   CWORD,   CWORD,
12171       CWORD,   CWORD,   CWORD,   CWORD,
12172       CWORD,   CWORD,   CWORD,   CWORD,
12173       CWORD,   CWORD,   CWORD,   CWORD,
12174       CWORD,   CWORD,   CWORD,   CWORD,
12175       CNL,     CWORD,   CWORD,   CWORD,
12176       CWORD,   CWORD,   CWORD,   CWORD,
12177       CWORD,   CWORD,   CWORD,   CWORD,
12178       CWORD,   CWORD,   CWORD,   CWORD,
12179       CWORD,   CWORD,   CWORD,   CWORD,
12180       CWORD,   CWORD,   CWORD,   CCTL,
12181       CENDQUOTE,CWORD,  CVAR,    CWORD,
12182       CWORD,   CWORD,   CWORD,   CWORD,
12183       CCTL,    CWORD,   CWORD,   CCTL,
12184       CWORD,   CCTL,    CWORD,   CWORD,
12185       CWORD,   CWORD,   CWORD,   CWORD,
12186       CWORD,   CWORD,   CWORD,   CWORD,
12187       CCTL,    CWORD,   CWORD,   CCTL,
12188       CWORD,   CCTL,    CWORD,   CWORD,
12189       CWORD,   CWORD,   CWORD,   CWORD,
12190       CWORD,   CWORD,   CWORD,   CWORD,
12191       CWORD,   CWORD,   CWORD,   CWORD,
12192       CWORD,   CWORD,   CWORD,   CWORD,
12193       CWORD,   CWORD,   CWORD,   CWORD,
12194       CWORD,   CWORD,   CWORD,   CWORD,
12195       CWORD,   CCTL,    CBACK,   CCTL,
12196       CWORD,   CWORD,   CBQUOTE, CWORD,
12197       CWORD,   CWORD,   CWORD,   CWORD,
12198       CWORD,   CWORD,   CWORD,   CWORD,
12199       CWORD,   CWORD,   CWORD,   CWORD,
12200       CWORD,   CWORD,   CWORD,   CWORD,
12201       CWORD,   CWORD,   CWORD,   CWORD,
12202       CWORD,   CWORD,   CWORD,   CWORD,
12203       CWORD,   CWORD,   CWORD,   CENDVAR,
12204       CCTL
12205 };
12206
12207 /* syntax table used when in single quotes */
12208 static const char sqsyntax[257] = {
12209       CEOF,    CIGN,    CWORD,   CCTL,
12210       CCTL,    CCTL,    CCTL,    CCTL,
12211       CCTL,    CCTL,    CCTL,    CWORD,
12212       CWORD,   CWORD,   CWORD,   CWORD,
12213       CWORD,   CWORD,   CWORD,   CWORD,
12214       CWORD,   CWORD,   CWORD,   CWORD,
12215       CWORD,   CWORD,   CWORD,   CWORD,
12216       CWORD,   CWORD,   CWORD,   CWORD,
12217       CWORD,   CWORD,   CWORD,   CWORD,
12218       CWORD,   CWORD,   CWORD,   CWORD,
12219       CWORD,   CWORD,   CWORD,   CWORD,
12220       CWORD,   CWORD,   CWORD,   CWORD,
12221       CWORD,   CWORD,   CWORD,   CWORD,
12222       CWORD,   CWORD,   CWORD,   CWORD,
12223       CWORD,   CWORD,   CWORD,   CWORD,
12224       CWORD,   CWORD,   CWORD,   CWORD,
12225       CWORD,   CWORD,   CWORD,   CWORD,
12226       CWORD,   CWORD,   CWORD,   CWORD,
12227       CWORD,   CWORD,   CWORD,   CWORD,
12228       CWORD,   CWORD,   CWORD,   CWORD,
12229       CWORD,   CWORD,   CWORD,   CWORD,
12230       CWORD,   CWORD,   CWORD,   CWORD,
12231       CWORD,   CWORD,   CWORD,   CWORD,
12232       CWORD,   CWORD,   CWORD,   CWORD,
12233       CWORD,   CWORD,   CWORD,   CWORD,
12234       CWORD,   CWORD,   CWORD,   CWORD,
12235       CWORD,   CWORD,   CWORD,   CWORD,
12236       CWORD,   CWORD,   CWORD,   CWORD,
12237       CWORD,   CWORD,   CWORD,   CWORD,
12238       CWORD,   CWORD,   CWORD,   CWORD,
12239       CWORD,   CWORD,   CWORD,   CWORD,
12240       CWORD,   CWORD,   CWORD,   CWORD,
12241       CWORD,   CWORD,   CWORD,   CWORD,
12242       CWORD,   CWORD,   CWORD,   CWORD,
12243       CWORD,   CWORD,   CWORD,   CWORD,
12244       CNL,     CWORD,   CWORD,   CWORD,
12245       CWORD,   CWORD,   CWORD,   CWORD,
12246       CWORD,   CWORD,   CWORD,   CWORD,
12247       CWORD,   CWORD,   CWORD,   CWORD,
12248       CWORD,   CWORD,   CWORD,   CWORD,
12249       CWORD,   CWORD,   CWORD,   CCTL,
12250       CWORD,   CWORD,   CWORD,   CWORD,
12251       CWORD,   CENDQUOTE,CWORD,  CWORD,
12252       CCTL,    CWORD,   CWORD,   CCTL,
12253       CWORD,   CCTL,    CWORD,   CWORD,
12254       CWORD,   CWORD,   CWORD,   CWORD,
12255       CWORD,   CWORD,   CWORD,   CWORD,
12256       CCTL,    CWORD,   CWORD,   CCTL,
12257       CWORD,   CCTL,    CWORD,   CWORD,
12258       CWORD,   CWORD,   CWORD,   CWORD,
12259       CWORD,   CWORD,   CWORD,   CWORD,
12260       CWORD,   CWORD,   CWORD,   CWORD,
12261       CWORD,   CWORD,   CWORD,   CWORD,
12262       CWORD,   CWORD,   CWORD,   CWORD,
12263       CWORD,   CWORD,   CWORD,   CWORD,
12264       CWORD,   CCTL,    CCTL,    CCTL,
12265       CWORD,   CWORD,   CWORD,   CWORD,
12266       CWORD,   CWORD,   CWORD,   CWORD,
12267       CWORD,   CWORD,   CWORD,   CWORD,
12268       CWORD,   CWORD,   CWORD,   CWORD,
12269       CWORD,   CWORD,   CWORD,   CWORD,
12270       CWORD,   CWORD,   CWORD,   CWORD,
12271       CWORD,   CWORD,   CWORD,   CWORD,
12272       CWORD,   CWORD,   CWORD,   CWORD,
12273       CCTL
12274 };
12275
12276 /* syntax table used when in arithmetic */
12277 static const char arisyntax[257] = {
12278       CEOF,    CIGN,    CWORD,   CCTL,
12279       CCTL,    CCTL,    CCTL,    CCTL,
12280       CCTL,    CCTL,    CCTL,    CWORD,
12281       CWORD,   CWORD,   CWORD,   CWORD,
12282       CWORD,   CWORD,   CWORD,   CWORD,
12283       CWORD,   CWORD,   CWORD,   CWORD,
12284       CWORD,   CWORD,   CWORD,   CWORD,
12285       CWORD,   CWORD,   CWORD,   CWORD,
12286       CWORD,   CWORD,   CWORD,   CWORD,
12287       CWORD,   CWORD,   CWORD,   CWORD,
12288       CWORD,   CWORD,   CWORD,   CWORD,
12289       CWORD,   CWORD,   CWORD,   CWORD,
12290       CWORD,   CWORD,   CWORD,   CWORD,
12291       CWORD,   CWORD,   CWORD,   CWORD,
12292       CWORD,   CWORD,   CWORD,   CWORD,
12293       CWORD,   CWORD,   CWORD,   CWORD,
12294       CWORD,   CWORD,   CWORD,   CWORD,
12295       CWORD,   CWORD,   CWORD,   CWORD,
12296       CWORD,   CWORD,   CWORD,   CWORD,
12297       CWORD,   CWORD,   CWORD,   CWORD,
12298       CWORD,   CWORD,   CWORD,   CWORD,
12299       CWORD,   CWORD,   CWORD,   CWORD,
12300       CWORD,   CWORD,   CWORD,   CWORD,
12301       CWORD,   CWORD,   CWORD,   CWORD,
12302       CWORD,   CWORD,   CWORD,   CWORD,
12303       CWORD,   CWORD,   CWORD,   CWORD,
12304       CWORD,   CWORD,   CWORD,   CWORD,
12305       CWORD,   CWORD,   CWORD,   CWORD,
12306       CWORD,   CWORD,   CWORD,   CWORD,
12307       CWORD,   CWORD,   CWORD,   CWORD,
12308       CWORD,   CWORD,   CWORD,   CWORD,
12309       CWORD,   CWORD,   CWORD,   CWORD,
12310       CWORD,   CWORD,   CWORD,   CWORD,
12311       CWORD,   CWORD,   CWORD,   CWORD,
12312       CWORD,   CWORD,   CWORD,   CWORD,
12313       CNL,     CWORD,   CWORD,   CWORD,
12314       CWORD,   CWORD,   CWORD,   CWORD,
12315       CWORD,   CWORD,   CWORD,   CWORD,
12316       CWORD,   CWORD,   CWORD,   CWORD,
12317       CWORD,   CWORD,   CWORD,   CWORD,
12318       CWORD,   CWORD,   CWORD,   CWORD,
12319       CDQUOTE, CWORD,   CVAR,    CWORD,
12320       CWORD,   CSQUOTE, CLP,     CRP,
12321       CWORD,   CWORD,   CWORD,   CWORD,
12322       CWORD,   CWORD,   CWORD,   CWORD,
12323       CWORD,   CWORD,   CWORD,   CWORD,
12324       CWORD,   CWORD,   CWORD,   CWORD,
12325       CWORD,   CWORD,   CWORD,   CWORD,
12326       CWORD,   CWORD,   CWORD,   CWORD,
12327       CWORD,   CWORD,   CWORD,   CWORD,
12328       CWORD,   CWORD,   CWORD,   CWORD,
12329       CWORD,   CWORD,   CWORD,   CWORD,
12330       CWORD,   CWORD,   CWORD,   CWORD,
12331       CWORD,   CWORD,   CWORD,   CWORD,
12332       CWORD,   CWORD,   CWORD,   CWORD,
12333       CWORD,   CWORD,   CBACK,   CWORD,
12334       CWORD,   CWORD,   CBQUOTE, CWORD,
12335       CWORD,   CWORD,   CWORD,   CWORD,
12336       CWORD,   CWORD,   CWORD,   CWORD,
12337       CWORD,   CWORD,   CWORD,   CWORD,
12338       CWORD,   CWORD,   CWORD,   CWORD,
12339       CWORD,   CWORD,   CWORD,   CWORD,
12340       CWORD,   CWORD,   CWORD,   CWORD,
12341       CWORD,   CWORD,   CWORD,   CENDVAR,
12342       CWORD
12343 };
12344
12345 /* character classification table */
12346 static const char is_type[257] = {
12347       0,       0,       0,       0,
12348       0,       0,       0,       0,
12349       0,       0,       0,       0,
12350       0,       0,       0,       0,
12351       0,       0,       0,       0,
12352       0,       0,       0,       0,
12353       0,       0,       0,       0,
12354       0,       0,       0,       0,
12355       0,       0,       0,       0,
12356       0,       0,       0,       0,
12357       0,       0,       0,       0,
12358       0,       0,       0,       0,
12359       0,       0,       0,       0,
12360       0,       0,       0,       0,
12361       0,       0,       0,       0,
12362       0,       0,       0,       0,
12363       0,       0,       0,       0,
12364       0,       0,       0,       0,
12365       0,       0,       0,       0,
12366       0,       0,       0,       0,
12367       0,       0,       0,       0,
12368       0,       0,       0,       0,
12369       0,       0,       0,       0,
12370       0,       0,       0,       0,
12371       0,       0,       0,       0,
12372       0,       0,       0,       0,
12373       0,       0,       0,       0,
12374       0,       0,       0,       0,
12375       0,       0,       0,       0,
12376       0,       0,       0,       0,
12377       0,       0,       0,       0,
12378       0,       0,       0,       0,
12379       0,       0,       0,       0,
12380       0,       0,       0,       0,
12381       0,       0,       0,       0,
12382       0,       0,       0,       0,
12383       0,       0,       0,       0,
12384       0,       0,       0,       0,
12385       0,       0,       0,       0,
12386       0,       0,       0,       0,
12387       0,       0,       0,       ISSPECL,
12388       0,       ISSPECL, ISSPECL, 0,
12389       0,       0,       0,       0,
12390       ISSPECL, 0,       0,       ISSPECL,
12391       0,       0,       ISDIGIT, ISDIGIT,
12392       ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
12393       ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
12394       0,       0,       0,       0,
12395       0,       ISSPECL, ISSPECL, ISUPPER,
12396       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12397       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12398       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12399       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12400       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12401       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12402       ISUPPER, 0,       0,       0,
12403       0,       ISUNDER, 0,       ISLOWER,
12404       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12405       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12406       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12407       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12408       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12409       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12410       ISLOWER, 0,       0,       0,
12411       0
12412 };
12413 /*      $NetBSD: trap.c,v 1.25 2001/02/04 19:52:07 christos Exp $       */
12414
12415 /*
12416  * The trap builtin.
12417  */
12418
12419 static int
12420 trapcmd(argc, argv)
12421         int argc;
12422         char **argv;
12423 {
12424         char *action;
12425         char **ap;
12426         int signo;
12427
12428         if (argc <= 1) {
12429                 for (signo = 0 ; signo < NSIG ; signo++) {
12430                         if (trap[signo] != NULL) {
12431                                 char *p;
12432
12433                                 p = single_quote(trap[signo]);
12434                                 out1fmt("trap -- %s %s\n", p,
12435                                         signal_names[signo] + (signo ? 3 : 0)
12436                                 );
12437                                 stunalloc(p);
12438                         }
12439                 }
12440                 return 0;
12441         }
12442         ap = argv + 1;
12443         if (argc == 2)
12444                 action = NULL;
12445         else
12446                 action = *ap++;
12447         while (*ap) {
12448                 if ((signo = decode_signal(*ap, 0)) < 0)
12449                         error("%s: bad trap", *ap);
12450                 INTOFF;
12451                 if (action) {
12452                         if (action[0] == '-' && action[1] == '\0')
12453                                 action = NULL;
12454                         else
12455                                 action = savestr(action);
12456                 }
12457                 if (trap[signo])
12458                         ckfree(trap[signo]);
12459                 trap[signo] = action;
12460                 if (signo != 0)
12461                         setsignal(signo);
12462                 INTON;
12463                 ap++;
12464         }
12465         return 0;
12466 }
12467
12468
12469
12470 /*
12471  * Clear traps on a fork.
12472  */
12473
12474 static void
12475 clear_traps() {
12476         char **tp;
12477
12478         for (tp = trap ; tp < &trap[NSIG] ; tp++) {
12479                 if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
12480                         INTOFF;
12481                         ckfree(*tp);
12482                         *tp = NULL;
12483                         if (tp != &trap[0])
12484                                 setsignal(tp - trap);
12485                         INTON;
12486                 }
12487         }
12488 }
12489
12490
12491
12492 /*
12493  * Set the signal handler for the specified signal.  The routine figures
12494  * out what it should be set to.
12495  */
12496
12497 static void
12498 setsignal(signo)
12499         int signo;
12500 {
12501         int action;
12502         char *t;
12503         struct sigaction act;
12504
12505         if ((t = trap[signo]) == NULL)
12506                 action = S_DFL;
12507         else if (*t != '\0')
12508                 action = S_CATCH;
12509         else
12510                 action = S_IGN;
12511         if (rootshell && action == S_DFL) {
12512                 switch (signo) {
12513                 case SIGINT:
12514                         if (iflag || minusc || sflag == 0)
12515                                 action = S_CATCH;
12516                         break;
12517                 case SIGQUIT:
12518 #ifdef DEBUG
12519                         {
12520                         extern int debug;
12521
12522                         if (debug)
12523                                 break;
12524                         }
12525 #endif
12526                         /* FALLTHROUGH */
12527                 case SIGTERM:
12528                         if (iflag)
12529                                 action = S_IGN;
12530                         break;
12531 #if JOBS
12532                 case SIGTSTP:
12533                 case SIGTTOU:
12534                         if (mflag)
12535                                 action = S_IGN;
12536                         break;
12537 #endif
12538                 }
12539         }
12540
12541         t = &sigmode[signo - 1];
12542         if (*t == 0) {
12543                 /*
12544                  * current setting unknown
12545                  */
12546                 if (sigaction(signo, 0, &act) == -1) {
12547                         /*
12548                          * Pretend it worked; maybe we should give a warning
12549                          * here, but other shells don't. We don't alter
12550                          * sigmode, so that we retry every time.
12551                          */
12552                         return;
12553                 }
12554                 if (act.sa_handler == SIG_IGN) {
12555                         if (mflag && (signo == SIGTSTP ||
12556                              signo == SIGTTIN || signo == SIGTTOU)) {
12557                                 *t = S_IGN;     /* don't hard ignore these */
12558                         } else
12559                                 *t = S_HARD_IGN;
12560                 } else {
12561                         *t = S_RESET;   /* force to be set */
12562                 }
12563         }
12564         if (*t == S_HARD_IGN || *t == action)
12565                 return;
12566         switch (action) {
12567         case S_CATCH:
12568                 act.sa_handler = onsig;
12569                 break;
12570         case S_IGN:
12571                 act.sa_handler = SIG_IGN;
12572                 break;
12573         default:
12574                 act.sa_handler = SIG_DFL;
12575         }
12576         *t = action;
12577         act.sa_flags = 0;
12578         sigemptyset(&act.sa_mask);
12579         sigaction(signo, &act, 0);
12580 }
12581
12582 /*
12583  * Ignore a signal.
12584  */
12585
12586 static void
12587 ignoresig(signo)
12588         int signo;
12589 {
12590         if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12591                 signal(signo, SIG_IGN);
12592         }
12593         sigmode[signo - 1] = S_HARD_IGN;
12594 }
12595
12596
12597 #ifdef mkinit
12598 INCLUDE <signal.h>
12599 INCLUDE "trap.h"
12600
12601 SHELLPROC {
12602         char *sm;
12603
12604         clear_traps();
12605         for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
12606                 if (*sm == S_IGN)
12607                         *sm = S_HARD_IGN;
12608         }
12609 }
12610 #endif
12611
12612
12613
12614 /*
12615  * Signal handler.
12616  */
12617
12618 static void
12619 onsig(signo)
12620         int signo;
12621 {
12622         if (signo == SIGINT && trap[SIGINT] == NULL) {
12623                 onint();
12624                 return;
12625         }
12626         gotsig[signo - 1] = 1;
12627         pendingsigs++;
12628 }
12629
12630
12631
12632 /*
12633  * Called to execute a trap.  Perhaps we should avoid entering new trap
12634  * handlers while we are executing a trap handler.
12635  */
12636
12637 static void
12638 dotrap() {
12639         int i;
12640         int savestatus;
12641
12642         for (;;) {
12643                 for (i = 1 ; ; i++) {
12644                         if (gotsig[i - 1])
12645                                 break;
12646                         if (i >= NSIG - 1)
12647                                 goto done;
12648                 }
12649                 gotsig[i - 1] = 0;
12650                 savestatus=exitstatus;
12651                 evalstring(trap[i], 0);
12652                 exitstatus=savestatus;
12653         }
12654 done:
12655         pendingsigs = 0;
12656 }
12657
12658
12659
12660 /*
12661  * Controls whether the shell is interactive or not.
12662  */
12663
12664
12665 static void
12666 setinteractive(on)
12667         int on;
12668 {
12669         static int is_interactive;
12670
12671         if (on == is_interactive)
12672                 return;
12673         setsignal(SIGINT);
12674         setsignal(SIGQUIT);
12675         setsignal(SIGTERM);
12676         chkmail(1);
12677         is_interactive = on;
12678 }
12679
12680
12681
12682 /*
12683  * Called to exit the shell.
12684  */
12685
12686 static void
12687 exitshell(status)
12688         int status;
12689 {
12690         struct jmploc loc1, loc2;
12691         char *p;
12692
12693         TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12694         if (setjmp(loc1.loc)) {
12695                 goto l1;
12696         }
12697         if (setjmp(loc2.loc)) {
12698                 goto l2;
12699         }
12700         handler = &loc1;
12701         if ((p = trap[0]) != NULL && *p != '\0') {
12702                 trap[0] = NULL;
12703                 evalstring(p, 0);
12704         }
12705 l1:   handler = &loc2;                  /* probably unnecessary */
12706         flushall();
12707 #if JOBS
12708         setjobctl(0);
12709 #endif
12710 l2:   _exit(status);
12711         /* NOTREACHED */
12712 }
12713
12714 static int decode_signal(const char *string, int minsig)
12715 {
12716         int signo;
12717
12718         if (is_number(string)) {
12719                 signo = atoi(string);
12720                 if (signo >= NSIG) {
12721                         return -1;
12722                 }
12723                 return signo;
12724         }
12725
12726         signo = minsig;
12727         if (!signo) {
12728                 goto zero;
12729         }
12730         for (; signo < NSIG; signo++) {
12731                 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12732                         return signo;
12733                 }
12734 zero:
12735                 if (!strcasecmp(string, signal_names[signo])) {
12736                         return signo;
12737                 }
12738         }
12739
12740         return -1;
12741 }
12742 /*      $NetBSD: var.c,v 1.27 2001/02/04 19:52:07 christos Exp $        */
12743
12744 #define VTABSIZE 39
12745
12746
12747 struct varinit {
12748         struct var *var;
12749         int flags;
12750         const char *text;
12751         void (*func) __P((const char *));
12752 };
12753
12754 struct localvar *localvars;
12755
12756 #if ATTY
12757 struct var vatty;
12758 #endif
12759 struct var vifs;
12760 struct var vmail;
12761 struct var vmpath;
12762 struct var vpath;
12763 struct var vps1;
12764 struct var vps2;
12765 struct var vvers;
12766 struct var voptind;
12767
12768 static const char defpathvar[] =
12769         "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
12770 #ifdef IFS_BROKEN
12771 static const char defifsvar[] = "IFS= \t\n";
12772 #else
12773 static const char defifs[] = " \t\n";
12774 #endif
12775
12776 static const struct varinit varinit[] = {
12777 #if ATTY
12778         { &vatty,       VSTRFIXED|VTEXTFIXED|VUNSET,    "ATTY=",
12779           NULL },
12780 #endif
12781 #ifdef IFS_BROKEN
12782         { &vifs,        VSTRFIXED|VTEXTFIXED,           defifsvar,
12783 #else
12784         { &vifs,        VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS=",
12785 #endif
12786           NULL },
12787         { &vmail,       VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL=",
12788           NULL },
12789         { &vmpath,      VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH=",
12790           NULL },
12791         { &vpath,       VSTRFIXED|VTEXTFIXED,           defpathvar,
12792           changepath },
12793         /*
12794          * vps1 depends on uid
12795          */
12796         { &vps2,        VSTRFIXED|VTEXTFIXED,           "PS2=> ",
12797           NULL },
12798         { &voptind,     VSTRFIXED|VTEXTFIXED,           "OPTIND=1",
12799           getoptsreset },
12800         { NULL, 0,                              NULL,
12801           NULL }
12802 };
12803
12804 struct var *vartab[VTABSIZE];
12805
12806 static struct var **hashvar __P((const char *));
12807 static void showvars __P((const char *, int, int));
12808 static struct var **findvar __P((struct var **, const char *));
12809
12810 /*
12811  * Initialize the varable symbol tables and import the environment
12812  */
12813
12814 #ifdef mkinit
12815 INCLUDE <unistd.h>
12816 INCLUDE "output.h"
12817 INCLUDE "var.h"
12818 static char **environ;
12819 INIT {
12820         char **envp;
12821         char ppid[32];
12822
12823         initvar();
12824         for (envp = environ ; *envp ; envp++) {
12825                 if (strchr(*envp, '=')) {
12826                         setvareq(*envp, VEXPORT|VTEXTFIXED);
12827                 }
12828         }
12829
12830         fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
12831         setvar("PPID", ppid, 0);
12832 }
12833 #endif
12834
12835
12836 /*
12837  * This routine initializes the builtin variables.  It is called when the
12838  * shell is initialized and again when a shell procedure is spawned.
12839  */
12840
12841 static void
12842 initvar() {
12843         const struct varinit *ip;
12844         struct var *vp;
12845         struct var **vpp;
12846
12847         for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12848                 if ((vp->flags & VEXPORT) == 0) {
12849                         vpp = hashvar(ip->text);
12850                         vp->next = *vpp;
12851                         *vpp = vp;
12852                         vp->text = strdup(ip->text);
12853                         vp->flags = ip->flags;
12854                         vp->func = ip->func;
12855                 }
12856         }
12857         /*
12858          * PS1 depends on uid
12859          */
12860         if ((vps1.flags & VEXPORT) == 0) {
12861                 vpp = hashvar("PS1=");
12862                 vps1.next = *vpp;
12863                 *vpp = &vps1;
12864                 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12865                 vps1.flags = VSTRFIXED|VTEXTFIXED;
12866         }
12867 }
12868
12869 /*
12870  * Set the value of a variable.  The flags argument is ored with the
12871  * flags of the variable.  If val is NULL, the variable is unset.
12872  */
12873
12874 static void
12875 setvar(name, val, flags)
12876         const char *name, *val;
12877         int flags;
12878 {
12879         const char *p;
12880         int len;
12881         int namelen;
12882         char *nameeq;
12883         int isbad;
12884         int vallen = 0;
12885
12886         isbad = 0;
12887         p = name;
12888         if (! is_name(*p))
12889                 isbad = 1;
12890         p++;
12891         for (;;) {
12892                 if (! is_in_name(*p)) {
12893                         if (*p == '\0' || *p == '=')
12894                                 break;
12895                         isbad = 1;
12896                 }
12897                 p++;
12898         }
12899         namelen = p - name;
12900         if (isbad)
12901                 error("%.*s: bad variable name", namelen, name);
12902         len = namelen + 2;              /* 2 is space for '=' and '\0' */
12903         if (val == NULL) {
12904                 flags |= VUNSET;
12905         } else {
12906                 len += vallen = strlen(val);
12907         }
12908         INTOFF;
12909         nameeq = ckmalloc(len);
12910         memcpy(nameeq, name, namelen);
12911         nameeq[namelen] = '=';
12912         if (val) {
12913                 memcpy(nameeq + namelen + 1, val, vallen + 1);
12914         } else {
12915                 nameeq[namelen + 1] = '\0';
12916         }
12917         setvareq(nameeq, flags);
12918         INTON;
12919 }
12920
12921
12922
12923 /*
12924  * Same as setvar except that the variable and value are passed in
12925  * the first argument as name=value.  Since the first argument will
12926  * be actually stored in the table, it should not be a string that
12927  * will go away.
12928  */
12929
12930 static void
12931 setvareq(s, flags)
12932         char *s;
12933         int flags;
12934 {
12935         struct var *vp, **vpp;
12936
12937         vpp = hashvar(s);
12938         flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12939         if ((vp = *findvar(vpp, s))) {
12940                 if (vp->flags & VREADONLY) {
12941                         size_t len = strchr(s, '=') - s;
12942                         error("%.*s: is read only", len, s);
12943                 }
12944                 INTOFF;
12945
12946                 if (vp->func && (flags & VNOFUNC) == 0)
12947                         (*vp->func)(strchr(s, '=') + 1);
12948
12949                 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12950                         ckfree(vp->text);
12951
12952                 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12953                 vp->flags |= flags;
12954                 vp->text = s;
12955
12956                 /*
12957                  * We could roll this to a function, to handle it as
12958                  * a regular variable function callback, but why bother?
12959                  */
12960                 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12961                         chkmail(1);
12962                 INTON;
12963                 return;
12964         }
12965         /* not found */
12966         vp = ckmalloc(sizeof (*vp));
12967         vp->flags = flags;
12968         vp->text = s;
12969         vp->next = *vpp;
12970         vp->func = NULL;
12971         *vpp = vp;
12972 }
12973
12974
12975
12976 /*
12977  * Process a linked list of variable assignments.
12978  */
12979
12980 static void
12981 listsetvar(mylist)
12982         struct strlist *mylist;
12983         {
12984         struct strlist *lp;
12985
12986         INTOFF;
12987         for (lp = mylist ; lp ; lp = lp->next) {
12988                 setvareq(savestr(lp->text), 0);
12989         }
12990         INTON;
12991 }
12992
12993
12994
12995 /*
12996  * Find the value of a variable.  Returns NULL if not set.
12997  */
12998
12999 static char *
13000 lookupvar(name)
13001         const char *name;
13002         {
13003         struct var *v;
13004
13005         if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
13006                 return strchr(v->text, '=') + 1;
13007         }
13008         return NULL;
13009 }
13010
13011
13012
13013 /*
13014  * Search the environment of a builtin command.
13015  */
13016
13017 static char *
13018 bltinlookup(name)
13019         const char *name;
13020 {
13021         struct strlist *sp;
13022
13023         for (sp = cmdenviron ; sp ; sp = sp->next) {
13024                 if (varequal(sp->text, name))
13025                         return strchr(sp->text, '=') + 1;
13026         }
13027         return lookupvar(name);
13028 }
13029
13030
13031
13032 /*
13033  * Generate a list of exported variables.  This routine is used to construct
13034  * the third argument to execve when executing a program.
13035  */
13036
13037 static char **
13038 environment() {
13039         int nenv;
13040         struct var **vpp;
13041         struct var *vp;
13042         char **env;
13043         char **ep;
13044
13045         nenv = 0;
13046         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13047                 for (vp = *vpp ; vp ; vp = vp->next)
13048                         if (vp->flags & VEXPORT)
13049                                 nenv++;
13050         }
13051         ep = env = stalloc((nenv + 1) * sizeof *env);
13052         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13053                 for (vp = *vpp ; vp ; vp = vp->next)
13054                         if (vp->flags & VEXPORT)
13055                                 *ep++ = vp->text;
13056         }
13057         *ep = NULL;
13058         return env;
13059 }
13060
13061
13062 /*
13063  * Called when a shell procedure is invoked to clear out nonexported
13064  * variables.  It is also necessary to reallocate variables of with
13065  * VSTACK set since these are currently allocated on the stack.
13066  */
13067
13068 #ifdef mkinit
13069 static void shprocvar __P((void));
13070
13071 SHELLPROC {
13072         shprocvar();
13073 }
13074 #endif
13075
13076 static void
13077 shprocvar() {
13078         struct var **vpp;
13079         struct var *vp, **prev;
13080
13081         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13082                 for (prev = vpp ; (vp = *prev) != NULL ; ) {
13083                         if ((vp->flags & VEXPORT) == 0) {
13084                                 *prev = vp->next;
13085                                 if ((vp->flags & VTEXTFIXED) == 0)
13086                                         ckfree(vp->text);
13087                                 if ((vp->flags & VSTRFIXED) == 0)
13088                                         ckfree(vp);
13089                         } else {
13090                                 if (vp->flags & VSTACK) {
13091                                         vp->text = savestr(vp->text);
13092                                         vp->flags &=~ VSTACK;
13093                                 }
13094                                 prev = &vp->next;
13095                         }
13096                 }
13097         }
13098         initvar();
13099 }
13100
13101
13102
13103 /*
13104  * Command to list all variables which are set.  Currently this command
13105  * is invoked from the set command when the set command is called without
13106  * any variables.
13107  */
13108
13109 static int
13110 showvarscmd(argc, argv)
13111         int argc;
13112         char **argv;
13113 {
13114         showvars(nullstr, VUNSET, VUNSET);
13115         return 0;
13116 }
13117
13118
13119
13120 /*
13121  * The export and readonly commands.
13122  */
13123
13124 static int
13125 exportcmd(argc, argv)
13126         int argc;
13127         char **argv;
13128 {
13129         struct var *vp;
13130         char *name;
13131         const char *p;
13132         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
13133         int pflag;
13134
13135         listsetvar(cmdenviron);
13136         pflag = (nextopt("p") == 'p');
13137         if (argc > 1 && !pflag) {
13138                 while ((name = *argptr++) != NULL) {
13139                         if ((p = strchr(name, '=')) != NULL) {
13140                                 p++;
13141                         } else {
13142                                 if ((vp = *findvar(hashvar(name), name))) {
13143                                         vp->flags |= flag;
13144                                         goto found;
13145                                 }
13146                         }
13147                         setvar(name, p, flag);
13148 found:;
13149                 }
13150         } else {
13151                 showvars(argv[0], flag, 0);
13152         }
13153         return 0;
13154 }
13155
13156
13157 /*
13158  * The "local" command.
13159  */
13160
13161 static int
13162 localcmd(argc, argv)
13163         int argc;
13164         char **argv;
13165 {
13166         char *name;
13167
13168         if (! in_function())
13169                 error("Not in a function");
13170         while ((name = *argptr++) != NULL) {
13171                 mklocal(name);
13172         }
13173         return 0;
13174 }
13175
13176
13177 /*
13178  * Make a variable a local variable.  When a variable is made local, it's
13179  * value and flags are saved in a localvar structure.  The saved values
13180  * will be restored when the shell function returns.  We handle the name
13181  * "-" as a special case.
13182  */
13183
13184 static void
13185 mklocal(name)
13186         char *name;
13187         {
13188         struct localvar *lvp;
13189         struct var **vpp;
13190         struct var *vp;
13191
13192         INTOFF;
13193         lvp = ckmalloc(sizeof (struct localvar));
13194         if (name[0] == '-' && name[1] == '\0') {
13195                 char *p;
13196                 p = ckmalloc(sizeof optlist);
13197                 lvp->text = memcpy(p, optlist, sizeof optlist);
13198                 vp = NULL;
13199         } else {
13200                 vpp = hashvar(name);
13201                 vp = *findvar(vpp, name);
13202                 if (vp == NULL) {
13203                         if (strchr(name, '='))
13204                                 setvareq(savestr(name), VSTRFIXED);
13205                         else
13206                                 setvar(name, NULL, VSTRFIXED);
13207                         vp = *vpp;      /* the new variable */
13208                         lvp->text = NULL;
13209                         lvp->flags = VUNSET;
13210                 } else {
13211                         lvp->text = vp->text;
13212                         lvp->flags = vp->flags;
13213                         vp->flags |= VSTRFIXED|VTEXTFIXED;
13214                         if (strchr(name, '='))
13215                                 setvareq(savestr(name), 0);
13216                 }
13217         }
13218         lvp->vp = vp;
13219         lvp->next = localvars;
13220         localvars = lvp;
13221         INTON;
13222 }
13223
13224
13225 /*
13226  * Called after a function returns.
13227  */
13228
13229 static void
13230 poplocalvars() {
13231         struct localvar *lvp;
13232         struct var *vp;
13233
13234         while ((lvp = localvars) != NULL) {
13235                 localvars = lvp->next;
13236                 vp = lvp->vp;
13237                 if (vp == NULL) {       /* $- saved */
13238                         memcpy(optlist, lvp->text, sizeof optlist);
13239                         ckfree(lvp->text);
13240                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
13241                         (void)unsetvar(vp->text);
13242                 } else {
13243                         if ((vp->flags & VTEXTFIXED) == 0)
13244                                 ckfree(vp->text);
13245                         vp->flags = lvp->flags;
13246                         vp->text = lvp->text;
13247                 }
13248                 ckfree(lvp);
13249         }
13250 }
13251
13252
13253 static int
13254 setvarcmd(argc, argv)
13255         int argc;
13256         char **argv;
13257 {
13258         if (argc <= 2)
13259                 return unsetcmd(argc, argv);
13260         else if (argc == 3)
13261                 setvar(argv[1], argv[2], 0);
13262         else
13263                 error("List assignment not implemented");
13264         return 0;
13265 }
13266
13267
13268 /*
13269  * The unset builtin command.  We unset the function before we unset the
13270  * variable to allow a function to be unset when there is a readonly variable
13271  * with the same name.
13272  */
13273
13274 static int
13275 unsetcmd(argc, argv)
13276         int argc;
13277         char **argv;
13278 {
13279         char **ap;
13280         int i;
13281         int flg_func = 0;
13282         int flg_var = 0;
13283         int ret = 0;
13284
13285         while ((i = nextopt("vf")) != '\0') {
13286                 if (i == 'f')
13287                         flg_func = 1;
13288                 else
13289                         flg_var = 1;
13290         }
13291         if (flg_func == 0 && flg_var == 0)
13292                 flg_var = 1;
13293
13294         for (ap = argptr; *ap ; ap++) {
13295                 if (flg_func)
13296                         unsetfunc(*ap);
13297                 if (flg_var)
13298                         ret |= unsetvar(*ap);
13299         }
13300         return ret;
13301 }
13302
13303
13304 /*
13305  * Unset the specified variable.
13306  */
13307
13308 static int
13309 unsetvar(s)
13310         const char *s;
13311         {
13312         struct var **vpp;
13313         struct var *vp;
13314
13315         vpp = findvar(hashvar(s), s);
13316         vp = *vpp;
13317         if (vp) {
13318                 if (vp->flags & VREADONLY)
13319                         return (1);
13320                 INTOFF;
13321                 if (*(strchr(vp->text, '=') + 1) != '\0')
13322                         setvar(s, nullstr, 0);
13323                 vp->flags &= ~VEXPORT;
13324                 vp->flags |= VUNSET;
13325                 if ((vp->flags & VSTRFIXED) == 0) {
13326                         if ((vp->flags & VTEXTFIXED) == 0)
13327                                 ckfree(vp->text);
13328                         *vpp = vp->next;
13329                         ckfree(vp);
13330                 }
13331                 INTON;
13332                 return (0);
13333         }
13334
13335         return (0);
13336 }
13337
13338
13339
13340 /*
13341  * Find the appropriate entry in the hash table from the name.
13342  */
13343
13344 static struct var **
13345 hashvar(p)
13346         const char *p;
13347         {
13348         unsigned int hashval;
13349
13350         hashval = ((unsigned char) *p) << 4;
13351         while (*p && *p != '=')
13352                 hashval += (unsigned char) *p++;
13353         return &vartab[hashval % VTABSIZE];
13354 }
13355
13356
13357
13358 /*
13359  * Returns true if the two strings specify the same varable.  The first
13360  * variable name is terminated by '='; the second may be terminated by
13361  * either '=' or '\0'.
13362  */
13363
13364 static int
13365 varequal(p, q)
13366         const char *p, *q;
13367         {
13368         while (*p == *q++) {
13369                 if (*p++ == '=')
13370                         return 1;
13371         }
13372         if (*p == '=' && *(q - 1) == '\0')
13373                 return 1;
13374         return 0;
13375 }
13376
13377 static void
13378 showvars(const char *myprefix, int mask, int xor)
13379 {
13380         struct var **vpp;
13381         struct var *vp;
13382         const char *sep = myprefix == nullstr ? myprefix : spcstr;
13383
13384         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13385                 for (vp = *vpp ; vp ; vp = vp->next) {
13386                         if ((vp->flags & mask) ^ xor) {
13387                                 char *p;
13388                                 int len;
13389
13390                                 p = strchr(vp->text, '=') + 1;
13391                                 len = p - vp->text;
13392                                 p = single_quote(p);
13393
13394                                 out1fmt(
13395                                         "%s%s%.*s%s\n", myprefix, sep, len,
13396                                         vp->text, p
13397                                 );
13398                                 stunalloc(p);
13399                         }
13400                 }
13401         }
13402 }
13403
13404 static struct var **
13405 findvar(struct var **vpp, const char *name)
13406 {
13407         for (; *vpp; vpp = &(*vpp)->next) {
13408                 if (varequal((*vpp)->text, name)) {
13409                         break;
13410                 }
13411         }
13412         return vpp;
13413 }
13414
13415 /*
13416  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13417  * This file contains code for the times builtin.
13418  * $Id: ash.c,v 1.3 2001/06/28 16:43:57 andersen Exp $
13419  */
13420 static int timescmd (int argc, char **argv)
13421 {
13422         struct tms buf;
13423         long int clk_tck = sysconf(_SC_CLK_TCK);
13424
13425         times(&buf);
13426         printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
13427                (int) (buf.tms_utime / clk_tck / 60),
13428                ((double) buf.tms_utime) / clk_tck,
13429                (int) (buf.tms_stime / clk_tck / 60),
13430                ((double) buf.tms_stime) / clk_tck,
13431                (int) (buf.tms_cutime / clk_tck / 60),
13432                ((double) buf.tms_cutime) / clk_tck,
13433                (int) (buf.tms_cstime / clk_tck / 60),
13434                ((double) buf.tms_cstime) / clk_tck);
13435         return 0;
13436 }
13437
13438
13439 /*-
13440  * Copyright (c) 1989, 1991, 1993, 1994
13441  *      The Regents of the University of California.  All rights reserved.
13442  *
13443  * This code is derived from software contributed to Berkeley by
13444  * Kenneth Almquist.
13445  *
13446  * Redistribution and use in source and binary forms, with or without
13447  * modification, are permitted provided that the following conditions
13448  * are met:
13449  * 1. Redistributions of source code must retain the above copyright
13450  *    notice, this list of conditions and the following disclaimer.
13451  * 2. Redistributions in binary form must reproduce the above copyright
13452  *    notice, this list of conditions and the following disclaimer in the
13453  *    documentation and/or other materials provided with the distribution.
13454  *
13455  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
13456  *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
13457  *
13458  * 4. Neither the name of the University nor the names of its contributors
13459  *    may be used to endorse or promote products derived from this software
13460  *    without specific prior written permission.
13461  *
13462  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13463  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13464  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13465  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13466  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13467  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13468  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13469  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13470  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13471  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13472  * SUCH DAMAGE.
13473  */